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