82bf0e4dfe6035d844d6b937d3217cafdcbf046d
[platform/upstream/coreclr.git] / src / vm / corhost.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 // CorHost.cpp
6 //
7 // Implementation for the meta data dispenser code.
8 //
9
10 //*****************************************************************************
11
12 #include "common.h"
13
14 #include "mscoree.h"
15 #include "corhost.h"
16 #include "excep.h"
17 #include "threads.h"
18 #include "jitinterface.h"
19 #include "eeconfig.h"
20 #include "dbginterface.h"
21 #include "ceemain.h"
22 #include "hosting.h"
23 #include "eepolicy.h"
24 #include "clrex.h"
25 #include "comcallablewrapper.h"
26 #include "invokeutil.h"
27 #include "appdomain.inl"
28 #include "vars.hpp"
29 #include "comdelegate.h"
30 #include "dllimportcallback.h"
31 #include "eventtrace.h"
32
33 #include "win32threadpool.h"
34 #include "eventtrace.h"
35 #include "finalizerthread.h"
36 #include "threadsuspend.h"
37
38 #ifndef FEATURE_PAL
39 #include "dwreport.h"
40 #endif // !FEATURE_PAL
41
42 #include "stringarraylist.h"
43 #ifdef FEATURE_PERFTRACING
44 #include "eventpipe.h"
45 #endif // FEATURE_PERFTRACING
46
47 #ifdef FEATURE_COMINTEROP
48 #include "winrttypenameconverter.h"
49 #endif
50
51
52 GVAL_IMPL_INIT(DWORD, g_fHostConfig, 0);
53
54 #ifndef __GNUC__
55 EXTERN_C __declspec(thread) ThreadLocalInfo gCurrentThreadInfo;
56 #else // !__GNUC__
57 EXTERN_C __thread ThreadLocalInfo gCurrentThreadInfo;
58 #endif // !__GNUC__
59 #ifndef FEATURE_PAL
60 EXTERN_C UINT32 _tls_index;
61 #else // FEATURE_PAL
62 UINT32 _tls_index = 0;
63 #endif // FEATURE_PAL
64
65 #if defined(FEATURE_WINDOWSPHONE)
66 SVAL_IMPL_INIT(ECustomDumpFlavor, CCLRErrorReportingManager, g_ECustomDumpFlavor, DUMP_FLAVOR_Default);
67 #endif
68
69 #ifndef DACCESS_COMPILE
70
71 extern void STDMETHODCALLTYPE EEShutDown(BOOL fIsDllUnloading);
72 extern HRESULT STDAPICALLTYPE CoInitializeEE(DWORD fFlags);
73 extern void PrintToStdOutA(const char *pszString);
74 extern void PrintToStdOutW(const WCHAR *pwzString);
75 extern BOOL g_fEEHostedStartup;
76
77 INT64 g_PauseTime;         // Total time in millisecond the CLR has been paused
78 Volatile<BOOL> g_IsPaused;  // True if the runtime is paused (FAS)
79 CLREventStatic g_ClrResumeEvent; // Event that is fired at FAS Resuming 
80
81 extern BYTE g_rbTestKeyBuffer[];
82
83 //***************************************************************************
84
85 ULONG CorRuntimeHostBase::m_Version = 0;
86
87
88 #if defined(FEATURE_WINDOWSPHONE)
89 CCLRErrorReportingManager g_CLRErrorReportingManager;
90 #endif // defined(FEATURE_WINDOWSPHONE)
91
92 #endif // !DAC
93
94 typedef DPTR(CONNID)   PTR_CONNID;
95
96
97
98 // Keep track connection id and name
99
100 #ifndef DACCESS_COMPILE
101
102
103
104
105 // *** ICorRuntimeHost methods ***
106
107 CorHost2::CorHost2() : m_fFirstToLoadCLR(FALSE), m_fStarted(FALSE), m_fAppDomainCreated(FALSE)
108 {
109     LIMITED_METHOD_CONTRACT;
110 }
111
112 static DangerousNonHostedSpinLock lockOnlyOneToInvokeStart;
113
114 STDMETHODIMP CorHost2::Start()
115 {
116     CONTRACTL
117     {
118         NOTHROW;
119         GC_TRIGGERS;
120         ENTRY_POINT;
121     }CONTRACTL_END;
122
123     HRESULT hr;
124
125     BEGIN_ENTRYPOINT_NOTHROW;
126
127     // Ensure that only one thread at a time gets in here
128     DangerousNonHostedSpinLockHolder lockHolder(&lockOnlyOneToInvokeStart);
129         
130     // To provide the complete semantic of Start/Stop in context of a given host, we check m_fStarted and let
131     // them invoke the Start only if they have not already. Likewise, they can invoke the Stop method
132     // only if they have invoked Start prior to that.
133     //
134     // This prevents a host from invoking Stop twice and hitting the refCount to zero, when another
135     // host is using the CLR, as CLR instance sharing across hosts is a scenario for CoreCLR.
136
137     if (g_fEEStarted)
138     {
139         hr = S_OK;
140         // CoreCLR is already running - but was Start already invoked by this host?
141         if (m_fStarted)
142         {
143             // This host had already invoked the Start method - return them an error
144             hr = HOST_E_INVALIDOPERATION;
145         }
146         else
147         {
148             // Increment the global (and dynamic) refCount...
149             FastInterlockIncrement(&m_RefCount);
150
151             // And set our flag that this host has invoked the Start...
152             m_fStarted = TRUE;
153         }
154     }
155     else
156     {
157         // Using managed C++ libraries, its possible that when the runtime is already running,
158         // MC++ will use CorBindToRuntimeEx to make callbacks into specific appdomain of its
159         // choice. Now, CorBindToRuntimeEx results in CorHost2::CreateObject being invoked
160         // that will set runtime hosted flag "g_fHostConfig |= CLRHOSTED".
161         //
162         // For the case when managed code started without CLR hosting and MC++ does a 
163         // CorBindToRuntimeEx, setting the CLR hosted flag is incorrect.
164         //
165         // Thus, before we attempt to start the runtime, we save the status of it being
166         // already running or not. Next, if we are able to successfully start the runtime
167         // and ONLY if it was not started earlier will we set the hosted flag below.
168         if (!g_fEEStarted)
169         {
170             g_fHostConfig |= CLRHOSTED;
171         }
172
173         hr = CorRuntimeHostBase::Start();
174         if (SUCCEEDED(hr))
175         {
176             // Set our flag that this host invoked the Start method.
177             m_fStarted = TRUE;
178
179             // And they also loaded the CoreCLR DLL in the memory (for this version).
180             // This is a special flag as the host that has got this flag set will be allowed
181             // to repeatedly invoke Stop method (without corresponding Start method invocations).
182             // This is to support scenarios like that of Office where they need to bring down
183             // the CLR at any cost.
184             // 
185             // So, if you want to do that, just make sure you are the first host to load the
186             // specific version of CLR in memory AND start it.
187             m_fFirstToLoadCLR = TRUE;
188             FastInterlockIncrement(&m_RefCount);
189         }
190     }
191
192     END_ENTRYPOINT_NOTHROW;
193     return hr;
194 }
195
196 // Starts the runtime. This is equivalent to CoInitializeEE();
197 HRESULT CorRuntimeHostBase::Start()
198 {
199     CONTRACTL
200     {
201         NOTHROW;
202         DISABLED(GC_TRIGGERS);
203         ENTRY_POINT;
204     }
205     CONTRACTL_END;
206
207     HRESULT hr = S_OK;
208
209     BEGIN_ENTRYPOINT_NOTHROW;
210     {
211         m_Started = TRUE;
212 #ifdef FEATURE_EVENT_TRACE
213         g_fEEHostedStartup = TRUE;
214 #endif // FEATURE_EVENT_TRACE
215         hr = InitializeEE(COINITEE_DEFAULT);
216     }
217     END_ENTRYPOINT_NOTHROW;
218
219     return hr;
220 }
221
222
223 HRESULT CorHost2::Stop()
224 {
225     CONTRACTL
226     {
227         NOTHROW;
228         ENTRY_POINT;    // We're bringing the EE down, so no point in probing
229         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
230     }
231     CONTRACTL_END;
232     if (!g_fEEStarted)
233     {
234         return E_UNEXPECTED;
235     }
236     HRESULT hr=S_OK;
237     BEGIN_ENTRYPOINT_NOTHROW;
238
239     // Is this host eligible to invoke the Stop method?
240     if ((!m_fStarted) && (!m_fFirstToLoadCLR))
241     {
242         // Well - since this host never invoked Start, it is not eligible to invoke Stop.
243         // Semantically, for such a host, CLR is not available in the process. The only
244         // exception to this condition is the host that first loaded this version of the
245         // CLR and invoked Start method. For details, refer to comments in CorHost2::Start implementation.
246         hr = HOST_E_CLRNOTAVAILABLE;
247     }
248     else
249     {
250         while (TRUE)
251         {
252             LONG refCount = m_RefCount;
253             if (refCount == 0)
254             {
255                 hr = HOST_E_CLRNOTAVAILABLE;
256                 break;
257             }
258             else
259             if (FastInterlockCompareExchange(&m_RefCount, refCount - 1, refCount) == refCount)
260             {
261                 // Indicate that we have got a Stop for a corresponding Start call from the
262                 // Host. Semantically, CoreCLR has stopped for them.
263                 m_fStarted = FALSE;
264
265                 if (refCount > 1)
266                 {
267                     hr=S_FALSE;
268                     break;
269                 }
270                 else
271                 {
272                     break;
273                 }
274             }
275         }
276     }
277     END_ENTRYPOINT_NOTHROW;
278
279
280     return hr;
281 }
282
283
284 HRESULT CorHost2::GetCurrentAppDomainId(DWORD *pdwAppDomainId)
285 {
286     CONTRACTL
287     {
288         NOTHROW;
289         GC_NOTRIGGER;
290         ENTRY_POINT;
291     }
292     CONTRACTL_END;
293
294     // No point going further if the runtime is not running...
295     // We use CanRunManagedCode() instead of IsRuntimeActive() because this allows us
296     // to specify test using the form that does not trigger a GC.
297     if (!(g_fEEStarted && CanRunManagedCode(LoaderLockCheck::None)))
298     {
299         return HOST_E_CLRNOTAVAILABLE;
300     }   
301     
302     HRESULT hr = S_OK;
303
304     BEGIN_ENTRYPOINT_NOTHROW;
305
306     if(pdwAppDomainId == NULL)
307     {
308         hr = E_POINTER;
309     }
310     else
311     {
312         Thread *pThread = GetThread();
313         if (!pThread)
314         {
315             hr = E_UNEXPECTED;
316         }
317         else
318         {
319             *pdwAppDomainId = SystemDomain::GetCurrentDomain()->GetId().m_dwId;
320         }
321     }
322
323     END_ENTRYPOINT_NOTHROW;
324
325     return hr;
326 }
327
328 HRESULT CorHost2::ExecuteApplication(LPCWSTR   pwzAppFullName,
329                                      DWORD     dwManifestPaths,
330                                      LPCWSTR   *ppwzManifestPaths,
331                                      DWORD     dwActivationData,
332                                      LPCWSTR   *ppwzActivationData,
333                                      int       *pReturnValue)
334 {
335     return E_NOTIMPL;
336 }
337
338 /*
339  * This method processes the arguments sent to the host which are then used
340  * to invoke the main method.
341  * Note -
342  * [0] - points to the assemblyName that has been sent by the host.
343  * The rest are the arguments sent to the assembly.
344  * Also note, this might not always return the exact same identity as the cmdLine
345  * used to invoke the method.
346  *
347  * For example :-
348  * ActualCmdLine - Foo arg1 arg2.
349  * (Host1)       - Full_path_to_Foo arg1 arg2
350 */
351 void SetCommandLineArgs(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR* argv)
352 {
353     CONTRACTL
354     {
355         THROWS;
356         GC_TRIGGERS;
357         MODE_COOPERATIVE;
358     }
359     CONTRACTL_END;
360
361     // Send the command line to EventPipe.
362 #ifdef FEATURE_PERFTRACING
363     EventPipe::SaveCommandLine(pwzAssemblyPath, argc, argv);
364 #endif // FEATURE_PERFTRACING
365
366     // Send the command line to System.Environment.
367     struct _gc
368     {
369         PTRARRAYREF cmdLineArgs;
370     } gc;
371
372     ZeroMemory(&gc, sizeof(gc));
373     GCPROTECT_BEGIN(gc);
374
375     gc.cmdLineArgs = (PTRARRAYREF)AllocateObjectArray(argc + 1 /* arg[0] should be the exe name*/, g_pStringClass);
376     OBJECTREF orAssemblyPath = StringObject::NewString(pwzAssemblyPath);
377     gc.cmdLineArgs->SetAt(0, orAssemblyPath);
378
379     for (int i = 0; i < argc; ++i)
380     {
381         OBJECTREF argument = StringObject::NewString(argv[i]);
382         gc.cmdLineArgs->SetAt(i + 1, argument);
383     }
384
385     MethodDescCallSite setCmdLineArgs(METHOD__ENVIRONMENT__SET_COMMAND_LINE_ARGS);
386
387     ARG_SLOT args[] =
388     {
389         ObjToArgSlot(gc.cmdLineArgs),
390     };
391     setCmdLineArgs.Call(args);
392
393     GCPROTECT_END();
394 }
395
396 HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId,
397                                       LPCWSTR pwzAssemblyPath,
398                                       int argc,
399                                       LPCWSTR* argv,
400                                       DWORD *pReturnValue)
401 {
402     CONTRACTL
403     {
404         THROWS; // Throws...as we do not want it to swallow the managed exception
405         ENTRY_POINT;
406     }
407     CONTRACTL_END;
408
409     // This is currently supported in default domain only
410     if (dwAppDomainId != DefaultADID)
411         return HOST_E_INVALIDOPERATION;
412
413     // No point going further if the runtime is not running...
414     if (!IsRuntimeActive())
415     {
416         return HOST_E_CLRNOTAVAILABLE;
417     }   
418    
419     if(!pwzAssemblyPath)
420         return E_POINTER;
421
422     if(argc < 0)
423     {
424         return E_INVALIDARG;
425     }
426
427     if(argc > 0 && argv == NULL)
428     {
429         return E_INVALIDARG;
430     }
431
432     HRESULT hr = S_OK;
433
434     AppDomain *pCurDomain = SystemDomain::GetCurrentDomain();
435
436     Thread *pThread = GetThread();
437     if (pThread == NULL)
438     {
439         pThread = SetupThreadNoThrow(&hr);
440         if (pThread == NULL)
441         {
442             goto ErrExit;
443         }
444     }
445
446     if(pCurDomain->GetId().m_dwId != DefaultADID)
447     {
448         return HOST_E_INVALIDOPERATION;
449     }
450
451     INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP;
452     INSTALL_UNWIND_AND_CONTINUE_HANDLER;
453
454     _ASSERTE (!pThread->PreemptiveGCDisabled());
455
456     Assembly *pAssembly = AssemblySpec::LoadAssembly(pwzAssemblyPath);
457
458 #if defined(FEATURE_MULTICOREJIT)
459     pCurDomain->GetMulticoreJitManager().AutoStartProfile(pCurDomain);
460 #endif // defined(FEATURE_MULTICOREJIT)
461
462     {
463         GCX_COOP();
464
465         // Here we call the managed method that gets the cmdLineArgs array.
466         SetCommandLineArgs(pwzAssemblyPath, argc, argv);
467
468         PTRARRAYREF arguments = NULL;
469         GCPROTECT_BEGIN(arguments);
470
471         arguments = (PTRARRAYREF)AllocateObjectArray(argc, g_pStringClass);
472         for (int i = 0; i < argc; ++i)
473         {
474             STRINGREF argument = StringObject::NewString(argv[i]);
475             arguments->SetAt(i, argument);
476         }
477
478         DWORD retval = pAssembly->ExecuteMainMethod(&arguments, TRUE /* waitForOtherThreads */);
479         if (pReturnValue)
480         {
481             *pReturnValue = retval;
482         }
483
484         GCPROTECT_END();
485
486     }
487
488     UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
489     UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP;
490
491 ErrExit:
492
493     return hr;
494 }
495
496 HRESULT CorHost2::ExecuteInDefaultAppDomain(LPCWSTR pwzAssemblyPath,
497                                             LPCWSTR pwzTypeName,
498                                             LPCWSTR pwzMethodName,
499                                             LPCWSTR pwzArgument,
500                                             DWORD   *pReturnValue)
501 {
502     CONTRACTL
503     {
504         NOTHROW;
505         ENTRY_POINT;
506     }
507     CONTRACTL_END;
508
509     // No point going further if the runtime is not running...
510     if (!IsRuntimeActive())
511     {
512         return HOST_E_CLRNOTAVAILABLE;
513     }   
514    
515     if(! (pwzAssemblyPath && pwzTypeName && pwzMethodName) )
516         return E_POINTER;
517
518     HRESULT hr = S_OK;
519
520     BEGIN_ENTRYPOINT_NOTHROW;
521
522     Thread *pThread = GetThread();
523     if (pThread == NULL)
524     {
525         pThread = SetupThreadNoThrow(&hr);
526         if (pThread == NULL)
527         {
528             goto ErrExit;
529         }
530     }
531
532     _ASSERTE (!pThread->PreemptiveGCDisabled());
533
534     _ASSERTE (SystemDomain::GetCurrentDomain()->GetId().m_dwId == DefaultADID);
535
536     INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP;
537     INSTALL_UNWIND_AND_CONTINUE_HANDLER;
538
539     EX_TRY
540     {
541         Assembly *pAssembly = AssemblySpec::LoadAssembly(pwzAssemblyPath);
542
543         SString szTypeName(pwzTypeName);
544         StackScratchBuffer buff1;
545         const char* szTypeNameUTF8 = szTypeName.GetUTF8(buff1);
546         MethodTable *pMT = ClassLoader::LoadTypeByNameThrowing(pAssembly,
547                                                             NULL,
548                                                             szTypeNameUTF8).AsMethodTable();
549
550         SString szMethodName(pwzMethodName);
551         StackScratchBuffer buff;
552         const char* szMethodNameUTF8 = szMethodName.GetUTF8(buff);
553         MethodDesc *pMethodMD = MemberLoader::FindMethod(pMT, szMethodNameUTF8, &gsig_SM_Str_RetInt);
554
555         if (!pMethodMD)
556         {
557             hr = COR_E_MISSINGMETHOD;
558         }
559         else
560         {
561             GCX_COOP();
562
563             MethodDescCallSite method(pMethodMD);
564
565             STRINGREF sref = NULL;
566             GCPROTECT_BEGIN(sref);
567
568             if (pwzArgument)
569                 sref = StringObject::NewString(pwzArgument);
570
571             ARG_SLOT MethodArgs[] =
572             {
573                 ObjToArgSlot(sref)
574             };
575             DWORD retval = method.Call_RetI4(MethodArgs);
576             if (pReturnValue)
577             {
578                 *pReturnValue = retval;
579             }
580
581             GCPROTECT_END();
582         }
583     }
584     EX_CATCH_HRESULT(hr);
585
586     UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
587     UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP;
588
589 ErrExit:
590
591     END_ENTRYPOINT_NOTHROW;
592
593     return hr;
594 }
595
596 HRESULT ExecuteInAppDomainHelper(FExecuteInAppDomainCallback pCallback,
597                                  void * cookie)
598 {
599     STATIC_CONTRACT_THROWS;
600
601     return pCallback(cookie);
602 }
603
604 HRESULT CorHost2::ExecuteInAppDomain(DWORD dwAppDomainId,
605                                      FExecuteInAppDomainCallback pCallback,
606                                      void * cookie)
607 {
608
609     // No point going further if the runtime is not running...
610     if (!IsRuntimeActive())
611     {
612         return HOST_E_CLRNOTAVAILABLE;
613     }       
614
615     // Moved this here since no point validating the pointer
616     // if the basic checks [above] fail
617     if( pCallback == NULL)
618         return E_POINTER;
619
620     CONTRACTL
621     {
622         NOTHROW;
623         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
624         ENTRY_POINT;  // This is called by a host.
625     }
626     CONTRACTL_END;
627
628     HRESULT hr = S_OK;
629
630     BEGIN_ENTRYPOINT_NOTHROW;
631     BEGIN_EXTERNAL_ENTRYPOINT(&hr);
632     GCX_COOP_THREAD_EXISTS(GET_THREAD());
633     ENTER_DOMAIN_ID(ADID(dwAppDomainId))
634     {
635         // We are calling an unmanaged function pointer, either an unmanaged function, or a marshaled out delegate.
636         // The thread should be in preemptive mode.
637         GCX_PREEMP();
638         hr=ExecuteInAppDomainHelper (pCallback, cookie);
639     }
640     END_DOMAIN_TRANSITION;
641     END_EXTERNAL_ENTRYPOINT;
642     END_ENTRYPOINT_NOTHROW;
643
644     return hr;
645 }
646
647 #define EMPTY_STRING_TO_NULL(s) {if(s && s[0] == 0) {s=NULL;};}
648
649 HRESULT CorHost2::_CreateAppDomain(
650     LPCWSTR wszFriendlyName,
651     DWORD  dwFlags,
652     LPCWSTR wszAppDomainManagerAssemblyName, 
653     LPCWSTR wszAppDomainManagerTypeName, 
654     int nProperties, 
655     LPCWSTR* pPropertyNames, 
656     LPCWSTR* pPropertyValues,
657     DWORD* pAppDomainID)
658 {
659     CONTRACTL
660     {
661         NOTHROW;
662         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
663         ENTRY_POINT;  // This is called by a host.
664     }
665     CONTRACTL_END;
666
667     HRESULT hr=S_OK;
668
669     //cannot call the function more than once when single appDomain is allowed
670     if (m_fAppDomainCreated)
671     {
672         return HOST_E_INVALIDOPERATION;
673     }
674
675     //normalize empty strings
676     EMPTY_STRING_TO_NULL(wszFriendlyName);
677     EMPTY_STRING_TO_NULL(wszAppDomainManagerAssemblyName);
678     EMPTY_STRING_TO_NULL(wszAppDomainManagerTypeName);
679
680     if (pAppDomainID==NULL)
681         return E_POINTER;
682
683     if (!m_fStarted)
684         return HOST_E_INVALIDOPERATION;
685
686     if (wszFriendlyName == NULL)
687         return E_INVALIDARG;
688
689     if ((wszAppDomainManagerAssemblyName != NULL) || (wszAppDomainManagerTypeName != NULL))
690         return E_INVALIDARG;
691
692     BEGIN_ENTRYPOINT_NOTHROW;
693
694     BEGIN_EXTERNAL_ENTRYPOINT(&hr);
695
696     AppDomain* pDomain = SystemDomain::System()->DefaultDomain();
697
698     pDomain->SetFriendlyName(wszFriendlyName);
699
700     ETW::LoaderLog::DomainLoad(pDomain, (LPWSTR)wszFriendlyName);
701
702     if (dwFlags & APPDOMAIN_IGNORE_UNHANDLED_EXCEPTIONS)
703         pDomain->SetIgnoreUnhandledExceptions();
704
705     if (dwFlags & APPDOMAIN_FORCE_TRIVIAL_WAIT_OPERATIONS)
706         pDomain->SetForceTrivialWaitOperations();
707
708     pDomain->CreateFusionContext();
709
710     {
711         GCX_COOP();
712
713         MethodDescCallSite setup(METHOD__APPCONTEXT__SETUP);
714
715         ARG_SLOT args[3];
716         args[0] = PtrToArgSlot(pPropertyNames);
717         args[1] = PtrToArgSlot(pPropertyValues);
718         args[2] = PtrToArgSlot(nProperties);
719
720         setup.Call(args);
721     }
722
723     LPCWSTR pwzNativeDllSearchDirectories = NULL;
724     LPCWSTR pwzTrustedPlatformAssemblies = NULL;
725     LPCWSTR pwzPlatformResourceRoots = NULL;
726     LPCWSTR pwzAppPaths = NULL;
727     LPCWSTR pwzAppNiPaths = NULL;
728 #ifdef FEATURE_COMINTEROP
729     LPCWSTR pwzAppLocalWinMD = NULL;
730 #endif
731
732     for (int i = 0; i < nProperties; i++)
733     {
734         if (wcscmp(pPropertyNames[i], W("NATIVE_DLL_SEARCH_DIRECTORIES")) == 0)
735         {
736             pwzNativeDllSearchDirectories = pPropertyValues[i];
737         }
738         else
739         if (wcscmp(pPropertyNames[i], W("TRUSTED_PLATFORM_ASSEMBLIES")) == 0)
740         {
741             pwzTrustedPlatformAssemblies = pPropertyValues[i];
742         }
743         else
744         if (wcscmp(pPropertyNames[i], W("PLATFORM_RESOURCE_ROOTS")) == 0)
745         {
746             pwzPlatformResourceRoots = pPropertyValues[i];
747         }
748         else
749         if (wcscmp(pPropertyNames[i], W("APP_PATHS")) == 0)
750         {
751             pwzAppPaths = pPropertyValues[i];
752         }
753         else
754         if (wcscmp(pPropertyNames[i], W("APP_NI_PATHS")) == 0)
755         {
756             pwzAppNiPaths = pPropertyValues[i];
757         }
758 #ifdef FEATURE_COMINTEROP
759         else
760         if (wcscmp(pPropertyNames[i], W("APP_LOCAL_WINMETADATA")) == 0)
761         {
762             pwzAppLocalWinMD = pPropertyValues[i];
763         }
764 #endif
765     }
766
767     pDomain->SetNativeDllSearchDirectories(pwzNativeDllSearchDirectories);
768
769     {
770         SString sTrustedPlatformAssemblies(pwzTrustedPlatformAssemblies);
771         SString sPlatformResourceRoots(pwzPlatformResourceRoots);
772         SString sAppPaths(pwzAppPaths);
773         SString sAppNiPaths(pwzAppNiPaths);
774
775         CLRPrivBinderCoreCLR *pBinder = pDomain->GetTPABinderContext();
776         _ASSERTE(pBinder != NULL);
777         IfFailThrow(pBinder->SetupBindingPaths(
778             sTrustedPlatformAssemblies,
779             sPlatformResourceRoots,
780             sAppPaths,
781             sAppNiPaths));
782     }
783
784 #ifdef FEATURE_COMINTEROP
785     if (WinRTSupported())
786     {
787         pDomain->SetWinrtApplicationContext(pwzAppLocalWinMD);
788     }
789 #endif
790
791     *pAppDomainID=pDomain->GetId().m_dwId;
792
793     m_fAppDomainCreated = TRUE;
794
795     END_EXTERNAL_ENTRYPOINT;
796
797     END_ENTRYPOINT_NOTHROW;
798
799     return hr;
800 }
801
802 HRESULT CorHost2::_CreateDelegate(
803     DWORD appDomainID,
804     LPCWSTR wszAssemblyName,     
805     LPCWSTR wszClassName,     
806     LPCWSTR wszMethodName,
807     INT_PTR* fnPtr)
808 {
809
810     CONTRACTL
811     {
812         NOTHROW;
813         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
814         ENTRY_POINT;  // This is called by a host.
815     }
816     CONTRACTL_END;
817
818     HRESULT hr=S_OK;
819
820     EMPTY_STRING_TO_NULL(wszAssemblyName);
821     EMPTY_STRING_TO_NULL(wszClassName);
822     EMPTY_STRING_TO_NULL(wszMethodName);
823
824     if (fnPtr == NULL)
825        return E_POINTER;
826     *fnPtr = NULL;
827
828     if(wszAssemblyName == NULL)
829         return E_INVALIDARG;
830     
831     if(wszClassName == NULL)
832         return E_INVALIDARG;
833
834     if(wszMethodName == NULL)
835         return E_INVALIDARG;
836     
837     BEGIN_ENTRYPOINT_NOTHROW;
838
839     BEGIN_EXTERNAL_ENTRYPOINT(&hr);
840     GCX_COOP_THREAD_EXISTS(GET_THREAD());
841
842     MAKE_UTF8PTR_FROMWIDE(szAssemblyName, wszAssemblyName);
843     MAKE_UTF8PTR_FROMWIDE(szClassName, wszClassName);
844     MAKE_UTF8PTR_FROMWIDE(szMethodName, wszMethodName);
845
846     ADID id;
847     id.m_dwId=appDomainID;
848
849     ENTER_DOMAIN_ID(id)
850
851     GCX_PREEMP();
852
853     AssemblySpec spec;
854     spec.Init(szAssemblyName);
855     Assembly* pAsm=spec.LoadAssembly(FILE_ACTIVE);
856
857     TypeHandle th=pAsm->GetLoader()->LoadTypeByNameThrowing(pAsm,NULL,szClassName);
858     MethodDesc* pMD=NULL;
859     
860     if (!th.IsTypeDesc()) 
861     {
862         pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Unique);
863         if (pMD == NULL)
864         {
865             // try again without the FM_Unique flag (error path)
866             pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Default);
867             if (pMD != NULL)
868             {
869                 // the method exists but is overloaded
870                 ThrowHR(COR_E_AMBIGUOUSMATCH);
871             }
872         }
873     }
874
875     if (pMD==NULL || !pMD->IsStatic() || pMD->ContainsGenericVariables()) 
876         ThrowHR(COR_E_MISSINGMETHOD);
877
878     UMEntryThunk *pUMEntryThunk = pMD->GetLoaderAllocator()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD);
879     *fnPtr = (INT_PTR)pUMEntryThunk->GetCode();
880
881     END_DOMAIN_TRANSITION;
882
883     END_EXTERNAL_ENTRYPOINT;
884
885     END_ENTRYPOINT_NOTHROW;
886
887     return hr;
888 }
889
890 HRESULT CorHost2::CreateAppDomainWithManager(
891     LPCWSTR wszFriendlyName,
892     DWORD  dwFlags,
893     LPCWSTR wszAppDomainManagerAssemblyName, 
894     LPCWSTR wszAppDomainManagerTypeName, 
895     int nProperties, 
896     LPCWSTR* pPropertyNames, 
897     LPCWSTR* pPropertyValues, 
898     DWORD* pAppDomainID)
899 {
900     WRAPPER_NO_CONTRACT;
901
902     return _CreateAppDomain(
903         wszFriendlyName,
904         dwFlags,
905         wszAppDomainManagerAssemblyName, 
906         wszAppDomainManagerTypeName, 
907         nProperties, 
908         pPropertyNames, 
909         pPropertyValues,
910         pAppDomainID);
911 }
912
913 HRESULT CorHost2::CreateDelegate(
914     DWORD appDomainID,
915     LPCWSTR wszAssemblyName,     
916     LPCWSTR wszClassName,     
917     LPCWSTR wszMethodName,
918     INT_PTR* fnPtr)
919 {
920     WRAPPER_NO_CONTRACT;
921
922     return _CreateDelegate(appDomainID, wszAssemblyName, wszClassName, wszMethodName, fnPtr);
923 }
924
925 HRESULT CorHost2::Authenticate(ULONGLONG authKey)
926 {
927     CONTRACTL
928     {
929         NOTHROW;
930         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
931         ENTRY_POINT;  // This is called by a host.
932     }
933     CONTRACTL_END;
934
935     // Host authentication was used by Silverlight. It is no longer relevant for CoreCLR.
936     return S_OK;
937 }
938
939 HRESULT CorHost2::RegisterMacEHPort()
940 {
941     CONTRACTL
942     {
943         NOTHROW;
944         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
945         ENTRY_POINT;  // This is called by a host.
946     }
947     CONTRACTL_END;
948
949     return S_OK;
950 }
951
952 HRESULT CorHost2::SetStartupFlags(STARTUP_FLAGS flag)
953 {
954     CONTRACTL
955     {
956         NOTHROW;
957         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
958         ENTRY_POINT;  // This is called by a host.
959     }
960     CONTRACTL_END;
961
962     if (g_fEEStarted)
963     {
964         return HOST_E_INVALIDOPERATION;
965     }
966
967     m_dwStartupFlags = flag;
968
969     return S_OK;
970 }
971
972
973
974 HRESULT SuspendEEForPause()
975 {
976     CONTRACTL
977     {
978         NOTHROW;
979         MODE_PREEMPTIVE;
980         GC_TRIGGERS;
981     }
982     CONTRACTL_END;
983
984     HRESULT hr = S_OK;
985
986     // In CoreCLR, we always resume from the same thread that paused.  So we can simply suspend the EE from this thread,
987     // knowing we'll restart from the same thread.
988     ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_OTHER);
989
990     return hr;
991 }
992
993 HRESULT RestartEEFromPauseAndSetResumeEvent()
994 {
995     CONTRACTL
996     {
997         NOTHROW;
998         MODE_PREEMPTIVE;
999         GC_TRIGGERS;
1000     }
1001     CONTRACTL_END;
1002
1003     // see comments in SuspendEEFromPause
1004     ThreadSuspend::RestartEE(FALSE, TRUE);
1005
1006     _ASSERTE(g_ClrResumeEvent.IsValid());
1007     g_ClrResumeEvent.Set();
1008
1009     return S_OK;
1010 }
1011     
1012
1013
1014 CorExecutionManager::CorExecutionManager()
1015     : m_dwFlags(0), m_pauseStartTime(0)
1016 {
1017     LIMITED_METHOD_CONTRACT;
1018     g_IsPaused = FALSE;
1019     g_PauseTime = 0;
1020 }
1021
1022 HRESULT CorExecutionManager::Pause(DWORD dwAppDomainId, DWORD dwFlags)
1023 {
1024     CONTRACTL
1025     {
1026         NOTHROW;
1027         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
1028         ENTRY_POINT;  // This is called by a host.
1029     }
1030     CONTRACTL_END;
1031
1032     HRESULT hr = S_OK;
1033
1034
1035     if(g_IsPaused)
1036         return E_FAIL;
1037
1038     EX_TRY
1039     {
1040         if(!g_ClrResumeEvent.IsValid())
1041             g_ClrResumeEvent.CreateManualEvent(FALSE);
1042         else
1043             g_ClrResumeEvent.Reset();
1044
1045     }
1046     EX_CATCH_HRESULT(hr);
1047     
1048     if (FAILED(hr))
1049         return hr;
1050     
1051     BEGIN_ENTRYPOINT_NOTHROW;
1052
1053     m_dwFlags = dwFlags;
1054
1055
1056     if (SUCCEEDED(hr))
1057     {
1058         g_IsPaused = TRUE;
1059
1060         hr = SuspendEEForPause();
1061
1062         // Even though this is named with TickCount, it returns milliseconds
1063         m_pauseStartTime = (INT64)CLRGetTickCount64(); 
1064     }
1065
1066     END_ENTRYPOINT_NOTHROW;
1067
1068     return hr;
1069 }
1070
1071
1072 HRESULT CorExecutionManager::Resume(DWORD dwAppDomainId)
1073 {
1074     CONTRACTL
1075     {
1076         NOTHROW;
1077         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
1078         ENTRY_POINT;  // This is called by a host.
1079     }
1080     CONTRACTL_END;
1081
1082     HRESULT hr = S_OK;
1083
1084
1085     if(!g_IsPaused)
1086         return E_FAIL;
1087
1088     // GCThread is the thread that did the Pause. Resume should also happen on that same thread
1089     Thread *pThread = GetThread();
1090     if(pThread != ThreadSuspend::GetSuspensionThread())
1091     {
1092         _ASSERTE(!"HOST BUG: The same thread that did Pause should do the Resume");
1093         return E_FAIL;
1094     }
1095
1096     BEGIN_ENTRYPOINT_NOTHROW;
1097
1098     // Even though this is named with TickCount, it returns milliseconds
1099     INT64 currTime = (INT64)CLRGetTickCount64(); 
1100     _ASSERTE(currTime >= m_pauseStartTime);
1101     _ASSERTE(m_pauseStartTime != 0);
1102
1103     g_PauseTime += (currTime - m_pauseStartTime);
1104     g_IsPaused = FALSE;
1105
1106     hr = RestartEEFromPauseAndSetResumeEvent();
1107
1108
1109     END_ENTRYPOINT_NOTHROW;
1110
1111     return hr;
1112 }
1113
1114
1115 #endif //!DACCESS_COMPILE
1116
1117 #ifndef DACCESS_COMPILE
1118 SVAL_IMPL(STARTUP_FLAGS, CorHost2, m_dwStartupFlags = STARTUP_CONCURRENT_GC);
1119 #else
1120 SVAL_IMPL(STARTUP_FLAGS, CorHost2, m_dwStartupFlags);
1121 #endif
1122
1123 STARTUP_FLAGS CorHost2::GetStartupFlags()
1124 {
1125     return m_dwStartupFlags;
1126 }
1127
1128 #ifndef DACCESS_COMPILE
1129
1130
1131 #ifdef FEATURE_COMINTEROP
1132
1133 // Enumerate currently existing domains.
1134 HRESULT CorRuntimeHostBase::EnumDomains(HDOMAINENUM *hEnum)
1135 {
1136     CONTRACTL
1137     {
1138         NOTHROW;
1139         MODE_PREEMPTIVE;
1140         WRAPPER(GC_TRIGGERS);
1141         ENTRY_POINT;
1142     }
1143     CONTRACTL_END;
1144
1145     if(hEnum == NULL) return E_POINTER;
1146
1147     // Thread setup happens in BEGIN_EXTERNAL_ENTRYPOINT below.
1148     // If the runtime has not started, we have nothing to do.
1149     if (!g_fEEStarted)
1150     {
1151         return HOST_E_CLRNOTAVAILABLE;
1152     }
1153
1154     HRESULT hr = E_OUTOFMEMORY;
1155     *hEnum = NULL;
1156     BEGIN_ENTRYPOINT_NOTHROW;
1157
1158     BEGIN_EXTERNAL_ENTRYPOINT(&hr)
1159
1160     AppDomainIterator *pEnum = new (nothrow) AppDomainIterator(FALSE);
1161     if(pEnum) {
1162         *hEnum = (HDOMAINENUM) pEnum;
1163         hr = S_OK;
1164     }
1165     END_EXTERNAL_ENTRYPOINT;
1166     END_ENTRYPOINT_NOTHROW;
1167
1168     return hr;
1169 }
1170
1171 #endif // FEATURE_COMINTEROP
1172
1173 extern "C"
1174 HRESULT  GetCLRRuntimeHost(REFIID riid, IUnknown **ppUnk)
1175 {
1176     WRAPPER_NO_CONTRACT;
1177
1178     return CorHost2::CreateObject(riid, (void**)ppUnk);
1179 }
1180
1181
1182 STDMETHODIMP CorHost2::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone)
1183 {
1184     return UnloadAppDomain2(dwDomainId, fWaitUntilDone, nullptr);
1185 }
1186
1187 STDMETHODIMP CorHost2::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDone, int *pLatchedExitCode)
1188 {
1189     WRAPPER_NO_CONTRACT;
1190
1191     if (!m_fStarted)
1192         return HOST_E_INVALIDOPERATION;
1193
1194     if (!g_fEEStarted)
1195     {
1196         return HOST_E_CLRNOTAVAILABLE;
1197     }
1198
1199     if(!m_fAppDomainCreated)
1200     {
1201         return HOST_E_INVALIDOPERATION;
1202     }
1203
1204     HRESULT hr=S_OK;
1205     BEGIN_ENTRYPOINT_NOTHROW;
1206     
1207     if (!m_fFirstToLoadCLR)
1208     {
1209         _ASSERTE(!"Not reachable");
1210         hr = HOST_E_CLRNOTAVAILABLE;
1211     }
1212     else
1213     {
1214         LONG refCount = m_RefCount;
1215         if (refCount == 0)
1216         {
1217             hr = HOST_E_CLRNOTAVAILABLE;
1218         }
1219         else
1220         if (1 == refCount)
1221         {
1222             // Stop coreclr on unload.
1223             EEShutDown(FALSE);
1224         }
1225         else
1226         {
1227             _ASSERTE(!"Not reachable");
1228             hr = S_FALSE;
1229         }
1230     }
1231     END_ENTRYPOINT_NOTHROW;
1232
1233     if (pLatchedExitCode)
1234     {
1235         *pLatchedExitCode = GetLatchedExitCode();
1236     }
1237
1238     return hr;
1239 }
1240
1241 HRESULT CorRuntimeHostBase::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone)
1242 {
1243     return UnloadAppDomain2(dwDomainId, fWaitUntilDone, nullptr);
1244 }
1245
1246 HRESULT CorRuntimeHostBase::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDone, int *pLatchedExitCode)
1247 {
1248     CONTRACTL
1249     {
1250         NOTHROW;
1251         GC_TRIGGERS;
1252         MODE_ANY;
1253         FORBID_FAULT; // Unloading domains cannot fail due to OOM
1254         ENTRY_POINT;
1255     }
1256     CONTRACTL_END;
1257
1258     return COR_E_CANNOTUNLOADAPPDOMAIN;
1259 }
1260
1261 //*****************************************************************************
1262 // Fiber Methods
1263 //*****************************************************************************
1264
1265 HRESULT CorRuntimeHostBase::LocksHeldByLogicalThread(DWORD *pCount)
1266 {
1267     if (!pCount)
1268         return E_POINTER;
1269
1270     CONTRACTL
1271     {
1272         NOTHROW;
1273         GC_NOTRIGGER;
1274         ENTRY_POINT;
1275     }
1276     CONTRACTL_END;
1277
1278     BEGIN_ENTRYPOINT_NOTHROW;
1279
1280     Thread* pThread = GetThread();
1281     if (pThread == NULL)
1282         *pCount = 0;
1283     else
1284         *pCount = pThread->m_dwLockCount;
1285
1286     END_ENTRYPOINT_NOTHROW;
1287
1288     return S_OK;
1289 }
1290
1291 //*****************************************************************************
1292 // ICorConfiguration
1293 //*****************************************************************************
1294
1295 //*****************************************************************************
1296 // IUnknown
1297 //*****************************************************************************
1298
1299 ULONG CorRuntimeHostBase::AddRef()
1300 {
1301     CONTRACTL
1302     {
1303         WRAPPER(THROWS);
1304         WRAPPER(GC_TRIGGERS);
1305     }
1306     CONTRACTL_END;
1307     return InterlockedIncrement(&m_cRef);
1308 }
1309
1310
1311 ULONG CorHost2::Release()
1312 {
1313     LIMITED_METHOD_CONTRACT;
1314
1315     ULONG cRef = InterlockedDecrement(&m_cRef);
1316     if (!cRef) {
1317             delete this;
1318     }
1319
1320     return (cRef);
1321 }
1322
1323
1324
1325 HRESULT CorHost2::QueryInterface(REFIID riid, void **ppUnk)
1326 {
1327     if (!ppUnk)
1328         return E_POINTER;
1329
1330     CONTRACTL
1331     {
1332         NOTHROW;
1333         GC_NOTRIGGER;
1334     }
1335     CONTRACTL_END;
1336
1337     if (ppUnk == NULL)
1338     {
1339         return E_POINTER;
1340     }
1341
1342     *ppUnk = 0;
1343
1344     // Deliberately do NOT hand out ICorConfiguration.  They must explicitly call
1345     // GetConfiguration to obtain that interface.
1346     if (riid == IID_IUnknown)
1347     {
1348         *ppUnk = static_cast<IUnknown *>(static_cast<ICLRRuntimeHost *>(this));
1349     }
1350     else if (riid == IID_ICLRRuntimeHost)
1351     {
1352         *ppUnk = static_cast<ICLRRuntimeHost *>(this);
1353     }
1354     else if (riid == IID_ICLRRuntimeHost2)
1355     {
1356         ULONG version = 2;
1357         if (m_Version == 0)
1358             FastInterlockCompareExchange((LONG*)&m_Version, version, 0);
1359
1360         *ppUnk = static_cast<ICLRRuntimeHost2 *>(this);
1361     }
1362     else if (riid == IID_ICLRRuntimeHost4)
1363     {
1364         ULONG version = 4;
1365         if (m_Version == 0)
1366             FastInterlockCompareExchange((LONG*)&m_Version, version, 0);
1367
1368         *ppUnk = static_cast<ICLRRuntimeHost4 *>(this);
1369     }
1370     else if (riid == IID_ICLRExecutionManager)
1371     {
1372         ULONG version = 2;
1373         if (m_Version == 0)
1374             FastInterlockCompareExchange((LONG*)&m_Version, version, 0);
1375
1376         *ppUnk = static_cast<ICLRExecutionManager *>(this);
1377     }
1378 #ifndef FEATURE_PAL
1379     else if (riid == IID_IPrivateManagedExceptionReporting)
1380     {
1381         *ppUnk = static_cast<IPrivateManagedExceptionReporting *>(this);
1382     }
1383 #endif // !FEATURE_PAL
1384     else
1385         return (E_NOINTERFACE);
1386     AddRef();
1387     return (S_OK);
1388 }
1389
1390
1391 #ifndef FEATURE_PAL
1392 HRESULT CorHost2::GetBucketParametersForCurrentException(BucketParameters *pParams)
1393 {
1394     CONTRACTL
1395     {
1396         NOTHROW;
1397         GC_NOTRIGGER;
1398     }
1399     CONTRACTL_END;
1400
1401     HRESULT hr = S_OK;
1402     BEGIN_ENTRYPOINT_NOTHROW;
1403
1404     // To avoid confusion, clear the buckets.
1405     memset(pParams, 0, sizeof(BucketParameters));
1406
1407     // Defer to Watson helper.
1408     hr = ::GetBucketParametersForCurrentException(pParams);
1409
1410     END_ENTRYPOINT_NOTHROW;
1411
1412     return hr;
1413 }
1414 #endif // !FEATURE_PAL
1415
1416 HRESULT CorHost2::CreateObject(REFIID riid, void **ppUnk)
1417 {
1418     CONTRACTL
1419     {
1420         NOTHROW;
1421         GC_NOTRIGGER;
1422     }
1423     CONTRACTL_END;
1424
1425     HRESULT hr = S_OK;
1426
1427     CorHost2 *pCorHost = new (nothrow) CorHost2();
1428     if (!pCorHost)
1429     {
1430         hr = E_OUTOFMEMORY;
1431     }
1432     else
1433     {
1434         hr = pCorHost->QueryInterface(riid, ppUnk);
1435     if (FAILED(hr))
1436         delete pCorHost;
1437     }
1438     return (hr);
1439 }
1440
1441
1442 //-----------------------------------------------------------------------------
1443 // MapFile - Maps a file into the runtime in a non-standard way
1444 //-----------------------------------------------------------------------------
1445
1446 static PEImage *MapFileHelper(HANDLE hFile)
1447 {
1448     CONTRACTL
1449     {
1450         THROWS;
1451         GC_TRIGGERS;
1452         MODE_ANY;
1453     }
1454     CONTRACTL_END;
1455
1456     GCX_PREEMP();
1457
1458     HandleHolder hFileMap(WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL));
1459     if (hFileMap == NULL)
1460         ThrowLastError();
1461
1462     CLRMapViewHolder base(CLRMapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0));
1463     if (base == NULL)
1464         ThrowLastError();
1465
1466     DWORD dwSize = SafeGetFileSize(hFile, NULL);
1467     if (dwSize == 0xffffffff && GetLastError() != NOERROR)
1468     {
1469         ThrowLastError();
1470     }
1471     PEImageHolder pImage(PEImage::LoadFlat(base, dwSize));
1472     return pImage.Extract();
1473 }
1474
1475 HRESULT CorRuntimeHostBase::MapFile(HANDLE hFile, HMODULE* phHandle)
1476 {
1477     CONTRACTL
1478     {
1479         NOTHROW;
1480         GC_TRIGGERS;
1481         MODE_PREEMPTIVE;
1482         ENTRY_POINT;
1483     }
1484     CONTRACTL_END;
1485
1486     HRESULT hr;
1487     BEGIN_ENTRYPOINT_NOTHROW;
1488
1489     BEGIN_EXTERNAL_ENTRYPOINT(&hr)
1490     {
1491         *phHandle = (HMODULE) (MapFileHelper(hFile)->GetLoadedLayout()->GetBase());
1492     }
1493     END_EXTERNAL_ENTRYPOINT;
1494     END_ENTRYPOINT_NOTHROW;
1495
1496
1497     return hr;
1498 }
1499
1500 ///////////////////////////////////////////////////////////////////////////////
1501 // IDebuggerInfo::IsDebuggerAttached
1502
1503 LONG CorHost2::m_RefCount = 0;
1504
1505 IHostControl *CorHost2::m_HostControl = NULL;
1506
1507 #ifdef _DEBUG
1508 extern void ValidateHostInterface();
1509 #endif
1510
1511 static Volatile<BOOL> fOneOnly = 0;
1512
1513 ///////////////////////////////////////////////////////////////////////////////
1514 // ICLRRuntimeHost::SetHostControl
1515 ///////////////////////////////////////////////////////////////////////////////
1516 HRESULT CorHost2::SetHostControl(IHostControl* pHostControl)
1517 {
1518     CONTRACTL
1519     {
1520         NOTHROW;
1521         GC_NOTRIGGER;
1522         ENTRY_POINT;
1523     }
1524     CONTRACTL_END;
1525     if (m_Version < 2)
1526         // CLR is hosted with v1 hosting interface.  Some part of v2 hosting API are disabled.
1527         return HOST_E_INVALIDOPERATION;
1528
1529     if (pHostControl == 0)
1530         return E_INVALIDARG;
1531
1532     // If Runtime has been started, do not allow setting HostMemoryManager
1533     if (g_fEEStarted)
1534         return E_ACCESSDENIED;
1535
1536     HRESULT hr = S_OK;
1537
1538     BEGIN_ENTRYPOINT_NOTHROW;
1539     
1540     DWORD dwSwitchCount = 0;
1541
1542     while (FastInterlockExchange((LONG*)&fOneOnly, 1) == 1)
1543     {
1544              __SwitchToThread(0, ++dwSwitchCount);
1545     }
1546     
1547
1548     if (m_HostControl == NULL)
1549     {
1550         m_HostControl = pHostControl;
1551         m_HostControl->AddRef();
1552     }
1553
1554     goto ErrExit;
1555
1556 ErrExit:
1557     fOneOnly = 0;
1558
1559     END_ENTRYPOINT_NOTHROW;
1560
1561     return hr;
1562 }
1563
1564 class CCLRPolicyManager: public ICLRPolicyManager
1565 {
1566 public:
1567     virtual HRESULT STDMETHODCALLTYPE SetDefaultAction(EClrOperation operation,
1568                                                        EPolicyAction action)
1569     {
1570         LIMITED_METHOD_CONTRACT;
1571         return E_NOTIMPL;
1572     }
1573
1574     virtual HRESULT STDMETHODCALLTYPE SetTimeout(EClrOperation operation,
1575                                                  DWORD dwMilliseconds)
1576     {
1577         LIMITED_METHOD_CONTRACT;
1578         return E_NOTIMPL;
1579     }
1580
1581     virtual HRESULT STDMETHODCALLTYPE SetActionOnTimeout(EClrOperation operation,
1582                                                          EPolicyAction action)
1583     {
1584         LIMITED_METHOD_CONTRACT;
1585         return E_NOTIMPL;
1586     }
1587
1588     virtual HRESULT STDMETHODCALLTYPE SetTimeoutAndAction(EClrOperation operation, DWORD dwMilliseconds,
1589                                                           EPolicyAction action)
1590     {
1591         LIMITED_METHOD_CONTRACT;
1592         return E_NOTIMPL;
1593     }
1594
1595     virtual HRESULT STDMETHODCALLTYPE SetActionOnFailure(EClrFailure failure,
1596                                                          EPolicyAction action)
1597     {
1598         // This is enabled for CoreCLR since a host can use this to 
1599         // specify action for handling AV.
1600         STATIC_CONTRACT_ENTRY_POINT;
1601         LIMITED_METHOD_CONTRACT;
1602         HRESULT hr;
1603         // For CoreCLR, this method just supports FAIL_AccessViolation as a valid
1604         // failure input arg. The validation of the specified action for the failure
1605         // will be done in EEPolicy::IsValidActionForFailure.
1606         if (failure != FAIL_AccessViolation)
1607         {
1608             return E_INVALIDARG;
1609         }
1610         BEGIN_ENTRYPOINT_NOTHROW;
1611         hr = GetEEPolicy()->SetActionOnFailure(failure,action);
1612         END_ENTRYPOINT_NOTHROW;
1613         return hr;
1614     }
1615
1616     virtual HRESULT STDMETHODCALLTYPE SetUnhandledExceptionPolicy(EClrUnhandledException policy)
1617     {
1618         LIMITED_METHOD_CONTRACT;
1619         return E_NOTIMPL;
1620     }
1621
1622     virtual ULONG STDMETHODCALLTYPE AddRef(void)
1623     {
1624         LIMITED_METHOD_CONTRACT;
1625         return 1;
1626     }
1627
1628     virtual ULONG STDMETHODCALLTYPE Release(void)
1629     {
1630         LIMITED_METHOD_CONTRACT;
1631         return 1;
1632     }
1633
1634     BEGIN_INTERFACE HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
1635                                                              void **ppvObject)
1636     {
1637         LIMITED_METHOD_CONTRACT;
1638         if (riid != IID_ICLRPolicyManager && riid != IID_IUnknown)
1639             return (E_NOINTERFACE);
1640
1641         // Ensure that the out going pointer is not null
1642         if (ppvObject == NULL)
1643             return E_POINTER;
1644
1645         *ppvObject = this;
1646         return S_OK;
1647     }
1648 };
1649
1650 static CCLRPolicyManager s_PolicyManager;
1651
1652
1653
1654 void ProcessEventForHost(EClrEvent event, void *data)
1655 {
1656 }
1657
1658 // We do not call ProcessEventForHost for stack overflow, since we have limit stack
1659 // and we should avoid calling GCX_PREEMPT
1660 void ProcessSOEventForHost(EXCEPTION_POINTERS *pExceptionInfo, BOOL fInSoTolerant)
1661 {
1662 }
1663
1664 BOOL IsHostRegisteredForEvent(EClrEvent event)
1665 {
1666     WRAPPER_NO_CONTRACT;
1667     return FALSE;
1668 }
1669
1670 inline size_t SizeInKBytes(size_t cbSize)
1671 {
1672     LIMITED_METHOD_CONTRACT;
1673     size_t cb = (cbSize % 1024) ? 1 : 0;
1674     return ((cbSize / 1024) + cb);
1675 }
1676
1677 SIZE_T Host_SegmentSize = 0;
1678 SIZE_T Host_MaxGen0Size = 0;
1679 BOOL  Host_fSegmentSizeSet = FALSE;
1680 BOOL  Host_fMaxGen0SizeSet = FALSE;
1681
1682 void UpdateGCSettingFromHost ()
1683 {
1684     WRAPPER_NO_CONTRACT;
1685     _ASSERTE (g_pConfig);
1686     if (Host_fSegmentSizeSet)
1687     {
1688         g_pConfig->SetSegmentSize(Host_SegmentSize);
1689     }
1690     if (Host_fMaxGen0SizeSet)
1691     {
1692         g_pConfig->SetGCgen0size(Host_MaxGen0Size);
1693     }
1694 }
1695
1696 #if defined(FEATURE_WINDOWSPHONE)
1697 class CCLRGCManager: public ICLRGCManager2
1698 {
1699 public:
1700     virtual HRESULT STDMETHODCALLTYPE Collect(LONG Generation)
1701     {
1702         CONTRACTL
1703         {
1704             NOTHROW;
1705             GC_TRIGGERS;
1706             ENTRY_POINT;
1707         }
1708         CONTRACTL_END;
1709
1710         HRESULT     hr = S_OK;
1711
1712         if (Generation > (int) GCHeapUtilities::GetGCHeap()->GetMaxGeneration())
1713             hr = E_INVALIDARG;
1714
1715         if (SUCCEEDED(hr))
1716         {
1717             // Set up a Thread object if this is called on a native thread.
1718             Thread *pThread;
1719             pThread = GetThread();
1720             if (pThread == NULL)
1721                 pThread = SetupThreadNoThrow(&hr);
1722             if (pThread != NULL)
1723             {
1724                 BEGIN_ENTRYPOINT_NOTHROW_WITH_THREAD(pThread);
1725                 GCX_COOP();
1726
1727                 EX_TRY
1728                 {
1729                     STRESS_LOG0(LF_GC, LL_INFO100, "Host triggers GC\n");
1730                     hr = GCHeapUtilities::GetGCHeap()->GarbageCollect(Generation);
1731                 }
1732                 EX_CATCH
1733                 {
1734                     hr = GET_EXCEPTION()->GetHR();
1735                 }
1736                 EX_END_CATCH(SwallowAllExceptions);
1737
1738                 END_ENTRYPOINT_NOTHROW_WITH_THREAD;
1739             }
1740         }
1741
1742         return (hr);
1743     }
1744
1745     virtual HRESULT STDMETHODCALLTYPE GetStats(COR_GC_STATS *pStats)
1746     {
1747         CONTRACTL
1748         {
1749             NOTHROW;
1750             GC_NOTRIGGER;
1751             ENTRY_POINT;
1752         }
1753         CONTRACTL_END;
1754
1755         HRESULT hr = S_OK;
1756         BEGIN_ENTRYPOINT_NOTHROW;
1757
1758     #if defined(ENABLE_PERF_COUNTERS)
1759
1760         Perf_GC     *pgc = &GetPerfCounters().m_GC;
1761
1762         if (!pStats)
1763             IfFailGo(E_INVALIDARG);
1764
1765         if (pStats->Flags & COR_GC_COUNTS)
1766         {
1767             pStats->ExplicitGCCount = pgc->cInducedGCs;
1768
1769             for (int idx=0; idx<3; idx++)
1770                 pStats->GenCollectionsTaken[idx] = pgc->cGenCollections[idx];
1771         }
1772
1773         if (pStats->Flags & COR_GC_MEMORYUSAGE)
1774         {
1775             pStats->CommittedKBytes = SizeInKBytes(pgc->cTotalCommittedBytes);
1776             pStats->ReservedKBytes = SizeInKBytes(pgc->cTotalReservedBytes);
1777             pStats->Gen0HeapSizeKBytes = SizeInKBytes(pgc->cGenHeapSize[0]);
1778             pStats->Gen1HeapSizeKBytes = SizeInKBytes(pgc->cGenHeapSize[1]);
1779             pStats->Gen2HeapSizeKBytes = SizeInKBytes(pgc->cGenHeapSize[2]);
1780             pStats->LargeObjectHeapSizeKBytes = SizeInKBytes(pgc->cLrgObjSize);
1781             pStats->KBytesPromotedFromGen0 = SizeInKBytes(pgc->cbPromotedMem[0]);
1782             pStats->KBytesPromotedFromGen1 = SizeInKBytes(pgc->cbPromotedMem[1]);
1783         }
1784         hr = S_OK;
1785 ErrExit:
1786     #else
1787         hr = E_NOTIMPL;
1788     #endif // ENABLE_PERF_COUNTERS
1789
1790         END_ENTRYPOINT_NOTHROW;
1791         return hr;
1792     }
1793     virtual HRESULT STDMETHODCALLTYPE SetGCStartupLimits(
1794         DWORD SegmentSize,
1795         DWORD MaxGen0Size)
1796     {
1797         CONTRACTL
1798         {
1799             NOTHROW;
1800             GC_NOTRIGGER;
1801             ENTRY_POINT;
1802
1803         }
1804         CONTRACTL_END;
1805
1806         HRESULT hr = S_OK;
1807         BEGIN_ENTRYPOINT_NOTHROW;
1808
1809         // Set default overrides if specified by caller.
1810         if (SegmentSize != (DWORD) ~0 && SegmentSize > 0)
1811         {
1812             hr = _SetGCSegmentSize(SegmentSize);
1813         }
1814
1815         if (SUCCEEDED(hr) && MaxGen0Size != (DWORD) ~0 && MaxGen0Size > 0)
1816         {
1817             hr = _SetGCMaxGen0Size(MaxGen0Size);
1818         }
1819
1820         END_ENTRYPOINT_NOTHROW;
1821
1822         return (hr);
1823     }
1824
1825     virtual HRESULT STDMETHODCALLTYPE SetGCStartupLimitsEx(
1826         SIZE_T SegmentSize,
1827         SIZE_T MaxGen0Size)
1828     {
1829         CONTRACTL
1830         {
1831             NOTHROW;
1832             GC_NOTRIGGER;
1833             ENTRY_POINT;
1834
1835         }
1836         CONTRACTL_END;
1837
1838         HRESULT hr = S_OK;
1839         BEGIN_ENTRYPOINT_NOTHROW;
1840
1841         // Set default overrides if specified by caller.
1842         if (SegmentSize != (SIZE_T) ~0 && SegmentSize > 0)
1843         {
1844             hr = _SetGCSegmentSize(SegmentSize);
1845         }
1846
1847         if (SUCCEEDED(hr) && MaxGen0Size != (SIZE_T) ~0 && MaxGen0Size > 0)
1848         {
1849             hr = _SetGCMaxGen0Size(MaxGen0Size);
1850         }
1851
1852         END_ENTRYPOINT_NOTHROW;
1853
1854         return (hr);
1855     }
1856
1857     virtual ULONG STDMETHODCALLTYPE AddRef(void)
1858     {
1859         LIMITED_METHOD_CONTRACT;
1860         return 1;
1861     }
1862
1863     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, OUT PVOID *ppUnk)
1864     {
1865         LIMITED_METHOD_CONTRACT;
1866         if (riid != IID_ICLRGCManager && riid != IID_ICLRGCManager2 && riid != IID_IUnknown)
1867             return (E_NOINTERFACE);
1868         *ppUnk = this;
1869         return S_OK;
1870     }
1871
1872     virtual ULONG STDMETHODCALLTYPE Release(void)
1873     {
1874         LIMITED_METHOD_CONTRACT;
1875         return 1;
1876     }
1877 private:
1878     HRESULT _SetGCSegmentSize(SIZE_T SegmentSize);
1879     HRESULT _SetGCMaxGen0Size(SIZE_T MaxGen0Size);
1880 };
1881
1882
1883 HRESULT CCLRGCManager::_SetGCSegmentSize(SIZE_T SegmentSize)
1884 {
1885     CONTRACTL
1886     {
1887         NOTHROW;
1888         GC_NOTRIGGER;
1889     }
1890     CONTRACTL_END;
1891
1892     HRESULT hr = S_OK;
1893
1894     // Sanity check the value, it must be a power of two and big enough.
1895     if (!GCHeapUtilities::GetGCHeap()->IsValidSegmentSize(SegmentSize))
1896     {
1897         hr = E_INVALIDARG;
1898     }
1899     else
1900     {
1901         Host_SegmentSize = SegmentSize;
1902         Host_fSegmentSizeSet = TRUE;
1903     }
1904
1905     return (hr);
1906 }
1907
1908 HRESULT CCLRGCManager::_SetGCMaxGen0Size(SIZE_T MaxGen0Size)
1909 {
1910     CONTRACTL
1911     {
1912         NOTHROW;
1913         GC_NOTRIGGER;
1914     }
1915     CONTRACTL_END;
1916
1917     HRESULT hr = S_OK;
1918
1919     // Sanity check the value is at least large enough.
1920     if (!GCHeapUtilities::GetGCHeap()->IsValidGen0MaxSize(MaxGen0Size))
1921     {
1922         hr = E_INVALIDARG;
1923     }
1924     else
1925     {
1926         Host_MaxGen0Size = MaxGen0Size;
1927         Host_fMaxGen0SizeSet = TRUE;
1928     }
1929
1930     return (hr);
1931 }
1932
1933 static CCLRGCManager s_GCManager;
1934 #endif //FEATURE_WINDOWSPHONE
1935
1936 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
1937 class CCLRAppDomainResourceMonitor : public ICLRAppDomainResourceMonitor
1938 {
1939 public:
1940     virtual HRESULT STDMETHODCALLTYPE GetCurrentAllocated(DWORD dwAppDomainId, 
1941                                                           ULONGLONG* pBytesAllocated)
1942     {
1943         CONTRACTL
1944         {
1945             NOTHROW;
1946             GC_NOTRIGGER;
1947             ENTRY_POINT;
1948         }
1949         CONTRACTL_END;
1950
1951         HRESULT     hr = S_OK;
1952
1953         BEGIN_ENTRYPOINT_NOTHROW;
1954
1955         SystemDomain::LockHolder lh;
1956
1957         AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD);        
1958         if (pBytesAllocated)
1959         {
1960             *pBytesAllocated = pAppDomain->GetAllocBytes();
1961         }
1962
1963         END_ENTRYPOINT_NOTHROW;
1964
1965         return (hr);
1966     }
1967
1968     virtual HRESULT STDMETHODCALLTYPE GetCurrentSurvived(DWORD dwAppDomainId, 
1969                                                          ULONGLONG* pAppDomainBytesSurvived, 
1970                                                          ULONGLONG* pTotalBytesSurvived)
1971     {
1972         CONTRACTL
1973         {
1974             NOTHROW;
1975             GC_NOTRIGGER;
1976             ENTRY_POINT;
1977         }
1978         CONTRACTL_END;
1979
1980         HRESULT     hr = S_OK;
1981         BEGIN_ENTRYPOINT_NOTHROW;
1982
1983         SystemDomain::LockHolder lh;
1984
1985         AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD);
1986         if (pAppDomainBytesSurvived)
1987         {
1988             *pAppDomainBytesSurvived = pAppDomain->GetSurvivedBytes();
1989         }
1990         if (pTotalBytesSurvived)
1991         {
1992             *pTotalBytesSurvived = SystemDomain::GetTotalSurvivedBytes();
1993         }
1994
1995         END_ENTRYPOINT_NOTHROW;
1996
1997         return (hr);
1998     }
1999
2000     virtual HRESULT STDMETHODCALLTYPE GetCurrentCpuTime(DWORD dwAppDomainId, 
2001                                                         ULONGLONG* pMilliseconds)
2002     {
2003         CONTRACTL
2004         {
2005             NOTHROW;
2006             GC_TRIGGERS;
2007             ENTRY_POINT;
2008         }
2009         CONTRACTL_END;
2010
2011         HRESULT hr = S_OK;
2012
2013         BEGIN_ENTRYPOINT_NOTHROW;
2014
2015         {
2016             SystemDomain::LockHolder lh;
2017     
2018             AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD);
2019             if (pMilliseconds)
2020             {
2021                 *pMilliseconds = pAppDomain->QueryProcessorUsage() / 10000;
2022             }
2023         }
2024
2025         END_ENTRYPOINT_NOTHROW;
2026
2027         return hr;
2028     }
2029
2030     virtual ULONG STDMETHODCALLTYPE AddRef(void)
2031     {
2032         LIMITED_METHOD_CONTRACT;
2033         return 1;
2034     }
2035
2036     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, OUT PVOID *ppUnk)
2037     {
2038         LIMITED_METHOD_CONTRACT;
2039         *ppUnk = NULL;
2040         if (riid == IID_IUnknown)
2041             *ppUnk = (IUnknown*)this;
2042         else if (riid == IID_ICLRAppDomainResourceMonitor)
2043             *ppUnk = (ICLRAppDomainResourceMonitor*)this;
2044         else
2045             return E_NOINTERFACE;
2046         return S_OK;
2047     }
2048
2049     virtual ULONG STDMETHODCALLTYPE Release(void)
2050     {
2051         LIMITED_METHOD_CONTRACT;
2052         return 1;
2053     }
2054 };
2055 static CCLRAppDomainResourceMonitor s_Arm;
2056 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2057
2058
2059 BOOL g_CLRPolicyRequested = FALSE;
2060
2061 class CCorCLRControl: public ICLRControl
2062 {
2063 public:
2064     virtual HRESULT STDMETHODCALLTYPE GetCLRManager(REFIID riid, void **ppObject)
2065     {
2066         CONTRACTL
2067         {
2068             NOTHROW;
2069             GC_NOTRIGGER;
2070         }
2071         CONTRACTL_END;
2072
2073         // Sanity check.
2074         if (ppObject == NULL)
2075             return E_INVALIDARG;
2076
2077 #if defined(FEATURE_WINDOWSPHONE)
2078         if (riid == IID_ICLRErrorReportingManager2)
2079         {
2080             *ppObject = &g_CLRErrorReportingManager;
2081             return S_OK;
2082         }
2083         else
2084 #endif //defined(FEATURE_WINDOWSPHONE)
2085         if (g_fEEStarted && !m_fFullAccess)
2086         {
2087             // If runtime has been started, do not allow user to obtain CLR managers.
2088             return HOST_E_INVALIDOPERATION;
2089         }
2090
2091         // CoreCLR supports ICLRPolicyManager since it allows the host
2092         // to specify the policy for AccessViolation.  
2093         else if (riid == IID_ICLRPolicyManager) {
2094             *ppObject = &s_PolicyManager;
2095             FastInterlockExchange((LONG*)&g_CLRPolicyRequested, TRUE);
2096             return S_OK;
2097         }
2098
2099 #if defined(FEATURE_WINDOWSPHONE)
2100         else if ((riid == IID_ICLRGCManager) || (riid == IID_ICLRGCManager2))
2101         {
2102             *ppObject = &s_GCManager;
2103             return S_OK;
2104         }
2105 #endif //FEATURE_WINDOWSPHONE
2106
2107 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2108         else if (riid == IID_ICLRAppDomainResourceMonitor)
2109         {
2110             EnableARM();
2111             *ppObject = &s_Arm;
2112             return S_OK;
2113         }
2114 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2115         else
2116             return (E_NOINTERFACE);
2117     }
2118
2119     virtual HRESULT STDMETHODCALLTYPE SetAppDomainManagerType(
2120         LPCWSTR pwzAppDomainManagerAssembly,
2121         LPCWSTR pwzAppDomainManagerType)
2122     {
2123         
2124         // CoreCLR does not support this method
2125         return E_NOTIMPL;
2126     }
2127
2128     virtual ULONG STDMETHODCALLTYPE AddRef(void)
2129     {
2130         LIMITED_METHOD_CONTRACT;
2131         return 1;
2132     }
2133
2134     virtual ULONG STDMETHODCALLTYPE Release(void)
2135     {
2136         LIMITED_METHOD_CONTRACT;
2137         return 1;
2138     }
2139
2140     BEGIN_INTERFACE HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
2141                                                              void **ppvObject)
2142     {
2143         LIMITED_METHOD_CONTRACT;
2144         if (riid != IID_ICLRControl && riid != IID_IUnknown)
2145             return (E_NOINTERFACE);
2146
2147         // Ensure that the out going pointer is not null
2148         if (ppvObject == NULL)
2149             return E_POINTER;
2150
2151         *ppvObject = this;
2152         return S_OK;
2153     }
2154
2155     // This is to avoid having ctor.  We have static objects, and it is
2156     // difficult to support ctor on certain platform.
2157     void SetAccess(BOOL fFullAccess)
2158     {
2159         LIMITED_METHOD_CONTRACT;
2160         m_fFullAccess = fFullAccess;
2161     }
2162 private:
2163     BOOL m_fFullAccess;
2164 };
2165
2166 // Before CLR starts, we give out s_CorCLRControl which has full access to all managers.
2167 // After CLR starts, we give out s_CorCLRControlLimited which allows limited access to managers.
2168 static CCorCLRControl s_CorCLRControl;
2169
2170
2171 ///////////////////////////////////////////////////////////////////////////////
2172 // ICLRRuntimeHost::GetCLRControl
2173 HRESULT CorHost2::GetCLRControl(ICLRControl** pCLRControl)
2174 {
2175     LIMITED_METHOD_CONTRACT;
2176     
2177     // Ensure that we have a valid pointer
2178     if (pCLRControl == NULL)
2179     {
2180         return E_POINTER;
2181     }
2182
2183     HRESULT hr = S_OK;
2184     
2185     STATIC_CONTRACT_ENTRY_POINT;
2186     BEGIN_ENTRYPOINT_NOTHROW;
2187     if (!g_fEEStarted && m_Version >= 2)
2188     {
2189         s_CorCLRControl.SetAccess(TRUE);
2190         *pCLRControl = &s_CorCLRControl;
2191     }
2192     else
2193     {
2194         // If :
2195         // 1) request comes for interface other than ICLRControl*, OR
2196         // 2) runtime has already started, OR
2197         // 3) version is not 2
2198         //
2199         // we will return failure and set the out pointer to NULL
2200         *pCLRControl = NULL;
2201         if (g_fEEStarted)
2202         {
2203             // Return HOST_E_INVALIDOPERATION as per MSDN if runtime has already started
2204             hr = HOST_E_INVALIDOPERATION;
2205         }
2206         else
2207         {
2208             hr = E_NOTIMPL;
2209         }
2210     }
2211     END_ENTRYPOINT_NOTHROW;
2212
2213     return hr;
2214 }
2215
2216 // static
2217 EInitializeNewDomainFlags CorHost2::GetAppDomainManagerInitializeNewDomainFlags()
2218 {
2219     LIMITED_METHOD_CONTRACT;
2220     return eInitializeNewDomainFlags_None;
2221 }
2222
2223
2224 #endif // !DAC
2225
2226
2227 #ifdef DACCESS_COMPILE
2228
2229
2230 #endif //DACCESS_COMPILE
2231
2232 #ifndef DACCESS_COMPILE
2233
2234
2235 #if defined(FEATURE_WINDOWSPHONE)
2236
2237 HRESULT CCLRErrorReportingManager::QueryInterface(REFIID riid, void** ppUnk)
2238 {
2239     if (!ppUnk)
2240         return E_POINTER;
2241
2242     CONTRACTL
2243     {
2244         NOTHROW;
2245         GC_NOTRIGGER;
2246     }
2247     CONTRACTL_END;
2248
2249     HRESULT hr = S_OK;
2250     
2251     if (ppUnk == NULL)
2252     {
2253         return E_POINTER;
2254     }
2255
2256     *ppUnk = 0;
2257
2258     // Deliberately do NOT hand out ICorConfiguration.  They must explicitly call
2259     // GetConfiguration to obtain that interface.
2260     if (riid == IID_IUnknown)
2261     {
2262         *ppUnk = (IUnknown *) this;
2263     }
2264     else if (riid == IID_ICLRErrorReportingManager)
2265     {
2266         *ppUnk = (ICLRErrorReportingManager *) this;
2267     }
2268 #ifdef FEATURE_WINDOWSPHONE
2269     else if (riid == IID_ICLRErrorReportingManager2)
2270     {
2271         *ppUnk = (ICLRErrorReportingManager2 *) this;
2272     }
2273 #endif // FEATURE_WINDOWSPHONE
2274     else
2275     {
2276         hr = E_NOINTERFACE;
2277     }
2278
2279     return hr;
2280
2281 } // HRESULT CCLRErrorReportingManager::QueryInterface()
2282
2283 ULONG CCLRErrorReportingManager::AddRef()
2284 {
2285     LIMITED_METHOD_CONTRACT;
2286     return 1;
2287 } // HRESULT CCLRErrorReportingManager::AddRef()
2288
2289 ULONG CCLRErrorReportingManager::Release()
2290 {
2291     LIMITED_METHOD_CONTRACT;
2292     return 1;
2293 } // HRESULT CCLRErrorReportingManager::Release()
2294
2295 // Get Watson bucket parameters for "current" exception (on calling thread).
2296 HRESULT CCLRErrorReportingManager::GetBucketParametersForCurrentException(
2297     BucketParameters *pParams)
2298 {
2299     CONTRACTL
2300     {
2301         WRAPPER(THROWS);
2302         WRAPPER(GC_TRIGGERS);
2303         ENTRY_POINT;
2304     }
2305     CONTRACTL_END;
2306
2307     HRESULT hr = S_OK;
2308     BEGIN_ENTRYPOINT_NOTHROW;
2309
2310     // To avoid confusion, clear the buckets.
2311     memset(pParams, 0, sizeof(BucketParameters));
2312
2313 #ifndef FEATURE_PAL   
2314     // Defer to Watson helper.
2315     hr = ::GetBucketParametersForCurrentException(pParams);
2316  #else
2317     // Watson doesn't exist on non-windows platforms
2318     hr = E_NOTIMPL;
2319 #endif // !FEATURE_PAL
2320
2321     END_ENTRYPOINT_NOTHROW;
2322
2323     return hr;
2324
2325 } // HRESULT CCLRErrorReportingManager::GetBucketParametersForCurrentException()
2326
2327 //
2328 // The BeginCustomDump function configures the custom dump support
2329 //
2330 // Parameters -
2331 // dwFlavor     - The flavor of the dump
2332 // dwNumItems   - The number of items in the CustomDumpItem array.
2333 //                  Should always be zero today, since no custom items are defined
2334 // items        - Array of CustomDumpItem structs specifying items to be added to the dump.
2335 //                  Should always be NULL today, since no custom items are defined.
2336 // dwReserved   - reserved for future use. Must be zero today
2337 //
2338 HRESULT CCLRErrorReportingManager::BeginCustomDump( ECustomDumpFlavor dwFlavor,
2339                                         DWORD dwNumItems,
2340                                         CustomDumpItem items[],
2341                                         DWORD dwReserved)
2342 {
2343     STATIC_CONTRACT_ENTRY_POINT;
2344     HRESULT hr = S_OK;
2345
2346     BEGIN_ENTRYPOINT_NOTHROW;
2347
2348     if (dwNumItems != 0 ||  items != NULL || dwReserved != 0)
2349     {
2350         IfFailGo(E_INVALIDARG);
2351     }
2352     if (g_ECustomDumpFlavor != DUMP_FLAVOR_Default)
2353     {
2354         // BeginCustomDump is called without matching EndCustomDump
2355         IfFailGo(E_INVALIDARG);
2356     }
2357     g_ECustomDumpFlavor = dwFlavor;
2358
2359 ErrExit:
2360     END_ENTRYPOINT_NOTHROW;
2361
2362     return hr;
2363 }
2364
2365 //
2366 // EndCustomDump clears the custom dump configuration
2367 //
2368 HRESULT CCLRErrorReportingManager::EndCustomDump()
2369 {
2370     STATIC_CONTRACT_ENTRY_POINT;
2371     // NOT IMPLEMENTED YET
2372     BEGIN_ENTRYPOINT_NOTHROW;
2373     g_ECustomDumpFlavor = DUMP_FLAVOR_Default;
2374     END_ENTRYPOINT_NOTHROW;
2375
2376     return S_OK;
2377 }
2378
2379 #ifdef FEATURE_WINDOWSPHONE
2380 HRESULT CopyStringWorker(_Out_ WCHAR** pTarget, WCHAR const* pSource)
2381 {
2382     LIMITED_METHOD_CONTRACT;
2383
2384     if (pTarget == NULL || pSource == NULL)
2385         return E_INVALIDARG;
2386
2387     if (*pTarget)
2388         delete[] (*pTarget);
2389
2390     // allocate space for the data plus one wchar for NULL
2391     size_t sourceLen = wcslen(pSource);
2392     *pTarget = new (nothrow) WCHAR[sourceLen + 1];
2393     
2394     if (!(*pTarget))
2395         return E_OUTOFMEMORY;
2396
2397     errno_t result = wcsncpy_s(*pTarget, sourceLen + 1, pSource, sourceLen);
2398     _ASSERTE(result == 0);
2399     
2400     if (result != 0)
2401     {
2402         delete[] (*pTarget);
2403         *pTarget = NULL;
2404
2405         return E_FAIL;
2406     }
2407
2408     return S_OK;
2409 }
2410
2411 CCLRErrorReportingManager::BucketParamsCache::BucketParamsCache(DWORD maxNumParams) : m_pParams(NULL), m_cMaxParams(maxNumParams)
2412 {
2413     LIMITED_METHOD_CONTRACT;
2414 }
2415
2416 CCLRErrorReportingManager::BucketParamsCache::~BucketParamsCache()
2417 {
2418     LIMITED_METHOD_CONTRACT;
2419
2420     if (m_pParams)
2421     {
2422         for (DWORD i = 0; i < m_cMaxParams; ++i)
2423             if (m_pParams[i]) delete[] m_pParams[i];
2424     }
2425 }
2426
2427 WCHAR const* CCLRErrorReportingManager::BucketParamsCache::GetAt(BucketParameterIndex index)
2428 {
2429     LIMITED_METHOD_CONTRACT;
2430
2431     if (index >= InvalidBucketParamIndex)
2432     {
2433         _ASSERTE(!"bad bucket parameter index");
2434         return NULL;
2435     }
2436
2437     if (!m_pParams)
2438         return NULL;
2439
2440     return m_pParams[index];
2441 }
2442
2443 HRESULT CCLRErrorReportingManager::BucketParamsCache::SetAt(BucketParameterIndex index, WCHAR const* val)
2444 {
2445     LIMITED_METHOD_CONTRACT;
2446
2447     if (index < 0 || index >= InvalidBucketParamIndex)
2448     {
2449         _ASSERTE(!"bad bucket parameter index");
2450         return E_INVALIDARG;
2451     }
2452
2453     if (!val)
2454         return E_INVALIDARG;
2455
2456     if (!m_pParams)
2457     {
2458         m_pParams = new (nothrow) WCHAR*[m_cMaxParams];
2459         if (!m_pParams)
2460             return E_OUTOFMEMORY;
2461
2462         for (DWORD i = 0; i < m_cMaxParams; ++i)
2463             m_pParams[i] = NULL;
2464     }
2465
2466     return CopyStringWorker(&m_pParams[index], val);
2467 }
2468
2469 HRESULT CCLRErrorReportingManager::CopyToDataCache(_Out_ WCHAR** pTarget, WCHAR const* pSource)
2470 {
2471     LIMITED_METHOD_CONTRACT;
2472
2473     return CopyStringWorker(pTarget, pSource);
2474 }
2475
2476 HRESULT CCLRErrorReportingManager::SetApplicationData(ApplicationDataKey key, WCHAR const* pValue)
2477 {
2478     STATIC_CONTRACT_ENTRY_POINT;
2479
2480     BEGIN_ENTRYPOINT_NOTHROW;
2481
2482     if(g_fEEStarted)
2483         return HOST_E_INVALIDOPERATION;
2484
2485     if (pValue == NULL || wcslen(pValue) > MAX_LONGPATH)
2486         return E_INVALIDARG;
2487
2488     HRESULT hr = S_OK;
2489
2490     switch (key)
2491     {
2492     case ApplicationID:
2493         hr = CopyToDataCache(&m_pApplicationId, pValue);
2494         break;
2495
2496     case InstanceID:
2497         hr = CopyToDataCache(&m_pInstanceId, pValue);
2498         break;
2499
2500     default:
2501         hr = E_INVALIDARG;
2502     }
2503     
2504     END_ENTRYPOINT_NOTHROW;
2505
2506     return hr;
2507 }
2508
2509 HRESULT CCLRErrorReportingManager::SetBucketParametersForUnhandledException(BucketParameters const* pBucketParams, DWORD* pCountParams)
2510 {
2511     STATIC_CONTRACT_ENTRY_POINT;
2512
2513     BEGIN_ENTRYPOINT_NOTHROW;
2514
2515     if(g_fEEStarted)
2516         return HOST_E_INVALIDOPERATION;
2517
2518     if (pBucketParams == NULL || pCountParams == NULL || pBucketParams->fInited != TRUE)
2519         return E_INVALIDARG;
2520
2521     *pCountParams = 0;
2522
2523     if (!m_pBucketParamsCache)
2524     {
2525         m_pBucketParamsCache = new (nothrow) BucketParamsCache(InvalidBucketParamIndex);
2526         if (!m_pBucketParamsCache)
2527             return E_OUTOFMEMORY;
2528     }
2529
2530     HRESULT hr = S_OK;
2531     bool hasOverride = false;
2532
2533     for (DWORD i = 0; i < InvalidBucketParamIndex; ++i)
2534     {
2535         if (pBucketParams->pszParams[i][0] != W('\0'))
2536         {
2537             hasOverride = true;
2538             hr = m_pBucketParamsCache->SetAt(static_cast<BucketParameterIndex>(i), pBucketParams->pszParams[i]);
2539             if (SUCCEEDED(hr))
2540                 *pCountParams += 1;
2541             else
2542                 break;
2543         }
2544     }
2545     
2546     if (!hasOverride)
2547         return E_INVALIDARG;
2548     
2549     END_ENTRYPOINT_NOTHROW;
2550
2551     return hr;
2552 }
2553
2554 WCHAR const* CCLRErrorReportingManager::GetApplicationData(ApplicationDataKey key)
2555 {
2556     LIMITED_METHOD_CONTRACT;
2557
2558     WCHAR* pValue = NULL;
2559
2560     switch (key)
2561     {
2562     case ApplicationID:
2563         pValue = m_pApplicationId;
2564         break;
2565
2566     case InstanceID:
2567         pValue = m_pInstanceId;
2568         break;
2569
2570     default:
2571         _ASSERTE(!"invalid key specified");
2572     }
2573
2574     return pValue;
2575 }
2576
2577 WCHAR const* CCLRErrorReportingManager::GetBucketParamOverride(BucketParameterIndex bucketParamId)
2578 {
2579     LIMITED_METHOD_CONTRACT;
2580
2581     if (!m_pBucketParamsCache)
2582         return NULL;
2583
2584     return m_pBucketParamsCache->GetAt(bucketParamId);
2585 }
2586
2587 #endif // FEATURE_WINDOWSPHONE
2588
2589 CCLRErrorReportingManager::CCLRErrorReportingManager()
2590 {
2591     LIMITED_METHOD_CONTRACT;
2592 #ifdef FEATURE_WINDOWSPHONE
2593     m_pApplicationId = NULL;
2594     m_pInstanceId = NULL;
2595     m_pBucketParamsCache = NULL;
2596 #endif
2597 }
2598
2599 CCLRErrorReportingManager::~CCLRErrorReportingManager()
2600 {
2601     LIMITED_METHOD_CONTRACT;
2602 #ifdef FEATURE_WINDOWSPHONE
2603     if (m_pApplicationId)
2604         delete[] m_pApplicationId;
2605
2606     if (m_pInstanceId)
2607         delete[] m_pInstanceId;
2608
2609     if (m_pBucketParamsCache)
2610         delete m_pBucketParamsCache;
2611 #endif
2612 }
2613
2614 #endif // defined(FEATURE_WINDOWSPHONE)
2615
2616 void GetProcessMemoryLoad(LPMEMORYSTATUSEX pMSEX)
2617 {
2618     CONTRACTL
2619     {
2620         NOTHROW;
2621         GC_NOTRIGGER;
2622     }
2623     CONTRACTL_END;
2624
2625     pMSEX->dwLength = sizeof(MEMORYSTATUSEX);
2626     BOOL fRet = GlobalMemoryStatusEx(pMSEX);
2627     _ASSERTE (fRet);
2628 }
2629
2630 // This is the instance that exposes interfaces out to all the other DLLs of the CLR
2631 // so they can use our services for TLS, synchronization, memory allocation, etc.
2632 static BYTE g_CEEInstance[sizeof(CExecutionEngine)];
2633 static Volatile<IExecutionEngine*> g_pCEE = NULL;
2634
2635 PTLS_CALLBACK_FUNCTION CExecutionEngine::Callbacks[MAX_PREDEFINED_TLS_SLOT];
2636
2637 extern "C" IExecutionEngine * __stdcall IEE()
2638 {
2639     LIMITED_METHOD_CONTRACT;
2640
2641     // Unfortunately,we can't probe here. The probing system requires the
2642     // use of TLS, and in order to initialize TLS we need to call IEE.
2643
2644     //BEGIN_ENTRYPOINT_VOIDRET;
2645
2646
2647     // The following code does NOT contain a race condition.  The following code is BY DESIGN.
2648     // The issue is that we can have two separate threads inside this if statement, both of which are
2649     // initializing the g_CEEInstance variable (and subsequently updating g_pCEE).  This works fine,
2650     // and will not cause an inconsistent state due to the fact that CExecutionEngine has no
2651     // local variables.  If multiple threads make it inside this if statement, it will copy the same
2652     // bytes over g_CEEInstance and there will not be a time when there is an inconsistent state.
2653     if ( !g_pCEE )
2654     {
2655         // Create a local copy on the stack and then copy it over to the static instance.
2656         // This avoids race conditions caused by multiple initializations of vtable in the constructor
2657        CExecutionEngine local;
2658        memcpy(&g_CEEInstance, (void*)&local, sizeof(CExecutionEngine));
2659
2660        g_pCEE = (IExecutionEngine*)(CExecutionEngine*)&g_CEEInstance;
2661     }
2662     //END_ENTRYPOINT_VOIDRET;
2663
2664     return g_pCEE;
2665 }
2666
2667
2668 HRESULT STDMETHODCALLTYPE CExecutionEngine::QueryInterface(REFIID id, void **pInterface)
2669 {
2670     LIMITED_METHOD_CONTRACT;
2671
2672     if (!pInterface)
2673         return E_POINTER;
2674
2675     *pInterface = NULL;
2676
2677     //CANNOTTHROWCOMPLUSEXCEPTION();
2678     if (id == IID_IExecutionEngine)
2679         *pInterface = (IExecutionEngine *)this;
2680     else if (id == IID_IEEMemoryManager)
2681         *pInterface = (IEEMemoryManager *)this;
2682     else if (id == IID_IUnknown)
2683         *pInterface = (IUnknown *)(IExecutionEngine *)this;
2684     else
2685         return E_NOINTERFACE;
2686
2687     AddRef();
2688     return S_OK;
2689 } // HRESULT STDMETHODCALLTYPE CExecutionEngine::QueryInterface()
2690
2691
2692 ULONG STDMETHODCALLTYPE CExecutionEngine::AddRef()
2693 {
2694     LIMITED_METHOD_CONTRACT;
2695     return 1;
2696 }
2697
2698 ULONG STDMETHODCALLTYPE CExecutionEngine::Release()
2699 {
2700     LIMITED_METHOD_CONTRACT;
2701     return 1;
2702 }
2703
2704 struct ClrTlsInfo
2705 {
2706     void* data[MAX_PREDEFINED_TLS_SLOT];
2707 };
2708
2709 #define DataToClrTlsInfo(a) ((ClrTlsInfo*)a)
2710
2711 void** CExecutionEngine::GetTlsData()
2712 {
2713     LIMITED_METHOD_CONTRACT;
2714
2715    return gCurrentThreadInfo.m_EETlsData;
2716 }
2717
2718 BOOL CExecutionEngine::SetTlsData (void** ppTlsInfo)
2719 {
2720     LIMITED_METHOD_CONTRACT;
2721
2722     gCurrentThreadInfo.m_EETlsData = ppTlsInfo;
2723     return TRUE;
2724 }
2725
2726 //---------------------------------------------------------------------------------------
2727 //
2728 // Returns the current logical thread's data block (ClrTlsInfo::data).
2729 //
2730 // Arguments:
2731 //    slot - Index of the slot that is about to be requested
2732 //    force - If the data block does not exist yet, create it as a side-effect
2733 //
2734 // Return Value:
2735 //    NULL, if the data block did not exist yet for the current thread and force was FALSE.
2736 //    A pointer to the data block, otherwise.
2737 //
2738 // Notes:
2739 //    If the underlying OS does not support fiber mode, the data block is stored in TLS.
2740 //    If the underlying OS does support fiber mode, it is primarily stored in FLS,
2741 //    and cached in TLS so that we can use our generated optimized TLS accessors.
2742 //
2743 // TLS support for the other DLLs of the CLR operates quite differently in hosted
2744 // and unhosted scenarios.
2745
2746 void **CExecutionEngine::CheckThreadState(DWORD slot, BOOL force)
2747 {
2748     STATIC_CONTRACT_GC_NOTRIGGER;
2749     STATIC_CONTRACT_THROWS;
2750     STATIC_CONTRACT_MODE_ANY;
2751     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
2752
2753     //<TODO> @TODO: Decide on an exception strategy for all the DLLs of the CLR, and then
2754     // enable all the exceptions out of this method.</TODO>
2755
2756     // Treat as a runtime assertion, since the invariant spans many DLLs.
2757     _ASSERTE(slot < MAX_PREDEFINED_TLS_SLOT);
2758 //    if (slot >= MAX_PREDEFINED_TLS_SLOT)
2759 //        COMPlusThrow(kArgumentOutOfRangeException);
2760
2761     void** pTlsData = CExecutionEngine::GetTlsData();
2762     BOOL fInTls = (pTlsData != NULL);
2763
2764     ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData);
2765     if (pTlsInfo == 0 && force)
2766     {
2767 #undef HeapAlloc
2768 #undef GetProcessHeap
2769         // !!! Contract uses our TLS support.  Contract may be used before our host support is set up.
2770         // !!! To better support contract, we call into OS for memory allocation.
2771         pTlsInfo = (ClrTlsInfo*) ::HeapAlloc(GetProcessHeap(),0,sizeof(ClrTlsInfo));
2772 #define GetProcessHeap() Dont_Use_GetProcessHeap()
2773 #define HeapAlloc(hHeap, dwFlags, dwBytes) Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes)
2774         if (pTlsInfo == NULL)
2775         {
2776             goto LError;
2777         }
2778         memset (pTlsInfo, 0, sizeof(ClrTlsInfo));
2779     }
2780
2781     if (!fInTls && pTlsInfo)
2782     {
2783         if (!CExecutionEngine::SetTlsData(pTlsInfo->data))
2784         {
2785             goto LError;
2786         }
2787     }
2788
2789     return pTlsInfo?pTlsInfo->data:NULL;
2790
2791 LError:
2792     if (pTlsInfo)
2793     {
2794 #undef HeapFree
2795 #undef GetProcessHeap
2796         ::HeapFree(GetProcessHeap(), 0, pTlsInfo);
2797 #define GetProcessHeap() Dont_Use_GetProcessHeap()
2798 #define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
2799     }
2800     // If this is for the stack probe, and we failed to allocate memory for it, we won't
2801     // put in a guard page.
2802     if (slot == TlsIdx_ClrDebugState)
2803         return NULL;
2804
2805     ThrowOutOfMemory();
2806 }
2807
2808
2809 void **CExecutionEngine::CheckThreadStateNoCreate(DWORD slot
2810 #ifdef _DEBUG
2811                                                   , BOOL fForDestruction
2812 #endif // _DEBUG
2813                                                   )
2814 {
2815     STATIC_CONTRACT_GC_NOTRIGGER;
2816     STATIC_CONTRACT_NOTHROW;
2817     STATIC_CONTRACT_MODE_ANY;
2818
2819     // !!! This function is called during Thread::SwitchIn and SwitchOut
2820     // !!! It is extremely important that while executing this function, we will not
2821     // !!! cause fiber switch.  This means we can not allocate memory, lock, etc...
2822
2823
2824     // Treat as a runtime assertion, since the invariant spans many DLLs.
2825     _ASSERTE(slot < MAX_PREDEFINED_TLS_SLOT);
2826
2827     void **pTlsData = CExecutionEngine::GetTlsData();
2828
2829     ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData);
2830
2831     return pTlsInfo?pTlsInfo->data:NULL;
2832 }
2833
2834 // Note: Sampling profilers also use this function to initialize TLS for a unmanaged 
2835 // sampling thread so that initialization can be done in advance to avoid deadlocks. 
2836 // See ProfToEEInterfaceImpl::InitializeCurrentThread for more details.
2837 void CExecutionEngine::SetupTLSForThread(Thread *pThread)
2838 {
2839     STATIC_CONTRACT_THROWS;
2840     STATIC_CONTRACT_GC_NOTRIGGER;
2841     STATIC_CONTRACT_MODE_ANY;
2842
2843 #ifdef STRESS_LOG
2844     if (StressLog::StressLogOn(~0u, 0))
2845     {
2846         StressLog::CreateThreadStressLog();
2847     }
2848 #endif
2849     void **pTlsData;
2850     pTlsData = CheckThreadState(0);
2851
2852     PREFIX_ASSUME(pTlsData != NULL);
2853
2854 #ifdef ENABLE_CONTRACTS
2855     // Profilers need the side effect of GetClrDebugState() to perform initialization
2856     // in advance to avoid deadlocks. Refer to ProfToEEInterfaceImpl::InitializeCurrentThread
2857     ClrDebugState *pDebugState = ::GetClrDebugState();
2858
2859     if (pThread)
2860         pThread->m_pClrDebugState = pDebugState; 
2861 #endif
2862 }
2863
2864 static void ThreadDetachingHelper(PTLS_CALLBACK_FUNCTION callback, void* pData)
2865 {
2866     // Do not use contract.  We are freeing TLS blocks.
2867     STATIC_CONTRACT_NOTHROW;
2868     STATIC_CONTRACT_GC_NOTRIGGER;
2869     STATIC_CONTRACT_MODE_ANY;
2870
2871     callback(pData);
2872 }
2873
2874 // Called here from a thread detach or from destruction of a Thread object.  In
2875 // the detach case, we get our info from TLS.  In the destruct case, it comes from
2876 // the object we are destructing.
2877 void CExecutionEngine::ThreadDetaching(void ** pTlsData)
2878 {
2879     // Can not cause memory allocation during thread detach, so no real contracts.
2880     STATIC_CONTRACT_NOTHROW;
2881     STATIC_CONTRACT_GC_NOTRIGGER;
2882     STATIC_CONTRACT_MODE_ANY;
2883
2884     // This function may be called twice:
2885     // 1. When a physical thread dies, our DLL_THREAD_DETACH calls this function with pTlsData = NULL
2886     // 2. When a fiber is destroyed, or OS calls FlsCallback after DLL_THREAD_DETACH process.
2887     // We will null the FLS and TLS entry if it matches the deleted one.
2888
2889     if (pTlsData)
2890     {
2891         DeleteTLS (pTlsData);
2892     }
2893 }
2894
2895 void CExecutionEngine::DeleteTLS(void ** pTlsData)
2896 {
2897     // Can not cause memory allocation during thread detach, so no real contracts.
2898     STATIC_CONTRACT_NOTHROW;
2899     STATIC_CONTRACT_GC_NOTRIGGER;
2900     STATIC_CONTRACT_MODE_ANY;
2901
2902     if (CExecutionEngine::GetTlsData() == NULL)
2903     {
2904         // We have not allocated TlsData yet.
2905         return;
2906     }
2907
2908     PREFIX_ASSUME(pTlsData != NULL);
2909
2910     ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData);
2911     BOOL fNeed;
2912     do
2913     {
2914         fNeed = FALSE;
2915         for (int i=0; i<MAX_PREDEFINED_TLS_SLOT; i++)
2916         {
2917             if (i == TlsIdx_ClrDebugState ||
2918                 i == TlsIdx_StressLog)
2919             {
2920                 // StressLog and DebugState may be needed during callback.
2921                 continue;
2922             }
2923             // If we have some data and a callback, issue it.
2924             if (Callbacks[i] != 0 && pTlsInfo->data[i] != 0)
2925             {
2926                 void* pData = pTlsInfo->data[i];
2927                 pTlsInfo->data[i] = 0;
2928                 ThreadDetachingHelper(Callbacks[i], pData);
2929                 fNeed = TRUE;
2930             }
2931         }
2932     } while (fNeed);
2933
2934     if (pTlsInfo->data[TlsIdx_StressLog] != 0)
2935     {
2936 #ifdef STRESS_LOG
2937         StressLog::ThreadDetach((ThreadStressLog *)pTlsInfo->data[TlsIdx_StressLog]);
2938 #else
2939         _ASSERTE (!"should not have StressLog");
2940 #endif
2941     }
2942
2943     if (Callbacks[TlsIdx_ClrDebugState] != 0 && pTlsInfo->data[TlsIdx_ClrDebugState] != 0)
2944     {
2945         void* pData = pTlsInfo->data[TlsIdx_ClrDebugState];
2946         pTlsInfo->data[TlsIdx_ClrDebugState] = 0;
2947         ThreadDetachingHelper(Callbacks[TlsIdx_ClrDebugState], pData);
2948     }
2949
2950     // NULL TLS and FLS entry so that we don't double free.
2951     // We may get two callback here on thread death
2952     // 1. From EEDllMain
2953     // 2. From OS callback on FLS destruction
2954     if (CExecutionEngine::GetTlsData() == pTlsData)
2955     {
2956         CExecutionEngine::SetTlsData(0);
2957     }
2958
2959 #undef HeapFree
2960 #undef GetProcessHeap
2961     ::HeapFree (GetProcessHeap(),0,pTlsInfo);
2962 #define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
2963 #define GetProcessHeap() Dont_Use_GetProcessHeap()
2964
2965 }
2966
2967 #ifdef ENABLE_CONTRACTS_IMPL
2968 // Fls callback to deallocate ClrDebugState when our FLS block goes away.
2969 void FreeClrDebugState(LPVOID pTlsData);
2970 #endif
2971
2972 VOID STDMETHODCALLTYPE CExecutionEngine::TLS_AssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback)
2973 {
2974     WRAPPER_NO_CONTRACT;
2975
2976     CheckThreadState(slot);
2977
2978     // They can toggle between a callback and no callback.  But anything else looks like
2979     // confusion on their part.
2980     //
2981     // (TlsIdx_ClrDebugState associates its callback from utilcode.lib - which can be replicated. But
2982     // all the callbacks are equally good.)
2983     _ASSERTE(slot == TlsIdx_ClrDebugState || Callbacks[slot] == 0 || Callbacks[slot] == callback || callback == 0);
2984     if (slot == TlsIdx_ClrDebugState)
2985     {
2986 #ifdef ENABLE_CONTRACTS_IMPL
2987         // ClrDebugState is shared among many dlls.  Some dll, like perfcounter.dll, may be unloaded.
2988         // We force the callback function to be in mscorwks.dll.
2989         Callbacks[slot] = FreeClrDebugState;
2990 #else
2991         _ASSERTE (!"should not get here");
2992 #endif
2993     }
2994     else
2995         Callbacks[slot] = callback;
2996 }
2997
2998 LPVOID* STDMETHODCALLTYPE CExecutionEngine::TLS_GetDataBlock()
2999 {
3000     STATIC_CONTRACT_GC_NOTRIGGER;
3001     STATIC_CONTRACT_THROWS;
3002     STATIC_CONTRACT_MODE_ANY;
3003     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
3004
3005     return CExecutionEngine::GetTlsData();
3006 }
3007
3008 LPVOID STDMETHODCALLTYPE CExecutionEngine::TLS_GetValue(DWORD slot)
3009 {
3010     WRAPPER_NO_CONTRACT;
3011     return EETlsGetValue(slot);
3012 }
3013
3014 BOOL STDMETHODCALLTYPE CExecutionEngine::TLS_CheckValue(DWORD slot, LPVOID * pValue)
3015 {
3016     WRAPPER_NO_CONTRACT;
3017     return EETlsCheckValue(slot, pValue);
3018 }
3019
3020 VOID STDMETHODCALLTYPE CExecutionEngine::TLS_SetValue(DWORD slot, LPVOID pData)
3021 {
3022     WRAPPER_NO_CONTRACT;
3023     EETlsSetValue(slot,pData);
3024 }
3025
3026
3027 VOID STDMETHODCALLTYPE CExecutionEngine::TLS_ThreadDetaching()
3028 {
3029     WRAPPER_NO_CONTRACT;
3030     CExecutionEngine::ThreadDetaching(NULL);
3031 }
3032
3033
3034 CRITSEC_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags)
3035 {
3036     CONTRACTL
3037     {
3038         NOTHROW;
3039         GC_NOTRIGGER;
3040         MODE_ANY;
3041         ENTRY_POINT;
3042     }
3043     CONTRACTL_END;
3044
3045     CRITSEC_COOKIE cookie = NULL;
3046     BEGIN_ENTRYPOINT_VOIDRET;
3047     cookie = ::EECreateCriticalSection(*(CrstType*)&level, flags);
3048     END_ENTRYPOINT_VOIDRET;
3049     return cookie;
3050 }
3051
3052 void STDMETHODCALLTYPE CExecutionEngine::DestroyLock(CRITSEC_COOKIE cookie)
3053 {
3054     WRAPPER_NO_CONTRACT;
3055     ::EEDeleteCriticalSection(cookie);
3056 }
3057
3058 void STDMETHODCALLTYPE CExecutionEngine::AcquireLock(CRITSEC_COOKIE cookie)
3059 {
3060     WRAPPER_NO_CONTRACT;
3061     ::EEEnterCriticalSection(cookie);
3062 }
3063
3064 void STDMETHODCALLTYPE CExecutionEngine::ReleaseLock(CRITSEC_COOKIE cookie)
3065 {
3066     WRAPPER_NO_CONTRACT;
3067     ::EELeaveCriticalSection(cookie);
3068 }
3069
3070 // Locking routines supplied by the EE to the other DLLs of the CLR.  In a _DEBUG
3071 // build of the EE, we poison the Crst as a poor man's attempt to do some argument
3072 // validation.
3073 #define POISON_BITS 3
3074
3075 static inline EVENT_COOKIE CLREventToCookie(CLREvent * pEvent)
3076 {
3077     LIMITED_METHOD_CONTRACT;
3078     _ASSERTE((((uintptr_t) pEvent) & POISON_BITS) == 0);
3079 #ifdef _DEBUG
3080     pEvent = (CLREvent *) (((uintptr_t) pEvent) | POISON_BITS);
3081 #endif
3082     return (EVENT_COOKIE) pEvent;
3083 }
3084
3085 static inline CLREvent *CookieToCLREvent(EVENT_COOKIE cookie)
3086 {
3087     LIMITED_METHOD_CONTRACT;
3088
3089     _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS);
3090 #ifdef _DEBUG
3091     if (cookie)
3092     {
3093     cookie = (EVENT_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS);
3094     }
3095 #endif
3096     return (CLREvent *) cookie;
3097 }
3098
3099
3100 EVENT_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateAutoEvent(BOOL bInitialState)
3101 {
3102     CONTRACTL
3103     {
3104         THROWS;
3105         MODE_ANY;
3106         GC_NOTRIGGER;
3107         ENTRY_POINT;
3108     }
3109     CONTRACTL_END;
3110
3111     EVENT_COOKIE event = NULL;
3112     BEGIN_ENTRYPOINT_THROWS;
3113     NewHolder<CLREvent> pEvent(new CLREvent());
3114     pEvent->CreateAutoEvent(bInitialState);
3115     event = CLREventToCookie(pEvent);
3116     pEvent.SuppressRelease();
3117     END_ENTRYPOINT_THROWS;
3118
3119     return event;
3120 }
3121
3122 EVENT_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateManualEvent(BOOL bInitialState)
3123 {
3124     CONTRACTL
3125     {
3126         THROWS;
3127         MODE_ANY;
3128         GC_NOTRIGGER;
3129         ENTRY_POINT;
3130     }
3131     CONTRACTL_END;
3132
3133     EVENT_COOKIE event = NULL;
3134     BEGIN_ENTRYPOINT_THROWS;
3135
3136     NewHolder<CLREvent> pEvent(new CLREvent());
3137     pEvent->CreateManualEvent(bInitialState);
3138     event = CLREventToCookie(pEvent);
3139     pEvent.SuppressRelease();
3140
3141     END_ENTRYPOINT_THROWS;
3142
3143     return event;
3144 }
3145
3146 void STDMETHODCALLTYPE CExecutionEngine::CloseEvent(EVENT_COOKIE event)
3147 {
3148     WRAPPER_NO_CONTRACT;
3149     if (event) {
3150         CLREvent *pEvent = CookieToCLREvent(event);
3151         pEvent->CloseEvent();
3152         delete pEvent;
3153     }
3154 }
3155
3156 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrSetEvent(EVENT_COOKIE event)
3157 {
3158     CONTRACTL
3159     {
3160         NOTHROW;
3161         GC_NOTRIGGER;
3162         MODE_ANY;
3163     }
3164     CONTRACTL_END;
3165     if (event) {
3166         CLREvent *pEvent = CookieToCLREvent(event);
3167         return pEvent->Set();
3168     }
3169     return FALSE;
3170 }
3171
3172 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrResetEvent(EVENT_COOKIE event)
3173 {
3174     CONTRACTL
3175     {
3176         NOTHROW;
3177         GC_NOTRIGGER;
3178         MODE_ANY;
3179     }
3180     CONTRACTL_END;
3181     if (event) {
3182         CLREvent *pEvent = CookieToCLREvent(event);
3183         return pEvent->Reset();
3184     }
3185     return FALSE;
3186 }
3187
3188 DWORD STDMETHODCALLTYPE CExecutionEngine::WaitForEvent(EVENT_COOKIE event,
3189                                                        DWORD dwMilliseconds,
3190                                                        BOOL bAlertable)
3191 {
3192     WRAPPER_NO_CONTRACT;
3193     if (event) {
3194         CLREvent *pEvent = CookieToCLREvent(event);
3195         return pEvent->Wait(dwMilliseconds,bAlertable);
3196     }
3197
3198     if (GetThread() && bAlertable)
3199         ThrowHR(E_INVALIDARG);
3200     return WAIT_FAILED;
3201 }
3202
3203 DWORD STDMETHODCALLTYPE CExecutionEngine::WaitForSingleObject(HANDLE handle,
3204                                                               DWORD dwMilliseconds)
3205 {
3206     STATIC_CONTRACT_WRAPPER;
3207     return ::WaitForSingleObject(handle,dwMilliseconds);
3208 }
3209
3210 static inline SEMAPHORE_COOKIE CLRSemaphoreToCookie(CLRSemaphore * pSemaphore)
3211 {
3212     LIMITED_METHOD_CONTRACT;
3213
3214     _ASSERTE((((uintptr_t) pSemaphore) & POISON_BITS) == 0);
3215 #ifdef _DEBUG
3216     pSemaphore = (CLRSemaphore *) (((uintptr_t) pSemaphore) | POISON_BITS);
3217 #endif
3218     return (SEMAPHORE_COOKIE) pSemaphore;
3219 }
3220
3221 static inline CLRSemaphore *CookieToCLRSemaphore(SEMAPHORE_COOKIE cookie)
3222 {
3223     LIMITED_METHOD_CONTRACT;
3224     _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS);
3225 #ifdef _DEBUG
3226     if (cookie)
3227     {
3228     cookie = (SEMAPHORE_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS);
3229     }
3230 #endif
3231     return (CLRSemaphore *) cookie;
3232 }
3233
3234
3235 SEMAPHORE_COOKIE STDMETHODCALLTYPE CExecutionEngine::ClrCreateSemaphore(DWORD dwInitial,
3236                                                                         DWORD dwMax)
3237 {
3238     CONTRACTL
3239     {
3240         THROWS;
3241         MODE_ANY;
3242         GC_NOTRIGGER;
3243     }
3244     CONTRACTL_END;
3245
3246     NewHolder<CLRSemaphore> pSemaphore(new CLRSemaphore());
3247     pSemaphore->Create(dwInitial, dwMax);
3248     SEMAPHORE_COOKIE ret = CLRSemaphoreToCookie(pSemaphore);;
3249     pSemaphore.SuppressRelease();
3250     return ret;
3251 }
3252
3253 void STDMETHODCALLTYPE CExecutionEngine::ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore)
3254 {
3255     CONTRACTL
3256     {
3257         NOTHROW;
3258         GC_NOTRIGGER;
3259         MODE_ANY;
3260     }
3261     CONTRACTL_END;
3262     CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore);
3263     pSemaphore->Close();
3264     delete pSemaphore;
3265 }
3266
3267 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore,
3268                                                              LONG lReleaseCount,
3269                                                              LONG *lpPreviousCount)
3270 {
3271     CONTRACTL
3272     {
3273         NOTHROW;
3274         GC_NOTRIGGER;
3275         MODE_ANY;
3276     }
3277     CONTRACTL_END;
3278     CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore);
3279     return pSemaphore->Release(lReleaseCount,lpPreviousCount);
3280 }
3281
3282 DWORD STDMETHODCALLTYPE CExecutionEngine::ClrWaitForSemaphore(SEMAPHORE_COOKIE semaphore,
3283                                                               DWORD dwMilliseconds,
3284                                                               BOOL bAlertable)
3285 {
3286     WRAPPER_NO_CONTRACT;
3287     CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore);
3288     return pSemaphore->Wait(dwMilliseconds,bAlertable);
3289 }
3290
3291 static inline MUTEX_COOKIE CLRMutexToCookie(CLRMutex * pMutex)
3292 {
3293     LIMITED_METHOD_CONTRACT;
3294     _ASSERTE((((uintptr_t) pMutex) & POISON_BITS) == 0);
3295 #ifdef _DEBUG
3296     pMutex = (CLRMutex *) (((uintptr_t) pMutex) | POISON_BITS);
3297 #endif
3298     return (MUTEX_COOKIE) pMutex;
3299 }
3300
3301 static inline CLRMutex *CookieToCLRMutex(MUTEX_COOKIE cookie)
3302 {
3303     LIMITED_METHOD_CONTRACT;
3304     _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS);
3305 #ifdef _DEBUG
3306     if (cookie)
3307     {
3308     cookie = (MUTEX_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS);
3309     }
3310 #endif
3311     return (CLRMutex *) cookie;
3312 }
3313
3314
3315 MUTEX_COOKIE STDMETHODCALLTYPE CExecutionEngine::ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,
3316                                                                 BOOL bInitialOwner,
3317                                                                 LPCTSTR lpName)
3318 {
3319     CONTRACTL
3320     {
3321         NOTHROW;
3322         MODE_ANY;
3323         GC_NOTRIGGER;
3324     }
3325     CONTRACTL_END;
3326
3327
3328     MUTEX_COOKIE mutex = 0;
3329     CLRMutex *pMutex = new (nothrow) CLRMutex();
3330     if (pMutex)
3331     {
3332         EX_TRY
3333         {
3334             pMutex->Create(lpMutexAttributes, bInitialOwner, lpName);
3335             mutex = CLRMutexToCookie(pMutex);
3336         }
3337         EX_CATCH
3338         {
3339             delete pMutex;
3340         }
3341         EX_END_CATCH(SwallowAllExceptions);
3342     }
3343     return mutex;
3344 }
3345
3346 void STDMETHODCALLTYPE CExecutionEngine::ClrCloseMutex(MUTEX_COOKIE mutex)
3347 {
3348     CONTRACTL
3349     {
3350         NOTHROW;
3351         GC_NOTRIGGER;
3352         MODE_ANY;
3353     }
3354     CONTRACTL_END;
3355     CLRMutex *pMutex = CookieToCLRMutex(mutex);
3356     pMutex->Close();
3357     delete pMutex;
3358 }
3359
3360 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrReleaseMutex(MUTEX_COOKIE mutex)
3361 {
3362     CONTRACTL
3363     {
3364         NOTHROW;
3365         GC_NOTRIGGER;
3366         MODE_ANY;
3367     }
3368     CONTRACTL_END;
3369     CLRMutex *pMutex = CookieToCLRMutex(mutex);
3370     return pMutex->Release();
3371 }
3372
3373 DWORD STDMETHODCALLTYPE CExecutionEngine::ClrWaitForMutex(MUTEX_COOKIE mutex,
3374                                                           DWORD dwMilliseconds,
3375                                                           BOOL bAlertable)
3376 {
3377     CONTRACTL
3378     {
3379         NOTHROW;
3380         GC_NOTRIGGER;
3381         MODE_ANY;
3382     }
3383     CONTRACTL_END;
3384     CLRMutex *pMutex = CookieToCLRMutex(mutex);
3385     return pMutex->Wait(dwMilliseconds,bAlertable);
3386 }
3387
3388 #undef ClrSleepEx
3389 DWORD STDMETHODCALLTYPE CExecutionEngine::ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable)
3390 {
3391     WRAPPER_NO_CONTRACT;
3392     return EESleepEx(dwMilliseconds,bAlertable);
3393 }
3394 #define ClrSleepEx EESleepEx
3395
3396 #undef ClrAllocationDisallowed
3397 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrAllocationDisallowed()
3398 {
3399     WRAPPER_NO_CONTRACT;
3400     return EEAllocationDisallowed();
3401 }
3402 #define ClrAllocationDisallowed EEAllocationDisallowed
3403
3404 #undef ClrVirtualAlloc
3405 LPVOID STDMETHODCALLTYPE CExecutionEngine::ClrVirtualAlloc(LPVOID lpAddress,
3406                                                            SIZE_T dwSize,
3407                                                            DWORD flAllocationType,
3408                                                            DWORD flProtect)
3409 {
3410     WRAPPER_NO_CONTRACT;
3411     return EEVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
3412 }
3413 #define ClrVirtualAlloc EEVirtualAlloc
3414
3415 #undef ClrVirtualFree
3416 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrVirtualFree(LPVOID lpAddress,
3417                                                         SIZE_T dwSize,
3418                                                         DWORD dwFreeType)
3419 {
3420     WRAPPER_NO_CONTRACT;
3421     return EEVirtualFree(lpAddress, dwSize, dwFreeType);
3422 }
3423 #define ClrVirtualFree EEVirtualFree
3424
3425 #undef ClrVirtualQuery
3426 SIZE_T STDMETHODCALLTYPE CExecutionEngine::ClrVirtualQuery(LPCVOID lpAddress,
3427                                                            PMEMORY_BASIC_INFORMATION lpBuffer,
3428                                                            SIZE_T dwLength)
3429 {
3430     WRAPPER_NO_CONTRACT;
3431     return EEVirtualQuery(lpAddress, lpBuffer, dwLength);
3432 }
3433 #define ClrVirtualQuery EEVirtualQuery
3434
3435 #if defined(_DEBUG) && !defined(FEATURE_PAL)
3436 static VolatilePtr<BYTE> s_pStartOfUEFSection = NULL;
3437 static VolatilePtr<BYTE> s_pEndOfUEFSectionBoundary = NULL;
3438 static Volatile<DWORD> s_dwProtection = 0;
3439 #endif // _DEBUG && !FEATURE_PAL
3440
3441 #undef ClrVirtualProtect
3442
3443 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrVirtualProtect(LPVOID lpAddress,
3444                                                            SIZE_T dwSize,
3445                                                            DWORD flNewProtect,
3446                                                            PDWORD lpflOldProtect)
3447 {
3448     WRAPPER_NO_CONTRACT;
3449
3450    // Get the UEF installation details - we will use these to validate
3451    // that the calls to ClrVirtualProtect are not going to affect the UEF.
3452    // 
3453    // The OS UEF invocation mechanism was updated. When a UEF is setup,the OS captures 
3454    // the following details about it:
3455    //  1) Protection of the pages in which the UEF lives
3456    //  2) The size of the region in which the UEF lives
3457    //  3) The region's Allocation Base
3458    //
3459    //  The OS verifies details surrounding the UEF before invocation.  For security reasons 
3460    //  the page protection cannot change between SetUnhandledExceptionFilter and invocation.
3461    //
3462    // Prior to this change, the UEF lived in a common section of code_Seg, along with
3463    // JIT_PatchedCode. Thus, their pages have the same protection, they live
3464    //  in the same region (and thus, its size is the same).
3465    //
3466    // In EEStartupHelper, when we setup the UEF and then invoke InitJitHelpers1 and InitJitHelpers2, 
3467    // they perform some optimizations that result in the memory page protection being changed. When
3468    // the UEF is to be invoked, the OS does the check on the UEF's cached details against the current
3469    // memory pages. This check used to fail when on 64bit retail builds when JIT_PatchedCode was
3470    // aligned after the UEF with a different memory page protection (post the optimizations by InitJitHelpers). 
3471    // Thus, the UEF was never invoked.
3472    //
3473    // To circumvent this, we put the UEF in its own section in the code segment so that any modifications
3474    // to memory pages will not affect the UEF details that the OS cached. This is done in Excep.cpp
3475    // using the "#pragma code_seg" directives.
3476    //
3477    // Below, we double check that:
3478    // 
3479    // 1) the address being protected does not lie in the region of of the UEF. 
3480    // 2) the section after UEF is not having the same memory protection as UEF section.
3481    //
3482    // We assert if either of the two conditions above are true.
3483
3484 #if defined(_DEBUG) && !defined(FEATURE_PAL)
3485    // We do this check in debug/checked builds only
3486
3487     // Do we have the UEF details?
3488     if (s_pEndOfUEFSectionBoundary.Load() == NULL)
3489     {
3490         // Get reference to MSCORWKS image in memory...
3491         PEDecoder pe(g_pMSCorEE);
3492
3493         // Find the UEF section from the image
3494         IMAGE_SECTION_HEADER* pUEFSection = pe.FindSection(CLR_UEF_SECTION_NAME);
3495         _ASSERTE(pUEFSection != NULL);
3496         if (pUEFSection)
3497         {
3498             // We got our section - get the start of the section
3499             BYTE* pStartOfUEFSection = static_cast<BYTE*>(pe.GetBase())+pUEFSection->VirtualAddress;
3500             s_pStartOfUEFSection = pStartOfUEFSection;
3501
3502             // Now we need the protection attributes for the memory region in which the
3503             // UEF section is...
3504             MEMORY_BASIC_INFORMATION uefInfo;
3505             if (ClrVirtualQuery(pStartOfUEFSection, &uefInfo, sizeof(uefInfo)) != 0)
3506             {
3507                 // Calculate how many pages does the UEF section take to get to the start of the
3508                 // next section. We dont calculate this as
3509                 //
3510                 // pStartOfUEFSection + uefInfo.RegionSize
3511                 //
3512                 // because the section following UEF will also be included in the region size
3513                 // if it has the same protection as the UEF section.
3514                 DWORD dwUEFSectionPageCount = ((pUEFSection->Misc.VirtualSize + GetOsPageSize() - 1)/GetOsPageSize());
3515
3516                 BYTE* pAddressOfFollowingSection = pStartOfUEFSection + (GetOsPageSize() * dwUEFSectionPageCount);
3517                 
3518                 // Ensure that the section following us is having different memory protection
3519                 MEMORY_BASIC_INFORMATION nextSectionInfo;
3520                 _ASSERTE(ClrVirtualQuery(pAddressOfFollowingSection, &nextSectionInfo, sizeof(nextSectionInfo)) != 0);
3521                 _ASSERTE(nextSectionInfo.Protect != uefInfo.Protect);
3522                 
3523                 // save the memory protection details
3524                 s_dwProtection = uefInfo.Protect;
3525
3526                 // Get the end of the UEF section
3527                 BYTE* pEndOfUEFSectionBoundary = pAddressOfFollowingSection - 1;
3528                 
3529                 // Set the end of UEF section boundary
3530                 FastInterlockExchangePointer(s_pEndOfUEFSectionBoundary.GetPointer(), pEndOfUEFSectionBoundary);
3531             }
3532             else
3533             {
3534                 _ASSERTE(!"Unable to get UEF Details!");
3535             }
3536         }
3537     }
3538
3539     if (s_pEndOfUEFSectionBoundary.Load() != NULL)
3540     {
3541         // Is the protection being changed?
3542         if (flNewProtect != s_dwProtection)
3543         {
3544             // Is the target address NOT affecting the UEF ? Possible cases:
3545             // 1) Starts and ends before the UEF start
3546             // 2) Starts after the UEF start
3547
3548             void* pEndOfRangeAddr = static_cast<BYTE*>(lpAddress)+dwSize-1;
3549
3550             _ASSERTE_MSG(((pEndOfRangeAddr < s_pStartOfUEFSection.Load()) || (lpAddress > s_pEndOfUEFSectionBoundary.Load())), 
3551                 "Do not virtual protect the section in which UEF lives!");
3552         }
3553     }
3554 #endif // _DEBUG && !FEATURE_PAL
3555
3556     return EEVirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect);
3557 }
3558 #define ClrVirtualProtect EEVirtualProtect
3559
3560 #undef ClrGetProcessHeap
3561 HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrGetProcessHeap()
3562 {
3563     WRAPPER_NO_CONTRACT;
3564     return EEGetProcessHeap();
3565 }
3566 #define ClrGetProcessHeap EEGetProcessHeap
3567
3568 #undef ClrGetProcessExecutableHeap
3569 HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrGetProcessExecutableHeap()
3570 {
3571     WRAPPER_NO_CONTRACT;
3572     return EEGetProcessExecutableHeap();
3573 }
3574 #define ClrGetProcessExecutableHeap EEGetProcessExecutableHeap
3575
3576
3577 #undef ClrHeapCreate
3578 HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrHeapCreate(DWORD flOptions,
3579                                                          SIZE_T dwInitialSize,
3580                                                          SIZE_T dwMaximumSize)
3581 {
3582     WRAPPER_NO_CONTRACT;
3583     return EEHeapCreate(flOptions, dwInitialSize, dwMaximumSize);
3584 }
3585 #define ClrHeapCreate EEHeapCreate
3586
3587 #undef ClrHeapDestroy
3588 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapDestroy(HANDLE hHeap)
3589 {
3590     WRAPPER_NO_CONTRACT;
3591     return EEHeapDestroy(hHeap);
3592 }
3593 #define ClrHeapDestroy EEHeapDestroy
3594
3595 #undef ClrHeapAlloc
3596 LPVOID STDMETHODCALLTYPE CExecutionEngine::ClrHeapAlloc(HANDLE hHeap,
3597                                                         DWORD dwFlags,
3598                                                         SIZE_T dwBytes)
3599 {
3600     WRAPPER_NO_CONTRACT;
3601
3602     return EEHeapAlloc(hHeap, dwFlags, dwBytes);
3603 }
3604 #define ClrHeapAlloc EEHeapAlloc
3605
3606 #undef ClrHeapFree
3607 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapFree(HANDLE hHeap,
3608                                                      DWORD dwFlags,
3609                                                      LPVOID lpMem)
3610 {
3611     WRAPPER_NO_CONTRACT;
3612     return EEHeapFree(hHeap, dwFlags, lpMem);
3613 }
3614 #define ClrHeapFree EEHeapFree
3615
3616 #undef ClrHeapValidate
3617 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapValidate(HANDLE hHeap,
3618                                                          DWORD dwFlags,
3619                                                          LPCVOID lpMem)
3620 {
3621     WRAPPER_NO_CONTRACT;
3622     return EEHeapValidate(hHeap, dwFlags, lpMem);
3623 }
3624 #define ClrHeapValidate EEHeapValidate
3625
3626 //------------------------------------------------------------------------------
3627 // Helper function to get an exception object from outside the exception.  In
3628 //  the CLR, it may be from the Thread object.  Non-CLR users have no thread object,
3629 //  and it will do nothing.
3630
3631 void CExecutionEngine::GetLastThrownObjectExceptionFromThread(void **ppvException)
3632 {
3633     WRAPPER_NO_CONTRACT;
3634
3635     // Cast to our real type.
3636     Exception **ppException = reinterpret_cast<Exception**>(ppvException);
3637
3638     // Try to get a better message.
3639     GetLastThrownObjectExceptionFromThread_Internal(ppException);
3640
3641 } // HRESULT CExecutionEngine::GetLastThrownObjectExceptionFromThread()
3642
3643
3644 LocaleID RuntimeGetFileSystemLocale()
3645 {
3646     return PEImage::GetFileSystemLocale();
3647 };
3648
3649 HRESULT CorHost2::DllGetActivationFactory(DWORD appDomainID, LPCWSTR wszTypeName, IActivationFactory ** factory)
3650 {
3651 #ifdef FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
3652     // WinRT activation currently supported in default domain only
3653     if (appDomainID != DefaultADID)
3654         return HOST_E_INVALIDOPERATION;
3655
3656     HRESULT hr = S_OK;
3657
3658     Thread *pThread = GetThread();
3659     if (pThread == NULL)
3660     {
3661         pThread = SetupThreadNoThrow(&hr);
3662         if (pThread == NULL)
3663         {
3664             return hr;
3665         }
3666     }
3667
3668     if(SystemDomain::GetCurrentDomain()->GetId().m_dwId != DefaultADID)
3669     {
3670         return HOST_E_INVALIDOPERATION;
3671     }
3672
3673     return DllGetActivationFactoryImpl(NULL, wszTypeName, NULL, factory);
3674 #else
3675     return E_NOTIMPL;
3676 #endif
3677 }
3678
3679
3680 #ifdef FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
3681
3682 HRESULT STDMETHODCALLTYPE DllGetActivationFactoryImpl(LPCWSTR wszAssemblyName, 
3683                                                       LPCWSTR wszTypeName, 
3684                                                       LPCWSTR wszCodeBase,
3685                                                       IActivationFactory ** factory)
3686 {
3687     CONTRACTL
3688     {
3689         DISABLED(NOTHROW);
3690         GC_TRIGGERS;
3691         MODE_ANY;
3692         ENTRY_POINT;
3693     }
3694     CONTRACTL_END;
3695
3696     HRESULT hr = S_OK;
3697
3698     BEGIN_ENTRYPOINT_NOTHROW;
3699
3700     AppDomain* pDomain = SystemDomain::System()->DefaultDomain();
3701     _ASSERTE(pDomain);
3702
3703     BEGIN_EXTERNAL_ENTRYPOINT(&hr);
3704     {
3705         GCX_COOP();
3706
3707         bool bIsPrimitive;
3708         TypeHandle typeHandle = WinRTTypeNameConverter::GetManagedTypeFromWinRTTypeName(wszTypeName, &bIsPrimitive);
3709         if (!bIsPrimitive && !typeHandle.IsNull() && !typeHandle.IsTypeDesc() && typeHandle.AsMethodTable()->IsExportedToWinRT())
3710         {
3711             struct _gc {
3712                 OBJECTREF type;
3713             } gc;
3714             memset(&gc, 0, sizeof(gc));
3715
3716
3717             IActivationFactory* activationFactory;
3718             GCPROTECT_BEGIN(gc);
3719
3720             gc.type = typeHandle.GetManagedClassObject();
3721
3722             MethodDescCallSite mdcs(METHOD__WINDOWSRUNTIMEMARSHAL__GET_ACTIVATION_FACTORY_FOR_TYPE);
3723             ARG_SLOT args[1] = {
3724                 ObjToArgSlot(gc.type)
3725             };
3726             activationFactory = (IActivationFactory*)mdcs.Call_RetLPVOID(args);
3727
3728             *factory = activationFactory;
3729
3730             GCPROTECT_END();
3731         }
3732         else
3733         {
3734             hr = COR_E_TYPELOAD;
3735         }
3736     }
3737     END_EXTERNAL_ENTRYPOINT;
3738     END_ENTRYPOINT_NOTHROW;
3739
3740     return hr;
3741 }
3742
3743 #endif // !FEATURE_COMINTEROP_MANAGED_ACTIVATION
3744
3745
3746
3747
3748 #endif // !DACCESS_COMPILE