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 //*****************************************************************************
7 // Implementation for the meta data dispenser code.
10 //*****************************************************************************
18 #include "jitinterface.h"
20 #include "dbginterface.h"
25 #include "comcallablewrapper.h"
26 #include "invokeutil.h"
27 #include "appdomain.inl"
29 #include "comdelegate.h"
30 #include "dllimportcallback.h"
31 #include "eventtrace.h"
33 #include "win32threadpool.h"
34 #include "eventtrace.h"
35 #include "finalizerthread.h"
36 #include "threadsuspend.h"
40 #endif // !FEATURE_PAL
42 #include "stringarraylist.h"
43 #ifdef FEATURE_PERFTRACING
44 #include "eventpipe.h"
45 #endif // FEATURE_PERFTRACING
47 #ifdef FEATURE_COMINTEROP
48 #include "winrttypenameconverter.h"
52 GVAL_IMPL_INIT(DWORD, g_fHostConfig, 0);
55 EXTERN_C __declspec(thread) ThreadLocalInfo gCurrentThreadInfo;
57 EXTERN_C __thread ThreadLocalInfo gCurrentThreadInfo;
60 EXTERN_C UINT32 _tls_index;
62 UINT32 _tls_index = 0;
65 #if defined(FEATURE_WINDOWSPHONE)
66 SVAL_IMPL_INIT(ECustomDumpFlavor, CCLRErrorReportingManager, g_ECustomDumpFlavor, DUMP_FLAVOR_Default);
69 #ifndef DACCESS_COMPILE
71 extern void STDMETHODCALLTYPE EEShutDown(BOOL fIsDllUnloading);
72 extern HRESULT STDAPICALLTYPE CoInitializeEE(DWORD fFlags);
73 extern void PrintToStdOutA(const char *pszString);
74 extern void PrintToStdOutW(const WCHAR *pwzString);
75 extern BOOL g_fEEHostedStartup;
77 INT64 g_PauseTime; // Total time in millisecond the CLR has been paused
78 Volatile<BOOL> g_IsPaused; // True if the runtime is paused (FAS)
79 CLREventStatic g_ClrResumeEvent; // Event that is fired at FAS Resuming
81 extern BYTE g_rbTestKeyBuffer[];
83 //***************************************************************************
85 ULONG CorRuntimeHostBase::m_Version = 0;
88 #if defined(FEATURE_WINDOWSPHONE)
89 CCLRErrorReportingManager g_CLRErrorReportingManager;
90 #endif // defined(FEATURE_WINDOWSPHONE)
94 typedef DPTR(CONNID) PTR_CONNID;
98 // Keep track connection id and name
100 #ifndef DACCESS_COMPILE
105 // *** ICorRuntimeHost methods ***
107 CorHost2::CorHost2() : m_fFirstToLoadCLR(FALSE), m_fStarted(FALSE), m_fAppDomainCreated(FALSE)
109 LIMITED_METHOD_CONTRACT;
112 static DangerousNonHostedSpinLock lockOnlyOneToInvokeStart;
114 STDMETHODIMP CorHost2::Start()
125 BEGIN_ENTRYPOINT_NOTHROW;
127 // Ensure that only one thread at a time gets in here
128 DangerousNonHostedSpinLockHolder lockHolder(&lockOnlyOneToInvokeStart);
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.
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.
140 // CoreCLR is already running - but was Start already invoked by this host?
143 // This host had already invoked the Start method - return them an error
144 hr = HOST_E_INVALIDOPERATION;
148 // Increment the global (and dynamic) refCount...
149 FastInterlockIncrement(&m_RefCount);
151 // And set our flag that this host has invoked the Start...
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".
162 // For the case when managed code started without CLR hosting and MC++ does a
163 // CorBindToRuntimeEx, setting the CLR hosted flag is incorrect.
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.
170 g_fHostConfig |= CLRHOSTED;
173 hr = CorRuntimeHostBase::Start();
176 // Set our flag that this host invoked the Start method.
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.
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);
192 END_ENTRYPOINT_NOTHROW;
196 // Starts the runtime. This is equivalent to CoInitializeEE();
197 HRESULT CorRuntimeHostBase::Start()
202 DISABLED(GC_TRIGGERS);
209 BEGIN_ENTRYPOINT_NOTHROW;
212 #ifdef FEATURE_EVENT_TRACE
213 g_fEEHostedStartup = TRUE;
214 #endif // FEATURE_EVENT_TRACE
215 hr = InitializeEE(COINITEE_DEFAULT);
217 END_ENTRYPOINT_NOTHROW;
223 HRESULT CorHost2::Stop()
228 ENTRY_POINT; // We're bringing the EE down, so no point in probing
229 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
237 BEGIN_ENTRYPOINT_NOTHROW;
239 // Is this host eligible to invoke the Stop method?
240 if ((!m_fStarted) && (!m_fFirstToLoadCLR))
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;
252 LONG refCount = m_RefCount;
255 hr = HOST_E_CLRNOTAVAILABLE;
259 if (FastInterlockCompareExchange(&m_RefCount, refCount - 1, refCount) == refCount)
261 // Indicate that we have got a Stop for a corresponding Start call from the
262 // Host. Semantically, CoreCLR has stopped for them.
277 END_ENTRYPOINT_NOTHROW;
284 HRESULT CorHost2::GetCurrentAppDomainId(DWORD *pdwAppDomainId)
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)))
299 return HOST_E_CLRNOTAVAILABLE;
304 BEGIN_ENTRYPOINT_NOTHROW;
306 if(pdwAppDomainId == NULL)
312 Thread *pThread = GetThread();
319 *pdwAppDomainId = SystemDomain::GetCurrentDomain()->GetId().m_dwId;
323 END_ENTRYPOINT_NOTHROW;
328 HRESULT CorHost2::ExecuteApplication(LPCWSTR pwzAppFullName,
329 DWORD dwManifestPaths,
330 LPCWSTR *ppwzManifestPaths,
331 DWORD dwActivationData,
332 LPCWSTR *ppwzActivationData,
339 * This method processes the arguments sent to the host which are then used
340 * to invoke the main method.
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.
348 * ActualCmdLine - Foo arg1 arg2.
349 * (Host1) - Full_path_to_Foo arg1 arg2
351 void SetCommandLineArgs(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR* argv)
361 // Send the command line to EventPipe.
362 #ifdef FEATURE_PERFTRACING
363 EventPipe::SaveCommandLine(pwzAssemblyPath, argc, argv);
364 #endif // FEATURE_PERFTRACING
366 // Send the command line to System.Environment.
369 PTRARRAYREF cmdLineArgs;
372 ZeroMemory(&gc, sizeof(gc));
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);
379 for (int i = 0; i < argc; ++i)
381 OBJECTREF argument = StringObject::NewString(argv[i]);
382 gc.cmdLineArgs->SetAt(i + 1, argument);
385 MethodDescCallSite setCmdLineArgs(METHOD__ENVIRONMENT__SET_COMMAND_LINE_ARGS);
389 ObjToArgSlot(gc.cmdLineArgs),
391 setCmdLineArgs.Call(args);
396 HRESULT CorHost2::ExecuteAssembly(DWORD dwAppDomainId,
397 LPCWSTR pwzAssemblyPath,
404 THROWS; // Throws...as we do not want it to swallow the managed exception
409 // This is currently supported in default domain only
410 if (dwAppDomainId != DefaultADID)
411 return HOST_E_INVALIDOPERATION;
413 // No point going further if the runtime is not running...
414 if (!IsRuntimeActive())
416 return HOST_E_CLRNOTAVAILABLE;
427 if(argc > 0 && argv == NULL)
434 AppDomain *pCurDomain = SystemDomain::GetCurrentDomain();
436 Thread *pThread = GetThread();
439 pThread = SetupThreadNoThrow(&hr);
446 if(pCurDomain->GetId().m_dwId != DefaultADID)
448 return HOST_E_INVALIDOPERATION;
451 INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP;
452 INSTALL_UNWIND_AND_CONTINUE_HANDLER;
454 _ASSERTE (!pThread->PreemptiveGCDisabled());
456 Assembly *pAssembly = AssemblySpec::LoadAssembly(pwzAssemblyPath);
458 #if defined(FEATURE_MULTICOREJIT)
459 pCurDomain->GetMulticoreJitManager().AutoStartProfile(pCurDomain);
460 #endif // defined(FEATURE_MULTICOREJIT)
465 // Here we call the managed method that gets the cmdLineArgs array.
466 SetCommandLineArgs(pwzAssemblyPath, argc, argv);
468 PTRARRAYREF arguments = NULL;
469 GCPROTECT_BEGIN(arguments);
471 arguments = (PTRARRAYREF)AllocateObjectArray(argc, g_pStringClass);
472 for (int i = 0; i < argc; ++i)
474 STRINGREF argument = StringObject::NewString(argv[i]);
475 arguments->SetAt(i, argument);
478 DWORD retval = pAssembly->ExecuteMainMethod(&arguments, TRUE /* waitForOtherThreads */);
481 *pReturnValue = retval;
488 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
489 UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP;
496 HRESULT CorHost2::ExecuteInDefaultAppDomain(LPCWSTR pwzAssemblyPath,
498 LPCWSTR pwzMethodName,
509 // No point going further if the runtime is not running...
510 if (!IsRuntimeActive())
512 return HOST_E_CLRNOTAVAILABLE;
515 if(! (pwzAssemblyPath && pwzTypeName && pwzMethodName) )
520 BEGIN_ENTRYPOINT_NOTHROW;
522 Thread *pThread = GetThread();
525 pThread = SetupThreadNoThrow(&hr);
532 _ASSERTE (!pThread->PreemptiveGCDisabled());
534 _ASSERTE (SystemDomain::GetCurrentDomain()->GetId().m_dwId == DefaultADID);
536 INSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP;
537 INSTALL_UNWIND_AND_CONTINUE_HANDLER;
541 Assembly *pAssembly = AssemblySpec::LoadAssembly(pwzAssemblyPath);
543 SString szTypeName(pwzTypeName);
544 StackScratchBuffer buff1;
545 const char* szTypeNameUTF8 = szTypeName.GetUTF8(buff1);
546 MethodTable *pMT = ClassLoader::LoadTypeByNameThrowing(pAssembly,
548 szTypeNameUTF8).AsMethodTable();
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);
557 hr = COR_E_MISSINGMETHOD;
563 MethodDescCallSite method(pMethodMD);
565 STRINGREF sref = NULL;
566 GCPROTECT_BEGIN(sref);
569 sref = StringObject::NewString(pwzArgument);
571 ARG_SLOT MethodArgs[] =
575 DWORD retval = method.Call_RetI4(MethodArgs);
578 *pReturnValue = retval;
584 EX_CATCH_HRESULT(hr);
586 UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
587 UNINSTALL_UNHANDLED_MANAGED_EXCEPTION_TRAP;
591 END_ENTRYPOINT_NOTHROW;
596 HRESULT ExecuteInAppDomainHelper(FExecuteInAppDomainCallback pCallback,
599 STATIC_CONTRACT_THROWS;
601 return pCallback(cookie);
604 HRESULT CorHost2::ExecuteInAppDomain(DWORD dwAppDomainId,
605 FExecuteInAppDomainCallback pCallback,
609 // No point going further if the runtime is not running...
610 if (!IsRuntimeActive())
612 return HOST_E_CLRNOTAVAILABLE;
615 // Moved this here since no point validating the pointer
616 // if the basic checks [above] fail
617 if( pCallback == NULL)
623 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
624 ENTRY_POINT; // This is called by a host.
630 BEGIN_ENTRYPOINT_NOTHROW;
631 BEGIN_EXTERNAL_ENTRYPOINT(&hr);
632 GCX_COOP_THREAD_EXISTS(GET_THREAD());
633 ENTER_DOMAIN_ID(ADID(dwAppDomainId))
635 // We are calling an unmanaged function pointer, either an unmanaged function, or a marshaled out delegate.
636 // The thread should be in preemptive mode.
638 hr=ExecuteInAppDomainHelper (pCallback, cookie);
640 END_DOMAIN_TRANSITION;
641 END_EXTERNAL_ENTRYPOINT;
642 END_ENTRYPOINT_NOTHROW;
647 #define EMPTY_STRING_TO_NULL(s) {if(s && s[0] == 0) {s=NULL;};}
649 HRESULT CorHost2::_CreateAppDomain(
650 LPCWSTR wszFriendlyName,
652 LPCWSTR wszAppDomainManagerAssemblyName,
653 LPCWSTR wszAppDomainManagerTypeName,
655 LPCWSTR* pPropertyNames,
656 LPCWSTR* pPropertyValues,
662 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
663 ENTRY_POINT; // This is called by a host.
669 //cannot call the function more than once when single appDomain is allowed
670 if (m_fAppDomainCreated)
672 return HOST_E_INVALIDOPERATION;
675 //normalize empty strings
676 EMPTY_STRING_TO_NULL(wszFriendlyName);
677 EMPTY_STRING_TO_NULL(wszAppDomainManagerAssemblyName);
678 EMPTY_STRING_TO_NULL(wszAppDomainManagerTypeName);
680 if (pAppDomainID==NULL)
684 return HOST_E_INVALIDOPERATION;
686 if (wszFriendlyName == NULL)
689 if ((wszAppDomainManagerAssemblyName != NULL) || (wszAppDomainManagerTypeName != NULL))
692 BEGIN_ENTRYPOINT_NOTHROW;
694 BEGIN_EXTERNAL_ENTRYPOINT(&hr);
696 AppDomain* pDomain = SystemDomain::System()->DefaultDomain();
698 pDomain->SetFriendlyName(wszFriendlyName);
700 ETW::LoaderLog::DomainLoad(pDomain, (LPWSTR)wszFriendlyName);
702 if (dwFlags & APPDOMAIN_IGNORE_UNHANDLED_EXCEPTIONS)
703 pDomain->SetIgnoreUnhandledExceptions();
705 if (dwFlags & APPDOMAIN_FORCE_TRIVIAL_WAIT_OPERATIONS)
706 pDomain->SetForceTrivialWaitOperations();
708 pDomain->CreateFusionContext();
713 MethodDescCallSite setup(METHOD__APPCONTEXT__SETUP);
716 args[0] = PtrToArgSlot(pPropertyNames);
717 args[1] = PtrToArgSlot(pPropertyValues);
718 args[2] = PtrToArgSlot(nProperties);
723 LPCWSTR pwzNativeDllSearchDirectories = NULL;
724 LPCWSTR pwzTrustedPlatformAssemblies = NULL;
725 LPCWSTR pwzPlatformResourceRoots = NULL;
726 LPCWSTR pwzAppPaths = NULL;
727 LPCWSTR pwzAppNiPaths = NULL;
728 #ifdef FEATURE_COMINTEROP
729 LPCWSTR pwzAppLocalWinMD = NULL;
732 for (int i = 0; i < nProperties; i++)
734 if (wcscmp(pPropertyNames[i], W("NATIVE_DLL_SEARCH_DIRECTORIES")) == 0)
736 pwzNativeDllSearchDirectories = pPropertyValues[i];
739 if (wcscmp(pPropertyNames[i], W("TRUSTED_PLATFORM_ASSEMBLIES")) == 0)
741 pwzTrustedPlatformAssemblies = pPropertyValues[i];
744 if (wcscmp(pPropertyNames[i], W("PLATFORM_RESOURCE_ROOTS")) == 0)
746 pwzPlatformResourceRoots = pPropertyValues[i];
749 if (wcscmp(pPropertyNames[i], W("APP_PATHS")) == 0)
751 pwzAppPaths = pPropertyValues[i];
754 if (wcscmp(pPropertyNames[i], W("APP_NI_PATHS")) == 0)
756 pwzAppNiPaths = pPropertyValues[i];
758 #ifdef FEATURE_COMINTEROP
760 if (wcscmp(pPropertyNames[i], W("APP_LOCAL_WINMETADATA")) == 0)
762 pwzAppLocalWinMD = pPropertyValues[i];
767 pDomain->SetNativeDllSearchDirectories(pwzNativeDllSearchDirectories);
770 SString sTrustedPlatformAssemblies(pwzTrustedPlatformAssemblies);
771 SString sPlatformResourceRoots(pwzPlatformResourceRoots);
772 SString sAppPaths(pwzAppPaths);
773 SString sAppNiPaths(pwzAppNiPaths);
775 CLRPrivBinderCoreCLR *pBinder = pDomain->GetTPABinderContext();
776 _ASSERTE(pBinder != NULL);
777 IfFailThrow(pBinder->SetupBindingPaths(
778 sTrustedPlatformAssemblies,
779 sPlatformResourceRoots,
784 #ifdef FEATURE_COMINTEROP
785 if (WinRTSupported())
787 pDomain->SetWinrtApplicationContext(pwzAppLocalWinMD);
791 *pAppDomainID=pDomain->GetId().m_dwId;
793 m_fAppDomainCreated = TRUE;
795 END_EXTERNAL_ENTRYPOINT;
797 END_ENTRYPOINT_NOTHROW;
802 HRESULT CorHost2::_CreateDelegate(
804 LPCWSTR wszAssemblyName,
805 LPCWSTR wszClassName,
806 LPCWSTR wszMethodName,
813 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
814 ENTRY_POINT; // This is called by a host.
820 EMPTY_STRING_TO_NULL(wszAssemblyName);
821 EMPTY_STRING_TO_NULL(wszClassName);
822 EMPTY_STRING_TO_NULL(wszMethodName);
828 if(wszAssemblyName == NULL)
831 if(wszClassName == NULL)
834 if(wszMethodName == NULL)
837 BEGIN_ENTRYPOINT_NOTHROW;
839 BEGIN_EXTERNAL_ENTRYPOINT(&hr);
840 GCX_COOP_THREAD_EXISTS(GET_THREAD());
842 MAKE_UTF8PTR_FROMWIDE(szAssemblyName, wszAssemblyName);
843 MAKE_UTF8PTR_FROMWIDE(szClassName, wszClassName);
844 MAKE_UTF8PTR_FROMWIDE(szMethodName, wszMethodName);
847 id.m_dwId=appDomainID;
854 spec.Init(szAssemblyName);
855 Assembly* pAsm=spec.LoadAssembly(FILE_ACTIVE);
857 TypeHandle th=pAsm->GetLoader()->LoadTypeByNameThrowing(pAsm,NULL,szClassName);
858 MethodDesc* pMD=NULL;
860 if (!th.IsTypeDesc())
862 pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Unique);
865 // try again without the FM_Unique flag (error path)
866 pMD = MemberLoader::FindMethodByName(th.GetMethodTable(), szMethodName, MemberLoader::FM_Default);
869 // the method exists but is overloaded
870 ThrowHR(COR_E_AMBIGUOUSMATCH);
875 if (pMD==NULL || !pMD->IsStatic() || pMD->ContainsGenericVariables())
876 ThrowHR(COR_E_MISSINGMETHOD);
878 UMEntryThunk *pUMEntryThunk = pMD->GetLoaderAllocator()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD);
879 *fnPtr = (INT_PTR)pUMEntryThunk->GetCode();
881 END_DOMAIN_TRANSITION;
883 END_EXTERNAL_ENTRYPOINT;
885 END_ENTRYPOINT_NOTHROW;
890 HRESULT CorHost2::CreateAppDomainWithManager(
891 LPCWSTR wszFriendlyName,
893 LPCWSTR wszAppDomainManagerAssemblyName,
894 LPCWSTR wszAppDomainManagerTypeName,
896 LPCWSTR* pPropertyNames,
897 LPCWSTR* pPropertyValues,
902 return _CreateAppDomain(
905 wszAppDomainManagerAssemblyName,
906 wszAppDomainManagerTypeName,
913 HRESULT CorHost2::CreateDelegate(
915 LPCWSTR wszAssemblyName,
916 LPCWSTR wszClassName,
917 LPCWSTR wszMethodName,
922 return _CreateDelegate(appDomainID, wszAssemblyName, wszClassName, wszMethodName, fnPtr);
925 HRESULT CorHost2::Authenticate(ULONGLONG authKey)
930 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
931 ENTRY_POINT; // This is called by a host.
935 // Host authentication was used by Silverlight. It is no longer relevant for CoreCLR.
939 HRESULT CorHost2::RegisterMacEHPort()
944 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
945 ENTRY_POINT; // This is called by a host.
952 HRESULT CorHost2::SetStartupFlags(STARTUP_FLAGS flag)
957 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
958 ENTRY_POINT; // This is called by a host.
964 return HOST_E_INVALIDOPERATION;
967 m_dwStartupFlags = flag;
974 HRESULT SuspendEEForPause()
986 // In CoreCLR, we always resume from the same thread that paused. So we can simply suspend the EE from this thread,
987 // knowing we'll restart from the same thread.
988 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_OTHER);
993 HRESULT RestartEEFromPauseAndSetResumeEvent()
1003 // see comments in SuspendEEFromPause
1004 ThreadSuspend::RestartEE(FALSE, TRUE);
1006 _ASSERTE(g_ClrResumeEvent.IsValid());
1007 g_ClrResumeEvent.Set();
1014 CorExecutionManager::CorExecutionManager()
1015 : m_dwFlags(0), m_pauseStartTime(0)
1017 LIMITED_METHOD_CONTRACT;
1022 HRESULT CorExecutionManager::Pause(DWORD dwAppDomainId, DWORD dwFlags)
1027 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
1028 ENTRY_POINT; // This is called by a host.
1040 if(!g_ClrResumeEvent.IsValid())
1041 g_ClrResumeEvent.CreateManualEvent(FALSE);
1043 g_ClrResumeEvent.Reset();
1046 EX_CATCH_HRESULT(hr);
1051 BEGIN_ENTRYPOINT_NOTHROW;
1053 m_dwFlags = dwFlags;
1060 hr = SuspendEEForPause();
1062 // Even though this is named with TickCount, it returns milliseconds
1063 m_pauseStartTime = (INT64)CLRGetTickCount64();
1066 END_ENTRYPOINT_NOTHROW;
1072 HRESULT CorExecutionManager::Resume(DWORD dwAppDomainId)
1077 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
1078 ENTRY_POINT; // This is called by a host.
1088 // GCThread is the thread that did the Pause. Resume should also happen on that same thread
1089 Thread *pThread = GetThread();
1090 if(pThread != ThreadSuspend::GetSuspensionThread())
1092 _ASSERTE(!"HOST BUG: The same thread that did Pause should do the Resume");
1096 BEGIN_ENTRYPOINT_NOTHROW;
1098 // Even though this is named with TickCount, it returns milliseconds
1099 INT64 currTime = (INT64)CLRGetTickCount64();
1100 _ASSERTE(currTime >= m_pauseStartTime);
1101 _ASSERTE(m_pauseStartTime != 0);
1103 g_PauseTime += (currTime - m_pauseStartTime);
1106 hr = RestartEEFromPauseAndSetResumeEvent();
1109 END_ENTRYPOINT_NOTHROW;
1115 #endif //!DACCESS_COMPILE
1117 #ifndef DACCESS_COMPILE
1118 SVAL_IMPL(STARTUP_FLAGS, CorHost2, m_dwStartupFlags = STARTUP_CONCURRENT_GC);
1120 SVAL_IMPL(STARTUP_FLAGS, CorHost2, m_dwStartupFlags);
1123 STARTUP_FLAGS CorHost2::GetStartupFlags()
1125 return m_dwStartupFlags;
1128 #ifndef DACCESS_COMPILE
1131 #ifdef FEATURE_COMINTEROP
1133 // Enumerate currently existing domains.
1134 HRESULT CorRuntimeHostBase::EnumDomains(HDOMAINENUM *hEnum)
1140 WRAPPER(GC_TRIGGERS);
1145 if(hEnum == NULL) return E_POINTER;
1147 // Thread setup happens in BEGIN_EXTERNAL_ENTRYPOINT below.
1148 // If the runtime has not started, we have nothing to do.
1151 return HOST_E_CLRNOTAVAILABLE;
1154 HRESULT hr = E_OUTOFMEMORY;
1156 BEGIN_ENTRYPOINT_NOTHROW;
1158 BEGIN_EXTERNAL_ENTRYPOINT(&hr)
1160 AppDomainIterator *pEnum = new (nothrow) AppDomainIterator(FALSE);
1162 *hEnum = (HDOMAINENUM) pEnum;
1165 END_EXTERNAL_ENTRYPOINT;
1166 END_ENTRYPOINT_NOTHROW;
1171 #endif // FEATURE_COMINTEROP
1174 HRESULT GetCLRRuntimeHost(REFIID riid, IUnknown **ppUnk)
1176 WRAPPER_NO_CONTRACT;
1178 return CorHost2::CreateObject(riid, (void**)ppUnk);
1182 STDMETHODIMP CorHost2::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone)
1184 return UnloadAppDomain2(dwDomainId, fWaitUntilDone, nullptr);
1187 STDMETHODIMP CorHost2::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDone, int *pLatchedExitCode)
1189 WRAPPER_NO_CONTRACT;
1192 return HOST_E_INVALIDOPERATION;
1196 return HOST_E_CLRNOTAVAILABLE;
1199 if(!m_fAppDomainCreated)
1201 return HOST_E_INVALIDOPERATION;
1205 BEGIN_ENTRYPOINT_NOTHROW;
1207 if (!m_fFirstToLoadCLR)
1209 _ASSERTE(!"Not reachable");
1210 hr = HOST_E_CLRNOTAVAILABLE;
1214 LONG refCount = m_RefCount;
1217 hr = HOST_E_CLRNOTAVAILABLE;
1222 // Stop coreclr on unload.
1227 _ASSERTE(!"Not reachable");
1231 END_ENTRYPOINT_NOTHROW;
1233 if (pLatchedExitCode)
1235 *pLatchedExitCode = GetLatchedExitCode();
1241 HRESULT CorRuntimeHostBase::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone)
1243 return UnloadAppDomain2(dwDomainId, fWaitUntilDone, nullptr);
1246 HRESULT CorRuntimeHostBase::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDone, int *pLatchedExitCode)
1253 FORBID_FAULT; // Unloading domains cannot fail due to OOM
1258 return COR_E_CANNOTUNLOADAPPDOMAIN;
1261 //*****************************************************************************
1263 //*****************************************************************************
1265 HRESULT CorRuntimeHostBase::LocksHeldByLogicalThread(DWORD *pCount)
1278 BEGIN_ENTRYPOINT_NOTHROW;
1280 Thread* pThread = GetThread();
1281 if (pThread == NULL)
1284 *pCount = pThread->m_dwLockCount;
1286 END_ENTRYPOINT_NOTHROW;
1291 //*****************************************************************************
1292 // ICorConfiguration
1293 //*****************************************************************************
1295 //*****************************************************************************
1297 //*****************************************************************************
1299 ULONG CorRuntimeHostBase::AddRef()
1304 WRAPPER(GC_TRIGGERS);
1307 return InterlockedIncrement(&m_cRef);
1311 ULONG CorHost2::Release()
1313 LIMITED_METHOD_CONTRACT;
1315 ULONG cRef = InterlockedDecrement(&m_cRef);
1325 HRESULT CorHost2::QueryInterface(REFIID riid, void **ppUnk)
1344 // Deliberately do NOT hand out ICorConfiguration. They must explicitly call
1345 // GetConfiguration to obtain that interface.
1346 if (riid == IID_IUnknown)
1348 *ppUnk = static_cast<IUnknown *>(static_cast<ICLRRuntimeHost *>(this));
1350 else if (riid == IID_ICLRRuntimeHost)
1352 *ppUnk = static_cast<ICLRRuntimeHost *>(this);
1354 else if (riid == IID_ICLRRuntimeHost2)
1358 FastInterlockCompareExchange((LONG*)&m_Version, version, 0);
1360 *ppUnk = static_cast<ICLRRuntimeHost2 *>(this);
1362 else if (riid == IID_ICLRRuntimeHost4)
1366 FastInterlockCompareExchange((LONG*)&m_Version, version, 0);
1368 *ppUnk = static_cast<ICLRRuntimeHost4 *>(this);
1370 else if (riid == IID_ICLRExecutionManager)
1374 FastInterlockCompareExchange((LONG*)&m_Version, version, 0);
1376 *ppUnk = static_cast<ICLRExecutionManager *>(this);
1379 else if (riid == IID_IPrivateManagedExceptionReporting)
1381 *ppUnk = static_cast<IPrivateManagedExceptionReporting *>(this);
1383 #endif // !FEATURE_PAL
1385 return (E_NOINTERFACE);
1392 HRESULT CorHost2::GetBucketParametersForCurrentException(BucketParameters *pParams)
1402 BEGIN_ENTRYPOINT_NOTHROW;
1404 // To avoid confusion, clear the buckets.
1405 memset(pParams, 0, sizeof(BucketParameters));
1407 // Defer to Watson helper.
1408 hr = ::GetBucketParametersForCurrentException(pParams);
1410 END_ENTRYPOINT_NOTHROW;
1414 #endif // !FEATURE_PAL
1416 HRESULT CorHost2::CreateObject(REFIID riid, void **ppUnk)
1427 CorHost2 *pCorHost = new (nothrow) CorHost2();
1434 hr = pCorHost->QueryInterface(riid, ppUnk);
1442 //-----------------------------------------------------------------------------
1443 // MapFile - Maps a file into the runtime in a non-standard way
1444 //-----------------------------------------------------------------------------
1446 static PEImage *MapFileHelper(HANDLE hFile)
1458 HandleHolder hFileMap(WszCreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL));
1459 if (hFileMap == NULL)
1462 CLRMapViewHolder base(CLRMapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0));
1466 DWORD dwSize = SafeGetFileSize(hFile, NULL);
1467 if (dwSize == 0xffffffff && GetLastError() != NOERROR)
1471 PEImageHolder pImage(PEImage::LoadFlat(base, dwSize));
1472 return pImage.Extract();
1475 HRESULT CorRuntimeHostBase::MapFile(HANDLE hFile, HMODULE* phHandle)
1487 BEGIN_ENTRYPOINT_NOTHROW;
1489 BEGIN_EXTERNAL_ENTRYPOINT(&hr)
1491 *phHandle = (HMODULE) (MapFileHelper(hFile)->GetLoadedLayout()->GetBase());
1493 END_EXTERNAL_ENTRYPOINT;
1494 END_ENTRYPOINT_NOTHROW;
1500 ///////////////////////////////////////////////////////////////////////////////
1501 // IDebuggerInfo::IsDebuggerAttached
1503 LONG CorHost2::m_RefCount = 0;
1505 IHostControl *CorHost2::m_HostControl = NULL;
1508 extern void ValidateHostInterface();
1511 static Volatile<BOOL> fOneOnly = 0;
1513 ///////////////////////////////////////////////////////////////////////////////
1514 // ICLRRuntimeHost::SetHostControl
1515 ///////////////////////////////////////////////////////////////////////////////
1516 HRESULT CorHost2::SetHostControl(IHostControl* pHostControl)
1526 // CLR is hosted with v1 hosting interface. Some part of v2 hosting API are disabled.
1527 return HOST_E_INVALIDOPERATION;
1529 if (pHostControl == 0)
1530 return E_INVALIDARG;
1532 // If Runtime has been started, do not allow setting HostMemoryManager
1534 return E_ACCESSDENIED;
1538 BEGIN_ENTRYPOINT_NOTHROW;
1540 DWORD dwSwitchCount = 0;
1542 while (FastInterlockExchange((LONG*)&fOneOnly, 1) == 1)
1544 __SwitchToThread(0, ++dwSwitchCount);
1548 if (m_HostControl == NULL)
1550 m_HostControl = pHostControl;
1551 m_HostControl->AddRef();
1559 END_ENTRYPOINT_NOTHROW;
1564 class CCLRPolicyManager: public ICLRPolicyManager
1567 virtual HRESULT STDMETHODCALLTYPE SetDefaultAction(EClrOperation operation,
1568 EPolicyAction action)
1570 LIMITED_METHOD_CONTRACT;
1574 virtual HRESULT STDMETHODCALLTYPE SetTimeout(EClrOperation operation,
1575 DWORD dwMilliseconds)
1577 LIMITED_METHOD_CONTRACT;
1581 virtual HRESULT STDMETHODCALLTYPE SetActionOnTimeout(EClrOperation operation,
1582 EPolicyAction action)
1584 LIMITED_METHOD_CONTRACT;
1588 virtual HRESULT STDMETHODCALLTYPE SetTimeoutAndAction(EClrOperation operation, DWORD dwMilliseconds,
1589 EPolicyAction action)
1591 LIMITED_METHOD_CONTRACT;
1595 virtual HRESULT STDMETHODCALLTYPE SetActionOnFailure(EClrFailure failure,
1596 EPolicyAction action)
1598 // This is enabled for CoreCLR since a host can use this to
1599 // specify action for handling AV.
1600 STATIC_CONTRACT_ENTRY_POINT;
1601 LIMITED_METHOD_CONTRACT;
1603 // For CoreCLR, this method just supports FAIL_AccessViolation as a valid
1604 // failure input arg. The validation of the specified action for the failure
1605 // will be done in EEPolicy::IsValidActionForFailure.
1606 if (failure != FAIL_AccessViolation)
1608 return E_INVALIDARG;
1610 BEGIN_ENTRYPOINT_NOTHROW;
1611 hr = GetEEPolicy()->SetActionOnFailure(failure,action);
1612 END_ENTRYPOINT_NOTHROW;
1616 virtual HRESULT STDMETHODCALLTYPE SetUnhandledExceptionPolicy(EClrUnhandledException policy)
1618 LIMITED_METHOD_CONTRACT;
1622 virtual ULONG STDMETHODCALLTYPE AddRef(void)
1624 LIMITED_METHOD_CONTRACT;
1628 virtual ULONG STDMETHODCALLTYPE Release(void)
1630 LIMITED_METHOD_CONTRACT;
1634 BEGIN_INTERFACE HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
1637 LIMITED_METHOD_CONTRACT;
1638 if (riid != IID_ICLRPolicyManager && riid != IID_IUnknown)
1639 return (E_NOINTERFACE);
1641 // Ensure that the out going pointer is not null
1642 if (ppvObject == NULL)
1650 static CCLRPolicyManager s_PolicyManager;
1654 void ProcessEventForHost(EClrEvent event, void *data)
1658 // We do not call ProcessEventForHost for stack overflow, since we have limit stack
1659 // and we should avoid calling GCX_PREEMPT
1660 void ProcessSOEventForHost(EXCEPTION_POINTERS *pExceptionInfo, BOOL fInSoTolerant)
1664 BOOL IsHostRegisteredForEvent(EClrEvent event)
1666 WRAPPER_NO_CONTRACT;
1670 inline size_t SizeInKBytes(size_t cbSize)
1672 LIMITED_METHOD_CONTRACT;
1673 size_t cb = (cbSize % 1024) ? 1 : 0;
1674 return ((cbSize / 1024) + cb);
1677 SIZE_T Host_SegmentSize = 0;
1678 SIZE_T Host_MaxGen0Size = 0;
1679 BOOL Host_fSegmentSizeSet = FALSE;
1680 BOOL Host_fMaxGen0SizeSet = FALSE;
1682 void UpdateGCSettingFromHost ()
1684 WRAPPER_NO_CONTRACT;
1685 _ASSERTE (g_pConfig);
1686 if (Host_fSegmentSizeSet)
1688 g_pConfig->SetSegmentSize(Host_SegmentSize);
1690 if (Host_fMaxGen0SizeSet)
1692 g_pConfig->SetGCgen0size(Host_MaxGen0Size);
1696 #if defined(FEATURE_WINDOWSPHONE)
1697 class CCLRGCManager: public ICLRGCManager2
1700 virtual HRESULT STDMETHODCALLTYPE Collect(LONG Generation)
1712 if (Generation > (int) GCHeapUtilities::GetGCHeap()->GetMaxGeneration())
1717 // Set up a Thread object if this is called on a native thread.
1719 pThread = GetThread();
1720 if (pThread == NULL)
1721 pThread = SetupThreadNoThrow(&hr);
1722 if (pThread != NULL)
1724 BEGIN_ENTRYPOINT_NOTHROW_WITH_THREAD(pThread);
1729 STRESS_LOG0(LF_GC, LL_INFO100, "Host triggers GC\n");
1730 hr = GCHeapUtilities::GetGCHeap()->GarbageCollect(Generation);
1734 hr = GET_EXCEPTION()->GetHR();
1736 EX_END_CATCH(SwallowAllExceptions);
1738 END_ENTRYPOINT_NOTHROW_WITH_THREAD;
1745 virtual HRESULT STDMETHODCALLTYPE GetStats(COR_GC_STATS *pStats)
1756 BEGIN_ENTRYPOINT_NOTHROW;
1758 #if defined(ENABLE_PERF_COUNTERS)
1760 Perf_GC *pgc = &GetPerfCounters().m_GC;
1763 IfFailGo(E_INVALIDARG);
1765 if (pStats->Flags & COR_GC_COUNTS)
1767 pStats->ExplicitGCCount = pgc->cInducedGCs;
1769 for (int idx=0; idx<3; idx++)
1770 pStats->GenCollectionsTaken[idx] = pgc->cGenCollections[idx];
1773 if (pStats->Flags & COR_GC_MEMORYUSAGE)
1775 pStats->CommittedKBytes = SizeInKBytes(pgc->cTotalCommittedBytes);
1776 pStats->ReservedKBytes = SizeInKBytes(pgc->cTotalReservedBytes);
1777 pStats->Gen0HeapSizeKBytes = SizeInKBytes(pgc->cGenHeapSize[0]);
1778 pStats->Gen1HeapSizeKBytes = SizeInKBytes(pgc->cGenHeapSize[1]);
1779 pStats->Gen2HeapSizeKBytes = SizeInKBytes(pgc->cGenHeapSize[2]);
1780 pStats->LargeObjectHeapSizeKBytes = SizeInKBytes(pgc->cLrgObjSize);
1781 pStats->KBytesPromotedFromGen0 = SizeInKBytes(pgc->cbPromotedMem[0]);
1782 pStats->KBytesPromotedFromGen1 = SizeInKBytes(pgc->cbPromotedMem[1]);
1788 #endif // ENABLE_PERF_COUNTERS
1790 END_ENTRYPOINT_NOTHROW;
1793 virtual HRESULT STDMETHODCALLTYPE SetGCStartupLimits(
1807 BEGIN_ENTRYPOINT_NOTHROW;
1809 // Set default overrides if specified by caller.
1810 if (SegmentSize != (DWORD) ~0 && SegmentSize > 0)
1812 hr = _SetGCSegmentSize(SegmentSize);
1815 if (SUCCEEDED(hr) && MaxGen0Size != (DWORD) ~0 && MaxGen0Size > 0)
1817 hr = _SetGCMaxGen0Size(MaxGen0Size);
1820 END_ENTRYPOINT_NOTHROW;
1825 virtual HRESULT STDMETHODCALLTYPE SetGCStartupLimitsEx(
1839 BEGIN_ENTRYPOINT_NOTHROW;
1841 // Set default overrides if specified by caller.
1842 if (SegmentSize != (SIZE_T) ~0 && SegmentSize > 0)
1844 hr = _SetGCSegmentSize(SegmentSize);
1847 if (SUCCEEDED(hr) && MaxGen0Size != (SIZE_T) ~0 && MaxGen0Size > 0)
1849 hr = _SetGCMaxGen0Size(MaxGen0Size);
1852 END_ENTRYPOINT_NOTHROW;
1857 virtual ULONG STDMETHODCALLTYPE AddRef(void)
1859 LIMITED_METHOD_CONTRACT;
1863 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, OUT PVOID *ppUnk)
1865 LIMITED_METHOD_CONTRACT;
1866 if (riid != IID_ICLRGCManager && riid != IID_ICLRGCManager2 && riid != IID_IUnknown)
1867 return (E_NOINTERFACE);
1872 virtual ULONG STDMETHODCALLTYPE Release(void)
1874 LIMITED_METHOD_CONTRACT;
1878 HRESULT _SetGCSegmentSize(SIZE_T SegmentSize);
1879 HRESULT _SetGCMaxGen0Size(SIZE_T MaxGen0Size);
1883 HRESULT CCLRGCManager::_SetGCSegmentSize(SIZE_T SegmentSize)
1894 // Sanity check the value, it must be a power of two and big enough.
1895 if (!GCHeapUtilities::GetGCHeap()->IsValidSegmentSize(SegmentSize))
1901 Host_SegmentSize = SegmentSize;
1902 Host_fSegmentSizeSet = TRUE;
1908 HRESULT CCLRGCManager::_SetGCMaxGen0Size(SIZE_T MaxGen0Size)
1919 // Sanity check the value is at least large enough.
1920 if (!GCHeapUtilities::GetGCHeap()->IsValidGen0MaxSize(MaxGen0Size))
1926 Host_MaxGen0Size = MaxGen0Size;
1927 Host_fMaxGen0SizeSet = TRUE;
1933 static CCLRGCManager s_GCManager;
1934 #endif //FEATURE_WINDOWSPHONE
1936 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
1937 class CCLRAppDomainResourceMonitor : public ICLRAppDomainResourceMonitor
1940 virtual HRESULT STDMETHODCALLTYPE GetCurrentAllocated(DWORD dwAppDomainId,
1941 ULONGLONG* pBytesAllocated)
1953 BEGIN_ENTRYPOINT_NOTHROW;
1955 SystemDomain::LockHolder lh;
1957 AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD);
1958 if (pBytesAllocated)
1960 *pBytesAllocated = pAppDomain->GetAllocBytes();
1963 END_ENTRYPOINT_NOTHROW;
1968 virtual HRESULT STDMETHODCALLTYPE GetCurrentSurvived(DWORD dwAppDomainId,
1969 ULONGLONG* pAppDomainBytesSurvived,
1970 ULONGLONG* pTotalBytesSurvived)
1981 BEGIN_ENTRYPOINT_NOTHROW;
1983 SystemDomain::LockHolder lh;
1985 AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD);
1986 if (pAppDomainBytesSurvived)
1988 *pAppDomainBytesSurvived = pAppDomain->GetSurvivedBytes();
1990 if (pTotalBytesSurvived)
1992 *pTotalBytesSurvived = SystemDomain::GetTotalSurvivedBytes();
1995 END_ENTRYPOINT_NOTHROW;
2000 virtual HRESULT STDMETHODCALLTYPE GetCurrentCpuTime(DWORD dwAppDomainId,
2001 ULONGLONG* pMilliseconds)
2013 BEGIN_ENTRYPOINT_NOTHROW;
2016 SystemDomain::LockHolder lh;
2018 AppDomain* pAppDomain = SystemDomain::GetAppDomainFromId((ADID)dwAppDomainId, ADV_CURRENTAD);
2021 *pMilliseconds = pAppDomain->QueryProcessorUsage() / 10000;
2025 END_ENTRYPOINT_NOTHROW;
2030 virtual ULONG STDMETHODCALLTYPE AddRef(void)
2032 LIMITED_METHOD_CONTRACT;
2036 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, OUT PVOID *ppUnk)
2038 LIMITED_METHOD_CONTRACT;
2040 if (riid == IID_IUnknown)
2041 *ppUnk = (IUnknown*)this;
2042 else if (riid == IID_ICLRAppDomainResourceMonitor)
2043 *ppUnk = (ICLRAppDomainResourceMonitor*)this;
2045 return E_NOINTERFACE;
2049 virtual ULONG STDMETHODCALLTYPE Release(void)
2051 LIMITED_METHOD_CONTRACT;
2055 static CCLRAppDomainResourceMonitor s_Arm;
2056 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2059 BOOL g_CLRPolicyRequested = FALSE;
2061 class CCorCLRControl: public ICLRControl
2064 virtual HRESULT STDMETHODCALLTYPE GetCLRManager(REFIID riid, void **ppObject)
2074 if (ppObject == NULL)
2075 return E_INVALIDARG;
2077 #if defined(FEATURE_WINDOWSPHONE)
2078 if (riid == IID_ICLRErrorReportingManager2)
2080 *ppObject = &g_CLRErrorReportingManager;
2084 #endif //defined(FEATURE_WINDOWSPHONE)
2085 if (g_fEEStarted && !m_fFullAccess)
2087 // If runtime has been started, do not allow user to obtain CLR managers.
2088 return HOST_E_INVALIDOPERATION;
2091 // CoreCLR supports ICLRPolicyManager since it allows the host
2092 // to specify the policy for AccessViolation.
2093 else if (riid == IID_ICLRPolicyManager) {
2094 *ppObject = &s_PolicyManager;
2095 FastInterlockExchange((LONG*)&g_CLRPolicyRequested, TRUE);
2099 #if defined(FEATURE_WINDOWSPHONE)
2100 else if ((riid == IID_ICLRGCManager) || (riid == IID_ICLRGCManager2))
2102 *ppObject = &s_GCManager;
2105 #endif //FEATURE_WINDOWSPHONE
2107 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2108 else if (riid == IID_ICLRAppDomainResourceMonitor)
2114 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2116 return (E_NOINTERFACE);
2119 virtual HRESULT STDMETHODCALLTYPE SetAppDomainManagerType(
2120 LPCWSTR pwzAppDomainManagerAssembly,
2121 LPCWSTR pwzAppDomainManagerType)
2124 // CoreCLR does not support this method
2128 virtual ULONG STDMETHODCALLTYPE AddRef(void)
2130 LIMITED_METHOD_CONTRACT;
2134 virtual ULONG STDMETHODCALLTYPE Release(void)
2136 LIMITED_METHOD_CONTRACT;
2140 BEGIN_INTERFACE HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
2143 LIMITED_METHOD_CONTRACT;
2144 if (riid != IID_ICLRControl && riid != IID_IUnknown)
2145 return (E_NOINTERFACE);
2147 // Ensure that the out going pointer is not null
2148 if (ppvObject == NULL)
2155 // This is to avoid having ctor. We have static objects, and it is
2156 // difficult to support ctor on certain platform.
2157 void SetAccess(BOOL fFullAccess)
2159 LIMITED_METHOD_CONTRACT;
2160 m_fFullAccess = fFullAccess;
2166 // Before CLR starts, we give out s_CorCLRControl which has full access to all managers.
2167 // After CLR starts, we give out s_CorCLRControlLimited which allows limited access to managers.
2168 static CCorCLRControl s_CorCLRControl;
2171 ///////////////////////////////////////////////////////////////////////////////
2172 // ICLRRuntimeHost::GetCLRControl
2173 HRESULT CorHost2::GetCLRControl(ICLRControl** pCLRControl)
2175 LIMITED_METHOD_CONTRACT;
2177 // Ensure that we have a valid pointer
2178 if (pCLRControl == NULL)
2185 STATIC_CONTRACT_ENTRY_POINT;
2186 BEGIN_ENTRYPOINT_NOTHROW;
2187 if (!g_fEEStarted && m_Version >= 2)
2189 s_CorCLRControl.SetAccess(TRUE);
2190 *pCLRControl = &s_CorCLRControl;
2195 // 1) request comes for interface other than ICLRControl*, OR
2196 // 2) runtime has already started, OR
2197 // 3) version is not 2
2199 // we will return failure and set the out pointer to NULL
2200 *pCLRControl = NULL;
2203 // Return HOST_E_INVALIDOPERATION as per MSDN if runtime has already started
2204 hr = HOST_E_INVALIDOPERATION;
2211 END_ENTRYPOINT_NOTHROW;
2217 EInitializeNewDomainFlags CorHost2::GetAppDomainManagerInitializeNewDomainFlags()
2219 LIMITED_METHOD_CONTRACT;
2220 return eInitializeNewDomainFlags_None;
2227 #ifdef DACCESS_COMPILE
2230 #endif //DACCESS_COMPILE
2232 #ifndef DACCESS_COMPILE
2235 #if defined(FEATURE_WINDOWSPHONE)
2237 HRESULT CCLRErrorReportingManager::QueryInterface(REFIID riid, void** ppUnk)
2258 // Deliberately do NOT hand out ICorConfiguration. They must explicitly call
2259 // GetConfiguration to obtain that interface.
2260 if (riid == IID_IUnknown)
2262 *ppUnk = (IUnknown *) this;
2264 else if (riid == IID_ICLRErrorReportingManager)
2266 *ppUnk = (ICLRErrorReportingManager *) this;
2268 #ifdef FEATURE_WINDOWSPHONE
2269 else if (riid == IID_ICLRErrorReportingManager2)
2271 *ppUnk = (ICLRErrorReportingManager2 *) this;
2273 #endif // FEATURE_WINDOWSPHONE
2281 } // HRESULT CCLRErrorReportingManager::QueryInterface()
2283 ULONG CCLRErrorReportingManager::AddRef()
2285 LIMITED_METHOD_CONTRACT;
2287 } // HRESULT CCLRErrorReportingManager::AddRef()
2289 ULONG CCLRErrorReportingManager::Release()
2291 LIMITED_METHOD_CONTRACT;
2293 } // HRESULT CCLRErrorReportingManager::Release()
2295 // Get Watson bucket parameters for "current" exception (on calling thread).
2296 HRESULT CCLRErrorReportingManager::GetBucketParametersForCurrentException(
2297 BucketParameters *pParams)
2302 WRAPPER(GC_TRIGGERS);
2308 BEGIN_ENTRYPOINT_NOTHROW;
2310 // To avoid confusion, clear the buckets.
2311 memset(pParams, 0, sizeof(BucketParameters));
2314 // Defer to Watson helper.
2315 hr = ::GetBucketParametersForCurrentException(pParams);
2317 // Watson doesn't exist on non-windows platforms
2319 #endif // !FEATURE_PAL
2321 END_ENTRYPOINT_NOTHROW;
2325 } // HRESULT CCLRErrorReportingManager::GetBucketParametersForCurrentException()
2328 // The BeginCustomDump function configures the custom dump support
2331 // dwFlavor - The flavor of the dump
2332 // dwNumItems - The number of items in the CustomDumpItem array.
2333 // Should always be zero today, since no custom items are defined
2334 // items - Array of CustomDumpItem structs specifying items to be added to the dump.
2335 // Should always be NULL today, since no custom items are defined.
2336 // dwReserved - reserved for future use. Must be zero today
2338 HRESULT CCLRErrorReportingManager::BeginCustomDump( ECustomDumpFlavor dwFlavor,
2340 CustomDumpItem items[],
2343 STATIC_CONTRACT_ENTRY_POINT;
2346 BEGIN_ENTRYPOINT_NOTHROW;
2348 if (dwNumItems != 0 || items != NULL || dwReserved != 0)
2350 IfFailGo(E_INVALIDARG);
2352 if (g_ECustomDumpFlavor != DUMP_FLAVOR_Default)
2354 // BeginCustomDump is called without matching EndCustomDump
2355 IfFailGo(E_INVALIDARG);
2357 g_ECustomDumpFlavor = dwFlavor;
2360 END_ENTRYPOINT_NOTHROW;
2366 // EndCustomDump clears the custom dump configuration
2368 HRESULT CCLRErrorReportingManager::EndCustomDump()
2370 STATIC_CONTRACT_ENTRY_POINT;
2371 // NOT IMPLEMENTED YET
2372 BEGIN_ENTRYPOINT_NOTHROW;
2373 g_ECustomDumpFlavor = DUMP_FLAVOR_Default;
2374 END_ENTRYPOINT_NOTHROW;
2379 #ifdef FEATURE_WINDOWSPHONE
2380 HRESULT CopyStringWorker(_Out_ WCHAR** pTarget, WCHAR const* pSource)
2382 LIMITED_METHOD_CONTRACT;
2384 if (pTarget == NULL || pSource == NULL)
2385 return E_INVALIDARG;
2388 delete[] (*pTarget);
2390 // allocate space for the data plus one wchar for NULL
2391 size_t sourceLen = wcslen(pSource);
2392 *pTarget = new (nothrow) WCHAR[sourceLen + 1];
2395 return E_OUTOFMEMORY;
2397 errno_t result = wcsncpy_s(*pTarget, sourceLen + 1, pSource, sourceLen);
2398 _ASSERTE(result == 0);
2402 delete[] (*pTarget);
2411 CCLRErrorReportingManager::BucketParamsCache::BucketParamsCache(DWORD maxNumParams) : m_pParams(NULL), m_cMaxParams(maxNumParams)
2413 LIMITED_METHOD_CONTRACT;
2416 CCLRErrorReportingManager::BucketParamsCache::~BucketParamsCache()
2418 LIMITED_METHOD_CONTRACT;
2422 for (DWORD i = 0; i < m_cMaxParams; ++i)
2423 if (m_pParams[i]) delete[] m_pParams[i];
2427 WCHAR const* CCLRErrorReportingManager::BucketParamsCache::GetAt(BucketParameterIndex index)
2429 LIMITED_METHOD_CONTRACT;
2431 if (index >= InvalidBucketParamIndex)
2433 _ASSERTE(!"bad bucket parameter index");
2440 return m_pParams[index];
2443 HRESULT CCLRErrorReportingManager::BucketParamsCache::SetAt(BucketParameterIndex index, WCHAR const* val)
2445 LIMITED_METHOD_CONTRACT;
2447 if (index < 0 || index >= InvalidBucketParamIndex)
2449 _ASSERTE(!"bad bucket parameter index");
2450 return E_INVALIDARG;
2454 return E_INVALIDARG;
2458 m_pParams = new (nothrow) WCHAR*[m_cMaxParams];
2460 return E_OUTOFMEMORY;
2462 for (DWORD i = 0; i < m_cMaxParams; ++i)
2463 m_pParams[i] = NULL;
2466 return CopyStringWorker(&m_pParams[index], val);
2469 HRESULT CCLRErrorReportingManager::CopyToDataCache(_Out_ WCHAR** pTarget, WCHAR const* pSource)
2471 LIMITED_METHOD_CONTRACT;
2473 return CopyStringWorker(pTarget, pSource);
2476 HRESULT CCLRErrorReportingManager::SetApplicationData(ApplicationDataKey key, WCHAR const* pValue)
2478 STATIC_CONTRACT_ENTRY_POINT;
2480 BEGIN_ENTRYPOINT_NOTHROW;
2483 return HOST_E_INVALIDOPERATION;
2485 if (pValue == NULL || wcslen(pValue) > MAX_LONGPATH)
2486 return E_INVALIDARG;
2493 hr = CopyToDataCache(&m_pApplicationId, pValue);
2497 hr = CopyToDataCache(&m_pInstanceId, pValue);
2504 END_ENTRYPOINT_NOTHROW;
2509 HRESULT CCLRErrorReportingManager::SetBucketParametersForUnhandledException(BucketParameters const* pBucketParams, DWORD* pCountParams)
2511 STATIC_CONTRACT_ENTRY_POINT;
2513 BEGIN_ENTRYPOINT_NOTHROW;
2516 return HOST_E_INVALIDOPERATION;
2518 if (pBucketParams == NULL || pCountParams == NULL || pBucketParams->fInited != TRUE)
2519 return E_INVALIDARG;
2523 if (!m_pBucketParamsCache)
2525 m_pBucketParamsCache = new (nothrow) BucketParamsCache(InvalidBucketParamIndex);
2526 if (!m_pBucketParamsCache)
2527 return E_OUTOFMEMORY;
2531 bool hasOverride = false;
2533 for (DWORD i = 0; i < InvalidBucketParamIndex; ++i)
2535 if (pBucketParams->pszParams[i][0] != W('\0'))
2538 hr = m_pBucketParamsCache->SetAt(static_cast<BucketParameterIndex>(i), pBucketParams->pszParams[i]);
2547 return E_INVALIDARG;
2549 END_ENTRYPOINT_NOTHROW;
2554 WCHAR const* CCLRErrorReportingManager::GetApplicationData(ApplicationDataKey key)
2556 LIMITED_METHOD_CONTRACT;
2558 WCHAR* pValue = NULL;
2563 pValue = m_pApplicationId;
2567 pValue = m_pInstanceId;
2571 _ASSERTE(!"invalid key specified");
2577 WCHAR const* CCLRErrorReportingManager::GetBucketParamOverride(BucketParameterIndex bucketParamId)
2579 LIMITED_METHOD_CONTRACT;
2581 if (!m_pBucketParamsCache)
2584 return m_pBucketParamsCache->GetAt(bucketParamId);
2587 #endif // FEATURE_WINDOWSPHONE
2589 CCLRErrorReportingManager::CCLRErrorReportingManager()
2591 LIMITED_METHOD_CONTRACT;
2592 #ifdef FEATURE_WINDOWSPHONE
2593 m_pApplicationId = NULL;
2594 m_pInstanceId = NULL;
2595 m_pBucketParamsCache = NULL;
2599 CCLRErrorReportingManager::~CCLRErrorReportingManager()
2601 LIMITED_METHOD_CONTRACT;
2602 #ifdef FEATURE_WINDOWSPHONE
2603 if (m_pApplicationId)
2604 delete[] m_pApplicationId;
2607 delete[] m_pInstanceId;
2609 if (m_pBucketParamsCache)
2610 delete m_pBucketParamsCache;
2614 #endif // defined(FEATURE_WINDOWSPHONE)
2616 void GetProcessMemoryLoad(LPMEMORYSTATUSEX pMSEX)
2625 pMSEX->dwLength = sizeof(MEMORYSTATUSEX);
2626 BOOL fRet = GlobalMemoryStatusEx(pMSEX);
2630 // This is the instance that exposes interfaces out to all the other DLLs of the CLR
2631 // so they can use our services for TLS, synchronization, memory allocation, etc.
2632 static BYTE g_CEEInstance[sizeof(CExecutionEngine)];
2633 static Volatile<IExecutionEngine*> g_pCEE = NULL;
2635 PTLS_CALLBACK_FUNCTION CExecutionEngine::Callbacks[MAX_PREDEFINED_TLS_SLOT];
2637 extern "C" IExecutionEngine * __stdcall IEE()
2639 LIMITED_METHOD_CONTRACT;
2641 // Unfortunately,we can't probe here. The probing system requires the
2642 // use of TLS, and in order to initialize TLS we need to call IEE.
2644 //BEGIN_ENTRYPOINT_VOIDRET;
2647 // The following code does NOT contain a race condition. The following code is BY DESIGN.
2648 // The issue is that we can have two separate threads inside this if statement, both of which are
2649 // initializing the g_CEEInstance variable (and subsequently updating g_pCEE). This works fine,
2650 // and will not cause an inconsistent state due to the fact that CExecutionEngine has no
2651 // local variables. If multiple threads make it inside this if statement, it will copy the same
2652 // bytes over g_CEEInstance and there will not be a time when there is an inconsistent state.
2655 // Create a local copy on the stack and then copy it over to the static instance.
2656 // This avoids race conditions caused by multiple initializations of vtable in the constructor
2657 CExecutionEngine local;
2658 memcpy(&g_CEEInstance, (void*)&local, sizeof(CExecutionEngine));
2660 g_pCEE = (IExecutionEngine*)(CExecutionEngine*)&g_CEEInstance;
2662 //END_ENTRYPOINT_VOIDRET;
2668 HRESULT STDMETHODCALLTYPE CExecutionEngine::QueryInterface(REFIID id, void **pInterface)
2670 LIMITED_METHOD_CONTRACT;
2677 //CANNOTTHROWCOMPLUSEXCEPTION();
2678 if (id == IID_IExecutionEngine)
2679 *pInterface = (IExecutionEngine *)this;
2680 else if (id == IID_IEEMemoryManager)
2681 *pInterface = (IEEMemoryManager *)this;
2682 else if (id == IID_IUnknown)
2683 *pInterface = (IUnknown *)(IExecutionEngine *)this;
2685 return E_NOINTERFACE;
2689 } // HRESULT STDMETHODCALLTYPE CExecutionEngine::QueryInterface()
2692 ULONG STDMETHODCALLTYPE CExecutionEngine::AddRef()
2694 LIMITED_METHOD_CONTRACT;
2698 ULONG STDMETHODCALLTYPE CExecutionEngine::Release()
2700 LIMITED_METHOD_CONTRACT;
2706 void* data[MAX_PREDEFINED_TLS_SLOT];
2709 #define DataToClrTlsInfo(a) ((ClrTlsInfo*)a)
2711 void** CExecutionEngine::GetTlsData()
2713 LIMITED_METHOD_CONTRACT;
2715 return gCurrentThreadInfo.m_EETlsData;
2718 BOOL CExecutionEngine::SetTlsData (void** ppTlsInfo)
2720 LIMITED_METHOD_CONTRACT;
2722 gCurrentThreadInfo.m_EETlsData = ppTlsInfo;
2726 //---------------------------------------------------------------------------------------
2728 // Returns the current logical thread's data block (ClrTlsInfo::data).
2731 // slot - Index of the slot that is about to be requested
2732 // force - If the data block does not exist yet, create it as a side-effect
2735 // NULL, if the data block did not exist yet for the current thread and force was FALSE.
2736 // A pointer to the data block, otherwise.
2739 // If the underlying OS does not support fiber mode, the data block is stored in TLS.
2740 // If the underlying OS does support fiber mode, it is primarily stored in FLS,
2741 // and cached in TLS so that we can use our generated optimized TLS accessors.
2743 // TLS support for the other DLLs of the CLR operates quite differently in hosted
2744 // and unhosted scenarios.
2746 void **CExecutionEngine::CheckThreadState(DWORD slot, BOOL force)
2748 STATIC_CONTRACT_GC_NOTRIGGER;
2749 STATIC_CONTRACT_THROWS;
2750 STATIC_CONTRACT_MODE_ANY;
2751 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
2753 //<TODO> @TODO: Decide on an exception strategy for all the DLLs of the CLR, and then
2754 // enable all the exceptions out of this method.</TODO>
2756 // Treat as a runtime assertion, since the invariant spans many DLLs.
2757 _ASSERTE(slot < MAX_PREDEFINED_TLS_SLOT);
2758 // if (slot >= MAX_PREDEFINED_TLS_SLOT)
2759 // COMPlusThrow(kArgumentOutOfRangeException);
2761 void** pTlsData = CExecutionEngine::GetTlsData();
2762 BOOL fInTls = (pTlsData != NULL);
2764 ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData);
2765 if (pTlsInfo == 0 && force)
2768 #undef GetProcessHeap
2769 // !!! Contract uses our TLS support. Contract may be used before our host support is set up.
2770 // !!! To better support contract, we call into OS for memory allocation.
2771 pTlsInfo = (ClrTlsInfo*) ::HeapAlloc(GetProcessHeap(),0,sizeof(ClrTlsInfo));
2772 #define GetProcessHeap() Dont_Use_GetProcessHeap()
2773 #define HeapAlloc(hHeap, dwFlags, dwBytes) Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes)
2774 if (pTlsInfo == NULL)
2778 memset (pTlsInfo, 0, sizeof(ClrTlsInfo));
2781 if (!fInTls && pTlsInfo)
2783 if (!CExecutionEngine::SetTlsData(pTlsInfo->data))
2789 return pTlsInfo?pTlsInfo->data:NULL;
2795 #undef GetProcessHeap
2796 ::HeapFree(GetProcessHeap(), 0, pTlsInfo);
2797 #define GetProcessHeap() Dont_Use_GetProcessHeap()
2798 #define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
2800 // If this is for the stack probe, and we failed to allocate memory for it, we won't
2801 // put in a guard page.
2802 if (slot == TlsIdx_ClrDebugState)
2809 void **CExecutionEngine::CheckThreadStateNoCreate(DWORD slot
2811 , BOOL fForDestruction
2815 STATIC_CONTRACT_GC_NOTRIGGER;
2816 STATIC_CONTRACT_NOTHROW;
2817 STATIC_CONTRACT_MODE_ANY;
2819 // !!! This function is called during Thread::SwitchIn and SwitchOut
2820 // !!! It is extremely important that while executing this function, we will not
2821 // !!! cause fiber switch. This means we can not allocate memory, lock, etc...
2824 // Treat as a runtime assertion, since the invariant spans many DLLs.
2825 _ASSERTE(slot < MAX_PREDEFINED_TLS_SLOT);
2827 void **pTlsData = CExecutionEngine::GetTlsData();
2829 ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData);
2831 return pTlsInfo?pTlsInfo->data:NULL;
2834 // Note: Sampling profilers also use this function to initialize TLS for a unmanaged
2835 // sampling thread so that initialization can be done in advance to avoid deadlocks.
2836 // See ProfToEEInterfaceImpl::InitializeCurrentThread for more details.
2837 void CExecutionEngine::SetupTLSForThread(Thread *pThread)
2839 STATIC_CONTRACT_THROWS;
2840 STATIC_CONTRACT_GC_NOTRIGGER;
2841 STATIC_CONTRACT_MODE_ANY;
2844 if (StressLog::StressLogOn(~0u, 0))
2846 StressLog::CreateThreadStressLog();
2850 pTlsData = CheckThreadState(0);
2852 PREFIX_ASSUME(pTlsData != NULL);
2854 #ifdef ENABLE_CONTRACTS
2855 // Profilers need the side effect of GetClrDebugState() to perform initialization
2856 // in advance to avoid deadlocks. Refer to ProfToEEInterfaceImpl::InitializeCurrentThread
2857 ClrDebugState *pDebugState = ::GetClrDebugState();
2860 pThread->m_pClrDebugState = pDebugState;
2864 static void ThreadDetachingHelper(PTLS_CALLBACK_FUNCTION callback, void* pData)
2866 // Do not use contract. We are freeing TLS blocks.
2867 STATIC_CONTRACT_NOTHROW;
2868 STATIC_CONTRACT_GC_NOTRIGGER;
2869 STATIC_CONTRACT_MODE_ANY;
2874 // Called here from a thread detach or from destruction of a Thread object. In
2875 // the detach case, we get our info from TLS. In the destruct case, it comes from
2876 // the object we are destructing.
2877 void CExecutionEngine::ThreadDetaching(void ** pTlsData)
2879 // Can not cause memory allocation during thread detach, so no real contracts.
2880 STATIC_CONTRACT_NOTHROW;
2881 STATIC_CONTRACT_GC_NOTRIGGER;
2882 STATIC_CONTRACT_MODE_ANY;
2884 // This function may be called twice:
2885 // 1. When a physical thread dies, our DLL_THREAD_DETACH calls this function with pTlsData = NULL
2886 // 2. When a fiber is destroyed, or OS calls FlsCallback after DLL_THREAD_DETACH process.
2887 // We will null the FLS and TLS entry if it matches the deleted one.
2891 DeleteTLS (pTlsData);
2895 void CExecutionEngine::DeleteTLS(void ** pTlsData)
2897 // Can not cause memory allocation during thread detach, so no real contracts.
2898 STATIC_CONTRACT_NOTHROW;
2899 STATIC_CONTRACT_GC_NOTRIGGER;
2900 STATIC_CONTRACT_MODE_ANY;
2902 if (CExecutionEngine::GetTlsData() == NULL)
2904 // We have not allocated TlsData yet.
2908 PREFIX_ASSUME(pTlsData != NULL);
2910 ClrTlsInfo *pTlsInfo = DataToClrTlsInfo(pTlsData);
2915 for (int i=0; i<MAX_PREDEFINED_TLS_SLOT; i++)
2917 if (i == TlsIdx_ClrDebugState ||
2918 i == TlsIdx_StressLog)
2920 // StressLog and DebugState may be needed during callback.
2923 // If we have some data and a callback, issue it.
2924 if (Callbacks[i] != 0 && pTlsInfo->data[i] != 0)
2926 void* pData = pTlsInfo->data[i];
2927 pTlsInfo->data[i] = 0;
2928 ThreadDetachingHelper(Callbacks[i], pData);
2934 if (pTlsInfo->data[TlsIdx_StressLog] != 0)
2937 StressLog::ThreadDetach((ThreadStressLog *)pTlsInfo->data[TlsIdx_StressLog]);
2939 _ASSERTE (!"should not have StressLog");
2943 if (Callbacks[TlsIdx_ClrDebugState] != 0 && pTlsInfo->data[TlsIdx_ClrDebugState] != 0)
2945 void* pData = pTlsInfo->data[TlsIdx_ClrDebugState];
2946 pTlsInfo->data[TlsIdx_ClrDebugState] = 0;
2947 ThreadDetachingHelper(Callbacks[TlsIdx_ClrDebugState], pData);
2950 // NULL TLS and FLS entry so that we don't double free.
2951 // We may get two callback here on thread death
2952 // 1. From EEDllMain
2953 // 2. From OS callback on FLS destruction
2954 if (CExecutionEngine::GetTlsData() == pTlsData)
2956 CExecutionEngine::SetTlsData(0);
2960 #undef GetProcessHeap
2961 ::HeapFree (GetProcessHeap(),0,pTlsInfo);
2962 #define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
2963 #define GetProcessHeap() Dont_Use_GetProcessHeap()
2967 #ifdef ENABLE_CONTRACTS_IMPL
2968 // Fls callback to deallocate ClrDebugState when our FLS block goes away.
2969 void FreeClrDebugState(LPVOID pTlsData);
2972 VOID STDMETHODCALLTYPE CExecutionEngine::TLS_AssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback)
2974 WRAPPER_NO_CONTRACT;
2976 CheckThreadState(slot);
2978 // They can toggle between a callback and no callback. But anything else looks like
2979 // confusion on their part.
2981 // (TlsIdx_ClrDebugState associates its callback from utilcode.lib - which can be replicated. But
2982 // all the callbacks are equally good.)
2983 _ASSERTE(slot == TlsIdx_ClrDebugState || Callbacks[slot] == 0 || Callbacks[slot] == callback || callback == 0);
2984 if (slot == TlsIdx_ClrDebugState)
2986 #ifdef ENABLE_CONTRACTS_IMPL
2987 // ClrDebugState is shared among many dlls. Some dll, like perfcounter.dll, may be unloaded.
2988 // We force the callback function to be in mscorwks.dll.
2989 Callbacks[slot] = FreeClrDebugState;
2991 _ASSERTE (!"should not get here");
2995 Callbacks[slot] = callback;
2998 LPVOID* STDMETHODCALLTYPE CExecutionEngine::TLS_GetDataBlock()
3000 STATIC_CONTRACT_GC_NOTRIGGER;
3001 STATIC_CONTRACT_THROWS;
3002 STATIC_CONTRACT_MODE_ANY;
3003 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
3005 return CExecutionEngine::GetTlsData();
3008 LPVOID STDMETHODCALLTYPE CExecutionEngine::TLS_GetValue(DWORD slot)
3010 WRAPPER_NO_CONTRACT;
3011 return EETlsGetValue(slot);
3014 BOOL STDMETHODCALLTYPE CExecutionEngine::TLS_CheckValue(DWORD slot, LPVOID * pValue)
3016 WRAPPER_NO_CONTRACT;
3017 return EETlsCheckValue(slot, pValue);
3020 VOID STDMETHODCALLTYPE CExecutionEngine::TLS_SetValue(DWORD slot, LPVOID pData)
3022 WRAPPER_NO_CONTRACT;
3023 EETlsSetValue(slot,pData);
3027 VOID STDMETHODCALLTYPE CExecutionEngine::TLS_ThreadDetaching()
3029 WRAPPER_NO_CONTRACT;
3030 CExecutionEngine::ThreadDetaching(NULL);
3034 CRITSEC_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags)
3045 CRITSEC_COOKIE cookie = NULL;
3046 BEGIN_ENTRYPOINT_VOIDRET;
3047 cookie = ::EECreateCriticalSection(*(CrstType*)&level, flags);
3048 END_ENTRYPOINT_VOIDRET;
3052 void STDMETHODCALLTYPE CExecutionEngine::DestroyLock(CRITSEC_COOKIE cookie)
3054 WRAPPER_NO_CONTRACT;
3055 ::EEDeleteCriticalSection(cookie);
3058 void STDMETHODCALLTYPE CExecutionEngine::AcquireLock(CRITSEC_COOKIE cookie)
3060 WRAPPER_NO_CONTRACT;
3061 ::EEEnterCriticalSection(cookie);
3064 void STDMETHODCALLTYPE CExecutionEngine::ReleaseLock(CRITSEC_COOKIE cookie)
3066 WRAPPER_NO_CONTRACT;
3067 ::EELeaveCriticalSection(cookie);
3070 // Locking routines supplied by the EE to the other DLLs of the CLR. In a _DEBUG
3071 // build of the EE, we poison the Crst as a poor man's attempt to do some argument
3073 #define POISON_BITS 3
3075 static inline EVENT_COOKIE CLREventToCookie(CLREvent * pEvent)
3077 LIMITED_METHOD_CONTRACT;
3078 _ASSERTE((((uintptr_t) pEvent) & POISON_BITS) == 0);
3080 pEvent = (CLREvent *) (((uintptr_t) pEvent) | POISON_BITS);
3082 return (EVENT_COOKIE) pEvent;
3085 static inline CLREvent *CookieToCLREvent(EVENT_COOKIE cookie)
3087 LIMITED_METHOD_CONTRACT;
3089 _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS);
3093 cookie = (EVENT_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS);
3096 return (CLREvent *) cookie;
3100 EVENT_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateAutoEvent(BOOL bInitialState)
3111 EVENT_COOKIE event = NULL;
3112 BEGIN_ENTRYPOINT_THROWS;
3113 NewHolder<CLREvent> pEvent(new CLREvent());
3114 pEvent->CreateAutoEvent(bInitialState);
3115 event = CLREventToCookie(pEvent);
3116 pEvent.SuppressRelease();
3117 END_ENTRYPOINT_THROWS;
3122 EVENT_COOKIE STDMETHODCALLTYPE CExecutionEngine::CreateManualEvent(BOOL bInitialState)
3133 EVENT_COOKIE event = NULL;
3134 BEGIN_ENTRYPOINT_THROWS;
3136 NewHolder<CLREvent> pEvent(new CLREvent());
3137 pEvent->CreateManualEvent(bInitialState);
3138 event = CLREventToCookie(pEvent);
3139 pEvent.SuppressRelease();
3141 END_ENTRYPOINT_THROWS;
3146 void STDMETHODCALLTYPE CExecutionEngine::CloseEvent(EVENT_COOKIE event)
3148 WRAPPER_NO_CONTRACT;
3150 CLREvent *pEvent = CookieToCLREvent(event);
3151 pEvent->CloseEvent();
3156 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrSetEvent(EVENT_COOKIE event)
3166 CLREvent *pEvent = CookieToCLREvent(event);
3167 return pEvent->Set();
3172 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrResetEvent(EVENT_COOKIE event)
3182 CLREvent *pEvent = CookieToCLREvent(event);
3183 return pEvent->Reset();
3188 DWORD STDMETHODCALLTYPE CExecutionEngine::WaitForEvent(EVENT_COOKIE event,
3189 DWORD dwMilliseconds,
3192 WRAPPER_NO_CONTRACT;
3194 CLREvent *pEvent = CookieToCLREvent(event);
3195 return pEvent->Wait(dwMilliseconds,bAlertable);
3198 if (GetThread() && bAlertable)
3199 ThrowHR(E_INVALIDARG);
3203 DWORD STDMETHODCALLTYPE CExecutionEngine::WaitForSingleObject(HANDLE handle,
3204 DWORD dwMilliseconds)
3206 STATIC_CONTRACT_WRAPPER;
3207 return ::WaitForSingleObject(handle,dwMilliseconds);
3210 static inline SEMAPHORE_COOKIE CLRSemaphoreToCookie(CLRSemaphore * pSemaphore)
3212 LIMITED_METHOD_CONTRACT;
3214 _ASSERTE((((uintptr_t) pSemaphore) & POISON_BITS) == 0);
3216 pSemaphore = (CLRSemaphore *) (((uintptr_t) pSemaphore) | POISON_BITS);
3218 return (SEMAPHORE_COOKIE) pSemaphore;
3221 static inline CLRSemaphore *CookieToCLRSemaphore(SEMAPHORE_COOKIE cookie)
3223 LIMITED_METHOD_CONTRACT;
3224 _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS);
3228 cookie = (SEMAPHORE_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS);
3231 return (CLRSemaphore *) cookie;
3235 SEMAPHORE_COOKIE STDMETHODCALLTYPE CExecutionEngine::ClrCreateSemaphore(DWORD dwInitial,
3246 NewHolder<CLRSemaphore> pSemaphore(new CLRSemaphore());
3247 pSemaphore->Create(dwInitial, dwMax);
3248 SEMAPHORE_COOKIE ret = CLRSemaphoreToCookie(pSemaphore);;
3249 pSemaphore.SuppressRelease();
3253 void STDMETHODCALLTYPE CExecutionEngine::ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore)
3262 CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore);
3263 pSemaphore->Close();
3267 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore,
3269 LONG *lpPreviousCount)
3278 CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore);
3279 return pSemaphore->Release(lReleaseCount,lpPreviousCount);
3282 DWORD STDMETHODCALLTYPE CExecutionEngine::ClrWaitForSemaphore(SEMAPHORE_COOKIE semaphore,
3283 DWORD dwMilliseconds,
3286 WRAPPER_NO_CONTRACT;
3287 CLRSemaphore *pSemaphore = CookieToCLRSemaphore(semaphore);
3288 return pSemaphore->Wait(dwMilliseconds,bAlertable);
3291 static inline MUTEX_COOKIE CLRMutexToCookie(CLRMutex * pMutex)
3293 LIMITED_METHOD_CONTRACT;
3294 _ASSERTE((((uintptr_t) pMutex) & POISON_BITS) == 0);
3296 pMutex = (CLRMutex *) (((uintptr_t) pMutex) | POISON_BITS);
3298 return (MUTEX_COOKIE) pMutex;
3301 static inline CLRMutex *CookieToCLRMutex(MUTEX_COOKIE cookie)
3303 LIMITED_METHOD_CONTRACT;
3304 _ASSERTE((((uintptr_t) cookie) & POISON_BITS) == POISON_BITS);
3308 cookie = (MUTEX_COOKIE) (((uintptr_t) cookie) & ~POISON_BITS);
3311 return (CLRMutex *) cookie;
3315 MUTEX_COOKIE STDMETHODCALLTYPE CExecutionEngine::ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,
3328 MUTEX_COOKIE mutex = 0;
3329 CLRMutex *pMutex = new (nothrow) CLRMutex();
3334 pMutex->Create(lpMutexAttributes, bInitialOwner, lpName);
3335 mutex = CLRMutexToCookie(pMutex);
3341 EX_END_CATCH(SwallowAllExceptions);
3346 void STDMETHODCALLTYPE CExecutionEngine::ClrCloseMutex(MUTEX_COOKIE mutex)
3355 CLRMutex *pMutex = CookieToCLRMutex(mutex);
3360 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrReleaseMutex(MUTEX_COOKIE mutex)
3369 CLRMutex *pMutex = CookieToCLRMutex(mutex);
3370 return pMutex->Release();
3373 DWORD STDMETHODCALLTYPE CExecutionEngine::ClrWaitForMutex(MUTEX_COOKIE mutex,
3374 DWORD dwMilliseconds,
3384 CLRMutex *pMutex = CookieToCLRMutex(mutex);
3385 return pMutex->Wait(dwMilliseconds,bAlertable);
3389 DWORD STDMETHODCALLTYPE CExecutionEngine::ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable)
3391 WRAPPER_NO_CONTRACT;
3392 return EESleepEx(dwMilliseconds,bAlertable);
3394 #define ClrSleepEx EESleepEx
3396 #undef ClrAllocationDisallowed
3397 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrAllocationDisallowed()
3399 WRAPPER_NO_CONTRACT;
3400 return EEAllocationDisallowed();
3402 #define ClrAllocationDisallowed EEAllocationDisallowed
3404 #undef ClrVirtualAlloc
3405 LPVOID STDMETHODCALLTYPE CExecutionEngine::ClrVirtualAlloc(LPVOID lpAddress,
3407 DWORD flAllocationType,
3410 WRAPPER_NO_CONTRACT;
3411 return EEVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
3413 #define ClrVirtualAlloc EEVirtualAlloc
3415 #undef ClrVirtualFree
3416 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrVirtualFree(LPVOID lpAddress,
3420 WRAPPER_NO_CONTRACT;
3421 return EEVirtualFree(lpAddress, dwSize, dwFreeType);
3423 #define ClrVirtualFree EEVirtualFree
3425 #undef ClrVirtualQuery
3426 SIZE_T STDMETHODCALLTYPE CExecutionEngine::ClrVirtualQuery(LPCVOID lpAddress,
3427 PMEMORY_BASIC_INFORMATION lpBuffer,
3430 WRAPPER_NO_CONTRACT;
3431 return EEVirtualQuery(lpAddress, lpBuffer, dwLength);
3433 #define ClrVirtualQuery EEVirtualQuery
3435 #if defined(_DEBUG) && !defined(FEATURE_PAL)
3436 static VolatilePtr<BYTE> s_pStartOfUEFSection = NULL;
3437 static VolatilePtr<BYTE> s_pEndOfUEFSectionBoundary = NULL;
3438 static Volatile<DWORD> s_dwProtection = 0;
3439 #endif // _DEBUG && !FEATURE_PAL
3441 #undef ClrVirtualProtect
3443 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrVirtualProtect(LPVOID lpAddress,
3446 PDWORD lpflOldProtect)
3448 WRAPPER_NO_CONTRACT;
3450 // Get the UEF installation details - we will use these to validate
3451 // that the calls to ClrVirtualProtect are not going to affect the UEF.
3453 // The OS UEF invocation mechanism was updated. When a UEF is setup,the OS captures
3454 // the following details about it:
3455 // 1) Protection of the pages in which the UEF lives
3456 // 2) The size of the region in which the UEF lives
3457 // 3) The region's Allocation Base
3459 // The OS verifies details surrounding the UEF before invocation. For security reasons
3460 // the page protection cannot change between SetUnhandledExceptionFilter and invocation.
3462 // Prior to this change, the UEF lived in a common section of code_Seg, along with
3463 // JIT_PatchedCode. Thus, their pages have the same protection, they live
3464 // in the same region (and thus, its size is the same).
3466 // In EEStartupHelper, when we setup the UEF and then invoke InitJitHelpers1 and InitJitHelpers2,
3467 // they perform some optimizations that result in the memory page protection being changed. When
3468 // the UEF is to be invoked, the OS does the check on the UEF's cached details against the current
3469 // memory pages. This check used to fail when on 64bit retail builds when JIT_PatchedCode was
3470 // aligned after the UEF with a different memory page protection (post the optimizations by InitJitHelpers).
3471 // Thus, the UEF was never invoked.
3473 // To circumvent this, we put the UEF in its own section in the code segment so that any modifications
3474 // to memory pages will not affect the UEF details that the OS cached. This is done in Excep.cpp
3475 // using the "#pragma code_seg" directives.
3477 // Below, we double check that:
3479 // 1) the address being protected does not lie in the region of of the UEF.
3480 // 2) the section after UEF is not having the same memory protection as UEF section.
3482 // We assert if either of the two conditions above are true.
3484 #if defined(_DEBUG) && !defined(FEATURE_PAL)
3485 // We do this check in debug/checked builds only
3487 // Do we have the UEF details?
3488 if (s_pEndOfUEFSectionBoundary.Load() == NULL)
3490 // Get reference to MSCORWKS image in memory...
3491 PEDecoder pe(g_pMSCorEE);
3493 // Find the UEF section from the image
3494 IMAGE_SECTION_HEADER* pUEFSection = pe.FindSection(CLR_UEF_SECTION_NAME);
3495 _ASSERTE(pUEFSection != NULL);
3498 // We got our section - get the start of the section
3499 BYTE* pStartOfUEFSection = static_cast<BYTE*>(pe.GetBase())+pUEFSection->VirtualAddress;
3500 s_pStartOfUEFSection = pStartOfUEFSection;
3502 // Now we need the protection attributes for the memory region in which the
3503 // UEF section is...
3504 MEMORY_BASIC_INFORMATION uefInfo;
3505 if (ClrVirtualQuery(pStartOfUEFSection, &uefInfo, sizeof(uefInfo)) != 0)
3507 // Calculate how many pages does the UEF section take to get to the start of the
3508 // next section. We dont calculate this as
3510 // pStartOfUEFSection + uefInfo.RegionSize
3512 // because the section following UEF will also be included in the region size
3513 // if it has the same protection as the UEF section.
3514 DWORD dwUEFSectionPageCount = ((pUEFSection->Misc.VirtualSize + GetOsPageSize() - 1)/GetOsPageSize());
3516 BYTE* pAddressOfFollowingSection = pStartOfUEFSection + (GetOsPageSize() * dwUEFSectionPageCount);
3518 // Ensure that the section following us is having different memory protection
3519 MEMORY_BASIC_INFORMATION nextSectionInfo;
3520 _ASSERTE(ClrVirtualQuery(pAddressOfFollowingSection, &nextSectionInfo, sizeof(nextSectionInfo)) != 0);
3521 _ASSERTE(nextSectionInfo.Protect != uefInfo.Protect);
3523 // save the memory protection details
3524 s_dwProtection = uefInfo.Protect;
3526 // Get the end of the UEF section
3527 BYTE* pEndOfUEFSectionBoundary = pAddressOfFollowingSection - 1;
3529 // Set the end of UEF section boundary
3530 FastInterlockExchangePointer(s_pEndOfUEFSectionBoundary.GetPointer(), pEndOfUEFSectionBoundary);
3534 _ASSERTE(!"Unable to get UEF Details!");
3539 if (s_pEndOfUEFSectionBoundary.Load() != NULL)
3541 // Is the protection being changed?
3542 if (flNewProtect != s_dwProtection)
3544 // Is the target address NOT affecting the UEF ? Possible cases:
3545 // 1) Starts and ends before the UEF start
3546 // 2) Starts after the UEF start
3548 void* pEndOfRangeAddr = static_cast<BYTE*>(lpAddress)+dwSize-1;
3550 _ASSERTE_MSG(((pEndOfRangeAddr < s_pStartOfUEFSection.Load()) || (lpAddress > s_pEndOfUEFSectionBoundary.Load())),
3551 "Do not virtual protect the section in which UEF lives!");
3554 #endif // _DEBUG && !FEATURE_PAL
3556 return EEVirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect);
3558 #define ClrVirtualProtect EEVirtualProtect
3560 #undef ClrGetProcessHeap
3561 HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrGetProcessHeap()
3563 WRAPPER_NO_CONTRACT;
3564 return EEGetProcessHeap();
3566 #define ClrGetProcessHeap EEGetProcessHeap
3568 #undef ClrGetProcessExecutableHeap
3569 HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrGetProcessExecutableHeap()
3571 WRAPPER_NO_CONTRACT;
3572 return EEGetProcessExecutableHeap();
3574 #define ClrGetProcessExecutableHeap EEGetProcessExecutableHeap
3577 #undef ClrHeapCreate
3578 HANDLE STDMETHODCALLTYPE CExecutionEngine::ClrHeapCreate(DWORD flOptions,
3579 SIZE_T dwInitialSize,
3580 SIZE_T dwMaximumSize)
3582 WRAPPER_NO_CONTRACT;
3583 return EEHeapCreate(flOptions, dwInitialSize, dwMaximumSize);
3585 #define ClrHeapCreate EEHeapCreate
3587 #undef ClrHeapDestroy
3588 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapDestroy(HANDLE hHeap)
3590 WRAPPER_NO_CONTRACT;
3591 return EEHeapDestroy(hHeap);
3593 #define ClrHeapDestroy EEHeapDestroy
3596 LPVOID STDMETHODCALLTYPE CExecutionEngine::ClrHeapAlloc(HANDLE hHeap,
3600 WRAPPER_NO_CONTRACT;
3602 return EEHeapAlloc(hHeap, dwFlags, dwBytes);
3604 #define ClrHeapAlloc EEHeapAlloc
3607 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapFree(HANDLE hHeap,
3611 WRAPPER_NO_CONTRACT;
3612 return EEHeapFree(hHeap, dwFlags, lpMem);
3614 #define ClrHeapFree EEHeapFree
3616 #undef ClrHeapValidate
3617 BOOL STDMETHODCALLTYPE CExecutionEngine::ClrHeapValidate(HANDLE hHeap,
3621 WRAPPER_NO_CONTRACT;
3622 return EEHeapValidate(hHeap, dwFlags, lpMem);
3624 #define ClrHeapValidate EEHeapValidate
3626 //------------------------------------------------------------------------------
3627 // Helper function to get an exception object from outside the exception. In
3628 // the CLR, it may be from the Thread object. Non-CLR users have no thread object,
3629 // and it will do nothing.
3631 void CExecutionEngine::GetLastThrownObjectExceptionFromThread(void **ppvException)
3633 WRAPPER_NO_CONTRACT;
3635 // Cast to our real type.
3636 Exception **ppException = reinterpret_cast<Exception**>(ppvException);
3638 // Try to get a better message.
3639 GetLastThrownObjectExceptionFromThread_Internal(ppException);
3641 } // HRESULT CExecutionEngine::GetLastThrownObjectExceptionFromThread()
3644 LocaleID RuntimeGetFileSystemLocale()
3646 return PEImage::GetFileSystemLocale();
3649 HRESULT CorHost2::DllGetActivationFactory(DWORD appDomainID, LPCWSTR wszTypeName, IActivationFactory ** factory)
3651 #ifdef FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
3652 // WinRT activation currently supported in default domain only
3653 if (appDomainID != DefaultADID)
3654 return HOST_E_INVALIDOPERATION;
3658 Thread *pThread = GetThread();
3659 if (pThread == NULL)
3661 pThread = SetupThreadNoThrow(&hr);
3662 if (pThread == NULL)
3668 if(SystemDomain::GetCurrentDomain()->GetId().m_dwId != DefaultADID)
3670 return HOST_E_INVALIDOPERATION;
3673 return DllGetActivationFactoryImpl(NULL, wszTypeName, NULL, factory);
3680 #ifdef FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION
3682 HRESULT STDMETHODCALLTYPE DllGetActivationFactoryImpl(LPCWSTR wszAssemblyName,
3683 LPCWSTR wszTypeName,
3684 LPCWSTR wszCodeBase,
3685 IActivationFactory ** factory)
3698 BEGIN_ENTRYPOINT_NOTHROW;
3700 AppDomain* pDomain = SystemDomain::System()->DefaultDomain();
3703 BEGIN_EXTERNAL_ENTRYPOINT(&hr);
3708 TypeHandle typeHandle = WinRTTypeNameConverter::GetManagedTypeFromWinRTTypeName(wszTypeName, &bIsPrimitive);
3709 if (!bIsPrimitive && !typeHandle.IsNull() && !typeHandle.IsTypeDesc() && typeHandle.AsMethodTable()->IsExportedToWinRT())
3714 memset(&gc, 0, sizeof(gc));
3717 IActivationFactory* activationFactory;
3718 GCPROTECT_BEGIN(gc);
3720 gc.type = typeHandle.GetManagedClassObject();
3722 MethodDescCallSite mdcs(METHOD__WINDOWSRUNTIMEMARSHAL__GET_ACTIVATION_FACTORY_FOR_TYPE);
3723 ARG_SLOT args[1] = {
3724 ObjToArgSlot(gc.type)
3726 activationFactory = (IActivationFactory*)mdcs.Call_RetLPVOID(args);
3728 *factory = activationFactory;
3734 hr = COR_E_TYPELOAD;
3737 END_EXTERNAL_ENTRYPOINT;
3738 END_ENTRYPOINT_NOTHROW;
3743 #endif // !FEATURE_COMINTEROP_MANAGED_ACTIVATION
3748 #endif // !DACCESS_COMPILE