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.
8 #include "appdomain.hpp"
9 #include "peimagelayout.inl"
11 #include "strongnameinternal.h"
14 #include "gcheaputilities.h"
15 #include "eventtrace.h"
16 #include "perfcounters.h"
17 #include "assemblyname.hpp"
18 #include "eeprofinterfaces.h"
19 #include "dbginterface.h"
20 #ifndef DACCESS_COMPILE
21 #include "eedbginterfaceimpl.h"
23 #include "comdynamic.h"
25 #include "posterror.h"
26 #include "assemblynative.hpp"
28 #include "stringliteralmap.h"
30 #include "comcallablewrapper.h"
31 #include "apithreadstress.h"
32 #include "eventtrace.h"
33 #include "comdelegate.h"
34 #include "siginfo.hpp"
39 #include "finalizerthread.h"
40 #include "threadsuspend.h"
43 #include "corcompile.h"
45 #endif // FEATURE_PREJIT
47 #ifdef FEATURE_COMINTEROP
48 #include "comtoclrcall.h"
49 #include "sxshelpers.h"
50 #include "runtimecallablewrapper.h"
51 #include "mngstdinterfaces.h"
52 #include "olevariant.h"
53 #include "rcwrefcache.h"
54 #include "olecontexthelpers.h"
55 #endif // FEATURE_COMINTEROP
56 #ifdef FEATURE_TYPEEQUIVALENCE
57 #include "typeequivalencehash.hpp"
60 #include "appdomain.inl"
61 #include "typeparse.h"
62 #include "mdaassistants.h"
63 #include "threadpoolrequest.h"
65 #include "nativeoverlapped.h"
67 #include "compatibilityflags.h"
71 #endif // !FEATURE_PAL
73 #include "stringarraylist.h"
75 #include "../binder/inc/clrprivbindercoreclr.h"
78 #include "clrprivtypecachewinrt.h"
81 #ifdef FEATURE_RANDOMIZED_STRING_HASHING
83 #pragma warning(disable:4324)
88 // this file handles string conversion errors for itself
89 #undef MAKE_TRANSLATIONFAILED
91 // Define these macro's to do strict validation for jit lock and class
92 // init entry leaks. This defines determine if the asserts that
93 // verify for these leaks are defined or not. These asserts can
94 // sometimes go off even if no entries have been leaked so this
95 // defines should be used with caution.
97 // If we are inside a .cctor when the application shut's down then the
98 // class init lock's head will be set and this will cause the assert
101 // If we are jitting a method when the application shut's down then
102 // the jit lock's head will be set causing the assert to go off.
104 //#define STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
106 static const WCHAR DEFAULT_DOMAIN_FRIENDLY_NAME[] = W("DefaultDomain");
107 static const WCHAR OTHER_DOMAIN_FRIENDLY_NAME_PREFIX[] = W("Domain");
109 #define STATIC_OBJECT_TABLE_BUCKET_SIZE 1020
111 #define MAX_URL_LENGTH 2084 // same as INTERNET_MAX_URL_LENGTH
113 //#define _DEBUG_ADUNLOAD 1
115 HRESULT RunDllMain(MethodDesc *pMD, HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved); // clsload.cpp
123 SPTR_IMPL(SystemDomain, SystemDomain, m_pSystemDomain);
124 SVAL_IMPL(ArrayListStatic, SystemDomain, m_appDomainIndexList);
125 SPTR_IMPL(SharedDomain, SharedDomain, m_pSharedDomain);
126 SVAL_IMPL(BOOL, SystemDomain, s_fForceDebug);
127 SVAL_IMPL(BOOL, SystemDomain, s_fForceProfiling);
128 SVAL_IMPL(BOOL, SystemDomain, s_fForceInstrument);
130 #ifndef DACCESS_COMPILE
132 // Base Domain Statics
133 CrstStatic BaseDomain::m_SpecialStaticsCrst;
135 int BaseDomain::m_iNumberOfProcessors = 0;
137 // Shared Domain Statics
139 static BYTE g_pSharedDomainMemory[sizeof(SharedDomain)];
141 // System Domain Statics
142 GlobalStringLiteralMap* SystemDomain::m_pGlobalStringLiteralMap = NULL;
145 static BYTE g_pSystemDomainMemory[sizeof(SystemDomain)];
147 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
148 size_t SystemDomain::m_totalSurvivedBytes = 0;
149 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
151 CrstStatic SystemDomain::m_SystemDomainCrst;
152 CrstStatic SystemDomain::m_DelayedUnloadCrst;
154 ULONG SystemDomain::s_dNumAppDomains = 0;
156 AppDomain * SystemDomain::m_pAppDomainBeingUnloaded = NULL;
157 ADIndex SystemDomain::m_dwIndexOfAppDomainBeingUnloaded;
158 Thread *SystemDomain::m_pAppDomainUnloadRequestingThread = 0;
159 Thread *SystemDomain::m_pAppDomainUnloadingThread = 0;
161 ArrayListStatic SystemDomain::m_appDomainIdList;
163 DWORD SystemDomain::m_dwLowestFreeIndex = 0;
167 // comparison function to be used for matching clsids in our clsid hash table
168 BOOL CompareCLSID(UPTR u1, UPTR u2)
176 INJECT_FAULT(COMPlusThrowOM(););
180 GUID *pguid = (GUID *)(u1 << 1);
181 _ASSERTE(pguid != NULL);
183 MethodTable *pMT= (MethodTable *)u2;
184 _ASSERTE(pMT!= NULL);
187 pMT->GetGuid(&guid, TRUE);
188 if (!IsEqualIID(guid, *pguid))
194 #ifndef CROSSGEN_COMPILE
195 // Constructor for the LargeHeapHandleBucket class.
196 LargeHeapHandleBucket::LargeHeapHandleBucket(LargeHeapHandleBucket *pNext, DWORD Size, BaseDomain *pDomain, BOOL bCrossAD)
200 , m_CurrentEmbeddedFreePos(0) // hint for where to start a search for an embedded free item
207 PRECONDITION(CheckPointer(pDomain));
208 INJECT_FAULT(COMPlusThrowOM(););
212 PTRARRAYREF HandleArrayObj;
214 // Allocate the array in the large object heap.
217 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
218 HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, TRUE);
222 // During AD creation we don't want to assign the handle array to the currently running AD but
223 // to the AD being created. Ensure that AllocateArrayEx doesn't set the AD and then set it here.
224 AppDomain *pAD = pDomain->AsAppDomain();
226 _ASSERTE(pAD->IsBeingCreated());
230 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
231 array = AllocateArrayEx(
232 ClassLoader::LoadArrayTypeThrowing(g_pObjectClass),
239 array->SetAppDomain(pAD);
241 HandleArrayObj = (PTRARRAYREF)array;
244 // Retrieve the pointer to the data inside the array. This is legal since the array
245 // is located in the large object heap and is guaranteed not to move.
246 m_pArrayDataPtr = (OBJECTREF *)HandleArrayObj->GetDataPtr();
248 // Store the array in a strong handle to keep it alive.
249 m_hndHandleArray = pDomain->CreatePinningHandle((OBJECTREF)HandleArrayObj);
253 // Destructor for the LargeHeapHandleBucket class.
254 LargeHeapHandleBucket::~LargeHeapHandleBucket()
263 if (m_hndHandleArray)
265 DestroyPinningHandle(m_hndHandleArray);
266 m_hndHandleArray = NULL;
271 // Allocate handles from the bucket.
272 OBJECTREF *LargeHeapHandleBucket::AllocateHandles(DWORD nRequested)
282 _ASSERTE(nRequested > 0 && nRequested <= GetNumRemainingHandles());
283 _ASSERTE(m_pArrayDataPtr == (OBJECTREF*)((PTRARRAYREF)ObjectFromHandle(m_hndHandleArray))->GetDataPtr());
285 // Store the handles in the buffer that was passed in
286 OBJECTREF* ret = &m_pArrayDataPtr[m_CurrentPos];
287 m_CurrentPos += nRequested;
292 // look for a free item embedded in the table
293 OBJECTREF *LargeHeapHandleBucket::TryAllocateEmbeddedFreeHandle()
303 OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
304 _ASSERTE(pPreallocatedSentinalObject != NULL);
306 for (int i = m_CurrentEmbeddedFreePos; i < m_CurrentPos; i++)
308 if (m_pArrayDataPtr[i] == pPreallocatedSentinalObject)
310 m_CurrentEmbeddedFreePos = i;
311 m_pArrayDataPtr[i] = NULL;
312 return &m_pArrayDataPtr[i];
316 // didn't find it (we don't bother wrapping around for a full search, it's not worth it to try that hard, we'll get it next time)
318 m_CurrentEmbeddedFreePos = 0;
323 // Maximum bucket size will be 64K on 32-bit and 128K on 64-bit.
324 // We subtract out a small amount to leave room for the object
325 // header and length of the array.
327 #define MAX_BUCKETSIZE (16384 - 4)
329 // Constructor for the LargeHeapHandleTable class.
330 LargeHeapHandleTable::LargeHeapHandleTable(BaseDomain *pDomain, DWORD InitialBucketSize)
333 , m_NextBucketSize(InitialBucketSize)
334 , m_pFreeSearchHint(NULL)
342 PRECONDITION(CheckPointer(pDomain));
343 INJECT_FAULT(COMPlusThrowOM(););
353 // Destructor for the LargeHeapHandleTable class.
354 LargeHeapHandleTable::~LargeHeapHandleTable()
363 // Delete the buckets.
366 LargeHeapHandleBucket *pOld = m_pHead;
367 m_pHead = pOld->GetNext();
372 //*****************************************************************************
374 // LOCKING RULES FOR AllocateHandles() and ReleaseHandles() 12/08/2004
377 // These functions are not protected by any locking in this location but rather the callers are
378 // assumed to be doing suitable locking for the handle table. The handle table itself is
379 // behaving rather like a thread-agnostic collection class -- it doesn't want to know
380 // much about the outside world and so it is just doing its job with no awareness of
383 // The instance in question is
384 // There are two locations you can find a LargeHeapHandleTable
385 // 1) there is one in every BaseDomain, it is used to keep track of the static members
387 // 2) there is one in the System Domain that is used for the GlobalStringLiteralMap
389 // the one in (2) is not the same as the one that is in the BaseDomain object that corresponds
390 // to the SystemDomain -- that one is basically stilborn because the string literals don't go
391 // there and of course the System Domain has no code loaded into it -- only regular
392 // AppDomains (like Domain 0) actually execute code. As a result handle tables are in
393 // practice used either for string literals or for static members but never for both.
394 // At least not at this writing.
396 // Now it's useful to consider what the locking discipline is for these classes.
400 // First case: (easiest) is the statics members
402 // Each BaseDomain has its own critical section
404 // BaseDomain::AllocateObjRefPtrsInLargeTable takes a lock with
405 // CrstHolder ch(&m_LargeHeapHandleTableCrst);
407 // it does this before it calls AllocateHandles which suffices. It does not call ReleaseHandles
408 // at any time (although ReleaseHandles may be called via AllocateHandles if the request
409 // doesn't fit in the current block, the remaining handles at the end of the block are released
410 // automatically as part of allocation/recycling)
412 // note: Recycled handles are only used during String Literal allocation because we only try
413 // to recycle handles if the allocation request is for exactly one handle.
415 // The handles in the BaseDomain handle table are released when the Domain is unloaded
416 // as the GC objects become rootless at that time.
418 // This dispenses with all of the Handle tables except the one that is used for string literals
422 // Second case: Allocation for use in a string literal
424 // AppDomainStringLiteralMap::GetStringLiteral
426 // LargeHeapHandleBlockHolder constructor
428 // m_Data = pOwner->AllocateHandles(nCount);
430 // before doing this AppDomainStringLiteralMap::GetStringLiteral takes this lock
432 // CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
434 // which is the lock for the hash table that it owns
436 // STRINGREF *AppDomainStringLiteralMap::GetInternedString
438 // has a similar call path and uses the same approach and the same lock
439 // this covers all the paths which allocate
443 // Third case: Releases for use in a string literal entry
445 // CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
446 // taken in the AppDomainStringLiteralMap functions below protects the 4 ways that this can happen
450 // in an appdomain unload case
452 // AppDomainStringLiteralMap::~AppDomainStringLiteralMap() takes the lock then
454 // StringLiteralEntry::Release
456 // SystemDomain::GetGlobalStringLiteralMapNoCreate()->RemoveStringLiteralEntry(this)
458 // m_LargeHeapHandleTable.ReleaseHandles((OBJECTREF*)pObjRef, 1);
462 // AppDomainStringLiteralMap::GetStringLiteral() can call StringLiteralEntry::Release in some
463 // error cases, leading to the same stack as above
467 // AppDomainStringLiteralMap::GetInternedString() can call StringLiteralEntry::Release in some
468 // error cases, leading to the same stack as above
472 // The same code paths in 3b and 3c and also end up releasing if an exception is thrown
473 // during their processing. Both these paths use a StringLiteralEntryHolder to assist in cleanup,
474 // the StaticRelease method of the StringLiteralEntry gets called, which in turn calls the
478 // Allocate handles from the large heap handle table.
479 OBJECTREF* LargeHeapHandleTable::AllocateHandles(DWORD nRequested, BOOL bCrossAD)
486 PRECONDITION(nRequested > 0);
487 INJECT_FAULT(COMPlusThrowOM(););
491 // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
493 // the lock must be registered and already held by the caller per contract
495 _ASSERTE(m_pCrstDebug != NULL);
496 _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
499 if (nRequested == 1 && m_cEmbeddedFree != 0)
501 // special casing singleton requests to look for slots that can be re-used
503 // we need to do this because string literals are allocated one at a time and then sometimes
504 // released. we do not wish for the number of handles consumed by string literals to
505 // increase forever as assemblies are loaded and unloaded
507 if (m_pFreeSearchHint == NULL)
508 m_pFreeSearchHint = m_pHead;
510 while (m_pFreeSearchHint)
512 OBJECTREF* pObjRef = m_pFreeSearchHint->TryAllocateEmbeddedFreeHandle();
515 // the slot is to have been prepared with a null ready to go
516 _ASSERTE(*pObjRef == NULL);
520 m_pFreeSearchHint = m_pFreeSearchHint->GetNext();
523 // the search doesn't wrap around so it's possible that we might have embedded free items
524 // and not find them but that's ok, we'll get them on the next alloc... all we're trying to do
525 // is to not have big leaks over time.
529 // Retrieve the remaining number of handles in the bucket.
530 DWORD NumRemainingHandlesInBucket = (m_pHead != NULL) ? m_pHead->GetNumRemainingHandles() : 0;
532 // create a new block if this request doesn't fit in the current block
533 if (nRequested > NumRemainingHandlesInBucket)
537 // mark the handles in that remaining region as available for re-use
538 ReleaseHandles(m_pHead->CurrentPos(), NumRemainingHandlesInBucket);
540 // mark what's left as having been used
541 m_pHead->ConsumeRemaining();
544 // create a new bucket for this allocation
546 // We need a block big enough to hold the requested handles
547 DWORD NewBucketSize = max(m_NextBucketSize, nRequested);
549 m_pHead = new LargeHeapHandleBucket(m_pHead, NewBucketSize, m_pDomain, bCrossAD);
551 m_NextBucketSize = min(m_NextBucketSize * 2, MAX_BUCKETSIZE);
554 return m_pHead->AllocateHandles(nRequested);
557 //*****************************************************************************
558 // Release object handles allocated using AllocateHandles().
559 void LargeHeapHandleTable::ReleaseHandles(OBJECTREF *pObjRef, DWORD nReleased)
566 PRECONDITION(CheckPointer(pObjRef));
570 // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
572 // the lock must be registered and already held by the caller per contract
574 _ASSERTE(m_pCrstDebug != NULL);
575 _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
578 OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
579 _ASSERTE(pPreallocatedSentinalObject != NULL);
582 // Add the released handles to the list of available handles.
583 for (DWORD i = 0; i < nReleased; i++)
585 SetObjectReference(&pObjRef[i], pPreallocatedSentinalObject, NULL);
588 m_cEmbeddedFree += nReleased;
594 // Constructor for the ThreadStaticHandleBucket class.
595 ThreadStaticHandleBucket::ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain)
604 PRECONDITION(CheckPointer(pDomain));
605 INJECT_FAULT(COMPlusThrowOM(););
609 PTRARRAYREF HandleArrayObj;
611 // Allocate the array on the GC heap.
612 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
613 HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, FALSE);
615 // Store the array in a strong handle to keep it alive.
616 m_hndHandleArray = pDomain->CreateStrongHandle((OBJECTREF)HandleArrayObj);
619 // Destructor for the ThreadStaticHandleBucket class.
620 ThreadStaticHandleBucket::~ThreadStaticHandleBucket()
630 if (m_hndHandleArray)
632 DestroyStrongHandle(m_hndHandleArray);
633 m_hndHandleArray = NULL;
637 // Allocate handles from the bucket.
638 OBJECTHANDLE ThreadStaticHandleBucket::GetHandles()
648 return m_hndHandleArray;
651 // Constructor for the ThreadStaticHandleTable class.
652 ThreadStaticHandleTable::ThreadStaticHandleTable(BaseDomain *pDomain)
661 PRECONDITION(CheckPointer(pDomain));
666 // Destructor for the ThreadStaticHandleTable class.
667 ThreadStaticHandleTable::~ThreadStaticHandleTable()
676 // Delete the buckets.
679 ThreadStaticHandleBucket *pOld = m_pHead;
680 m_pHead = pOld->GetNext();
685 // Allocate handles from the large heap handle table.
686 OBJECTHANDLE ThreadStaticHandleTable::AllocateHandles(DWORD nRequested)
693 PRECONDITION(nRequested > 0);
694 INJECT_FAULT(COMPlusThrowOM(););
698 // create a new bucket for this allocation
699 m_pHead = new ThreadStaticHandleBucket(m_pHead, nRequested, m_pDomain);
701 return m_pHead->GetHandles();
704 #endif // CROSSGEN_COMPILE
707 //*****************************************************************************
709 //*****************************************************************************
710 void BaseDomain::Attach()
712 #ifdef FEATURE_RANDOMIZED_STRING_HASHING
713 // Randomized string hashing is on by default for String.GetHashCode in coreclr.
714 COMNlsHashProvider::s_NlsHashProvider.SetUseRandomHashing((CorHost2::GetStartupFlags() & STARTUP_DISABLE_RANDOMIZED_STRING_HASHING) == 0);
715 #endif // FEATURE_RANDOMIZED_STRING_HASHING
716 m_SpecialStaticsCrst.Init(CrstSpecialStatics);
719 BaseDomain::BaseDomain()
721 // initialize fields so the domain can be safely destructed
722 // shouldn't call anything that can fail here - use ::Init instead
732 m_fDisableInterfaceCache = FALSE;
734 m_pFusionContext = NULL;
735 m_pTPABinderContext = NULL;
737 // Make sure the container is set to NULL so that it gets loaded when it is used.
738 m_pLargeHeapHandleTable = NULL;
740 #ifndef CROSSGEN_COMPILE
741 // Note that m_handleStore is overridden by app domains
742 m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
744 m_handleStore = NULL;
747 m_pMarshalingData = NULL;
749 m_dwContextStatics = 0;
750 #ifdef FEATURE_COMINTEROP
751 m_pMngStdInterfacesInfo = NULL;
752 m_pWinRtBinder = NULL;
754 m_FileLoadLock.PreInit();
756 m_ClassInitLock.PreInit();
757 m_ILStubGenLock.PreInit();
759 #ifdef FEATURE_CODE_VERSIONING
760 m_codeVersionManager.PreInit(this == (BaseDomain *)g_pSharedDomainMemory);
763 } //BaseDomain::BaseDomain
765 //*****************************************************************************
766 void BaseDomain::Init()
773 INJECT_FAULT(COMPlusThrowOM(););
778 // Initialize the domain locks
781 if (this == reinterpret_cast<BaseDomain*>(&g_pSharedDomainMemory[0]))
782 m_DomainCrst.Init(CrstSharedBaseDomain);
783 else if (this == reinterpret_cast<BaseDomain*>(&g_pSystemDomainMemory[0]))
784 m_DomainCrst.Init(CrstSystemBaseDomain);
786 m_DomainCrst.Init(CrstBaseDomain);
788 m_DomainCacheCrst.Init(CrstAppDomainCache);
789 m_DomainLocalBlockCrst.Init(CrstDomainLocalBlock);
791 m_InteropDataCrst.Init(CrstInteropData, CRST_REENTRANCY);
793 m_WinRTFactoryCacheCrst.Init(CrstWinRTFactoryCache, CRST_UNSAFE_COOPGC);
795 // NOTE: CRST_UNSAFE_COOPGC prevents a GC mode switch to preemptive when entering this crst.
796 // If you remove this flag, we will switch to preemptive mode when entering
797 // m_FileLoadLock, which means all functions that enter it will become
798 // GC_TRIGGERS. (This includes all uses of PEFileListLockHolder, LoadLockHolder, etc.) So be sure
799 // to update the contracts if you remove this flag.
800 m_FileLoadLock.Init(CrstAssemblyLoader,
801 CrstFlags(CRST_HOST_BREAKABLE), TRUE);
804 // The JIT lock and the CCtor locks are at the same level (and marked as
805 // UNSAFE_SAME_LEVEL) because they are all part of the same deadlock detection mechanism. We
806 // see through cycles of JITting and .cctor execution and then explicitly allow the cycle to
807 // be broken by giving access to uninitialized classes. If there is no cycle or if the cycle
808 // involves other locks that arent part of this special deadlock-breaking semantics, then
809 // we continue to block.
811 m_JITLock.Init(CrstJit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
812 m_ClassInitLock.Init(CrstClassInit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
814 m_ILStubGenLock.Init(CrstILStubGen, CrstFlags(CRST_REENTRANCY), TRUE);
816 // Large heap handle table CRST.
817 m_LargeHeapHandleTableCrst.Init(CrstAppDomainHandleTable);
819 m_crstLoaderAllocatorReferences.Init(CrstLoaderAllocatorReferences);
820 // Has to switch thread to GC_NOTRIGGER while being held (see code:BaseDomain#AssemblyListLock)
821 m_crstAssemblyList.Init(CrstAssemblyList, CrstFlags(
822 CRST_GC_NOTRIGGER_WHEN_TAKEN | CRST_DEBUGGER_THREAD | CRST_TAKEN_DURING_SHUTDOWN));
824 // Initialize the EE marshaling data to NULL.
825 m_pMarshalingData = NULL;
827 #ifdef FEATURE_COMINTEROP
828 // Allocate the managed standard interfaces information.
829 m_pMngStdInterfacesInfo = new MngStdInterfacesInfo();
832 CLRPrivBinderWinRT::NamespaceResolutionKind fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_WindowsAPI;
833 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DesignerNamespaceResolutionEnabled) != FALSE)
835 fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_DesignerResolveEvent;
837 CLRPrivTypeCacheWinRT * pWinRtTypeCache = CLRPrivTypeCacheWinRT::GetOrCreateTypeCache();
838 m_pWinRtBinder = CLRPrivBinderWinRT::GetOrCreateBinder(pWinRtTypeCache, fNamespaceResolutionKind);
840 #endif // FEATURE_COMINTEROP
842 // Init the COM Interop data hash
844 LockOwner lock = {&m_InteropDataCrst, IsOwnerOfCrst};
845 m_interopDataHash.Init(0, NULL, false, &lock);
848 m_dwSizedRefHandles = 0;
849 if (!m_iNumberOfProcessors)
851 m_iNumberOfProcessors = GetCurrentProcessCpuCount();
855 #undef LOADERHEAP_PROFILE_COUNTER
857 #ifndef CROSSGEN_COMPILE
858 //*****************************************************************************
859 void BaseDomain::Terminate()
869 m_crstLoaderAllocatorReferences.Destroy();
870 m_DomainCrst.Destroy();
871 m_DomainCacheCrst.Destroy();
872 m_DomainLocalBlockCrst.Destroy();
873 m_InteropDataCrst.Destroy();
875 JitListLockEntry* pJitElement;
876 ListLockEntry* pElement;
878 // All the threads that are in this domain had better be stopped by this
881 // We might be jitting or running a .cctor so we need to empty that queue.
882 pJitElement = m_JITLock.Pop(TRUE);
885 #ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
886 _ASSERTE ((m_JITLock.m_pHead->m_dwRefCount == 1
887 && m_JITLock.m_pHead->m_hrResultCode == E_FAIL) ||
888 dbg_fDrasticShutdown || g_fInControlC);
889 #endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
891 pJitElement = m_JITLock.Pop(TRUE);
896 pElement = m_ClassInitLock.Pop(TRUE);
899 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
900 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
903 pElement = m_ClassInitLock.Pop(TRUE);
905 m_ClassInitLock.Destroy();
907 FileLoadLock* pFileElement;
908 pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
911 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
912 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
914 pFileElement->Release();
915 pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
917 m_FileLoadLock.Destroy();
919 pElement = m_ILStubGenLock.Pop(TRUE);
922 #ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
923 _ASSERTE ((m_ILStubGenLock.m_pHead->m_dwRefCount == 1
924 && m_ILStubGenLock.m_pHead->m_hrResultCode == E_FAIL) ||
925 dbg_fDrasticShutdown || g_fInControlC);
926 #endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
928 pElement = m_ILStubGenLock.Pop(TRUE);
930 m_ILStubGenLock.Destroy();
932 m_LargeHeapHandleTableCrst.Destroy();
934 if (m_pLargeHeapHandleTable != NULL)
936 delete m_pLargeHeapHandleTable;
937 m_pLargeHeapHandleTable = NULL;
942 // Kind of a workaround - during unloading, we need to have an EE halt
943 // around deleting this stuff. So it gets deleted in AppDomain::Terminate()
944 // for those things (because there is a convenient place there.)
945 GetLoaderAllocator()->CleanupStringLiteralMap();
948 #ifdef FEATURE_COMINTEROP
949 if (m_pMngStdInterfacesInfo)
951 delete m_pMngStdInterfacesInfo;
952 m_pMngStdInterfacesInfo = NULL;
955 if (m_pWinRtBinder != NULL)
957 m_pWinRtBinder->Release();
959 #endif // FEATURE_COMINTEROP
961 ClearFusionContext();
963 m_dwSizedRefHandles = 0;
965 #endif // CROSSGEN_COMPILE
967 void BaseDomain::InitVSD()
969 STANDARD_VM_CONTRACT;
971 // This is a workaround for gcc, since it fails to successfully resolve
972 // "TypeIDMap::STARTING_SHARED_DOMAIN_ID" when used within the ?: operator.
974 if (IsSharedDomain())
976 startingId = TypeIDMap::STARTING_SHARED_DOMAIN_ID;
980 startingId = TypeIDMap::STARTING_UNSHARED_DOMAIN_ID;
983 // By passing false as the last parameter, interfaces loaded in the
984 // shared domain will not be given fat type ids if RequiresFatDispatchTokens
985 // is set. This is correct, as the fat dispatch tokens are only needed to solve
986 // uniqueness problems involving domain specific types.
987 m_typeIDMap.Init(startingId, 2, !IsSharedDomain());
989 #ifndef CROSSGEN_COMPILE
990 GetLoaderAllocator()->InitVirtualCallStubManager(this);
994 #ifndef CROSSGEN_COMPILE
996 DWORD BaseDomain::AllocateContextStaticsOffset(DWORD* pOffsetSlot)
1005 CrstHolder ch(&m_SpecialStaticsCrst);
1007 DWORD dwOffset = *pOffsetSlot;
1009 if (dwOffset == (DWORD)-1)
1011 // Allocate the slot
1012 dwOffset = m_dwContextStatics++;
1013 *pOffsetSlot = dwOffset;
1019 void BaseDomain::ClearFusionContext()
1029 if(m_pFusionContext) {
1030 m_pFusionContext->Release();
1031 m_pFusionContext = NULL;
1033 if (m_pTPABinderContext) {
1034 m_pTPABinderContext->Release();
1035 m_pTPABinderContext = NULL;
1039 #ifdef FEATURE_PREJIT
1040 void AppDomain::DeleteNativeCodeRanges()
1051 // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized
1052 // and yet we are destroying it. (This is the case if we OOM during AppDomain creation.)
1053 if (m_Assemblies.IsEmpty())
1056 // Shutdown assemblies
1057 AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad) );
1058 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1060 while (i.Next(pDomainAssembly.This()))
1062 Assembly * assembly = pDomainAssembly->m_pAssembly;
1063 if ((assembly != NULL) && !assembly->IsDomainNeutral())
1064 assembly->DeleteNativeCodeRanges();
1069 void AppDomain::ShutdownAssemblies()
1079 // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized
1080 // and yet we are destroying it. (This is the case if we OOM during AppDomain creation.)
1081 if (m_Assemblies.IsEmpty())
1084 // Shutdown assemblies
1085 // has two stages because Terminate needs info from the Assembly's dependencies
1087 // Stage 1: call code:Assembly::Terminate
1088 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1089 kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
1090 DomainAssembly * pDomainAssembly = NULL;
1092 while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1094 // Note: cannot use DomainAssembly::GetAssembly() here as it asserts that the assembly has been
1095 // loaded to at least the FILE_LOAD_ALLOCATE level. Since domain shutdown can take place
1096 // asynchronously this property cannot be guaranteed. Access the m_pAssembly field directly instead.
1097 Assembly * assembly = pDomainAssembly->m_pAssembly;
1098 if (assembly && !assembly->IsDomainNeutral())
1099 assembly->Terminate();
1102 // Stage 2: Clear the list of assemblies
1103 i = IterateAssembliesEx((AssemblyIterationFlags)(
1104 kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
1105 while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1107 // We are in shutdown path, no one else can get to the list anymore
1108 delete pDomainAssembly;
1110 m_Assemblies.Clear(this);
1112 // Stage 2: Clear the loader allocators registered for deletion from code:Assembly:Terminate calls in
1114 // Note: It is not clear to me why we cannot delete the loader allocator from within
1115 // code:DomainAssembly::~DomainAssembly
1116 ShutdownFreeLoaderAllocators(FALSE);
1117 } // AppDomain::ShutdownAssemblies
1119 void AppDomain::ShutdownFreeLoaderAllocators(BOOL bFromManagedCode)
1121 // If we're called from managed code (i.e. the finalizer thread) we take a lock in
1122 // LoaderAllocator::CleanupFailedTypeInit, which may throw. Otherwise we're called
1123 // from the app-domain shutdown path in which we can avoid taking the lock.
1127 if (bFromManagedCode) THROWS; else NOTHROW;
1133 CrstHolder ch(GetLoaderAllocatorReferencesLock());
1135 // Shutdown the LoaderAllocators associated with collectible assemblies
1136 while (m_pDelayedLoaderAllocatorUnloadList != NULL)
1138 LoaderAllocator * pCurrentLoaderAllocator = m_pDelayedLoaderAllocatorUnloadList;
1139 // Remove next loader allocator from the list
1140 m_pDelayedLoaderAllocatorUnloadList = m_pDelayedLoaderAllocatorUnloadList->m_pLoaderAllocatorDestroyNext;
1142 if (bFromManagedCode)
1144 // For loader allocator finalization, we need to be careful about cleaning up per-appdomain allocations
1145 // and synchronizing with GC using delay unload list. We need to wait for next Gen2 GC to finish to ensure
1146 // that GC heap does not have any references to the MethodTables being unloaded.
1148 pCurrentLoaderAllocator->CleanupFailedTypeInit();
1150 pCurrentLoaderAllocator->CleanupHandles();
1153 SystemDomain::System()->AddToDelayedUnloadList(pCurrentLoaderAllocator);
1157 // For appdomain unload, delete the loader allocator right away
1158 delete pCurrentLoaderAllocator;
1161 } // AppDomain::ShutdownFreeLoaderAllocators
1163 //---------------------------------------------------------------------------------------
1165 // Register the loader allocator for deletion in code:AppDomain::ShutdownFreeLoaderAllocators.
1167 void AppDomain::RegisterLoaderAllocatorForDeletion(LoaderAllocator * pLoaderAllocator)
1178 CrstHolder ch(GetLoaderAllocatorReferencesLock());
1180 pLoaderAllocator->m_pLoaderAllocatorDestroyNext = m_pDelayedLoaderAllocatorUnloadList;
1181 m_pDelayedLoaderAllocatorUnloadList = pLoaderAllocator;
1184 void AppDomain::ShutdownNativeDllSearchDirectories()
1186 LIMITED_METHOD_CONTRACT;
1187 // Shutdown assemblies
1188 PathIterator i = IterateNativeDllSearchDirectories();
1195 m_NativeDllSearchDirectories.Clear();
1198 void AppDomain::ReleaseDomainBoundInfo()
1207 // Shutdown assemblies
1208 m_AssemblyCache.OnAppDomainUnload();
1210 AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeFailedToLoad) );
1211 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1213 while (i.Next(pDomainAssembly.This()))
1215 pDomainAssembly->ReleaseManagedData();
1219 void AppDomain::ReleaseFiles()
1221 STANDARD_VM_CONTRACT;
1223 // Shutdown assemblies
1224 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1225 kIncludeLoaded | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeLoading));
1226 CollectibleAssemblyHolder<DomainAssembly *> pAsm;
1228 while (i.Next(pAsm.This()))
1230 if (pAsm->GetCurrentAssembly() == NULL)
1232 // Might be domain neutral or not, but should have no live objects as it has not been
1233 // really loaded yet. Just reset it.
1234 _ASSERTE(FitsIn<DWORD>(i.GetIndex()));
1235 m_Assemblies.Set(this, static_cast<DWORD>(i.GetIndex()), NULL);
1236 delete pAsm.Extract();
1240 if (!pAsm->GetCurrentAssembly()->IsDomainNeutral())
1241 pAsm->ReleaseFiles();
1244 } // AppDomain::ReleaseFiles
1247 OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate, BOOL bCrossAD)
1254 PRECONDITION((nRequested > 0));
1255 INJECT_FAULT(COMPlusThrowOM(););
1259 if (ppLazyAllocate && *ppLazyAllocate)
1261 // Allocation already happened
1262 return *ppLazyAllocate;
1265 // Enter preemptive state, take the lock and go back to cooperative mode.
1267 CrstHolder ch(&m_LargeHeapHandleTableCrst);
1270 if (ppLazyAllocate && *ppLazyAllocate)
1272 // Allocation already happened
1273 return *ppLazyAllocate;
1276 // Make sure the large heap handle table is initialized.
1277 if (!m_pLargeHeapHandleTable)
1278 InitLargeHeapHandleTable();
1280 // Allocate the handles.
1281 OBJECTREF* result = m_pLargeHeapHandleTable->AllocateHandles(nRequested, bCrossAD);
1285 *ppLazyAllocate = result;
1291 #endif // CROSSGEN_COMPILE
1293 #endif // !DACCESS_COMPILE
1296 PTR_BaseDomain BaseDomain::ComputeBaseDomain(
1297 BaseDomain * pGenericDefinitionDomain, // the domain that owns the generic type or method
1298 Instantiation classInst, // the type arguments to the type (if any)
1299 Instantiation methodInst) // the type arguments to the method (if any)
1301 CONTRACT(PTR_BaseDomain)
1307 POSTCONDITION(CheckPointer(RETVAL));
1313 if (pGenericDefinitionDomain && pGenericDefinitionDomain->IsAppDomain())
1314 RETURN PTR_BaseDomain(pGenericDefinitionDomain);
1316 for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
1318 PTR_BaseDomain pArgDomain = classInst[i].GetDomain();
1319 if (pArgDomain->IsAppDomain())
1323 for (DWORD i = 0; i < methodInst.GetNumArgs(); i++)
1325 PTR_BaseDomain pArgDomain = methodInst[i].GetDomain();
1326 if (pArgDomain->IsAppDomain())
1329 RETURN (pGenericDefinitionDomain ?
1330 PTR_BaseDomain(pGenericDefinitionDomain) :
1331 PTR_BaseDomain(SystemDomain::System()));
1334 PTR_BaseDomain BaseDomain::ComputeBaseDomain(TypeKey * pKey)
1346 if (pKey->GetKind() == ELEMENT_TYPE_CLASS)
1347 return BaseDomain::ComputeBaseDomain(pKey->GetModule()->GetDomain(),
1348 pKey->GetInstantiation());
1349 else if (pKey->GetKind() != ELEMENT_TYPE_FNPTR)
1350 return pKey->GetElementType().GetDomain();
1352 return BaseDomain::ComputeBaseDomain(NULL,Instantiation(pKey->GetRetAndArgTypes(), pKey->GetNumArgs()+1));
1359 #ifndef DACCESS_COMPILE
1361 // Insert class in the hash table
1362 void AppDomain::InsertClassForCLSID(MethodTable* pMT, BOOL fForceInsert /*=FALSE*/)
1369 INJECT_FAULT(COMPlusThrowOM(););
1375 // Ensure that registered classes are activated for allocation
1376 pMT->EnsureInstanceActive();
1378 // Note that it is possible for multiple classes to claim the same CLSID, and in such a
1379 // case it is arbitrary which one we will return for a future query for a given app domain.
1381 pMT->GetGuid(&cvid, fForceInsert);
1383 if (!IsEqualIID(cvid, GUID_NULL))
1385 //<TODO>@todo get a better key</TODO>
1386 LPVOID val = (LPVOID)pMT;
1388 LockHolder lh(this);
1390 if (LookupClass(cvid) != pMT)
1392 m_clsidHash.InsertValue(GetKeyFromGUID(&cvid), val);
1398 void AppDomain::InsertClassForCLSID(MethodTable* pMT, GUID *pGuid)
1403 PRECONDITION(CheckPointer(pMT));
1404 PRECONDITION(CheckPointer(pGuid));
1408 LPVOID val = (LPVOID)pMT;
1410 LockHolder lh(this);
1413 if (LookupClass(*cvid) != pMT)
1415 m_clsidHash.InsertValue(GetKeyFromGUID(pGuid), val);
1421 #endif // DACCESS_COMPILE
1423 #ifdef FEATURE_COMINTEROP
1425 #ifndef DACCESS_COMPILE
1426 void AppDomain::CacheTypeByName(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1428 WRAPPER_NO_CONTRACT;
1429 LockHolder lh(this);
1430 CacheTypeByNameWorker(ssClassName, vCacheVersion, typeHandle, bFlags, bReplaceExisting);
1433 void AppDomain::CacheTypeByNameWorker(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1439 PRECONDITION(!typeHandle.IsNull());
1443 NewArrayHolder<WCHAR> wzClassName(DuplicateStringThrowing(ssClassName.GetUnicode()));
1445 if (m_vNameToTypeMapVersion != vCacheVersion)
1448 if (m_pNameToTypeMap == nullptr)
1450 m_pNameToTypeMap = new NameToTypeMapTable();
1453 NameToTypeMapEntry e;
1454 e.m_key.m_wzName = wzClassName;
1455 e.m_key.m_cchName = ssClassName.GetCount();
1456 e.m_typeHandle = typeHandle;
1457 e.m_nEpoch = this->m_nEpoch;
1458 e.m_bFlags = bFlags;
1459 if (!bReplaceExisting)
1460 m_pNameToTypeMap->Add(e);
1462 m_pNameToTypeMap->AddOrReplace(e);
1464 wzClassName.SuppressRelease();
1466 #endif // DACCESS_COMPILE
1468 TypeHandle AppDomain::LookupTypeByName(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1470 WRAPPER_NO_CONTRACT;
1471 LockHolder lh(this);
1472 return LookupTypeByNameWorker(ssClassName, pvCacheVersion, pbFlags);
1475 TypeHandle AppDomain::LookupTypeByNameWorker(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1482 PRECONDITION(CheckPointer(pbFlags, NULL_OK));
1486 *pvCacheVersion = m_vNameToTypeMapVersion;
1488 if (m_pNameToTypeMap == nullptr)
1489 return TypeHandle(); // a null TypeHandle
1491 NameToTypeMapEntry::Key key;
1492 key.m_cchName = ssClassName.GetCount();
1493 key.m_wzName = ssClassName.GetUnicode();
1495 const NameToTypeMapEntry * pEntry = m_pNameToTypeMap->LookupPtr(key);
1497 return TypeHandle(); // a null TypeHandle
1499 if (pbFlags != NULL)
1500 *pbFlags = pEntry->m_bFlags;
1502 return pEntry->m_typeHandle;
1505 PTR_MethodTable AppDomain::LookupTypeByGuid(const GUID & guid)
1519 GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1520 sGuid.Append(wszGuid);
1523 TypeHandle th = LookupTypeByName(sGuid, &ver, NULL);
1527 _ASSERTE(!th.IsTypeDesc());
1528 return th.AsMethodTable();
1531 #ifdef FEATURE_PREJIT
1534 // Next look in each ngen'ed image in turn
1535 AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1536 kIncludeLoaded | kIncludeExecution));
1537 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1538 while (assemblyIterator.Next(pDomainAssembly.This()))
1540 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1542 DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1545 Module * pModule = i.GetLoadedModule();
1546 if (!pModule->HasNativeImage())
1548 _ASSERTE(!pModule->IsCollectible());
1549 PTR_MethodTable pMT = pModule->LookupTypeByGuid(guid);
1557 #endif // FEATURE_PREJIT
1561 #ifndef DACCESS_COMPILE
1562 void AppDomain::CacheWinRTTypeByGuid(TypeHandle typeHandle)
1569 PRECONDITION(!typeHandle.IsTypeDesc());
1570 PRECONDITION(CanCacheWinRTTypeByGuid(typeHandle));
1574 PTR_MethodTable pMT = typeHandle.AsMethodTable();
1577 if (pMT->GetGuidForWinRT(&guid))
1583 GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1584 sGuid.Append(wszGuid);
1591 LockHolder lh(this);
1592 th = LookupTypeByNameWorker(sGuid, &vCacheVersion, &bFlags);
1596 // no other entry with the same GUID exists in the cache
1597 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags);
1599 else if (typeHandle.AsMethodTable() != th.AsMethodTable() && th.IsProjectedFromWinRT())
1601 // If we found a native WinRT type cached with the same GUID, replace it.
1602 // Otherwise simply add the new mapping to the cache.
1603 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags, TRUE);
1608 #endif // DACCESS_COMPILE
1610 void AppDomain::GetCachedWinRTTypes(
1611 SArray<PTR_MethodTable> * pTypes,
1612 SArray<GUID> * pGuids,
1625 LockHolder lh(this);
1627 for (auto it = m_pNameToTypeMap->Begin(), end = m_pNameToTypeMap->End();
1631 NameToTypeMapEntry entry = (NameToTypeMapEntry)(*it);
1632 TypeHandle th = entry.m_typeHandle;
1633 if (th.AsMethodTable() != NULL &&
1634 entry.m_key.m_wzName[0] == W('{') &&
1635 entry.m_nEpoch >= minEpoch)
1637 _ASSERTE(!th.IsTypeDesc());
1638 PTR_MethodTable pMT = th.AsMethodTable();
1639 // we're parsing the GUID value from the cache, because projected types do not cache the
1640 // COM GUID in their GetGuid() but rather the legacy GUID
1642 if (LPWSTRToGuid(&iid, entry.m_key.m_wzName, 38) && iid != GUID_NULL)
1644 pTypes->Append(pMT);
1645 pGuids->Append(iid);
1650 #ifdef FEATURE_PREJIT
1651 // Next look in each ngen'ed image in turn
1652 AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1653 kIncludeLoaded | kIncludeExecution));
1654 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1655 while (assemblyIterator.Next(pDomainAssembly.This()))
1657 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1659 DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1662 Module * pModule = i.GetLoadedModule();
1663 if (!pModule->HasNativeImage())
1665 _ASSERTE(!pModule->IsCollectible());
1667 pModule->GetCachedWinRTTypes(pTypes, pGuids);
1670 #endif // FEATURE_PREJIT
1672 if (pCurEpoch != NULL)
1673 *pCurEpoch = m_nEpoch;
1677 #ifndef CROSSGEN_COMPILE
1678 #ifndef DACCESS_COMPILE
1680 void WinRTFactoryCacheTraits::OnDestructPerEntryCleanupAction(const WinRTFactoryCacheEntry& e)
1682 WRAPPER_NO_CONTRACT;
1683 if (e.m_pCtxEntry != NULL)
1685 e.m_pCtxEntry->Release();
1687 // the AD is going away, no need to destroy the OBJECTHANDLE
1690 void AppDomain::CacheWinRTFactoryObject(MethodTable *pClassMT, OBJECTREF *refFactory, LPVOID lpCtxCookie)
1697 PRECONDITION(CheckPointer(pClassMT));
1701 CtxEntryHolder pNewCtxEntry;
1702 if (lpCtxCookie != NULL)
1704 // We don't want to insert the context cookie in the cache because it's just an address
1705 // of an internal COM data structure which will be freed when the apartment is torn down.
1706 // What's worse, if another apartment is later created, its context cookie may have exactly
1707 // the same value leading to incorrect cache hits. We'll use our CtxEntry instead which
1708 // is ref-counted and keeps the COM data structure alive even after the apartment ceases
1710 pNewCtxEntry = CtxEntryCache::GetCtxEntryCache()->FindCtxEntry(lpCtxCookie, GetThread());
1713 WinRTFactoryCacheLockHolder lh(this);
1715 if (m_pWinRTFactoryCache == nullptr)
1717 m_pWinRTFactoryCache = new WinRTFactoryCache();
1720 WinRTFactoryCacheEntry *pEntry = const_cast<WinRTFactoryCacheEntry*>(m_pWinRTFactoryCache->LookupPtr(pClassMT));
1724 // No existing entry for this cache
1727 WinRTFactoryCacheEntry e;
1729 OBJECTHANDLEHolder ohNewHandle(CreateHandle(*refFactory));
1732 e.m_pCtxEntry = pNewCtxEntry;
1733 e.m_ohFactoryObject = ohNewHandle;
1735 m_pWinRTFactoryCache->Add(e);
1737 // suppress release of the CtxEntry and handle after we successfully inserted the new entry
1738 pNewCtxEntry.SuppressRelease();
1739 ohNewHandle.SuppressRelease();
1746 // release the old CtxEntry and update the entry
1747 CtxEntry *pTemp = pNewCtxEntry.Extract();
1748 pNewCtxEntry = pEntry->m_pCtxEntry;
1749 pEntry->m_pCtxEntry = pTemp;
1751 IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
1752 mgr->StoreObjectInHandle(pEntry->m_ohFactoryObject, OBJECTREFToObject(*refFactory));
1756 OBJECTREF AppDomain::LookupWinRTFactoryObject(MethodTable *pClassMT, LPVOID lpCtxCookie)
1763 PRECONDITION(CheckPointer(pClassMT));
1764 PRECONDITION(CheckPointer(m_pWinRTFactoryCache, NULL_OK));
1769 if (m_pWinRTFactoryCache == nullptr)
1773 // Retrieve cached factory
1775 WinRTFactoryCacheLockHolder lh(this);
1777 const WinRTFactoryCacheEntry *pEntry = m_pWinRTFactoryCache->LookupPtr(pClassMT);
1782 // Ignore factories from a different context, unless lpCtxCookie == NULL,
1783 // which means the factory is free-threaded
1784 // Note that we cannot touch the RCW to retrieve cookie at this point
1785 // because the RCW might belong to a STA thread and that STA thread might die
1786 // and take the RCW with it. Therefore we have to save cookie in this cache
1788 if (pEntry->m_pCtxEntry == NULL || pEntry->m_pCtxEntry->GetCtxCookie() == lpCtxCookie)
1789 return ObjectFromHandle(pEntry->m_ohFactoryObject);
1794 void AppDomain::RemoveWinRTFactoryObjects(LPVOID pCtxCookie)
1804 if (m_pWinRTFactoryCache == nullptr)
1807 // helper class for delayed CtxEntry cleanup
1808 class CtxEntryListReleaseHolder
1811 CQuickArrayList<CtxEntry *> m_list;
1813 ~CtxEntryListReleaseHolder()
1823 for (SIZE_T i = 0; i < m_list.Size(); i++)
1825 m_list[i]->Release();
1828 } ctxEntryListReleaseHolder;
1832 WinRTFactoryCacheLockHolder lh(this);
1834 // Go through the hash table and remove items in the given context
1835 for (WinRTFactoryCache::Iterator it = m_pWinRTFactoryCache->Begin(); it != m_pWinRTFactoryCache->End(); it++)
1837 if (it->m_pCtxEntry != NULL && it->m_pCtxEntry->GetCtxCookie() == pCtxCookie)
1839 // Releasing the CtxEntry may trigger GC which we can't do under the lock so we push
1840 // it on our local list and release them all after we're done iterating the hashtable.
1841 ctxEntryListReleaseHolder.m_list.Push(it->m_pCtxEntry);
1843 DestroyHandle(it->m_ohFactoryObject);
1844 m_pWinRTFactoryCache->Remove(it);
1850 OBJECTREF AppDomain::GetMissingObject()
1863 FieldDesc *pValueFD = MscorlibBinder::GetField(FIELD__MISSING__VALUE);
1865 pValueFD->CheckRunClassInitThrowing();
1867 // Retrieve the value static field and store it.
1868 OBJECTHANDLE hndMissing = CreateHandle(pValueFD->GetStaticOBJECTREF());
1870 if (FastInterlockCompareExchangePointer(&m_hndMissing, hndMissing, NULL) != NULL)
1872 // Exchanged failed. The m_hndMissing did not equal NULL and was returned.
1873 DestroyHandle(hndMissing);
1877 return ObjectFromHandle(m_hndMissing);
1880 #endif // DACCESS_COMPILE
1881 #endif //CROSSGEN_COMPILE
1882 #endif // FEATURE_COMINTEROP
1884 #ifndef DACCESS_COMPILE
1886 EEMarshalingData *BaseDomain::GetMarshalingData()
1888 CONTRACT (EEMarshalingData*)
1893 INJECT_FAULT(COMPlusThrowOM());
1894 POSTCONDITION(CheckPointer(m_pMarshalingData));
1898 if (!m_pMarshalingData)
1901 CrstHolder holder(&m_InteropDataCrst);
1903 if (!m_pMarshalingData)
1905 LoaderHeap* pHeap = GetLoaderAllocator()->GetLowFrequencyHeap();
1906 m_pMarshalingData = new (pHeap) EEMarshalingData(this, pHeap, &m_DomainCrst);
1910 RETURN m_pMarshalingData;
1913 void BaseDomain::DeleteMarshalingData()
1923 // We are in shutdown - no need to take any lock
1924 if (m_pMarshalingData)
1926 delete m_pMarshalingData;
1927 m_pMarshalingData = NULL;
1931 #ifndef CROSSGEN_COMPILE
1933 STRINGREF *BaseDomain::IsStringInterned(STRINGREF *pString)
1940 PRECONDITION(CheckPointer(pString));
1941 INJECT_FAULT(COMPlusThrowOM(););
1945 return GetLoaderAllocator()->IsStringInterned(pString);
1948 STRINGREF *BaseDomain::GetOrInternString(STRINGREF *pString)
1955 PRECONDITION(CheckPointer(pString));
1956 INJECT_FAULT(COMPlusThrowOM(););
1960 return GetLoaderAllocator()->GetOrInternString(pString);
1963 void BaseDomain::InitLargeHeapHandleTable()
1970 PRECONDITION(m_pLargeHeapHandleTable==NULL);
1971 INJECT_FAULT(COMPlusThrowOM(););
1975 m_pLargeHeapHandleTable = new LargeHeapHandleTable(this, STATIC_OBJECT_TABLE_BUCKET_SIZE);
1978 m_pLargeHeapHandleTable->RegisterCrstDebug(&m_LargeHeapHandleTableCrst);
1982 #ifdef FEATURE_COMINTEROP
1983 MethodTable* AppDomain::GetLicenseInteropHelperMethodTable()
1992 if(m_pLicenseInteropHelperMT == NULL)
1994 // Do this work outside of the lock so we don't have an unbreakable lock condition
1996 TypeHandle licenseMgrTypeHnd;
1997 MethodDescCallSite loadLM(METHOD__MARSHAL__LOAD_LICENSE_MANAGER);
1999 licenseMgrTypeHnd = (MethodTable*) loadLM.Call_RetLPVOID((ARG_SLOT*)NULL);
2002 // Look up this method by name, because the type is actually declared in System.dll. <TODO>@todo: why?</TODO>
2005 MethodDesc *pGetLIHMD = MemberLoader::FindMethod(licenseMgrTypeHnd.AsMethodTable(),
2006 "GetLicenseInteropHelperType", &gsig_SM_Void_RetIntPtr);
2007 _ASSERTE(pGetLIHMD);
2009 TypeHandle lihTypeHnd;
2011 MethodDescCallSite getLIH(pGetLIHMD);
2012 lihTypeHnd = (MethodTable*) getLIH.Call_RetLPVOID((ARG_SLOT*)NULL);
2014 BaseDomain::LockHolder lh(this);
2016 if(m_pLicenseInteropHelperMT == NULL)
2017 m_pLicenseInteropHelperMT = lihTypeHnd.AsMethodTable();
2019 return m_pLicenseInteropHelperMT;
2022 COMorRemotingFlag AppDomain::GetComOrRemotingFlag()
2032 // 0. check if the value is already been set
2033 if (m_COMorRemotingFlag != COMorRemoting_NotInitialized)
2034 return m_COMorRemotingFlag;
2036 // 1. check whether the process is AppX
2037 if (AppX::IsAppXProcess())
2039 // do not use Remoting in AppX
2040 m_COMorRemotingFlag = COMorRemoting_COM;
2041 return m_COMorRemotingFlag;
2044 // 2. check the xml file
2045 m_COMorRemotingFlag = GetPreferComInsteadOfManagedRemotingFromConfigFile();
2046 if (m_COMorRemotingFlag != COMorRemoting_NotInitialized)
2048 return m_COMorRemotingFlag;
2051 // 3. check the global setting
2052 if (NULL != g_pConfig && g_pConfig->ComInsteadOfManagedRemoting())
2054 m_COMorRemotingFlag = COMorRemoting_COM;
2058 m_COMorRemotingFlag = COMorRemoting_Remoting;
2061 return m_COMorRemotingFlag;
2064 BOOL AppDomain::GetPreferComInsteadOfManagedRemoting()
2066 WRAPPER_NO_CONTRACT;
2068 return (GetComOrRemotingFlag() == COMorRemoting_COM);
2071 STDAPI GetXMLObjectEx(IXMLParser **ppv);
2073 COMorRemotingFlag AppDomain::GetPreferComInsteadOfManagedRemotingFromConfigFile()
2083 return COMorRemoting_COM;
2085 #endif // FEATURE_COMINTEROP
2087 #endif // CROSSGEN_COMPILE
2089 //*****************************************************************************
2090 //*****************************************************************************
2091 //*****************************************************************************
2093 void *SystemDomain::operator new(size_t size, void *pInPlace)
2095 LIMITED_METHOD_CONTRACT;
2100 void SystemDomain::operator delete(void *pMem)
2102 LIMITED_METHOD_CONTRACT;
2103 // Do nothing - new() was in-place
2107 void SystemDomain::SetCompilationOverrides(BOOL fForceDebug,
2108 BOOL fForceProfiling,
2109 BOOL fForceInstrument)
2111 LIMITED_METHOD_CONTRACT;
2112 s_fForceDebug = fForceDebug;
2113 s_fForceProfiling = fForceProfiling;
2114 s_fForceInstrument = fForceInstrument;
2117 #endif //!DACCESS_COMPILE
2119 void SystemDomain::GetCompilationOverrides(BOOL * fForceDebug,
2120 BOOL * fForceProfiling,
2121 BOOL * fForceInstrument)
2123 LIMITED_METHOD_DAC_CONTRACT;
2124 *fForceDebug = s_fForceDebug;
2125 *fForceProfiling = s_fForceProfiling;
2126 *fForceInstrument = s_fForceInstrument;
2129 #ifndef DACCESS_COMPILE
2131 void SystemDomain::Attach()
2138 PRECONDITION(m_pSystemDomain == NULL);
2139 INJECT_FAULT(COMPlusThrowOM(););
2143 #ifndef CROSSGEN_COMPILE
2144 // Initialize stub managers
2145 PrecodeStubManager::Init();
2146 DelegateInvokeStubManager::Init();
2147 JumpStubStubManager::Init();
2148 RangeSectionStubManager::Init();
2149 ILStubManager::Init();
2150 InteropDispatchStubManager::Init();
2151 StubLinkStubManager::Init();
2153 ThunkHeapStubManager::Init();
2155 TailCallStubManager::Init();
2157 PerAppDomainTPCountList::InitAppDomainIndexList();
2158 #endif // CROSSGEN_COMPILE
2160 m_appDomainIndexList.Init();
2161 m_appDomainIdList.Init();
2163 m_SystemDomainCrst.Init(CrstSystemDomain, (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN));
2164 m_DelayedUnloadCrst.Init(CrstSystemDomainDelayedUnloadList, CRST_UNSAFE_COOPGC);
2166 // Initialize the ID dispenser that is used for domain neutral module IDs
2167 g_pModuleIndexDispenser = new IdDispenser();
2169 // Create the global SystemDomain and initialize it.
2170 m_pSystemDomain = new (&g_pSystemDomainMemory[0]) SystemDomain();
2171 // No way it can fail since g_pSystemDomainMemory is a static array.
2172 CONSISTENCY_CHECK(CheckPointer(m_pSystemDomain));
2174 LOG((LF_CLASSLOADER,
2176 "Created system domain at %p\n",
2179 // We need to initialize the memory pools etc. for the system domain.
2180 m_pSystemDomain->BaseDomain::Init(); // Setup the memory heaps
2182 // Create the default domain
2183 m_pSystemDomain->CreateDefaultDomain();
2184 SharedDomain::Attach();
2186 // Each domain gets its own ReJitManager, and ReJitManager has its own static
2187 // initialization to run
2188 ReJitManager::InitStatic();
2191 #ifndef CROSSGEN_COMPILE
2193 void SystemDomain::DetachBegin()
2195 WRAPPER_NO_CONTRACT;
2196 // Shut down the domain and its children (but don't deallocate anything just
2199 // TODO: we should really not running managed DLLMain during process detach.
2200 if (GetThread() == NULL)
2206 m_pSystemDomain->Stop();
2209 void SystemDomain::DetachEnd()
2218 // Shut down the domain and its children (but don't deallocate anything just
2223 m_pSystemDomain->ClearFusionContext();
2224 if (m_pSystemDomain->m_pDefaultDomain)
2225 m_pSystemDomain->m_pDefaultDomain->ClearFusionContext();
2229 void SystemDomain::Stop()
2231 WRAPPER_NO_CONTRACT;
2232 AppDomainIterator i(TRUE);
2235 if (i.GetDomain()->m_Stage < AppDomain::STAGE_CLEARED)
2236 i.GetDomain()->Stop();
2240 void SystemDomain::Terminate() // bNotifyProfiler is ignored
2250 // This ignores the refences and terminates the appdomains
2251 AppDomainIterator i(FALSE);
2255 delete i.GetDomain();
2256 // Keep the iterator from Releasing the current domain
2257 i.m_pCurrent = NULL;
2260 if (m_pSystemFile != NULL) {
2261 m_pSystemFile->Release();
2262 m_pSystemFile = NULL;
2265 m_pSystemAssembly = NULL;
2268 delete[] m_pwDevpath;
2274 if (m_pGlobalStringLiteralMap) {
2275 delete m_pGlobalStringLiteralMap;
2276 m_pGlobalStringLiteralMap = NULL;
2280 SharedDomain::Detach();
2282 BaseDomain::Terminate();
2284 #ifdef FEATURE_COMINTEROP
2285 if (g_pRCWCleanupList != NULL)
2286 delete g_pRCWCleanupList;
2287 #endif // FEATURE_COMINTEROP
2288 m_GlobalAllocator.Terminate();
2292 void SystemDomain::PreallocateSpecialObjects()
2299 INJECT_FAULT(COMPlusThrowOM(););
2303 _ASSERTE(g_pPreallocatedSentinelObject == NULL);
2305 OBJECTREF pPreallocatedSentinalObject = AllocateObject(g_pObjectClass);
2306 #if CHECK_APP_DOMAIN_LEAKS
2307 pPreallocatedSentinalObject->SetSyncBlockAppDomainAgile();
2309 g_pPreallocatedSentinelObject = CreatePinningHandle( pPreallocatedSentinalObject );
2311 #ifdef FEATURE_PREJIT
2312 if (SystemModule()->HasNativeImage())
2314 CORCOMPILE_EE_INFO_TABLE *pEEInfo = SystemModule()->GetNativeImage()->GetNativeEEInfoTable();
2315 pEEInfo->emptyString = (CORINFO_Object **)StringObject::GetEmptyStringRefPtr();
2320 void SystemDomain::CreatePreallocatedExceptions()
2327 INJECT_FAULT(COMPlusThrowOM(););
2331 EXCEPTIONREF pBaseException = (EXCEPTIONREF)AllocateObject(g_pExceptionClass);
2332 pBaseException->SetHResult(COR_E_EXCEPTION);
2333 pBaseException->SetXCode(EXCEPTION_COMPLUS);
2334 _ASSERTE(g_pPreallocatedBaseException == NULL);
2335 g_pPreallocatedBaseException = CreateHandle(pBaseException);
2338 EXCEPTIONREF pOutOfMemory = (EXCEPTIONREF)AllocateObject(g_pOutOfMemoryExceptionClass);
2339 pOutOfMemory->SetHResult(COR_E_OUTOFMEMORY);
2340 pOutOfMemory->SetXCode(EXCEPTION_COMPLUS);
2341 _ASSERTE(g_pPreallocatedOutOfMemoryException == NULL);
2342 g_pPreallocatedOutOfMemoryException = CreateHandle(pOutOfMemory);
2345 EXCEPTIONREF pStackOverflow = (EXCEPTIONREF)AllocateObject(g_pStackOverflowExceptionClass);
2346 pStackOverflow->SetHResult(COR_E_STACKOVERFLOW);
2347 pStackOverflow->SetXCode(EXCEPTION_COMPLUS);
2348 _ASSERTE(g_pPreallocatedStackOverflowException == NULL);
2349 g_pPreallocatedStackOverflowException = CreateHandle(pStackOverflow);
2352 EXCEPTIONREF pExecutionEngine = (EXCEPTIONREF)AllocateObject(g_pExecutionEngineExceptionClass);
2353 pExecutionEngine->SetHResult(COR_E_EXECUTIONENGINE);
2354 pExecutionEngine->SetXCode(EXCEPTION_COMPLUS);
2355 _ASSERTE(g_pPreallocatedExecutionEngineException == NULL);
2356 g_pPreallocatedExecutionEngineException = CreateHandle(pExecutionEngine);
2359 EXCEPTIONREF pRudeAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2360 #if CHECK_APP_DOMAIN_LEAKS
2361 pRudeAbortException->SetSyncBlockAppDomainAgile();
2363 pRudeAbortException->SetHResult(COR_E_THREADABORTED);
2364 pRudeAbortException->SetXCode(EXCEPTION_COMPLUS);
2365 _ASSERTE(g_pPreallocatedRudeThreadAbortException == NULL);
2366 g_pPreallocatedRudeThreadAbortException = CreateHandle(pRudeAbortException);
2369 EXCEPTIONREF pAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2370 #if CHECK_APP_DOMAIN_LEAKS
2371 pAbortException->SetSyncBlockAppDomainAgile();
2373 pAbortException->SetHResult(COR_E_THREADABORTED);
2374 pAbortException->SetXCode(EXCEPTION_COMPLUS);
2375 _ASSERTE(g_pPreallocatedThreadAbortException == NULL);
2376 g_pPreallocatedThreadAbortException = CreateHandle( pAbortException );
2378 #endif // CROSSGEN_COMPILE
2380 void SystemDomain::Init()
2382 STANDARD_VM_CONTRACT;
2390 "sizeof(EEClass) = %d\n"
2391 "sizeof(MethodTable) = %d\n"
2392 "sizeof(MethodDesc)= %d\n"
2393 "sizeof(FieldDesc) = %d\n"
2394 "sizeof(Module) = %d\n",
2396 sizeof(MethodTable),
2403 // The base domain is initialized in SystemDomain::Attach()
2404 // to allow stub caches to use the memory pool. Do not
2405 // initialze it here!
2407 #ifndef CROSSGEN_COMPILE
2409 Context *curCtx = GetCurrentContext();
2412 _ASSERTE(curCtx->GetDomain() != NULL);
2416 g_fVerifierOff = g_pConfig->IsVerifierOff();
2419 #ifdef FEATURE_PREJIT
2420 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapDisable) != 0)
2421 g_fAllowNativeImages = false;
2424 m_pSystemFile = NULL;
2425 m_pSystemAssembly = NULL;
2430 // Get the install directory so we can find mscorlib
2431 hr = GetInternalSystemDirectory(NULL, &size);
2432 if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
2435 // GetInternalSystemDirectory returns a size, including the null!
2436 WCHAR *buffer = m_SystemDirectory.OpenUnicodeBuffer(size-1);
2437 IfFailThrow(GetInternalSystemDirectory(buffer, &size));
2438 m_SystemDirectory.CloseBuffer();
2439 m_SystemDirectory.Normalize();
2441 // At this point m_SystemDirectory should already be canonicalized
2444 m_BaseLibrary.Append(m_SystemDirectory);
2445 if (!m_BaseLibrary.EndsWith(DIRECTORY_SEPARATOR_CHAR_W))
2447 m_BaseLibrary.Append(DIRECTORY_SEPARATOR_CHAR_W);
2449 m_BaseLibrary.Append(g_pwBaseLibrary);
2450 m_BaseLibrary.Normalize();
2452 LoadBaseSystemClasses();
2455 // We are about to start allocating objects, so we must be in cooperative mode.
2456 // However, many of the entrypoints to the system (DllGetClassObject and all
2457 // N/Direct exports) get called multiple times. Sometimes they initialize the EE,
2458 // but generally they remain in preemptive mode. So we really want to push/pop
2462 #ifndef CROSSGEN_COMPILE
2463 if (!NingenEnabled())
2465 CreatePreallocatedExceptions();
2467 PreallocateSpecialObjects();
2471 // Finish loading mscorlib now.
2472 m_pSystemAssembly->GetDomainAssembly()->EnsureActive();
2476 BOOL fPause = EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_PauseOnLoad, FALSE);
2480 ClrSleepEx(20, TRUE);
2485 #ifndef CROSSGEN_COMPILE
2486 void SystemDomain::LazyInitGlobalStringLiteralMap()
2493 INJECT_FAULT(COMPlusThrowOM(););
2497 // Allocate the global string literal map.
2498 NewHolder<GlobalStringLiteralMap> pGlobalStringLiteralMap(new GlobalStringLiteralMap());
2500 // Initialize the global string literal map.
2501 pGlobalStringLiteralMap->Init();
2503 if (InterlockedCompareExchangeT<GlobalStringLiteralMap *>(&m_pGlobalStringLiteralMap, pGlobalStringLiteralMap, NULL) == NULL)
2505 pGlobalStringLiteralMap.SuppressRelease();
2509 void AppDomain::CreateADUnloadStartEvent()
2520 g_pUnloadStartEvent = new CLREvent();
2521 g_pUnloadStartEvent->CreateAutoEvent(FALSE);
2524 /*static*/ void SystemDomain::EnumAllStaticGCRefs(promote_func* fn, ScanContext* sc)
2534 // We don't do a normal AppDomainIterator because we can't take the SystemDomain lock from
2536 // We're only supposed to call this from a Server GC. We're walking here m_appDomainIdList
2537 // m_appDomainIdList will have an AppDomain* or will be NULL. So the only danger is if we
2538 // Fetch an AppDomain and then in some other thread the AppDomain is deleted.
2540 // If the thread deleting the AppDomain (AppDomain::~AppDomain)was in Preemptive mode
2541 // while doing SystemDomain::EnumAllStaticGCRefs we will issue a GCX_COOP(), which will wait
2542 // for the GC to finish, so we are safe
2544 // If the thread is in cooperative mode, it must have been suspended for the GC so a delete
2547 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
2548 GCHeapUtilities::IsServerHeap() &&
2549 IsGCSpecialThread());
2551 SystemDomain* sysDomain = SystemDomain::System();
2555 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2556 for (i = 0 ; i < count ; i++)
2558 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2559 if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
2561 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2564 sc->pCurrentDomain = pAppDomain;
2566 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2567 pAppDomain->EnumStaticGCRefs(fn, sc);
2575 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2576 void SystemDomain::ResetADSurvivedBytes()
2586 _ASSERTE(GCHeapUtilities::IsGCInProgress());
2588 SystemDomain* sysDomain = SystemDomain::System();
2592 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2593 for (i = 0 ; i < count ; i++)
2595 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2596 if (pAppDomain && pAppDomain->IsUserActive())
2598 pAppDomain->ResetSurvivedBytes();
2606 ULONGLONG SystemDomain::GetADSurvivedBytes()
2616 SystemDomain* sysDomain = SystemDomain::System();
2617 ULONGLONG ullTotalADSurvived = 0;
2621 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2622 for (i = 0 ; i < count ; i++)
2624 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2625 if (pAppDomain && pAppDomain->IsUserActive())
2627 ULONGLONG ullSurvived = pAppDomain->GetSurvivedBytes();
2628 ullTotalADSurvived += ullSurvived;
2633 return ullTotalADSurvived;
2636 void SystemDomain::RecordTotalSurvivedBytes(size_t totalSurvivedBytes)
2646 m_totalSurvivedBytes = totalSurvivedBytes;
2648 SystemDomain* sysDomain = SystemDomain::System();
2652 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2653 for (i = 0 ; i < count ; i++)
2655 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2656 if (pAppDomain && pAppDomain->IsUserActive())
2658 FireEtwAppDomainMemSurvived((ULONGLONG)pAppDomain, pAppDomain->GetSurvivedBytes(), totalSurvivedBytes, GetClrInstanceId());
2665 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2667 // Only called when EE is suspended.
2668 DWORD SystemDomain::GetTotalNumSizedRefHandles()
2678 SystemDomain* sysDomain = SystemDomain::System();
2679 DWORD dwTotalNumSizedRefHandles = 0;
2683 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2684 for (i = 0 ; i < count ; i++)
2686 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2687 if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
2689 dwTotalNumSizedRefHandles += pAppDomain->GetNumSizedRefHandles();
2694 return dwTotalNumSizedRefHandles;
2696 #endif // CROSSGEN_COMPILE
2698 void SystemDomain::LoadBaseSystemClasses()
2700 STANDARD_VM_CONTRACT;
2702 ETWOnStartup(LdSysBases_V1, LdSysBasesEnd_V1);
2705 m_pSystemFile = PEAssembly::OpenSystem(NULL);
2707 // Only partially load the system assembly. Other parts of the code will want to access
2708 // the globals in this function before finishing the load.
2709 m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemFile, FILE_LOAD_POST_LOADLIBRARY)->GetCurrentAssembly();
2711 // Set up binder for mscorlib
2712 MscorlibBinder::AttachModule(m_pSystemAssembly->GetManifestModule());
2715 g_pObjectClass = MscorlibBinder::GetClass(CLASS__OBJECT);
2717 // Now that ObjectClass is loaded, we can set up
2718 // the system for finalizers. There is no point in deferring this, since we need
2719 // to know this before we allocate our first object.
2720 g_pObjectFinalizerMD = MscorlibBinder::GetMethod(METHOD__OBJECT__FINALIZE);
2723 g_pCanonMethodTableClass = MscorlibBinder::GetClass(CLASS____CANON);
2725 // NOTE: !!!IMPORTANT!!! ValueType and Enum MUST be loaded one immediately after
2726 // the other, because we have coded MethodTable::IsChildValueType
2727 // in such a way that it depends on this behaviour.
2728 // Load the ValueType class
2729 g_pValueTypeClass = MscorlibBinder::GetClass(CLASS__VALUE_TYPE);
2731 // Load the enum class
2732 g_pEnumClass = MscorlibBinder::GetClass(CLASS__ENUM);
2733 _ASSERTE(!g_pEnumClass->IsValueType());
2735 // Load System.RuntimeType
2736 g_pRuntimeTypeClass = MscorlibBinder::GetClass(CLASS__CLASS);
2737 _ASSERTE(g_pRuntimeTypeClass->IsFullyLoaded());
2740 g_pArrayClass = MscorlibBinder::GetClass(CLASS__ARRAY);
2742 // Calling a method on IList<T> for an array requires redirection to a method on
2743 // the SZArrayHelper class. Retrieving such methods means calling
2744 // GetActualImplementationForArrayGenericIListMethod, which calls FetchMethod for
2745 // the corresponding method on SZArrayHelper. This basically results in a class
2746 // load due to a method call, which the debugger cannot handle, so we pre-load
2747 // the SZArrayHelper class here.
2748 g_pSZArrayHelperClass = MscorlibBinder::GetClass(CLASS__SZARRAYHELPER);
2750 // Load ByReference class
2752 // NOTE: ByReference<T> must be the first by-ref-like system type to be loaded,
2753 // because MethodTable::ClassifyEightBytesWithManagedLayout depends on it.
2754 g_pByReferenceClass = MscorlibBinder::GetClass(CLASS__BYREFERENCE);
2756 // Load Nullable class
2757 g_pNullableClass = MscorlibBinder::GetClass(CLASS__NULLABLE);
2759 // Load the Object array class.
2760 g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pObjectClass)).AsArray();
2762 // We have delayed allocation of mscorlib's static handles until we load the object class
2763 MscorlibBinder::GetModule()->AllocateRegularStaticHandles(DefaultDomain());
2765 g_TypedReferenceMT = MscorlibBinder::GetClass(CLASS__TYPED_REFERENCE);
2767 // Make sure all primitive types are loaded
2768 for (int et = ELEMENT_TYPE_VOID; et <= ELEMENT_TYPE_R8; et++)
2769 MscorlibBinder::LoadPrimitiveType((CorElementType)et);
2771 MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_I);
2772 MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_U);
2774 // unfortunately, the following cannot be delay loaded since the jit
2775 // uses it to compute method attributes within a function that cannot
2776 // handle Complus exception and the following call goes through a path
2777 // where a complus exception can be thrown. It is unfortunate, because
2778 // we know that the delegate class and multidelegate class are always
2779 // guaranteed to be found.
2780 g_pDelegateClass = MscorlibBinder::GetClass(CLASS__DELEGATE);
2781 g_pMulticastDelegateClass = MscorlibBinder::GetClass(CLASS__MULTICAST_DELEGATE);
2783 // used by IsImplicitInterfaceOfSZArray
2784 MscorlibBinder::GetClass(CLASS__IENUMERABLEGENERIC);
2785 MscorlibBinder::GetClass(CLASS__ICOLLECTIONGENERIC);
2786 MscorlibBinder::GetClass(CLASS__ILISTGENERIC);
2787 MscorlibBinder::GetClass(CLASS__IREADONLYCOLLECTIONGENERIC);
2788 MscorlibBinder::GetClass(CLASS__IREADONLYLISTGENERIC);
2791 g_pStringClass = MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_STRING);
2792 _ASSERTE(g_pStringClass->GetBaseSize() == ObjSizeOf(StringObject)+sizeof(WCHAR));
2793 _ASSERTE(g_pStringClass->GetComponentSize() == 2);
2795 // Used by Buffer::BlockCopy
2796 g_pByteArrayMT = ClassLoader::LoadArrayTypeThrowing(
2797 TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1))).AsArray()->GetMethodTable();
2799 #ifndef CROSSGEN_COMPILE
2800 ECall::PopulateManagedStringConstructors();
2801 #endif // CROSSGEN_COMPILE
2803 g_pExceptionClass = MscorlibBinder::GetClass(CLASS__EXCEPTION);
2804 g_pOutOfMemoryExceptionClass = MscorlibBinder::GetException(kOutOfMemoryException);
2805 g_pStackOverflowExceptionClass = MscorlibBinder::GetException(kStackOverflowException);
2806 g_pExecutionEngineExceptionClass = MscorlibBinder::GetException(kExecutionEngineException);
2807 g_pThreadAbortExceptionClass = MscorlibBinder::GetException(kThreadAbortException);
2810 // used by gc to handle predefined agility checking
2811 g_pThreadClass = MscorlibBinder::GetClass(CLASS__THREAD);
2813 #ifdef FEATURE_COMINTEROP
2814 g_pBaseCOMObject = MscorlibBinder::GetClass(CLASS__COM_OBJECT);
2815 g_pBaseRuntimeClass = MscorlibBinder::GetClass(CLASS__RUNTIME_CLASS);
2817 MscorlibBinder::GetClass(CLASS__IDICTIONARYGENERIC);
2818 MscorlibBinder::GetClass(CLASS__IREADONLYDICTIONARYGENERIC);
2819 MscorlibBinder::GetClass(CLASS__ATTRIBUTE);
2820 MscorlibBinder::GetClass(CLASS__EVENT_HANDLERGENERIC);
2822 MscorlibBinder::GetClass(CLASS__IENUMERABLE);
2823 MscorlibBinder::GetClass(CLASS__ICOLLECTION);
2824 MscorlibBinder::GetClass(CLASS__ILIST);
2825 MscorlibBinder::GetClass(CLASS__IDISPOSABLE);
2828 WinRTInterfaceRedirector::VerifyRedirectedInterfaceStubs();
2832 #ifdef FEATURE_ICASTABLE
2833 g_pICastableInterface = MscorlibBinder::GetClass(CLASS__ICASTABLE);
2834 #endif // FEATURE_ICASTABLE
2836 // Load a special marker method used to detect Constrained Execution Regions
2838 g_pExecuteBackoutCodeHelperMethod = MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__EXECUTE_BACKOUT_CODE_HELPER);
2840 // Make sure that FCall mapping for Monitor.Enter is initialized. We need it in case Monitor.Enter is used only as JIT helper.
2841 // For more details, see comment in code:JITutil_MonEnterWorker around "__me = GetEEFuncEntryPointMacro(JIT_MonEnter)".
2842 ECall::GetFCallImpl(MscorlibBinder::GetMethod(METHOD__MONITOR__ENTER));
2844 #ifdef PROFILING_SUPPORTED
2845 // Note that g_profControlBlock.fBaseSystemClassesLoaded must be set to TRUE only after
2846 // all base system classes are loaded. Profilers are not allowed to call any type-loading
2847 // APIs until g_profControlBlock.fBaseSystemClassesLoaded is TRUE. It is important that
2848 // all base system classes need to be loaded before profilers can trigger the type loading.
2849 g_profControlBlock.fBaseSystemClassesLoaded = TRUE;
2850 #endif // PROFILING_SUPPORTED
2852 #if defined(_DEBUG) && !defined(CROSSGEN_COMPILE)
2853 if (!NingenEnabled())
2859 #if defined(HAVE_GCCOVER) && defined(FEATURE_PREJIT)
2860 if (GCStress<cfg_instr_ngen>::IsEnabled())
2862 // Setting up gc coverage requires the base system classes
2863 // to be initialized. So we have deferred it until now for mscorlib.
2864 Module *pModule = MscorlibBinder::GetModule();
2865 _ASSERTE(pModule->IsSystem());
2866 if(pModule->HasNativeImage())
2868 SetupGcCoverageForNativeImage(pModule);
2871 #endif // defined(HAVE_GCCOVER) && !defined(FEATURE_PREJIT)
2875 void SystemDomain::LoadDomain(AppDomain *pDomain)
2882 PRECONDITION(CheckPointer(System()));
2883 INJECT_FAULT(COMPlusThrowOM(););
2887 pDomain->SetCanUnload(); // by default can unload any domain
2888 SystemDomain::System()->AddDomain(pDomain);
2891 ADIndex SystemDomain::GetNewAppDomainIndex(AppDomain *pAppDomain)
2893 STANDARD_VM_CONTRACT;
2895 DWORD count = m_appDomainIndexList.GetCount();
2901 // So that we can keep AD index inside object header.
2902 // We do not want to create syncblock unless needed.
2909 // Look for an unused index. Note that in a checked build,
2910 // we never reuse indexes - this makes it easier to tell
2911 // when we are looking at a stale app domain.
2914 i = m_appDomainIndexList.FindElement(m_dwLowestFreeIndex, NULL);
2915 if (i == (DWORD) ArrayList::NOT_FOUND)
2917 m_dwLowestFreeIndex = i+1;
2919 if (m_dwLowestFreeIndex >= 2000)
2921 m_dwLowestFreeIndex = 0;
2927 IfFailThrow(m_appDomainIndexList.Append(pAppDomain));
2929 m_appDomainIndexList.Set(i, pAppDomain);
2931 _ASSERTE(i < m_appDomainIndexList.GetCount());
2933 // Note that index 0 means domain agile.
2934 return ADIndex(i+1);
2937 void SystemDomain::ReleaseAppDomainIndex(ADIndex index)
2939 WRAPPER_NO_CONTRACT;
2940 SystemDomain::LockHolder lh;
2941 // Note that index 0 means domain agile.
2944 _ASSERTE(m_appDomainIndexList.Get(index.m_dwIndex) != NULL);
2946 m_appDomainIndexList.Set(index.m_dwIndex, NULL);
2949 if (index.m_dwIndex < m_dwLowestFreeIndex)
2950 m_dwLowestFreeIndex = index.m_dwIndex;
2954 #endif // !DACCESS_COMPILE
2956 PTR_AppDomain SystemDomain::GetAppDomainAtIndex(ADIndex index)
2958 LIMITED_METHOD_CONTRACT;
2960 _ASSERTE(index.m_dwIndex != 0);
2962 PTR_AppDomain pAppDomain = TestGetAppDomainAtIndex(index);
2964 _ASSERTE(pAppDomain || !"Attempt to access unloaded app domain");
2969 PTR_AppDomain SystemDomain::TestGetAppDomainAtIndex(ADIndex index)
2971 LIMITED_METHOD_CONTRACT;
2973 _ASSERTE(index.m_dwIndex != 0);
2976 #ifndef DACCESS_COMPILE
2977 _ASSERTE(index.m_dwIndex < (DWORD)m_appDomainIndexList.GetCount());
2978 AppDomain *pAppDomain = (AppDomain*) m_appDomainIndexList.Get(index.m_dwIndex);
2979 #else // DACCESS_COMPILE
2980 PTR_ArrayListStatic pList = &m_appDomainIndexList;
2981 AppDomain *pAppDomain = dac_cast<PTR_AppDomain>(pList->Get(index.m_dwIndex));
2982 #endif // DACCESS_COMPILE
2983 return PTR_AppDomain(pAppDomain);
2986 #ifndef DACCESS_COMPILE
2988 // See also code:SystemDomain::ReleaseAppDomainId
2989 ADID SystemDomain::GetNewAppDomainId(AppDomain *pAppDomain)
2996 INJECT_FAULT(COMPlusThrowOM(););
3000 DWORD i = m_appDomainIdList.GetCount();
3002 IfFailThrow(m_appDomainIdList.Append(pAppDomain));
3004 _ASSERTE(i < m_appDomainIdList.GetCount());
3009 AppDomain *SystemDomain::GetAppDomainAtId(ADID index)
3014 if (!SystemDomain::IsUnderDomainLock() && !IsGCThread()) { MODE_COOPERATIVE;} else { DISABLED(MODE_ANY);}
3022 if(index.m_dwId == 0)
3024 DWORD requestedID = index.m_dwId - 1;
3026 if(requestedID >= (DWORD)m_appDomainIdList.GetCount())
3029 AppDomain * result = (AppDomain *)m_appDomainIdList.Get(requestedID);
3031 #ifndef CROSSGEN_COMPILE
3032 if(result==NULL && GetThread() == FinalizerThread::GetFinalizerThread() &&
3033 SystemDomain::System()->AppDomainBeingUnloaded()!=NULL &&
3034 SystemDomain::System()->AppDomainBeingUnloaded()->GetId()==index)
3035 result=SystemDomain::System()->AppDomainBeingUnloaded();
3036 // If the current thread can't enter the AppDomain, then don't return it.
3037 if (!result || !result->CanThreadEnter(GetThread()))
3039 #endif // CROSSGEN_COMPILE
3044 // Releases an appdomain index. Note that today we have code that depends on these
3045 // indexes not being recycled, so we don't actually shrink m_appDomainIdList, but
3046 // simply zero out an entry. THus we 'leak' the memory associated the slot in
3047 // m_appDomainIdList.
3049 // TODO make this a sparse structure so that we avoid that leak.
3051 void SystemDomain::ReleaseAppDomainId(ADID index)
3053 LIMITED_METHOD_CONTRACT;
3056 _ASSERTE(index.m_dwId < (DWORD)m_appDomainIdList.GetCount());
3058 m_appDomainIdList.Set(index.m_dwId, NULL);
3061 #if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3064 int g_fMainThreadApartmentStateSet = 0;
3067 Thread::ApartmentState SystemDomain::GetEntryPointThreadAptState(IMDInternalImport* pScope, mdMethodDef mdMethod)
3069 STANDARD_VM_CONTRACT;
3072 IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
3073 DEFAULTDOMAIN_MTA_TYPE,
3076 BOOL fIsMTA = FALSE;
3080 IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
3081 DEFAULTDOMAIN_STA_TYPE,
3084 BOOL fIsSTA = FALSE;
3088 if (fIsSTA && fIsMTA)
3089 COMPlusThrowHR(COR_E_CUSTOMATTRIBUTEFORMAT);
3092 return Thread::AS_InSTA;
3094 return Thread::AS_InMTA;
3096 return Thread::AS_Unknown;
3099 void SystemDomain::SetThreadAptState (IMDInternalImport* pScope, Thread::ApartmentState state)
3101 STANDARD_VM_CONTRACT;
3103 BOOL fIsLegacy = FALSE;
3105 // Check for legacy behavior regarding COM Apartment state of the main thread.
3107 #define METAMODEL_MAJOR_VER_WITH_NEW_BEHAVIOR 2
3108 #define METAMODEL_MINOR_VER_WITH_NEW_BEHAVIOR 0
3111 IfFailThrow(pScope->GetVersionString(&pVer));
3113 // Does this look like a version?
3116 // Is it 'vN.' where N is a digit?
3117 if ((pVer[0] == 'v' || pVer[0] == 'V') &&
3118 IS_DIGIT(pVer[1]) &&
3121 // Looks like a version. Is it lesser than v2.0 major version where we start using new behavior?
3122 fIsLegacy = DIGIT_TO_INT(pVer[1]) < METAMODEL_MAJOR_VER_WITH_NEW_BEHAVIOR;
3126 if (!fIsLegacy && g_pConfig != NULL)
3128 fIsLegacy = g_pConfig->LegacyApartmentInitPolicy();
3132 Thread* pThread = GetThread();
3135 if(state == Thread::AS_InSTA)
3137 Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InSTA, TRUE);
3138 _ASSERTE(pState == Thread::AS_InSTA);
3140 else if ((state == Thread::AS_InMTA) || (!fIsLegacy))
3142 // If either MTAThreadAttribute is specified or (if no attribute is specified and we are not
3143 // running in legacy mode), then
3144 // we will set the apartment state to MTA. The reason for this is to ensure the apartment
3145 // state is consistent and reliably set. Without this, the apartment state for the main
3146 // thread would be undefined and would actually be dependent on if the assembly was
3147 // ngen'd, which other type were loaded, etc.
3148 Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InMTA, TRUE);
3149 _ASSERTE(pState == Thread::AS_InMTA);
3153 g_fMainThreadApartmentStateSet++;
3156 #endif // defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3158 // Looks in all the modules for the DefaultDomain attribute
3159 // The order is assembly and then the modules. It is first
3160 // come, first serve.
3161 BOOL SystemDomain::SetGlobalSharePolicyUsingAttribute(IMDInternalImport* pScope, mdMethodDef mdMethod)
3163 STANDARD_VM_CONTRACT;
3169 void SystemDomain::SetupDefaultDomain()
3176 INJECT_FAULT(COMPlusThrowOM(););
3181 Thread *pThread = GetThread();
3185 pDomain = pThread->GetDomain();
3190 ENTER_DOMAIN_PTR(SystemDomain::System()->DefaultDomain(),ADV_DEFAULTAD)
3192 // Push this frame around loading the main assembly to ensure the
3193 // debugger can properly recgonize any managed code that gets run
3194 // as "class initializaion" code.
3195 FrameWithCookie<DebuggerClassInitMarkFrame> __dcimf;
3199 InitializeDefaultDomain(TRUE);
3204 END_DOMAIN_TRANSITION;
3209 HRESULT SystemDomain::SetupDefaultDomainNoThrow()
3222 SystemDomain::SetupDefaultDomain();
3224 EX_CATCH_HRESULT(hr);
3230 int g_fInitializingInitialAD = 0;
3233 // This routine completes the initialization of the default domaine.
3234 // After this call mananged code can be executed.
3235 void SystemDomain::InitializeDefaultDomain(
3236 BOOL allowRedirects,
3237 ICLRPrivBinder * pBinder)
3239 STANDARD_VM_CONTRACT;
3241 WCHAR* pwsConfig = NULL;
3242 WCHAR* pwsPath = NULL;
3244 ETWOnStartup (InitDefaultDomain_V1, InitDefaultDomainEnd_V1);
3247 // Setup the default AppDomain.
3250 g_fInitializingInitialAD++;
3253 AppDomain* pDefaultDomain = SystemDomain::System()->DefaultDomain();
3255 if (pBinder != nullptr)
3257 pDefaultDomain->SetLoadContextHostBinder(pBinder);
3263 pDefaultDomain->InitializeDomainContext(allowRedirects, pwsPath, pwsConfig);
3265 #ifndef CROSSGEN_COMPILE
3266 if (!NingenEnabled())
3269 if (!IsSingleAppDomain())
3271 pDefaultDomain->InitializeDefaultDomainManager();
3274 #endif // CROSSGEN_COMPILE
3277 // DefaultDomain Load event
3278 ETW::LoaderLog::DomainLoad(pDefaultDomain);
3281 g_fInitializingInitialAD--;
3284 TESTHOOKCALL(RuntimeStarted(RTS_DEFAULTADREADY));
3289 #ifndef CROSSGEN_COMPILE
3292 Volatile<LONG> g_fInExecuteMainMethod = 0;
3298 #endif // CROSSGEN_COMPILE
3302 // Helper function to load an assembly. This is called from LoadCOMClass.
3305 Assembly *AppDomain::LoadAssemblyHelper(LPCWSTR wszAssembly,
3306 LPCWSTR wszCodeBase)
3308 CONTRACT(Assembly *)
3311 POSTCONDITION(CheckPointer(RETVAL));
3312 PRECONDITION(wszAssembly || wszCodeBase);
3313 INJECT_FAULT(COMPlusThrowOM(););
3319 #define MAKE_TRANSLATIONFAILED { ThrowOutOfMemory(); }
3320 MAKE_UTF8PTR_FROMWIDE(szAssembly,wszAssembly);
3321 #undef MAKE_TRANSLATIONFAILED
3323 IfFailThrow(spec.Init(szAssembly));
3327 spec.SetCodeBase(wszCodeBase);
3329 RETURN spec.LoadAssembly(FILE_LOADED);
3332 #if defined(FEATURE_CLASSIC_COMINTEROP) && !defined(CROSSGEN_COMPILE)
3334 MethodTable *AppDomain::LoadCOMClass(GUID clsid,
3335 BOOL bLoadRecord/*=FALSE*/,
3336 BOOL* pfAssemblyInReg/*=NULL*/)
3338 // @CORESYSTODO: what to do here?
3342 #endif // FEATURE_CLASSIC_COMINTEROP && !CROSSGEN_COMPILE
3346 bool SystemDomain::IsReflectionInvocationMethod(MethodDesc* pMeth)
3356 MethodTable* pCaller = pMeth->GetMethodTable();
3358 // All Reflection Invocation methods are defined in mscorlib.dll
3359 if (!pCaller->GetModule()->IsSystem())
3362 /* List of types that should be skipped to identify true caller */
3363 static const BinderClassID reflectionInvocationTypes[] = {
3368 CLASS__CONSTRUCTOR_INFO,
3371 CLASS__METHOD_HANDLE,
3372 CLASS__FIELD_HANDLE,
3375 CLASS__RT_FIELD_INFO,
3380 CLASS__PROPERTY_INFO,
3383 CLASS__ASSEMBLYBASE,
3385 CLASS__TYPE_DELEGATOR,
3386 CLASS__RUNTIME_HELPERS,
3387 CLASS__LAZY_INITIALIZER,
3388 CLASS__DYNAMICMETHOD,
3390 CLASS__MULTICAST_DELEGATE,
3394 static const BinderClassID genericReflectionInvocationTypes[] = {
3398 static mdTypeDef genericReflectionInvocationTypeDefs[NumItems(genericReflectionInvocationTypes)];
3400 static bool fInited = false;
3402 if (!VolatileLoad(&fInited))
3404 // Make sure all types are loaded so that we can use faster GetExistingClass()
3405 for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3407 MscorlibBinder::GetClass(reflectionInvocationTypes[i]);
3410 // Make sure all types are loaded so that we can use faster GetExistingClass()
3411 for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypes); i++)
3413 genericReflectionInvocationTypeDefs[i] = MscorlibBinder::GetClass(genericReflectionInvocationTypes[i])->GetCl();
3416 MscorlibBinder::GetClass(CLASS__APP_DOMAIN);
3418 VolatileStore(&fInited, true);
3421 if (pCaller->HasInstantiation())
3423 // For generic types, pCaller will be an instantiated type and never equal to the type definition.
3424 // So we compare their TypeDef tokens instead.
3425 for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypeDefs); i++)
3427 if (pCaller->GetCl() == genericReflectionInvocationTypeDefs[i])
3433 for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3435 if (MscorlibBinder::GetExistingClass(reflectionInvocationTypes[i]) == pCaller)
3443 #ifndef CROSSGEN_COMPILE
3444 struct CallersDataWithStackMark
3446 StackCrawlMark* stackMark;
3448 MethodDesc* pFoundMethod;
3449 MethodDesc* pPrevMethod;
3450 AppDomain* pAppDomain;
3454 MethodDesc* SystemDomain::GetCallersMethod(StackCrawlMark* stackMark,
3455 AppDomain **ppAppDomain/*=NULL*/)
3463 INJECT_FAULT(COMPlusThrowOM(););
3469 CallersDataWithStackMark cdata;
3470 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3471 cdata.stackMark = stackMark;
3473 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3475 if(cdata.pFoundMethod) {
3477 *ppAppDomain = cdata.pAppDomain;
3478 return cdata.pFoundMethod;
3484 MethodTable* SystemDomain::GetCallersType(StackCrawlMark* stackMark,
3485 AppDomain **ppAppDomain/*=NULL*/)
3493 INJECT_FAULT(COMPlusThrowOM(););
3497 CallersDataWithStackMark cdata;
3498 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3499 cdata.stackMark = stackMark;
3501 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3503 if(cdata.pFoundMethod) {
3505 *ppAppDomain = cdata.pAppDomain;
3506 return cdata.pFoundMethod->GetMethodTable();
3512 Module* SystemDomain::GetCallersModule(StackCrawlMark* stackMark,
3513 AppDomain **ppAppDomain/*=NULL*/)
3521 INJECT_FAULT(COMPlusThrowOM(););
3527 CallersDataWithStackMark cdata;
3528 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3529 cdata.stackMark = stackMark;
3531 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3533 if(cdata.pFoundMethod) {
3535 *ppAppDomain = cdata.pAppDomain;
3536 return cdata.pFoundMethod->GetModule();
3544 MethodDesc* pMethod;
3548 Assembly* SystemDomain::GetCallersAssembly(StackCrawlMark *stackMark,
3549 AppDomain **ppAppDomain/*=NULL*/)
3551 WRAPPER_NO_CONTRACT;
3552 Module* mod = GetCallersModule(stackMark, ppAppDomain);
3554 return mod->GetAssembly();
3559 Module* SystemDomain::GetCallersModule(int skip)
3566 INJECT_FAULT(COMPlusThrowOM(););
3573 ZeroMemory(&cdata, sizeof(CallersData));
3576 StackWalkFunctions(GetThread(), CallersMethodCallback, &cdata);
3579 return cdata.pMethod->GetModule();
3585 StackWalkAction SystemDomain::CallersMethodCallbackWithStackMark(CrawlFrame* pCf, VOID* data)
3593 INJECT_FAULT(COMPlusThrowOM(););
3598 MethodDesc *pFunc = pCf->GetFunction();
3600 /* We asked to be called back only for functions */
3603 CallersDataWithStackMark* pCaller = (CallersDataWithStackMark*) data;
3604 if (pCaller->stackMark)
3606 if (!pCf->IsInCalleesFrames(pCaller->stackMark))
3608 // save the current in case it is the one we want
3609 pCaller->pPrevMethod = pFunc;
3610 pCaller->pAppDomain = pCf->GetAppDomain();
3611 return SWA_CONTINUE;
3614 // LookForMe stack crawl marks needn't worry about reflection or
3615 // remoting frames on the stack. Each frame above (newer than) the
3616 // target will be captured by the logic above. Once we transition to
3617 // finding the stack mark below the AofRA, we know that we hit the
3618 // target last time round and immediately exit with the cached result.
3620 if (*(pCaller->stackMark) == LookForMe)
3622 pCaller->pFoundMethod = pCaller->pPrevMethod;
3627 // Skip reflection and remoting frames that could lie between a stack marked
3628 // method and its true caller (or that caller and its own caller). These
3629 // frames are infrastructure and logically transparent to the stack crawling
3632 // Skipping remoting frames. We always skip entire client to server spans
3633 // (though we see them in the order server then client during a stack crawl
3636 // We spot the server dispatcher end because all calls are dispatched
3637 // through a single method: StackBuilderSink._PrivateProcessMessage.
3639 Frame* frame = pCf->GetFrame();
3640 _ASSERTE(pCf->IsFrameless() || frame);
3644 // Skipping reflection frames. We don't need to be quite as exhaustive here
3645 // as the security or reflection stack walking code since we know this logic
3646 // is only invoked for selected methods in mscorlib itself. So we're
3647 // reasonably sure we won't have any sensitive methods late bound invoked on
3648 // constructors, properties or events. This leaves being invoked via
3649 // MethodInfo, Type or Delegate (and depending on which invoke overload is
3650 // being used, several different reflection classes may be involved).
3652 g_IBCLogger.LogMethodDescAccess(pFunc);
3654 if (SystemDomain::IsReflectionInvocationMethod(pFunc))
3655 return SWA_CONTINUE;
3657 if (frame && frame->GetFrameType() == Frame::TYPE_MULTICAST)
3659 // This must be either a secure delegate frame or a true multicast delegate invocation.
3661 _ASSERTE(pFunc->GetMethodTable()->IsDelegate());
3663 DELEGATEREF del = (DELEGATEREF)((SecureDelegateFrame*)frame)->GetThis(); // This can throw.
3665 if (COMDelegate::IsSecureDelegate(del))
3667 if (del->IsWrapperDelegate())
3669 // On ARM, we use secure delegate infrastructure to preserve R4 register.
3670 return SWA_CONTINUE;
3672 // For a secure delegate frame, we should return the delegate creator instead
3673 // of the delegate method itself.
3674 pFunc = (MethodDesc*) del->GetMethodPtrAux();
3678 _ASSERTE(COMDelegate::IsTrueMulticastDelegate(del));
3679 return SWA_CONTINUE;
3683 // Return the first non-reflection/remoting frame if no stack mark was
3685 if (!pCaller->stackMark)
3687 pCaller->pFoundMethod = pFunc;
3688 pCaller->pAppDomain = pCf->GetAppDomain();
3692 // If we got here, we must already be in the frame containing the stack mark and we are not looking for "me".
3693 _ASSERTE(pCaller->stackMark &&
3694 pCf->IsInCalleesFrames(pCaller->stackMark) &&
3695 *(pCaller->stackMark) != LookForMe);
3697 // When looking for caller's caller, we delay returning results for another
3698 // round (the way this is structured, we will still be able to skip
3699 // reflection and remoting frames between the caller and the caller's
3702 if ((*(pCaller->stackMark) == LookForMyCallersCaller) &&
3703 (pCaller->pFoundMethod == NULL))
3705 pCaller->pFoundMethod = pFunc;
3706 return SWA_CONTINUE;
3709 // If remoting is not available, we only set the caller if the crawlframe is from the same domain.
3710 // Why? Because if the callerdomain is different from current domain,
3711 // there have to be interop/native frames in between.
3712 // For example, in the CORECLR, if we find the caller to be in a different domain, then the
3713 // call into reflection is due to an unmanaged call into mscorlib. For that
3714 // case, the caller really is an INTEROP method.
3715 // In general, if the caller is INTEROP, we set the caller/callerdomain to be NULL
3716 // (To be precise: they are already NULL and we don't change them).
3717 if (pCf->GetAppDomain() == GetAppDomain())
3718 // We must either be looking for the caller, or the caller's caller when
3719 // we've already found the caller (we used a non-null value in pFoundMethod
3720 // simply as a flag, the correct method to return in both case is the
3723 pCaller->pFoundMethod = pFunc;
3724 pCaller->pAppDomain = pCf->GetAppDomain();
3731 StackWalkAction SystemDomain::CallersMethodCallback(CrawlFrame* pCf, VOID* data)
3733 LIMITED_METHOD_CONTRACT;
3734 STATIC_CONTRACT_SO_TOLERANT;
3735 MethodDesc *pFunc = pCf->GetFunction();
3737 /* We asked to be called back only for functions */
3740 CallersData* pCaller = (CallersData*) data;
3741 if(pCaller->skip == 0) {
3742 pCaller->pMethod = pFunc;
3747 return SWA_CONTINUE;
3751 #endif // CROSSGEN_COMPILE
3753 #ifdef CROSSGEN_COMPILE
3754 // defined in compile.cpp
3755 extern CompilationDomain * theDomain;
3758 void SystemDomain::CreateDefaultDomain()
3760 STANDARD_VM_CONTRACT;
3762 #ifdef CROSSGEN_COMPILE
3763 AppDomainRefHolder pDomain(theDomain);
3765 AppDomainRefHolder pDomain(new AppDomain());
3768 SystemDomain::LockHolder lh;
3771 // need to make this assignment here since we'll be releasing
3772 // the lock before calling AddDomain. So any other thread
3773 // grabbing this lock after we release it will find that
3774 // the COM Domain has already been created
3775 m_pDefaultDomain = pDomain;
3776 _ASSERTE (pDomain->GetId().m_dwId == DefaultADID);
3778 // allocate a Virtual Call Stub Manager for the default domain
3779 m_pDefaultDomain->InitVSD();
3781 pDomain->SetStage(AppDomain::STAGE_OPEN);
3782 pDomain.SuppressRelease();
3784 LOG((LF_CLASSLOADER | LF_CORDB,
3786 "Created default domain at %p\n", m_pDefaultDomain));
3789 #ifdef DEBUGGING_SUPPORTED
3791 void SystemDomain::PublishAppDomainAndInformDebugger (AppDomain *pDomain)
3795 if(!g_fEEInit) {THROWS;} else {DISABLED(NOTHROW);};
3796 if(!g_fEEInit) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);};
3801 LOG((LF_CORDB, LL_INFO100, "SD::PADAID: Adding 0x%x\n", pDomain));
3803 // Call the publisher API to add this appdomain entry to the list
3804 // The publisher will handle failures, so we don't care if this succeeds or fails.
3805 if (g_pDebugInterface != NULL)
3807 g_pDebugInterface->AddAppDomainToIPC(pDomain);
3811 #endif // DEBUGGING_SUPPORTED
3813 void SystemDomain::AddDomain(AppDomain* pDomain)
3820 PRECONDITION(CheckPointer((pDomain)));
3827 _ASSERTE (pDomain->m_Stage != AppDomain::STAGE_CREATING);
3828 if (pDomain->m_Stage == AppDomain::STAGE_READYFORMANAGEDCODE ||
3829 pDomain->m_Stage == AppDomain::STAGE_ACTIVE)
3831 pDomain->SetStage(AppDomain::STAGE_OPEN);
3832 IncrementNumAppDomains(); // Maintain a count of app domains added to the list.
3836 // Note that if you add another path that can reach here without calling
3837 // PublishAppDomainAndInformDebugger, then you should go back & make sure
3838 // that PADAID gets called. Right after this call, if not sooner.
3839 LOG((LF_CORDB, LL_INFO1000, "SD::AD:Would have added domain here! 0x%x\n",
3843 BOOL SystemDomain::RemoveDomain(AppDomain* pDomain)
3850 PRECONDITION(CheckPointer(pDomain));
3851 PRECONDITION(!pDomain->IsDefaultDomain());
3855 // You can not remove the default domain.
3858 if (!pDomain->IsActive())
3867 #ifdef PROFILING_SUPPORTED
3868 void SystemDomain::NotifyProfilerStartup()
3879 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3881 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System());
3886 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3888 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System(), S_OK);
3893 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3894 _ASSERTE(System()->DefaultDomain());
3895 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System()->DefaultDomain());
3900 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3901 _ASSERTE(System()->DefaultDomain());
3902 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3907 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3908 _ASSERTE(SharedDomain::GetDomain());
3909 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) SharedDomain::GetDomain());
3914 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3915 _ASSERTE(SharedDomain::GetDomain());
3916 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) SharedDomain::GetDomain(), S_OK);
3921 HRESULT SystemDomain::NotifyProfilerShutdown()
3932 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3934 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System());
3939 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3941 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System(), S_OK);
3946 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3947 _ASSERTE(System()->DefaultDomain());
3948 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System()->DefaultDomain());
3953 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3954 _ASSERTE(System()->DefaultDomain());
3955 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3960 #endif // PROFILING_SUPPORTED
3964 struct AppDomain::ThreadTrackInfo {
3966 CDynArray<Frame *> frameStack;
3970 AppDomain::AppDomain()
3972 // initialize fields so the appdomain can be safely destructed
3973 // shouldn't call anything that can fail here - use ::Init instead
3984 m_pNextInDelayedUnloadList = NULL;
3985 m_fRudeUnload = FALSE;
3986 m_pUnloadRequestThread = NULL;
3987 m_ADUnloadSink=NULL;
3990 // Initialize Shared state. Assemblies are loaded
3991 // into each domain by default.
3992 #ifdef FEATURE_LOADER_OPTIMIZATION
3993 m_SharePolicy = SHARE_POLICY_UNSPECIFIED;
3996 m_pRootAssembly = NULL;
3998 m_pwDynamicDir = NULL;
4001 m_pDefaultContext = NULL;
4002 #ifdef FEATURE_COMINTEROP
4003 m_pComCallWrapperCache = NULL;
4005 m_pRCWRefCache = NULL;
4006 m_pLicenseInteropHelperMT = NULL;
4007 m_COMorRemotingFlag = COMorRemoting_NotInitialized;
4008 memset(m_rpCLRTypes, 0, sizeof(m_rpCLRTypes));
4009 #endif // FEATURE_COMINTEROP
4011 m_pUMEntryThunkCache = NULL;
4013 m_pAsyncPool = NULL;
4014 m_handleStore = NULL;
4016 m_ExposedObject = NULL;
4017 m_pComIPForExposedObject = NULL;
4020 m_pThreadTrackInfoList = NULL;
4021 m_TrackSpinLock = 0;
4022 m_Assemblies.Debug_SetAppDomain(this);
4025 m_dwThreadEnterCount = 0;
4026 m_dwThreadsStillInAppDomain = (ULONG)-1;
4028 #ifdef FEATURE_COMINTEROP
4029 m_pRefDispIDCache = NULL;
4030 m_hndMissing = NULL;
4033 m_pRefClassFactHash = NULL;
4034 m_anonymouslyHostedDynamicMethodsAssembly = NULL;
4036 m_ReversePInvokeCanEnter=TRUE;
4037 m_ForceTrivialWaitOperations = false;
4038 m_Stage=STAGE_CREATING;
4040 m_bForceGCOnUnload=FALSE;
4041 m_bUnloadingFromUnloadEvent=FALSE;
4045 m_dwCreationHolders=0;
4048 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4049 m_ullTotalProcessorUsage = 0;
4050 m_pullAllocBytes = NULL;
4051 m_pullSurvivedBytes = NULL;
4052 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4054 #ifdef FEATURE_TYPEEQUIVALENCE
4055 m_pTypeEquivalenceTable = NULL;
4056 #endif // FEATURE_TYPEEQUIVALENCE
4058 #ifdef FEATURE_COMINTEROP
4059 m_pNameToTypeMap = NULL;
4060 m_vNameToTypeMapVersion = 0;
4062 m_pWinRTFactoryCache = NULL;
4063 #endif // FEATURE_COMINTEROP
4065 #ifdef FEATURE_PREJIT
4066 m_pDomainFileWithNativeImageList = NULL;
4069 m_fIsBindingModelLocked.Store(FALSE);
4071 } // AppDomain::AppDomain
4073 AppDomain::~AppDomain()
4083 #ifndef CROSSGEN_COMPILE
4085 _ASSERTE(m_dwCreationHolders == 0);
4087 // release the TPIndex. note that since TPIndex values are recycled the TPIndex
4088 // can only be released once all threads in the AppDomain have exited.
4089 if (GetTPIndex().m_dwIndex != 0)
4090 PerAppDomainTPCountList::ResetAppDomainIndex(GetTPIndex());
4092 if (m_dwId.m_dwId!=0)
4093 SystemDomain::ReleaseAppDomainId(m_dwId);
4095 m_AssemblyCache.Clear();
4098 m_ADUnloadSink->Release();
4106 #ifdef FEATURE_COMINTEROP
4107 if (m_pNameToTypeMap != nullptr)
4109 delete m_pNameToTypeMap;
4110 m_pNameToTypeMap = nullptr;
4112 if (m_pWinRTFactoryCache != nullptr)
4114 delete m_pWinRTFactoryCache;
4115 m_pWinRTFactoryCache = nullptr;
4117 #endif //FEATURE_COMINTEROP
4120 // If we were tracking thread AD transitions, cleanup the list on shutdown
4121 if (m_pThreadTrackInfoList)
4123 while (m_pThreadTrackInfoList->Count() > 0)
4125 // Get the very last element
4126 ThreadTrackInfo *pElem = *(m_pThreadTrackInfoList->Get(m_pThreadTrackInfoList->Count() - 1));
4132 // Remove pointer entry from the list
4133 m_pThreadTrackInfoList->Delete(m_pThreadTrackInfoList->Count() - 1);
4136 // Now delete the list itself
4137 delete m_pThreadTrackInfoList;
4138 m_pThreadTrackInfoList = NULL;
4142 #endif // CROSSGEN_COMPILE
4145 //*****************************************************************************
4146 //*****************************************************************************
4147 //*****************************************************************************
4148 void AppDomain::Init()
4153 PRECONDITION(SystemDomain::IsUnderDomainLock());
4157 m_pDelayedLoaderAllocatorUnloadList = NULL;
4159 SetStage( STAGE_CREATING);
4162 // The lock is taken also during stack walking (GC or profiler)
4163 // - To prevent deadlock with GC thread, we cannot trigger GC while holding the lock
4164 // - To prevent deadlock with profiler thread, we cannot allow thread suspension
4165 m_crstHostAssemblyMap.Init(
4166 CrstHostAssemblyMap,
4167 (CrstFlags)(CRST_GC_NOTRIGGER_WHEN_TAKEN
4168 | CRST_DEBUGGER_THREAD
4169 INDEBUG(| CRST_DEBUG_ONLY_CHECK_FORBID_SUSPEND_THREAD)));
4170 m_crstHostAssemblyMapAdd.Init(CrstHostAssemblyMapAdd);
4172 m_dwId = SystemDomain::GetNewAppDomainId(this);
4174 m_LoaderAllocator.Init(this);
4176 #ifndef CROSSGEN_COMPILE
4177 //Allocate the threadpool entry before the appdomin id list. Otherwise,
4178 //the thread pool list will be out of sync if insertion of id in
4179 //the appdomain fails.
4180 m_tpIndex = PerAppDomainTPCountList::AddNewTPIndex();
4181 #endif // CROSSGEN_COMPILE
4183 m_dwIndex = SystemDomain::GetNewAppDomainIndex(this);
4185 #ifndef CROSSGEN_COMPILE
4186 PerAppDomainTPCountList::SetAppDomainId(m_tpIndex, m_dwId);
4188 m_ADUnloadSink=new ADUnloadSink();
4193 // Set up the IL stub cache
4194 m_ILStubCache.Init(GetLoaderAllocator()->GetHighFrequencyHeap());
4196 // Set up the binding caches
4197 m_AssemblyCache.Init(&m_DomainCacheCrst, GetHighFrequencyHeap());
4198 m_UnmanagedCache.InitializeTable(this, &m_DomainCacheCrst);
4200 m_MemoryPressure = 0;
4202 m_sDomainLocalBlock.Init(this);
4204 #ifndef CROSSGEN_COMPILE
4206 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4207 // NOTE: it's important that we initialize ARM data structures before calling
4208 // Ref_CreateHandleTableBucket, this is because AD::Init() can race with GC
4209 // and once we add ourselves to the handle table map the GC can start walking
4210 // our handles and calling AD::RecordSurvivedBytes() which touches ARM data.
4211 if (GCHeapUtilities::IsServerHeap())
4212 m_dwNumHeaps = CPUGroupInfo::CanEnableGCCPUGroups() ?
4213 CPUGroupInfo::GetNumActiveProcessors() :
4214 GetCurrentProcessCpuCount();
4217 m_pullAllocBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
4218 m_pullSurvivedBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
4219 for (DWORD i = 0; i < m_dwNumHeaps; i++)
4221 m_pullAllocBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
4222 m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
4224 m_ullLastEtwAllocBytes = 0;
4225 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4227 // Default domain reuses the handletablemap that was created during EEStartup since
4228 // default domain cannot be unloaded.
4229 if (GetId().m_dwId == DefaultADID)
4231 m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
4235 m_handleStore = GCHandleUtilities::GetGCHandleManager()->CreateHandleStore((void*)(uintptr_t)m_dwIndex.m_dwIndex);
4243 #endif // CROSSGEN_COMPILE
4245 #ifdef FEATURE_TYPEEQUIVALENCE
4246 m_TypeEquivalenceCrst.Init(CrstTypeEquivalenceMap);
4249 m_ReflectionCrst.Init(CrstReflection, CRST_UNSAFE_ANYMODE);
4250 m_RefClassFactCrst.Init(CrstClassFactInfoHash);
4253 LockOwner lock = {&m_DomainCrst, IsOwnerOfCrst};
4254 m_clsidHash.Init(0,&CompareCLSID,true, &lock); // init hash table
4257 SetStage(STAGE_READYFORMANAGEDCODE);
4259 #ifndef CROSSGEN_COMPILE
4260 m_pDefaultContext = new Context(this);
4262 m_ExposedObject = CreateHandle(NULL);
4264 // Create the Application Security Descriptor
4266 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains++);
4268 #ifdef FEATURE_COMINTEROP
4269 if (!AppX::IsAppXProcess())
4272 #endif //FEATURE_COMINTEROP
4274 #ifdef FEATURE_TIERED_COMPILATION
4275 m_tieredCompilationManager.Init(GetId());
4277 #endif // CROSSGEN_COMPILE
4278 } // AppDomain::Init
4281 /*********************************************************************/
4283 BOOL AppDomain::IsCompilationDomain()
4285 LIMITED_METHOD_CONTRACT;
4287 BOOL isCompilationDomain = (m_dwFlags & COMPILATION_DOMAIN) != 0;
4288 #ifdef FEATURE_PREJIT
4289 _ASSERTE(!isCompilationDomain ||
4290 (IsCompilationProcess() && IsPassiveDomain()));
4291 #endif // FEATURE_PREJIT
4292 return isCompilationDomain;
4295 #ifndef CROSSGEN_COMPILE
4297 extern int g_fADUnloadWorkerOK;
4300 // This helper will send the AppDomain creation notifications for profiler / debugger.
4301 // If it throws, its backout code will also send a notification.
4302 // If it succeeds, then we still need to send a AppDomainCreateFinished notification.
4303 void AppDomain::CreateUnmanagedObject(AppDomainCreationHolder<AppDomain>& pDomain)
4310 INJECT_FAULT(COMPlusThrowOM(););
4316 pDomain.Assign(new AppDomain());
4317 if (g_fADUnloadWorkerOK<0)
4319 AppDomain::CreateADUnloadWorker();
4323 // We addref Appdomain object here and notify a profiler that appdomain
4324 // creation has started, then return to managed code which will call
4325 // the function that releases the appdomain and notifies a profiler that we finished
4326 // creating the appdomain. If an exception is raised while we're in that managed code
4327 // we will leak memory and the profiler will not be notified about the failure
4329 #ifdef PROFILING_SUPPORTED
4330 // Signal profile if present.
4332 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
4333 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) (AppDomain*) pDomain);
4337 #endif // PROFILING_SUPPORTED
4340 SystemDomain::LockHolder lh;
4342 // allocate a Virtual Call Stub Manager for this domain
4346 pDomain->SetCanUnload(); // by default can unload any domain
4348 #ifdef DEBUGGING_SUPPORTED
4349 // Notify the debugger here, before the thread transitions into the
4350 // AD to finish the setup, and before any assemblies are loaded into it.
4351 SystemDomain::PublishAppDomainAndInformDebugger(pDomain);
4352 #endif // DEBUGGING_SUPPORTED
4354 STRESS_LOG2 (LF_APPDOMAIN, LL_INFO100, "Create domain [%d] %p\n", pDomain->GetId().m_dwId, (AppDomain*)pDomain);
4355 pDomain->LoadSystemAssemblies();
4356 pDomain->SetupSharedStatics();
4358 pDomain->SetStage(AppDomain::STAGE_ACTIVE);
4360 #ifdef PROFILING_SUPPORTED
4363 // Need the first assembly loaded in to get any data on an app domain.
4365 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
4366 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID)(AppDomain*) pDomain, GET_EXCEPTION()->GetHR());
4372 // On success, caller must still send the AppDomainCreationFinished notification.
4373 #endif // PROFILING_SUPPORTED
4376 void AppDomain::Stop()
4386 #ifdef FEATURE_MULTICOREJIT
4387 GetMulticoreJitManager().StopProfile(true);
4390 // Set the unloaded flag before notifying the debugger
4391 GetLoaderAllocator()->SetIsUnloaded();
4393 #ifdef DEBUGGING_SUPPORTED
4394 if (IsDebuggerAttached())
4395 NotifyDebuggerUnload();
4396 #endif // DEBUGGING_SUPPORTED
4398 m_pRootAssembly = NULL; // This assembly is in the assembly list;
4400 #ifdef DEBUGGING_SUPPORTED
4401 if (NULL != g_pDebugInterface)
4403 // Call the publisher API to delete this appdomain entry from the list
4404 CONTRACT_VIOLATION(ThrowsViolation);
4405 g_pDebugInterface->RemoveAppDomainFromIPC (this);
4407 #endif // DEBUGGING_SUPPORTED
4410 void AppDomain::Terminate()
4423 _ASSERTE(m_dwThreadEnterCount == 0 || IsDefaultDomain());
4425 if (m_pComIPForExposedObject)
4427 m_pComIPForExposedObject->Release();
4428 m_pComIPForExposedObject = NULL;
4431 delete m_pDefaultContext;
4432 m_pDefaultContext = NULL;
4434 if (m_pUMEntryThunkCache)
4436 delete m_pUMEntryThunkCache;
4437 m_pUMEntryThunkCache = NULL;
4440 #ifdef FEATURE_COMINTEROP
4449 delete m_pRCWRefCache;
4450 m_pRCWRefCache = NULL;
4453 if (m_pComCallWrapperCache)
4455 m_pComCallWrapperCache->Neuter();
4456 m_pComCallWrapperCache->Release();
4459 // if the above released the wrapper cache, then it will call back and reset our
4460 // m_pComCallWrapperCache to null. If not null, then need to set it's domain pointer to
4462 if (! m_pComCallWrapperCache)
4464 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::Terminate ComCallWrapperCache released\n"));
4469 m_pComCallWrapperCache = NULL;
4470 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::Terminate ComCallWrapperCache not released\n"));
4474 #endif // FEATURE_COMINTEROP
4477 if (!IsAtProcessExit())
4479 // if we're not shutting down everything then clean up the string literals associated
4480 // with this appdomain -- note that is no longer needs to happen while suspended
4481 // because the appropriate locks are taken in the GlobalStringLiteralMap
4482 // this is important as this locks have a higher lock number than does the
4483 // thread-store lock which is taken when we suspend.
4484 GetLoaderAllocator()->CleanupStringLiteralMap();
4486 // Suspend the EE to do some clean up that can only occur
4487 // while no threads are running.
4488 GCX_COOP (); // SuspendEE may require current thread to be in Coop mode
4489 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
4492 // Note that this must be performed before restarting the EE. It will clean
4493 // the cache and prevent others from using stale cache entries.
4494 //@TODO: Would be nice to get this back to BaseDomain, but need larger fix for that.
4495 // NOTE: Must have the runtime suspended to unlink managers
4496 // NOTE: May be NULL due to OOM during initialization. Can skip in that case.
4497 GetLoaderAllocator()->UninitVirtualCallStubManager();
4498 MethodTable::ClearMethodDataCache();
4499 ClearJitGenericHandleCache(this);
4501 // @TODO s_TPMethodTableCrst prevents us from from keeping the whole
4502 // assembly shutdown logic here. See if we can do better in the next milestone
4503 #ifdef FEATURE_PREJIT
4504 DeleteNativeCodeRanges();
4507 if (!IsAtProcessExit())
4510 ThreadSuspend::RestartEE(FALSE, TRUE);
4513 ShutdownAssemblies();
4514 ShutdownNativeDllSearchDirectories();
4516 if (m_pRefClassFactHash)
4518 m_pRefClassFactHash->Destroy();
4519 // storage for m_pRefClassFactHash itself is allocated on the loader heap
4522 #ifdef FEATURE_TYPEEQUIVALENCE
4523 m_TypeEquivalenceCrst.Destroy();
4526 m_ReflectionCrst.Destroy();
4527 m_RefClassFactCrst.Destroy();
4529 m_LoaderAllocator.Terminate();
4531 BaseDomain::Terminate();
4535 GCHandleUtilities::GetGCHandleManager()->DestroyHandleStore(m_handleStore);
4536 m_handleStore = NULL;
4539 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4540 if (m_pullAllocBytes)
4542 delete [] m_pullAllocBytes;
4544 if (m_pullSurvivedBytes)
4546 delete [] m_pullSurvivedBytes;
4548 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4550 if(m_dwIndex.m_dwIndex != 0)
4551 SystemDomain::ReleaseAppDomainIndex(m_dwIndex);
4552 } // AppDomain::Terminate
4554 void AppDomain::CloseDomain()
4565 BOOL bADRemoved=FALSE;;
4567 AddRef(); // Hold a reference
4568 AppDomainRefHolder AdHolder(this);
4570 SystemDomain::LockHolder lh;
4572 SystemDomain::System()->DecrementNumAppDomains(); // Maintain a count of app domains added to the list.
4573 bADRemoved = SystemDomain::System()->RemoveDomain(this);
4580 /*********************************************************************/
4582 struct GetExposedObject_Args
4588 static void GetExposedObject_Wrapper(LPVOID ptr)
4597 GetExposedObject_Args *args = (GetExposedObject_Args *) ptr;
4598 *(args->ref) = args->pDomain->GetExposedObject();
4602 OBJECTREF AppDomain::GetExposedObject()
4609 INJECT_FAULT(COMPlusThrowOM(););
4613 OBJECTREF ref = GetRawExposedObject();
4616 APPDOMAINREF obj = NULL;
4618 Thread *pThread = GetThread();
4619 if (pThread->GetDomain() != this)
4621 GCPROTECT_BEGIN(ref);
4622 GetExposedObject_Args args = {this, &ref};
4623 // call through DoCallBack with a domain transition
4624 pThread->DoADCallBack(this,GetExposedObject_Wrapper, &args,ADV_CREATING|ADV_RUNNINGIN);
4628 MethodTable *pMT = MscorlibBinder::GetClass(CLASS__APP_DOMAIN);
4630 // Create the module object
4631 obj = (APPDOMAINREF) AllocateObject(pMT);
4632 obj->SetDomain(this);
4634 if (!StoreFirstObjectInHandle(m_ExposedObject, (OBJECTREF) obj))
4636 obj = (APPDOMAINREF) GetRawExposedObject();
4640 return (OBJECTREF) obj;
4648 OBJECTREF AppDomain::DoSetup(OBJECTREF* setupInfo)
4655 INJECT_FAULT(COMPlusThrowOM(););
4659 ADID adid=GetAppDomain()->GetId();
4661 OBJECTREF retval=NULL;
4662 GCPROTECT_BEGIN(retval);
4664 ENTER_DOMAIN_PTR(this,ADV_CREATING);
4666 MethodDescCallSite setup(METHOD__APP_DOMAIN__SETUP);
4670 args[0]=ObjToArgSlot(*setupInfo);
4672 OBJECTREF activator;
4673 activator=setup.Call_RetOBJECTREF(args);
4674 _ASSERTE(activator==NULL);
4676 #if defined(FEATURE_MULTICOREJIT)
4677 // Disable AutoStartProfile in default domain from this code path.
4678 // It's called from SystemDomain::ExecuteMainMethod for normal program, not needed for SL and Asp.Net
4679 if (! IsDefaultDomain())
4683 GetMulticoreJitManager().AutoStartProfile(this);
4687 END_DOMAIN_TRANSITION;
4692 #endif // !CROSSGEN_COMPILE
4694 #ifdef FEATURE_COMINTEROP
4695 #ifndef CROSSGEN_COMPILE
4696 HRESULT AppDomain::GetComIPForExposedObject(IUnknown **pComIP)
4698 // Assumption: This function is called for AppDomain's that the current
4699 // thread is in or has entered, or the AppDomain is kept alive.
4701 // Assumption: This function can now throw. The caller is responsible for any
4702 // BEGIN_EXTERNAL_ENTRYPOINT, EX_TRY, or other
4703 // techniques to convert to a COM HRESULT protocol.
4713 Thread *pThread = GetThread();
4714 if (m_pComIPForExposedObject)
4716 GCX_PREEMP_THREAD_EXISTS(pThread);
4717 m_pComIPForExposedObject->AddRef();
4718 *pComIP = m_pComIPForExposedObject;
4722 IUnknown* punk = NULL;
4724 OBJECTREF ref = NULL;
4725 GCPROTECT_BEGIN(ref);
4729 ENTER_DOMAIN_PTR(this,ADV_DEFAULTAD)
4731 ref = GetExposedObject();
4732 punk = GetComIPFromObjectRef(&ref);
4733 if (FastInterlockCompareExchangePointer(&m_pComIPForExposedObject, punk, NULL) == NULL)
4735 GCX_PREEMP_THREAD_EXISTS(pThread);
4736 m_pComIPForExposedObject->AddRef();
4739 END_DOMAIN_TRANSITION;
4745 *pComIP = m_pComIPForExposedObject;
4750 #endif //#ifndef CROSSGEN_COMPILE
4752 MethodTable *AppDomain::GetRedirectedType(WinMDAdapter::RedirectedTypeIndex index)
4762 // If we have the type loaded already, use that
4763 if (m_rpCLRTypes[index] != nullptr)
4765 return m_rpCLRTypes[index];
4768 WinMDAdapter::FrameworkAssemblyIndex frameworkAssemblyIndex;
4769 WinMDAdapter::GetRedirectedTypeInfo(index, nullptr, nullptr, nullptr, &frameworkAssemblyIndex, nullptr, nullptr);
4770 MethodTable * pMT = LoadRedirectedType(index, frameworkAssemblyIndex);
4771 m_rpCLRTypes[index] = pMT;
4775 MethodTable* AppDomain::LoadRedirectedType(WinMDAdapter::RedirectedTypeIndex index, WinMDAdapter::FrameworkAssemblyIndex assembly)
4782 PRECONDITION(index < WinMDAdapter::RedirectedTypeIndex_Count);
4786 LPCSTR szClrNamespace;
4788 LPCSTR szFullWinRTName;
4789 WinMDAdapter::FrameworkAssemblyIndex nFrameworkAssemblyIndex;
4791 WinMDAdapter::GetRedirectedTypeInfo(index, &szClrNamespace, &szClrName, &szFullWinRTName, &nFrameworkAssemblyIndex, nullptr, nullptr);
4793 _ASSERTE(nFrameworkAssemblyIndex >= WinMDAdapter::FrameworkAssembly_Mscorlib &&
4794 nFrameworkAssemblyIndex < WinMDAdapter::FrameworkAssembly_Count);
4796 if (assembly != nFrameworkAssemblyIndex)
4798 // The framework type does not live in the assembly we were requested to load redirected types from
4801 else if (nFrameworkAssemblyIndex == WinMDAdapter::FrameworkAssembly_Mscorlib)
4803 return ClassLoader::LoadTypeByNameThrowing(MscorlibBinder::GetModule()->GetAssembly(),
4806 ClassLoader::ThrowIfNotFound,
4807 ClassLoader::LoadTypes,
4808 CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4813 AssemblyMetaDataInternal context;
4814 const BYTE * pbKeyToken;
4815 DWORD cbKeyTokenLength;
4818 WinMDAdapter::GetExtraAssemblyRefProps(nFrameworkAssemblyIndex,
4825 Assembly* pAssembly = AssemblySpec::LoadAssembly(pSimpleName,
4831 return ClassLoader::LoadTypeByNameThrowing(
4835 ClassLoader::ThrowIfNotFound,
4836 ClassLoader::LoadTypes,
4837 CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4840 #endif //FEATURE_COMINTEROP
4842 #endif //!DACCESS_COMPILE
4844 #ifndef DACCESS_COMPILE
4846 bool IsPlatformAssembly(LPCSTR szName, DomainAssembly *pDomainAssembly)
4853 PRECONDITION(CheckPointer(szName));
4854 PRECONDITION(CheckPointer(pDomainAssembly));
4858 PEAssembly *pPEAssembly = pDomainAssembly->GetFile();
4860 if (strcmp(szName, pPEAssembly->GetSimpleName()) != 0)
4866 const BYTE *pbPublicKey = static_cast<const BYTE *>(pPEAssembly->GetPublicKey(&cbPublicKey));
4867 if (pbPublicKey == nullptr)
4872 return StrongNameIsSilverlightPlatformKey(pbPublicKey, cbPublicKey);
4875 void AppDomain::AddAssembly(DomainAssembly * assem)
4882 INJECT_FAULT(COMPlusThrowOM(););
4887 CrstHolder ch(GetAssemblyListLock());
4889 // Attempt to find empty space in assemblies list
4890 DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4891 for (DWORD i = 0; i < asmCount; ++i)
4893 if (m_Assemblies.Get_UnlockedNoReference(i) == NULL)
4895 m_Assemblies.Set_Unlocked(i, assem);
4900 // If empty space not found, simply add to end of list
4901 IfFailThrow(m_Assemblies.Append_Unlocked(assem));
4905 void AppDomain::RemoveAssembly_Unlocked(DomainAssembly * pAsm)
4914 _ASSERTE(GetAssemblyListLock()->OwnedByCurrentThread());
4916 DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4917 for (DWORD i = 0; i < asmCount; ++i)
4919 if (m_Assemblies.Get_UnlockedNoReference(i) == pAsm)
4921 m_Assemblies.Set_Unlocked(i, NULL);
4926 _ASSERTE(!"Unreachable");
4929 BOOL AppDomain::ContainsAssembly(Assembly * assem)
4931 WRAPPER_NO_CONTRACT;
4932 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
4934 (assem->IsIntrospectionOnly() ? kIncludeIntrospection : kIncludeExecution)));
4935 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
4937 while (i.Next(pDomainAssembly.This()))
4939 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
4940 if (pAssembly == assem)
4947 EEClassFactoryInfoHashTable* AppDomain::SetupClassFactHash()
4954 INJECT_FAULT(COMPlusThrowOM(););
4958 CrstHolder ch(&m_ReflectionCrst);
4960 if (m_pRefClassFactHash == NULL)
4962 AllocMemHolder<void> pCache(GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (EEClassFactoryInfoHashTable))));
4963 EEClassFactoryInfoHashTable *tmp = new (pCache) EEClassFactoryInfoHashTable;
4964 LockOwner lock = {&m_RefClassFactCrst,IsOwnerOfCrst};
4965 if (!tmp->Init(20, &lock))
4967 pCache.SuppressRelease();
4968 m_pRefClassFactHash = tmp;
4971 return m_pRefClassFactHash;
4974 #ifdef FEATURE_COMINTEROP
4975 DispIDCache* AppDomain::SetupRefDispIDCache()
4982 INJECT_FAULT(COMPlusThrowOM(););
4986 CrstHolder ch(&m_ReflectionCrst);
4988 if (m_pRefDispIDCache == NULL)
4990 AllocMemHolder<void> pCache = GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (DispIDCache)));
4992 DispIDCache *tmp = new (pCache) DispIDCache;
4995 pCache.SuppressRelease();
4996 m_pRefDispIDCache = tmp;
4999 return m_pRefDispIDCache;
5002 #endif // FEATURE_COMINTEROP
5004 FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
5011 PRECONDITION(pLock->HasLock());
5012 PRECONDITION(pLock->FindFileLock(pFile) == NULL);
5013 INJECT_FAULT(COMPlusThrowOM(););
5017 NewHolder<FileLoadLock> result(new FileLoadLock(pLock, pFile, pDomainFile));
5019 pLock->AddElement(result);
5020 result->AddRef(); // Add one ref on behalf of the ListLock's reference. The corresponding Release() happens in FileLoadLock::CompleteLoadLevel.
5021 return result.Extract();
5024 FileLoadLock::~FileLoadLock()
5034 ((PEFile *) m_data)->Release();
5037 DomainFile *FileLoadLock::GetDomainFile()
5039 LIMITED_METHOD_CONTRACT;
5040 return m_pDomainFile;
5043 FileLoadLevel FileLoadLock::GetLoadLevel()
5045 LIMITED_METHOD_CONTRACT;
5049 ADID FileLoadLock::GetAppDomainId()
5051 LIMITED_METHOD_CONTRACT;
5052 return m_AppDomainId;
5055 // Acquire will return FALSE and not take the lock if the file
5056 // has already been loaded to the target level. Otherwise,
5057 // it will return TRUE and take the lock.
5059 // Note that the taker must release the lock via IncrementLoadLevel.
5061 BOOL FileLoadLock::Acquire(FileLoadLevel targetLevel)
5063 WRAPPER_NO_CONTRACT;
5065 // If we are already loaded to the desired level, the lock is "free".
5066 if (m_level >= targetLevel)
5069 if (!DeadlockAwareEnter())
5071 // We failed to get the lock due to a deadlock.
5075 if (m_level >= targetLevel)
5084 BOOL FileLoadLock::CanAcquire(FileLoadLevel targetLevel)
5086 // If we are already loaded to the desired level, the lock is "free".
5087 if (m_level >= targetLevel)
5090 return CanDeadlockAwareEnter();
5093 #if !defined(DACCESS_COMPILE) && (defined(LOGGING) || defined(STRESS_LOG))
5094 static const char *fileLoadLevelName[] =
5096 "CREATE", // FILE_LOAD_CREATE
5097 "BEGIN", // FILE_LOAD_BEGIN
5098 "FIND_NATIVE_IMAGE", // FILE_LOAD_FIND_NATIVE_IMAGE
5099 "VERIFY_NATIVE_IMAGE_DEPENDENCIES", // FILE_LOAD_VERIFY_NATIVE_IMAGE_DEPENDENCIES
5100 "ALLOCATE", // FILE_LOAD_ALLOCATE
5101 "ADD_DEPENDENCIES", // FILE_LOAD_ADD_DEPENDENCIES
5102 "PRE_LOADLIBRARY", // FILE_LOAD_PRE_LOADLIBRARY
5103 "LOADLIBRARY", // FILE_LOAD_LOADLIBRARY
5104 "POST_LOADLIBRARY", // FILE_LOAD_POST_LOADLIBRARY
5105 "EAGER_FIXUPS", // FILE_LOAD_EAGER_FIXUPS
5106 "VTABLE FIXUPS", // FILE_LOAD_VTABLE_FIXUPS
5107 "DELIVER_EVENTS", // FILE_LOAD_DELIVER_EVENTS
5108 "LOADED", // FILE_LOADED
5109 "VERIFY_EXECUTION", // FILE_LOAD_VERIFY_EXECUTION
5110 "ACTIVE", // FILE_ACTIVE
5112 #endif // !DACCESS_COMPILE && (LOGGING || STRESS_LOG)
5114 BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success)
5121 PRECONDITION(HasLock());
5125 // Increment may happen more than once if reentrancy occurs (e.g. LoadLibrary)
5126 if (level > m_level)
5128 // Must complete each level in turn, unless we have an error
5129 CONSISTENCY_CHECK(m_pDomainFile->IsError() || (level == (m_level+1)));
5130 // Remove the lock from the list if the load is completed
5131 if (level >= FILE_ACTIVE)
5135 PEFileListLockHolder lock((PEFileListLock*)m_pList);
5138 BOOL fDbgOnly_SuccessfulUnlink =
5140 m_pList->Unlink(this);
5141 _ASSERTE(fDbgOnly_SuccessfulUnlink);
5143 m_pDomainFile->ClearLoading();
5145 CONSISTENCY_CHECK(m_dwRefCount >= 2); // Caller (LoadDomainFile) should have 1 refcount and m_pList should have another which was acquired in FileLoadLock::Create.
5147 m_level = (FileLoadLevel)level;
5150 // In AppDomain::IsLoading, if the lock is taken on m_pList and then FindFileLock returns NULL,
5151 // we depend on the DomainFile's load level being up to date. Hence we must update the load
5152 // level while the m_pList lock is held.
5154 m_pDomainFile->SetLoadLevel(level);
5158 Release(); // Release m_pList's refcount on this lock, which was acquired in FileLoadLock::Create
5163 m_level = (FileLoadLevel)level;
5166 m_pDomainFile->SetLoadLevel(level);
5169 #ifndef DACCESS_COMPILE
5172 case FILE_LOAD_ALLOCATE:
5173 case FILE_LOAD_ADD_DEPENDENCIES:
5174 case FILE_LOAD_DELIVER_EVENTS:
5176 case FILE_ACTIVE: // The timing of stress logs is not critical, so even for the FILE_ACTIVE stage we need not do it while the m_pList lock is held.
5177 STRESS_LOG4(LF_CLASSLOADER, LL_INFO100, "Completed Load Level %s for DomainFile %p in AD %i - success = %i\n", fileLoadLevelName[level], m_pDomainFile, m_AppDomainId.m_dwId, success);
5190 void FileLoadLock::SetError(Exception *ex)
5197 PRECONDITION(CheckPointer(ex));
5198 PRECONDITION(HasLock());
5199 INJECT_FAULT(COMPlusThrowOM(););
5203 m_cachedHR = ex->GetHR();
5205 LOG((LF_LOADER, LL_WARNING, "LOADER: %x:***%s*\t!!!Non-transient error 0x%x\n",
5206 m_pDomainFile->GetAppDomain(), m_pDomainFile->GetSimpleName(), m_cachedHR));
5208 m_pDomainFile->SetError(ex);
5210 CompleteLoadLevel(FILE_ACTIVE, FALSE);
5213 void FileLoadLock::AddRef()
5215 LIMITED_METHOD_CONTRACT;
5216 FastInterlockIncrement((LONG *) &m_dwRefCount);
5219 UINT32 FileLoadLock::Release()
5229 LONG count = FastInterlockDecrement((LONG *) &m_dwRefCount);
5236 FileLoadLock::FileLoadLock(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
5237 : ListLockEntry(pLock, pFile, "File load lock"),
5238 m_level((FileLoadLevel) (FILE_LOAD_CREATE)),
5239 m_pDomainFile(pDomainFile),
5241 m_AppDomainId(pDomainFile->GetAppDomain()->GetId())
5243 WRAPPER_NO_CONTRACT;
5247 void FileLoadLock::HolderLeave(FileLoadLock *pThis)
5249 LIMITED_METHOD_CONTRACT;
5259 // Assembly loading:
5261 // Assembly loading is carefully layered to avoid deadlocks in the
5262 // presence of circular loading dependencies.
5263 // A LoadLevel is associated with each assembly as it is being loaded. During the
5264 // act of loading (abstractly, increasing its load level), its lock is
5265 // held, and the current load level is stored on the thread. Any
5266 // recursive loads during that period are automatically restricted to
5267 // only partially load the dependent assembly to the same level as the
5268 // caller (or to one short of that level in the presence of a deadlock
5271 // Each loading stage must be carfully constructed so that
5272 // this constraint is expected and can be dealt with.
5274 // Note that there is one case where this still doesn't handle recursion, and that is the
5275 // security subsytem. The security system runs managed code, and thus must typically fully
5276 // initialize assemblies of permission sets it is trying to use. (And of course, these may be used
5277 // while those assemblies are initializing.) This is dealt with in the historical manner - namely
5278 // the security system passes in a special flag which says that it will deal with null return values
5279 // in the case where a load cannot be safely completed due to such issues.
5282 void AppDomain::LoadSystemAssemblies()
5284 STANDARD_VM_CONTRACT;
5286 // The only reason to make an assembly a "system assembly" is if the EE is caching
5287 // pointers to stuff in the assembly. Because this is going on, we need to preserve
5288 // the invariant that the assembly is loaded into every app domain.
5290 // Right now we have only one system assembly. We shouldn't need to add any more.
5292 LoadAssembly(NULL, SystemDomain::System()->SystemFile(), FILE_ACTIVE);
5295 FileLoadLevel AppDomain::GetDomainFileLoadLevel(DomainFile *pFile)
5305 LoadLockHolder lock(this);
5307 FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5309 if (pLockEntry == NULL)
5310 return pFile->GetLoadLevel();
5312 return pLockEntry->GetLoadLevel();
5315 // This checks if the thread has initiated (or completed) loading at the given level. A false guarantees that
5316 // (a) The current thread (or a thread blocking on the current thread) has not started loading the file
5317 // at the given level, and
5318 // (b) No other thread had started loading the file at this level at the start of this function call.
5320 // Note that another thread may start loading the file at that level in a race with the completion of
5321 // this function. However, the caller still has the guarantee that such a load started after this
5322 // function was called (and e.g. any state in place before the function call will be seen by the other thread.)
5324 // Conversely, a true guarantees that either the current thread has started the load step, or another
5325 // thread has completed the load step.
5328 BOOL AppDomain::IsLoading(DomainFile *pFile, FileLoadLevel level)
5331 if (pFile->GetLoadLevel() < level)
5333 FileLoadLock *pLock = NULL;
5335 LoadLockHolder lock(this);
5337 pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5341 // No thread involved with loading
5342 return pFile->GetLoadLevel() >= level;
5348 FileLoadLockRefHolder lockRef(pLock);
5350 if (pLock->Acquire(level))
5352 // We got the lock - therefore no other thread has started this loading step yet.
5357 // We didn't get the lock - either this thread is already doing the load,
5358 // or else the load has already finished.
5363 // CheckLoading is a weaker form of IsLoading, which will not block on
5364 // other threads waiting for their status. This is appropriate for asserts.
5365 CHECK AppDomain::CheckLoading(DomainFile *pFile, FileLoadLevel level)
5368 if (pFile->GetLoadLevel() < level)
5370 FileLoadLock *pLock = NULL;
5372 LoadLockHolder lock(this);
5374 pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5377 && pLock->CanAcquire(level))
5379 // We can get the lock - therefore no other thread has started this loading step yet.
5380 CHECK_FAILF(("Loading step %d has not been initiated yet", level));
5383 // We didn't get the lock - either this thread is already doing the load,
5384 // or else the load has already finished.
5390 CHECK AppDomain::CheckCanLoadTypes(Assembly *pAssembly)
5399 CHECK_MSG(CheckValidModule(pAssembly->GetManifestModule()),
5400 "Type loading can occur only when executing in the assembly's app domain");
5404 CHECK AppDomain::CheckCanExecuteManagedCode(MethodDesc* pMD)
5414 Module* pModule=pMD->GetModule();
5416 CHECK_MSG(CheckValidModule(pModule),
5417 "Managed code can only run when executing in the module's app domain");
5419 if (!pMD->IsInterface() || pMD->IsStatic()) //interfaces require no activation for instance methods
5421 //cctor could have been interupted by ADU
5422 CHECK_MSG(HasUnloadStarted() || pModule->CheckActivated(),
5423 "Managed code can only run when its module has been activated in the current app domain");
5426 CHECK_MSG(!IsPassiveDomain() || pModule->CanExecuteCode(),
5427 "Executing managed code from an unsafe assembly in a Passive AppDomain");
5432 #endif // !DACCESS_COMPILE
5434 void AppDomain::LoadDomainFile(DomainFile *pFile,
5435 FileLoadLevel targetLevel)
5439 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
5440 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
5441 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM();); }
5442 INJECT_FAULT(COMPlusThrowOM(););
5446 // Quick exit if finished
5447 if (pFile->GetLoadLevel() >= targetLevel)
5450 // Handle the error case
5451 pFile->ThrowIfError(targetLevel);
5454 #ifndef DACCESS_COMPILE
5456 if (pFile->IsLoading())
5460 // Load some more if appropriate
5461 LoadLockHolder lock(this);
5463 FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5464 if (pLockEntry == NULL)
5466 _ASSERTE (!pFile->IsLoading());
5470 pLockEntry->AddRef();
5474 LoadDomainFile(pLockEntry, targetLevel);
5477 #else // DACCESS_COMPILE
5479 #endif // DACCESS_COMPILE
5482 #ifndef DACCESS_COMPILE
5484 FileLoadLevel AppDomain::GetThreadFileLoadLevel()
5486 WRAPPER_NO_CONTRACT;
5487 if (GetThread()->GetLoadLevelLimiter() == NULL)
5490 return (FileLoadLevel)(GetThread()->GetLoadLevelLimiter()->GetLoadLevel()-1);
5494 Assembly *AppDomain::LoadAssembly(AssemblySpec* pIdentity,
5496 FileLoadLevel targetLevel)
5498 CONTRACT(Assembly *)
5503 PRECONDITION(CheckPointer(pFile));
5504 POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // May be NULL in recursive load case
5505 INJECT_FAULT(COMPlusThrowOM(););
5509 DomainAssembly *pAssembly = LoadDomainAssembly(pIdentity, pFile, targetLevel);
5510 PREFIX_ASSUME(pAssembly != NULL);
5512 RETURN pAssembly->GetAssembly();
5515 #ifndef CROSSGEN_COMPILE
5517 class LoadDomainAssemblyStress : APIThreadStress
5521 AssemblySpec* pSpec;
5523 FileLoadLevel targetLevel;
5525 LoadDomainAssemblyStress(AppDomain *pThis, AssemblySpec* pSpec, PEAssembly *pFile, FileLoadLevel targetLevel)
5526 : pThis(pThis), pSpec(pSpec), pFile(pFile), targetLevel(targetLevel) {LIMITED_METHOD_CONTRACT;}
5530 WRAPPER_NO_CONTRACT;
5531 STATIC_CONTRACT_SO_INTOLERANT;
5533 pThis->LoadDomainAssembly(pSpec, pFile, targetLevel);
5536 #endif // CROSSGEN_COMPILE
5538 extern BOOL AreSameBinderInstance(ICLRPrivBinder *pBinderA, ICLRPrivBinder *pBinderB);
5540 DomainAssembly* AppDomain::LoadDomainAssembly( AssemblySpec* pSpec,
5542 FileLoadLevel targetLevel)
5544 STATIC_CONTRACT_THROWS;
5546 if (pSpec == nullptr)
5548 // skip caching, since we don't have anything to base it on
5549 return LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
5552 DomainAssembly* pRetVal = NULL;
5555 pRetVal = LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
5559 Exception* pEx=GET_EXCEPTION();
5560 if (!pEx->IsTransient())
5562 // Setup the binder reference in AssemblySpec from the PEAssembly if one is not already set.
5563 ICLRPrivBinder* pCurrentBindingContext = pSpec->GetBindingContext();
5564 ICLRPrivBinder* pBindingContextFromPEAssembly = pFile->GetBindingContext();
5566 if (pCurrentBindingContext == NULL)
5568 // Set the binding context we got from the PEAssembly if AssemblySpec does not
5569 // have that information
5570 _ASSERTE(pBindingContextFromPEAssembly != NULL);
5571 pSpec->SetBindingContext(pBindingContextFromPEAssembly);
5576 // Binding context in the spec should be the same as the binding context in the PEAssembly
5577 _ASSERTE(AreSameBinderInstance(pCurrentBindingContext, pBindingContextFromPEAssembly));
5581 if (!EEFileLoadException::CheckType(pEx))
5584 pSpec->GetFileOrDisplayName(0, name);
5585 pEx=new EEFileLoadException(name, pEx->GetHR(), NULL, pEx);
5586 AddExceptionToCache(pSpec, pEx);
5587 PAL_CPP_THROW(Exception *, pEx);
5590 AddExceptionToCache(pSpec, pEx);
5599 DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
5601 FileLoadLevel targetLevel)
5603 CONTRACT(DomainAssembly *)
5608 PRECONDITION(CheckPointer(pFile));
5609 PRECONDITION(pFile->IsSystem() || ::GetAppDomain()==this);
5610 POSTCONDITION(CheckPointer(RETVAL));
5611 POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
5612 || RETVAL->GetLoadLevel() >= targetLevel);
5613 POSTCONDITION(RETVAL->CheckNoError(targetLevel));
5614 INJECT_FAULT(COMPlusThrowOM(););
5619 DomainAssembly * result;
5621 #ifndef CROSSGEN_COMPILE
5622 LoadDomainAssemblyStress ts (this, pIdentity, pFile, targetLevel);
5625 // Go into preemptive mode since this may take a while.
5628 // Check for existing fully loaded assembly, or for an assembly which has failed during the loading process.
5629 result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
5633 // Allocate the DomainAssembly a bit early to avoid GC mode problems. We could potentially avoid
5634 // a rare redundant allocation by moving this closer to FileLoadLock::Create, but it's not worth it.
5636 NewHolder<DomainAssembly> pDomainAssembly;
5637 pDomainAssembly = new DomainAssembly(this, pFile, this->GetLoaderAllocator());
5639 LoadLockHolder lock(this);
5641 // Find the list lock entry
5642 FileLoadLock * fileLock = (FileLoadLock *)lock->FindFileLock(pFile);
5643 if (fileLock == NULL)
5645 // Check again in case we were racing
5646 result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
5649 // We are the first one in - create the DomainAssembly
5650 fileLock = FileLoadLock::Create(lock, pFile, pDomainAssembly);
5651 pDomainAssembly.SuppressRelease();
5663 // We pass our ref on fileLock to LoadDomainFile to release.
5665 // Note that if we throw here, we will poison fileLock with an error condition,
5666 // so it will not be removed until app domain unload. So there is no need
5667 // to release our ref count.
5668 result = (DomainAssembly *)LoadDomainFile(fileLock, targetLevel);
5672 result->EnsureLoadLevel(targetLevel);
5676 result->EnsureLoadLevel(targetLevel);
5678 // Malformed metadata may contain a Module reference to what is actually
5679 // an Assembly. In this case we need to throw an exception, since returning
5680 // a DomainModule as a DomainAssembly is a type safety violation.
5681 if (!result->IsAssembly())
5683 ThrowHR(COR_E_ASSEMBLYEXPECTED);
5686 // Cache result in all cases, since found pFile could be from a different AssemblyRef than pIdentity
5687 // Do not cache WindowsRuntime assemblies, they are cached in code:CLRPrivTypeCacheWinRT
5688 if ((pIdentity != NULL) && (pIdentity->CanUseWithBindingCache()) && (result->CanUseWithBindingCache()))
5689 GetAppDomain()->AddAssemblyToCache(pIdentity, result);
5692 } // AppDomain::LoadDomainAssembly
5697 FileLoadLock *pLock;
5698 FileLoadLevel targetLevel;
5702 #ifndef CROSSGEN_COMPILE
5703 static void LoadDomainFile_Wrapper(void *ptr)
5705 WRAPPER_NO_CONTRACT;
5706 STATIC_CONTRACT_SO_INTOLERANT;
5708 LoadFileArgs *args = (LoadFileArgs *) ptr;
5709 args->result = GetAppDomain()->LoadDomainFile(args->pLock, args->targetLevel);
5711 #endif // !CROSSGEN_COMPILE
5713 DomainFile *AppDomain::LoadDomainFile(FileLoadLock *pLock, FileLoadLevel targetLevel)
5715 CONTRACT(DomainFile *)
5718 PRECONDITION(CheckPointer(pLock));
5719 PRECONDITION(pLock->GetDomainFile()->GetAppDomain() == this);
5720 POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
5721 || RETVAL->GetLoadLevel() >= targetLevel);
5722 POSTCONDITION(RETVAL->CheckNoError(targetLevel));
5728 COMPlusThrow(kAppDomainUnloadedException);
5731 APIThreadStress::SyncThreadStress();
5733 DomainFile *pFile = pLock->GetDomainFile();
5735 // Make sure we release the lock on exit
5736 FileLoadLockRefHolder lockRef(pLock);
5738 // We need to perform the early steps of loading mscorlib without a domain transition. This is
5739 // important for bootstrapping purposes - we need to get mscorlib at least partially loaded
5740 // into a domain before we can run serialization code to do the transition.
5742 // Note that we cannot do this in general for all assemblies, because some of the security computations
5743 // require the managed exposed object, which must be created in the correct app domain.
5745 if (this != GetAppDomain()
5746 && pFile->GetFile()->IsSystem()
5747 && targetLevel > FILE_LOAD_ALLOCATE)
5749 // Re-call the routine with a limited load level. This will cause the first part of the load to
5750 // get performed in the current app domain.
5753 LoadDomainFile(pLock, targetLevel > FILE_LOAD_ALLOCATE ? FILE_LOAD_ALLOCATE : targetLevel);
5755 // Now continue on to complete the rest of the load, if any.
5758 // Do a quick out check for the already loaded case.
5759 if (pLock->GetLoadLevel() >= targetLevel)
5761 pFile->ThrowIfError(targetLevel);
5766 #ifndef CROSSGEN_COMPILE
5767 // Make sure we are in the right domain. Many of the load operations require the target domain
5768 // to be the current app domain, most notably anything involving managed code or managed object
5770 if (this != GetAppDomain()
5771 && (!pFile->GetFile()->IsSystem() || targetLevel > FILE_LOAD_ALLOCATE))
5773 // Transition to the correct app domain and perform the load there.
5776 // we will release the lock in the other app domain
5777 lockRef.SuppressRelease();
5779 if(!CanLoadCode() || GetDefaultContext() ==NULL)
5780 COMPlusThrow(kAppDomainUnloadedException);
5781 LoadFileArgs args = {pLock, targetLevel, NULL};
5782 GetThread()->DoADCallBack(this, LoadDomainFile_Wrapper, (void *) &args, ADV_CREATING);
5786 #endif // CROSSGEN_COMPILE
5788 // Initialize a loading queue. This will hold any loads which are triggered recursively but
5789 // which cannot be immediately satisfied due to anti-deadlock constraints.
5791 // PendingLoadQueues are allocated on the stack during a load, and
5792 // shared with all nested loads on the same thread. (Note that we won't use
5793 // "candidate" if we are in a recursive load; that's OK since they are cheap to
5795 FileLoadLevel immediateTargetLevel = targetLevel;
5797 LoadLevelLimiter limit;
5800 // We cannot set a target level higher than that allowed by the limiter currently.
5801 // This is because of anti-deadlock constraints.
5802 if (immediateTargetLevel > limit.GetLoadLevel())
5803 immediateTargetLevel = limit.GetLoadLevel();
5805 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t>>>Load initiated, %s/%s\n",
5806 pFile->GetAppDomain(), pFile->GetSimpleName(),
5807 fileLoadLevelName[immediateTargetLevel], fileLoadLevelName[targetLevel]));
5809 // Now loop and do the load incrementally to the target level.
5810 if (pLock->GetLoadLevel() < immediateTargetLevel)
5813 APIThreadStress::SyncThreadStress();
5815 while (pLock->Acquire(immediateTargetLevel))
5817 FileLoadLevel workLevel;
5819 FileLoadLockHolder fileLock(pLock);
5821 // Work level is next step to do
5822 workLevel = (FileLoadLevel)(fileLock->GetLoadLevel()+1);
5824 // Set up the anti-deadlock constraint: we cannot safely recursively load any assemblies
5825 // on this thread to a higher level than this assembly is being loaded now.
5826 // Note that we do allow work at a parallel level; any deadlocks caused here will
5827 // be resolved by the deadlock detection in the FileLoadLocks.
5828 limit.SetLoadLevel(workLevel);
5831 (workLevel == FILE_LOAD_BEGIN
5832 || workLevel == FILE_LOADED
5833 || workLevel == FILE_ACTIVE)
5834 ? LL_INFO10 : LL_INFO1000,
5835 "LOADER: %p:***%s*\t loading at level %s\n",
5836 this, pFile->GetSimpleName(), fileLoadLevelName[workLevel]));
5838 TryIncrementalLoad(pFile, workLevel, fileLock);
5840 TESTHOOKCALL(CompletedFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5843 if (pLock->GetLoadLevel() == immediateTargetLevel-1)
5845 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load limited due to detected deadlock, %s\n",
5846 pFile->GetAppDomain(), pFile->GetSimpleName(),
5847 fileLoadLevelName[immediateTargetLevel-1]));
5851 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load completed, %s\n",
5852 pFile->GetAppDomain(), pFile->GetSimpleName(),
5853 fileLoadLevelName[pLock->GetLoadLevel()]));
5857 // There may have been an error stored on the domain file by another thread, or from a previous load
5858 pFile->ThrowIfError(targetLevel);
5860 // There are two normal results from the above loop.
5862 // 1. We succeeded in loading the file to the current thread's load level.
5863 // 2. We succeeded in loading the file to the current thread's load level - 1, due
5864 // to deadlock condition with another thread loading the same assembly.
5866 // Either of these are considered satisfactory results, as code inside a load must expect
5867 // a parial load result.
5869 // However, if load level elevation has occurred, then it is possible for a deadlock to
5870 // prevent us from loading an assembly which was loading before the elevation at a radically
5871 // lower level. In such a case, we throw an exception which transiently fails the current
5872 // load, since it is likely we have not satisfied the caller.
5873 // (An alternate, and possibly preferable, strategy here would be for all callers to explicitly
5874 // identify the minimum load level acceptable via CheckLoadDomainFile and throw from there.)
5876 pFile->RequireLoadLevel((FileLoadLevel)(immediateTargetLevel-1));
5882 void AppDomain::TryIncrementalLoad(DomainFile *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder)
5884 STANDARD_VM_CONTRACT;
5886 // This is factored out so we don't call EX_TRY in a loop (EX_TRY can _alloca)
5888 BOOL released = FALSE;
5889 FileLoadLock* pLoadLock = lockHolder.GetValue();
5894 // Special case: for LoadLibrary, we cannot hold the lock during the
5895 // actual LoadLibrary call, because we might get a callback from _CorDllMain on any
5896 // other thread. (Note that this requires DomainFile's LoadLibrary to be independently threadsafe.)
5898 if (workLevel == FILE_LOAD_LOADLIBRARY)
5900 lockHolder.Release();
5905 TESTHOOKCALL(NextFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5906 BOOL success = pFile->DoIncrementalLoad(workLevel);
5907 TESTHOOKCALL(CompletingFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5910 // Reobtain lock to increment level. (Note that another thread may
5911 // have already done it which is OK.
5912 if (pLoadLock->Acquire(workLevel))
5914 // note lockHolder.Acquire isn't wired up to actually take the lock
5915 lockHolder = pLoadLock;
5922 // Complete the level.
5923 if (pLoadLock->CompleteLoadLevel(workLevel, success) &&
5924 pLoadLock->GetLoadLevel()==FILE_LOAD_DELIVER_EVENTS)
5926 lockHolder.Release();
5928 pFile->DeliverAsyncEvents();
5934 Exception *pEx = GET_EXCEPTION();
5937 //We will cache this error and wire this load to forever fail,
5938 // unless the exception is transient or the file is loaded OK but just cannot execute
5939 if (!pEx->IsTransient() && !pFile->IsLoaded())
5944 // Reobtain lock to increment level. (Note that another thread may
5945 // have already done it which is OK.
5946 if (pLoadLock->Acquire(workLevel)) // note pLockHolder->Acquire isn't wired up to actually take the lock
5948 // note lockHolder.Acquire isn't wired up to actually take the lock
5949 lockHolder = pLoadLock;
5956 // Report the error in the lock
5957 pLoadLock->SetError(pEx);
5960 if (!EEFileLoadException::CheckType(pEx))
5961 EEFileLoadException::Throw(pFile->GetFile(), pEx->GetHR(), pEx);
5964 // Otherwise, we simply abort this load, and can retry later on.
5965 // @todo cleanup: make sure that each level is restartable after an exception, and
5966 // leaves no bad side effects
5971 // Checks whether the module is valid to be in the given app domain (need not be yet loaded)
5972 CHECK AppDomain::CheckValidModule(Module * pModule)
5982 if (pModule->FindDomainFile(this) != NULL)
5987 Assembly * pAssembly = pModule->GetAssembly();
5989 CCHECK(pAssembly->IsDomainNeutral());
5990 #ifdef FEATURE_LOADER_OPTIMIZATION
5991 Assembly * pSharedAssembly = NULL;
5992 _ASSERTE(this == ::GetAppDomain());
5994 SharedAssemblyLocator locator(pAssembly->GetManifestFile());
5995 pSharedAssembly = SharedDomain::GetDomain()->FindShareableAssembly(&locator);
5998 CCHECK(pAssembly == pSharedAssembly);
6006 #ifdef FEATURE_LOADER_OPTIMIZATION
6007 // Loads an existing Module into an AppDomain
6008 // WARNING: this can only be done in a very limited scenario - the Module must be an unloaded domain neutral
6009 // dependency in the app domain in question. Normal code should not call this!
6010 DomainFile *AppDomain::LoadDomainNeutralModuleDependency(Module *pModule, FileLoadLevel targetLevel)
6012 CONTRACT(DomainFile *)
6017 PRECONDITION(::GetAppDomain()==this);
6018 PRECONDITION(CheckPointer(pModule));
6019 POSTCONDITION(CheckValidModule(pModule));
6020 POSTCONDITION(CheckPointer(RETVAL));
6021 POSTCONDITION(RETVAL->GetModule() == pModule);
6025 DomainFile *pDomainFile = pModule->FindDomainFile(this);
6027 STRESS_LOG3(LF_CLASSLOADER, LL_INFO100,"LDNMD: DomainFile %p for module %p in AppDomain %i\n",pDomainFile,pModule,GetId().m_dwId);
6029 if (pDomainFile == NULL)
6033 Assembly *pAssembly = pModule->GetAssembly();
6035 DomainAssembly *pDomainAssembly = pAssembly->FindDomainAssembly(this);
6036 if (pDomainAssembly == NULL)
6038 AssemblySpec spec(this);
6039 spec.InitializeSpec(pAssembly->GetManifestFile());
6041 pDomainAssembly = spec.LoadDomainAssembly(targetLevel);
6045 //if the domain assembly already exists, we need to load it to the target level
6046 pDomainAssembly->EnsureLoadLevel (targetLevel);
6049 if(pAssembly != pDomainAssembly->GetAssembly())
6051 ThrowHR(SECURITY_E_INCOMPATIBLE_SHARE);
6054 _ASSERTE (pModule == pAssembly->GetManifestModule());
6055 pDomainFile = pDomainAssembly;
6059 // If the DomainFile already exists, we need to load it to the target level.
6060 pDomainFile->EnsureLoadLevel (targetLevel);
6066 AppDomain::SharePolicy AppDomain::GetSharePolicy()
6068 LIMITED_METHOD_CONTRACT;
6070 return SHARE_POLICY_NEVER;
6072 #endif // FEATURE_LOADER_OPTIMIZATION
6075 void AppDomain::CheckForMismatchedNativeImages(AssemblySpec * pSpec, const GUID * pGuid)
6077 STANDARD_VM_CONTRACT;
6080 // The native images are ever used only for trusted images in CoreCLR.
6081 // We don't wish to open the IL file at runtime so we just forgo any
6082 // eager consistency checking. But we still want to prevent mistmatched
6083 // NGen images from being used. We record all mappings between assembly
6084 // names and MVID, and fail once we detect mismatch.
6087 if (pSpec->IsStrongNamed() && pSpec->HasPublicKey())
6089 pSpec->ConvertPublicKeyToToken();
6093 // CoreCLR binder unifies assembly versions. Ignore assembly version here to
6094 // detect more types of potential mismatches.
6096 AssemblyMetaDataInternal * pContext = pSpec->GetContext();
6097 pContext->usMajorVersion = (USHORT)-1;
6098 pContext->usMinorVersion = (USHORT)-1;
6099 pContext->usBuildNumber = (USHORT)-1;
6100 pContext->usRevisionNumber = (USHORT)-1;
6102 // Ignore the WinRT type while considering if two assemblies have the same identity.
6103 pSpec->SetWindowsRuntimeType(NULL, NULL);
6105 CrstHolder ch(&m_DomainCrst);
6107 const NativeImageDependenciesEntry * pEntry = m_NativeImageDependencies.Lookup(pSpec);
6111 if (*pGuid != pEntry->m_guidMVID)
6114 msg.Printf("ERROR: Native images generated against multiple versions of assembly %s. ", pSpec->GetName());
6115 WszOutputDebugString(msg.GetUnicode());
6116 COMPlusThrowNonLocalized(kFileLoadException, msg.GetUnicode());
6122 // No entry yet - create one
6124 AllocMemTracker amTracker;
6125 AllocMemTracker *pamTracker = &amTracker;
6127 NativeImageDependenciesEntry * pNewEntry =
6128 new (pamTracker->Track(GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(NativeImageDependenciesEntry)))))
6129 NativeImageDependenciesEntry();
6131 pNewEntry->m_AssemblySpec.CopyFrom(pSpec);
6132 pNewEntry->m_AssemblySpec.CloneFieldsToLoaderHeap(AssemblySpec::ALL_OWNED, GetLowFrequencyHeap(), pamTracker);
6134 pNewEntry->m_guidMVID = *pGuid;
6136 m_NativeImageDependencies.Add(pNewEntry);
6137 amTracker.SuppressRelease();
6142 void AppDomain::SetupSharedStatics()
6149 INJECT_FAULT(COMPlusThrowOM(););
6153 #ifndef CROSSGEN_COMPILE
6154 if (NingenEnabled())
6157 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: SetupSharedStatics()"));
6159 // don't do any work in init stage. If not init only do work in non-shared case if are default domain
6160 _ASSERTE(!g_fEEInit);
6162 // Because we are allocating/referencing objects, need to be in cooperative mode
6165 static OBJECTHANDLE hSharedStaticsHandle = NULL;
6167 if (hSharedStaticsHandle == NULL) {
6168 // Note that there is no race here since the default domain is always set up first
6169 _ASSERTE(IsDefaultDomain());
6171 MethodTable *pMT = MscorlibBinder::GetClass(CLASS__SHARED_STATICS);
6172 _ASSERTE(pMT->IsClassPreInited());
6174 hSharedStaticsHandle = CreateGlobalHandle(AllocateObject(pMT));
6177 DomainLocalModule *pLocalModule;
6179 if (IsSingleAppDomain())
6181 pLocalModule = MscorlibBinder::GetModule()->GetDomainLocalModule();
6185 pLocalModule = GetDomainLocalBlock()->GetModuleSlot(
6186 MscorlibBinder::GetModule()->GetModuleIndex());
6189 FieldDesc *pFD = MscorlibBinder::GetField(FIELD__SHARED_STATICS__SHARED_STATICS);
6191 OBJECTREF* pHandle = (OBJECTREF*)
6192 ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pFD->GetOffset());
6193 SetObjectReference( pHandle, ObjectFromHandle(hSharedStaticsHandle), this );
6195 // This is a convenient place to initialize String.Empty.
6196 // It is treated as intrinsic by the JIT as so the static constructor would never run.
6197 // Leaving it uninitialized would confuse debuggers.
6199 // String should not have any static constructors.
6200 _ASSERTE(g_pStringClass->IsClassPreInited());
6202 FieldDesc * pEmptyStringFD = MscorlibBinder::GetField(FIELD__STRING__EMPTY);
6203 OBJECTREF* pEmptyStringHandle = (OBJECTREF*)
6204 ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pEmptyStringFD->GetOffset());
6205 SetObjectReference( pEmptyStringHandle, StringObject::GetEmptyString(), this );
6206 #endif // CROSSGEN_COMPILE
6209 DomainAssembly * AppDomain::FindAssembly(PEAssembly * pFile, FindAssemblyOptions options/* = FindAssemblyOptions_None*/)
6216 INJECT_FAULT(COMPlusThrowOM(););
6220 const bool includeFailedToLoad = (options & FindAssemblyOptions_IncludeFailedToLoad) != 0;
6222 if (pFile->HasHostAssembly())
6224 DomainAssembly * pDA = FindAssembly(pFile->GetHostAssembly());
6225 if (pDA != nullptr && (pDA->IsLoaded() || (includeFailedToLoad && pDA->IsError())))
6232 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
6234 (includeFailedToLoad ? kIncludeFailedToLoad : 0) |
6235 (pFile->IsIntrospectionOnly() ? kIncludeIntrospection : kIncludeExecution)));
6236 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
6238 while (i.Next(pDomainAssembly.This()))
6240 PEFile * pManifestFile = pDomainAssembly->GetFile();
6241 if (pManifestFile &&
6242 !pManifestFile->IsResource() &&
6243 pManifestFile->Equals(pFile))
6245 // Caller already has PEAssembly, so we can give DomainAssembly away freely without AddRef
6246 return pDomainAssembly.Extract();
6252 static const AssemblyIterationFlags STANDARD_IJW_ITERATOR_FLAGS =
6253 (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kExcludeCollectible);
6256 void AppDomain::SetFriendlyName(LPCWSTR pwzFriendlyName, BOOL fDebuggerCares/*=TRUE*/)
6261 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6263 INJECT_FAULT(COMPlusThrowOM(););
6267 // Do all computations into a temporary until we're ensured of success
6268 SString tmpFriendlyName;
6271 if (pwzFriendlyName)
6272 tmpFriendlyName.Set(pwzFriendlyName);
6275 // If there is an assembly, try to get the name from it.
6276 // If no assembly, but if it's the DefaultDomain, then give it a name
6278 if (m_pRootAssembly)
6280 tmpFriendlyName.SetUTF8(m_pRootAssembly->GetSimpleName());
6282 SString::Iterator i = tmpFriendlyName.End();
6283 if (tmpFriendlyName.FindBack(i, '.'))
6284 tmpFriendlyName.Truncate(i);
6288 if (IsDefaultDomain())
6289 tmpFriendlyName.Set(DEFAULT_DOMAIN_FRIENDLY_NAME);
6291 // This is for the profiler - if they call GetFriendlyName on an AppdomainCreateStarted
6292 // event, then we want to give them a temporary name they can use.
6293 else if (GetId().m_dwId != 0)
6295 tmpFriendlyName.Clear();
6296 tmpFriendlyName.Printf(W("%s %d"), OTHER_DOMAIN_FRIENDLY_NAME_PREFIX, GetId().m_dwId);
6302 tmpFriendlyName.Normalize();
6305 m_friendlyName = tmpFriendlyName;
6306 m_friendlyName.Normalize();
6308 if(g_pDebugInterface)
6310 // update the name in the IPC publishing block
6311 if (SUCCEEDED(g_pDebugInterface->UpdateAppDomainEntryInIPC(this)))
6313 // inform the attached debugger that the name of this appdomain has changed.
6314 if (IsDebuggerAttached() && fDebuggerCares)
6315 g_pDebugInterface->NameChangeEvent(this, NULL);
6320 void AppDomain::ResetFriendlyName(BOOL fDebuggerCares/*=TRUE*/)
6322 WRAPPER_NO_CONTRACT;
6323 SetFriendlyName(NULL, fDebuggerCares);
6326 LPCWSTR AppDomain::GetFriendlyName(BOOL fDebuggerCares/*=TRUE*/)
6331 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6333 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6334 INJECT_FAULT(COMPlusThrowOM(););
6339 // Handle NULL this pointer - this happens sometimes when printing log messages
6340 // but in general shouldn't occur in real code
6345 if (m_friendlyName.IsEmpty())
6346 SetFriendlyName(NULL, fDebuggerCares);
6348 RETURN m_friendlyName;
6351 LPCWSTR AppDomain::GetFriendlyNameForLogging()
6358 POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
6362 // Handle NULL this pointer - this happens sometimes when printing log messages
6363 // but in general shouldn't occur in real code
6367 RETURN (m_friendlyName.IsEmpty() ?W(""):(LPCWSTR)m_friendlyName);
6370 LPCWSTR AppDomain::GetFriendlyNameForDebugger()
6375 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6377 POSTCONDITION(CheckPointer(RETVAL));
6382 if (m_friendlyName.IsEmpty())
6384 BOOL fSuccess = FALSE;
6388 SetFriendlyName(NULL);
6394 // Gobble all exceptions.
6396 EX_END_CATCH(SwallowAllExceptions);
6404 RETURN m_friendlyName;
6408 #endif // !DACCESS_COMPILE
6410 #ifdef DACCESS_COMPILE
6412 PVOID AppDomain::GetFriendlyNameNoSet(bool* isUtf8)
6416 if (!m_friendlyName.IsEmpty())
6419 return m_friendlyName.DacGetRawContent();
6421 else if (m_pRootAssembly)
6424 return (PVOID)m_pRootAssembly->GetSimpleName();
6426 else if (dac_cast<TADDR>(this) ==
6427 dac_cast<TADDR>(SystemDomain::System()->DefaultDomain()))
6430 return (PVOID)DEFAULT_DOMAIN_FRIENDLY_NAME;
6438 #endif // DACCESS_COMPILE
6440 void AppDomain::CacheStringsForDAC()
6451 // If the application base, private bin paths, and configuration file are
6452 // available, cache them so DAC can read them out of memory
6456 #ifndef DACCESS_COMPILE
6458 BOOL AppDomain::AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAllowFailure)
6465 PRECONDITION(CheckPointer(pSpec));
6466 // Hosted fusion binder makes an exception here, so we cannot assert.
6467 //PRECONDITION(pSpec->CanUseWithBindingCache());
6468 //PRECONDITION(pFile->CanUseWithBindingCache());
6469 INJECT_FAULT(COMPlusThrowOM(););
6473 CrstHolder holder(&m_DomainCacheCrst);
6474 // !!! suppress exceptions
6475 if(!m_AssemblyCache.StoreFile(pSpec, pFile) && !fAllowFailure)
6477 // TODO: Disabling the below assertion as currently we experience
6478 // inconsistency on resolving the Microsoft.Office.Interop.MSProject.dll
6479 // This causes below assertion to fire and crashes the VS. This issue
6480 // is being tracked with Dev10 Bug 658555. Brought back it when this bug
6484 EEFileLoadException::Throw(pSpec, FUSION_E_CACHEFILE_FAILED, NULL);
6490 BOOL AppDomain::AddAssemblyToCache(AssemblySpec* pSpec, DomainAssembly *pAssembly)
6497 PRECONDITION(CheckPointer(pSpec));
6498 PRECONDITION(CheckPointer(pAssembly));
6499 PRECONDITION(pSpec->CanUseWithBindingCache());
6500 PRECONDITION(pAssembly->CanUseWithBindingCache());
6501 INJECT_FAULT(COMPlusThrowOM(););
6505 CrstHolder holder(&m_DomainCacheCrst);
6506 // !!! suppress exceptions
6507 BOOL bRetVal = m_AssemblyCache.StoreAssembly(pSpec, pAssembly);
6511 BOOL AppDomain::AddExceptionToCache(AssemblySpec* pSpec, Exception *ex)
6518 PRECONDITION(CheckPointer(pSpec));
6519 PRECONDITION(pSpec->CanUseWithBindingCache());
6520 INJECT_FAULT(COMPlusThrowOM(););
6524 if (ex->IsTransient())
6527 CrstHolder holder(&m_DomainCacheCrst);
6528 // !!! suppress exceptions
6529 return m_AssemblyCache.StoreException(pSpec, ex);
6532 void AppDomain::AddUnmanagedImageToCache(LPCWSTR libraryName, HMODULE hMod)
6539 PRECONDITION(CheckPointer(libraryName));
6540 INJECT_FAULT(COMPlusThrowOM(););
6546 spec.SetCodeBase(libraryName);
6547 m_UnmanagedCache.InsertEntry(&spec, hMod);
6553 HMODULE AppDomain::FindUnmanagedImageInCache(LPCWSTR libraryName)
6560 PRECONDITION(CheckPointer(libraryName,NULL_OK));
6561 POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
6562 INJECT_FAULT(COMPlusThrowOM(););
6565 if(libraryName == NULL) RETURN NULL;
6568 spec.SetCodeBase(libraryName);
6569 RETURN (HMODULE) m_UnmanagedCache.LookupEntry(&spec, 0);
6573 BOOL AppDomain::IsCached(AssemblySpec *pSpec)
6575 WRAPPER_NO_CONTRACT;
6577 // Check to see if this fits our rather loose idea of a reference to mscorlib.
6578 // If so, don't use fusion to bind it - do it ourselves.
6579 if (pSpec->IsMscorlib())
6582 return m_AssemblyCache.Contains(pSpec);
6585 void AppDomain::GetCacheAssemblyList(SetSHash<PTR_DomainAssembly>& assemblyList)
6587 CrstHolder holder(&m_DomainCacheCrst);
6588 m_AssemblyCache.GetAllAssemblies(assemblyList);
6591 PEAssembly* AppDomain::FindCachedFile(AssemblySpec* pSpec, BOOL fThrow /*=TRUE*/)
6607 // Check to see if this fits our rather loose idea of a reference to mscorlib.
6608 // If so, don't use fusion to bind it - do it ourselves.
6609 if (fThrow && pSpec->IsMscorlib())
6611 CONSISTENCY_CHECK(SystemDomain::System()->SystemAssembly() != NULL);
6612 PEAssembly *pFile = SystemDomain::System()->SystemFile();
6617 return m_AssemblyCache.LookupFile(pSpec, fThrow);
6621 BOOL AppDomain::PostBindResolveAssembly(AssemblySpec *pPrePolicySpec,
6622 AssemblySpec *pPostPolicySpec,
6623 HRESULT hrBindResult,
6624 AssemblySpec **ppFailedSpec)
6626 STATIC_CONTRACT_THROWS;
6627 STATIC_CONTRACT_GC_TRIGGERS;
6628 PRECONDITION(CheckPointer(pPrePolicySpec));
6629 PRECONDITION(CheckPointer(pPostPolicySpec));
6630 PRECONDITION(CheckPointer(ppFailedSpec));
6632 BOOL fFailure = TRUE;
6633 *ppFailedSpec = pPrePolicySpec;
6636 PEAssemblyHolder result;
6638 if ((EEFileLoadException::GetFileLoadKind(hrBindResult) == kFileNotFoundException) ||
6639 (hrBindResult == FUSION_E_REF_DEF_MISMATCH) ||
6640 (hrBindResult == FUSION_E_INVALID_NAME))
6642 result = TryResolveAssembly(*ppFailedSpec, FALSE /* fPreBind */);
6644 if (result != NULL && pPrePolicySpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
6648 // Given the post-policy resolve event construction of the CLR binder,
6649 // chained managed resolve events can race with each other, therefore we do allow
6650 // the adding of the result to fail. Checking for already chached specs
6651 // is not an option as it would introduce another race window.
6652 // The binder does a re-fetch of the
6653 // orignal binding spec and therefore will not cause inconsistency here.
6654 // For the purposes of the resolve event, failure to add to the cache still is a success.
6655 AddFileToCache(pPrePolicySpec, result, TRUE /* fAllowFailure */);
6656 if (*ppFailedSpec != pPrePolicySpec && pPostPolicySpec->CanUseWithBindingCache())
6658 AddFileToCache(pPostPolicySpec, result, TRUE /* fAllowFailure */ );
6666 //----------------------------------------------------------------------------------------
6667 // Helper class for hosted binder
6669 class PEAssemblyAsPrivAssemblyInfo : public IUnknownCommon<ICLRPrivAssemblyInfo>
6672 //------------------------------------------------------------------------------------
6675 PEAssemblyAsPrivAssemblyInfo(PEAssembly *pPEAssembly)
6677 LIMITED_METHOD_CONTRACT;
6678 STATIC_CONTRACT_THROWS;
6680 if (pPEAssembly == nullptr)
6681 ThrowHR(E_UNEXPECTED);
6683 pPEAssembly->AddRef();
6684 m_pPEAssembly = pPEAssembly;
6687 //------------------------------------------------------------------------------------
6688 // ICLRPrivAssemblyInfo methods
6690 //------------------------------------------------------------------------------------
6691 STDMETHOD(GetAssemblyName)(
6692 __in DWORD cchBuffer,
6693 __out_opt LPDWORD pcchBuffer,
6694 __out_ecount_part_opt(cchBuffer, *pcchBuffer) LPWSTR wzBuffer)
6706 if ((cchBuffer == 0) != (wzBuffer == nullptr))
6708 return E_INVALIDARG;
6711 LPCUTF8 szName = m_pPEAssembly->GetSimpleName();
6715 IfFailRet(FString::Utf8_Unicode_Length(szName, &bIsAscii, &cchName));
6717 if (cchBuffer < cchName + 1)
6719 if (pcchBuffer != nullptr)
6721 *pcchBuffer = cchName + 1;
6723 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6727 IfFailRet(FString::Utf8_Unicode(szName, bIsAscii, wzBuffer, cchName));
6728 if (pcchBuffer != nullptr)
6730 *pcchBuffer = cchName;
6736 //------------------------------------------------------------------------------------
6737 STDMETHOD(GetAssemblyVersion)(
6743 WRAPPER_NO_CONTRACT;
6744 return m_pPEAssembly->GetVersion(pMajor, pMinor, pBuild, pRevision);
6747 //------------------------------------------------------------------------------------
6748 STDMETHOD(GetAssemblyPublicKey)(
6753 STATIC_CONTRACT_LIMITED_METHOD;
6754 STATIC_CONTRACT_CAN_TAKE_LOCK;
6756 VALIDATE_PTR_RET(pcbBuffer);
6757 VALIDATE_CONDITION((pbBuffer == nullptr) == (cbBuffer == 0), return E_INVALIDARG);
6763 // Note: PEAssembly::GetPublicKey will return bogus data pointer when *pcbBuffer == 0
6764 LPCVOID pbKey = m_pPEAssembly->GetPublicKey(pcbBuffer);
6766 if (*pcbBuffer != 0)
6768 if (pbBuffer != nullptr && cbBuffer >= *pcbBuffer)
6770 memcpy(pbBuffer, pbKey, *pcbBuffer);
6775 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6780 hr = S_FALSE; // ==> No public key
6783 EX_CATCH_HRESULT(hr);
6789 ReleaseHolder<PEAssembly> m_pPEAssembly;
6792 //-----------------------------------------------------------------------------------------------------------------
6793 static HRESULT VerifyBindHelper(
6794 ICLRPrivAssembly *pPrivAssembly,
6795 IAssemblyName *pAssemblyName,
6796 PEAssembly *pPEAssembly)
6798 STATIC_CONTRACT_THROWS;
6799 STATIC_CONTRACT_GC_TRIGGERS;
6802 // Create an ICLRPrivAssemblyInfo to call to ICLRPrivAssembly::VerifyBind
6803 NewHolder<PEAssemblyAsPrivAssemblyInfo> pPrivAssemblyInfoImpl = new PEAssemblyAsPrivAssemblyInfo(pPEAssembly);
6804 ReleaseHolder<ICLRPrivAssemblyInfo> pPrivAssemblyInfo;
6805 IfFailRet(pPrivAssemblyInfoImpl->QueryInterface(__uuidof(ICLRPrivAssemblyInfo), (LPVOID *)&pPrivAssemblyInfo));
6806 pPrivAssemblyInfoImpl.SuppressRelease();
6808 // Call VerifyBind to give the host a chance to reject the bind based on assembly image contents.
6809 IfFailRet(pPrivAssembly->VerifyBind(pAssemblyName, pPrivAssembly, pPrivAssemblyInfo));
6814 //-----------------------------------------------------------------------------------------------------------------
6815 HRESULT AppDomain::BindAssemblySpecForHostedBinder(
6816 AssemblySpec * pSpec,
6817 IAssemblyName * pAssemblyName,
6818 ICLRPrivBinder * pBinder,
6819 PEAssembly ** ppAssembly)
6821 STANDARD_VM_CONTRACT;
6823 PRECONDITION(CheckPointer(pSpec));
6824 PRECONDITION(pSpec->GetAppDomain() == this);
6825 PRECONDITION(CheckPointer(ppAssembly));
6826 PRECONDITION(pSpec->GetCodeBase() == nullptr);
6831 // The Fusion binder can throw (to preserve compat, since it will actually perform an assembly
6832 // load as part of it's bind), so we need to be careful here to catch any FileNotFoundException
6833 // objects if fThrowIfNotFound is false.
6834 ReleaseHolder<ICLRPrivAssembly> pPrivAssembly;
6836 // We return HRESULTs here on failure instead of throwing as failures here are not necessarily indicative
6837 // of an actual application problem. Returning an error code is substantially faster than throwing, and
6838 // should be used when possible.
6839 IfFailRet(pBinder->BindAssemblyByName(pAssemblyName, &pPrivAssembly));
6841 IfFailRet(BindHostedPrivAssembly(nullptr, pPrivAssembly, pAssemblyName, ppAssembly));
6847 //-----------------------------------------------------------------------------------------------------------------
6849 AppDomain::BindHostedPrivAssembly(
6850 PEAssembly * pParentAssembly,
6851 ICLRPrivAssembly * pPrivAssembly,
6852 IAssemblyName * pAssemblyName,
6853 PEAssembly ** ppAssembly,
6854 BOOL fIsIntrospectionOnly) // = FALSE
6856 STANDARD_VM_CONTRACT;
6858 PRECONDITION(CheckPointer(pPrivAssembly));
6859 PRECONDITION(CheckPointer(ppAssembly));
6863 *ppAssembly = nullptr;
6865 // See if result has been previously loaded.
6867 DomainAssembly* pDomainAssembly = FindAssembly(pPrivAssembly);
6868 if (pDomainAssembly != nullptr)
6870 *ppAssembly = clr::SafeAddRef(pDomainAssembly->GetFile());
6874 if (*ppAssembly != nullptr)
6875 { // Already exists: ask the binder to verify and return the assembly.
6876 return VerifyBindHelper(pPrivAssembly, pAssemblyName, *ppAssembly);
6879 // Get the IL PEFile.
6880 PEImageHolder pPEImageIL;
6882 // Does not already exist, so get the resource for the assembly and load it.
6884 ReleaseHolder<ICLRPrivResource> pIResourceIL;
6886 IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_IL, &dwImageType, &pIResourceIL));
6887 _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_IL);
6889 pPEImageIL = PEImage::OpenImage(pIResourceIL, MDInternalImport_Default);
6892 // See if an NI is available.
6893 DWORD dwAvailableImages;
6894 IfFailRet(pPrivAssembly->GetAvailableImageTypes(&dwAvailableImages));
6895 _ASSERTE(dwAvailableImages & ASSEMBLY_IMAGE_TYPE_IL); // Just double checking that IL bit is always set.
6897 // Get the NI PEFile if available.
6898 PEImageHolder pPEImageNI;
6899 if (dwAvailableImages & ASSEMBLY_IMAGE_TYPE_NATIVE)
6902 ReleaseHolder<ICLRPrivResource> pIResourceNI;
6904 IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_NATIVE, &dwImageType, &pIResourceNI));
6905 _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_NATIVE || FAILED(hr));
6907 pPEImageNI = PEImage::OpenImage(pIResourceNI, MDInternalImport_TrustedNativeImage);
6909 _ASSERTE(pPEImageIL != nullptr);
6911 // Create a PEAssembly using the IL and NI images.
6912 PEAssemblyHolder pPEAssembly = PEAssembly::Open(pParentAssembly, pPEImageIL, pPEImageNI, pPrivAssembly, fIsIntrospectionOnly);
6915 // Ask the binder to verify.
6916 IfFailRet(VerifyBindHelper(pPrivAssembly, pAssemblyName, pPEAssembly));
6919 *ppAssembly = pPEAssembly.Extract();
6922 } // AppDomain::BindHostedPrivAssembly
6924 //---------------------------------------------------------------------------------------------------------------------
6925 PEAssembly * AppDomain::BindAssemblySpec(
6926 AssemblySpec * pSpec,
6927 BOOL fThrowOnFileNotFound,
6928 BOOL fRaisePrebindEvents,
6929 StackCrawlMark * pCallerStackMark,
6930 BOOL fUseHostBinderIfAvailable)
6932 STATIC_CONTRACT_THROWS;
6933 STATIC_CONTRACT_GC_TRIGGERS;
6934 PRECONDITION(CheckPointer(pSpec));
6935 PRECONDITION(pSpec->GetAppDomain() == this);
6936 PRECONDITION(this==::GetAppDomain());
6940 BOOL fForceReThrow = FALSE;
6942 #if defined(FEATURE_COMINTEROP)
6943 // Handle WinRT assemblies in the classic/hybrid scenario. If this is an AppX process,
6944 // then this case will be handled by the previous block as part of the full set of
6945 // available binding hosts.
6946 if (pSpec->IsContentType_WindowsRuntime())
6950 // Get the assembly display name.
6951 ReleaseHolder<IAssemblyName> pAssemblyName;
6953 IfFailThrow(pSpec->CreateFusionName(&pAssemblyName, TRUE, TRUE));
6956 PEAssemblyHolder pAssembly;
6960 hr = BindAssemblySpecForHostedBinder(pSpec, pAssemblyName, m_pWinRtBinder, &pAssembly);
6962 goto EndTry2; // Goto end of try block.
6965 // The combination of this conditional catch/ the following if statement which will throw reduces the count of exceptions
6966 // thrown in scenarios where the exception does not escape the method. We cannot get rid of the try/catch block, as
6967 // there are cases within some of the clrpriv binder's which throw.
6968 // Note: In theory, FileNotFound should always come here as HRESULT, never as exception.
6969 EX_CATCH_HRESULT_IF(hr,
6970 !fThrowOnFileNotFound && Assembly::FileNotFound(hr))
6972 if (FAILED(hr) && (fThrowOnFileNotFound || !Assembly::FileNotFound(hr)))
6974 if (Assembly::FileNotFound(hr))
6976 _ASSERTE(fThrowOnFileNotFound);
6977 // Uses defaultScope
6978 EEFileLoadException::Throw(pSpec, hr);
6981 // WinRT type bind failures
6982 _ASSERTE(pSpec->IsContentType_WindowsRuntime());
6983 if (hr == HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE)) // Returned by RoResolveNamespace when using 3rd party WinRT types in classic process
6985 if (fThrowOnFileNotFound)
6986 { // Throw NotSupportedException (with custom message) wrapped by TypeLoadException to give user type name for diagnostics
6987 // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6988 EEMessageException ex(kNotSupportedException, IDS_EE_WINRT_THIRDPARTY_NOTSUPPORTED);
6989 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
6992 else if ((hr == CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT) || // Returned e.g. for WinRT type name without namespace
6993 (hr == COR_E_PLATFORMNOTSUPPORTED)) // Using WinRT on pre-Win8 OS
6995 if (fThrowOnFileNotFound)
6996 { // Throw ArgumentException/PlatformNotSupportedException wrapped by TypeLoadException to give user type name for diagnostics
6997 // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6998 EEMessageException ex(hr);
6999 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
7007 _ASSERTE((FAILED(hr) && !fThrowOnFileNotFound) || pAssembly != nullptr);
7009 return pAssembly.Extract();
7012 #endif // FEATURE_COMINTEROP
7013 if (pSpec->HasUniqueIdentity())
7015 HRESULT hrBindResult = S_OK;
7016 PEAssemblyHolder result;
7021 if (!IsCached(pSpec))
7025 bool fAddFileToCache = false;
7027 BOOL fIsWellKnown = FALSE;
7029 // Use CoreClr's fusion alternative
7030 CoreBindResult bindResult;
7032 pSpec->Bind(this, fThrowOnFileNotFound, &bindResult, FALSE /* fNgenExplicitBind */, FALSE /* fExplicitBindToNativeImage */, pCallerStackMark);
7033 hrBindResult = bindResult.GetHRBindResult();
7035 if (bindResult.Found())
7037 if (SystemDomain::SystemFile() && bindResult.IsMscorlib())
7039 // Avoid rebinding to another copy of mscorlib
7040 result = SystemDomain::SystemFile();
7041 result.SuppressRelease(); // Didn't get a refcount
7045 // IsSystem on the PEFile should be false, even for mscorlib satellites
7046 result = PEAssembly::Open(&bindResult,
7047 FALSE, pSpec->IsIntrospectionOnly());
7049 fAddFileToCache = true;
7051 // Setup the reference to the binder, which performed the bind, into the AssemblySpec
7052 ICLRPrivBinder* pBinder = result->GetBindingContext();
7053 _ASSERTE(pBinder != NULL);
7054 pSpec->SetBindingContext(pBinder);
7058 if (fAddFileToCache)
7062 if (pSpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
7064 // Failure to add simply means someone else beat us to it. In that case
7065 // the FindCachedFile call below (after catch block) will update result
7066 // to the cached value.
7067 AddFileToCache(pSpec, result, TRUE /*fAllowFailure*/);
7070 else if (!fIsWellKnown)
7072 _ASSERTE(fThrowOnFileNotFound == FALSE);
7074 // Don't trigger the resolve event for the CoreLib satellite assembly. A misbehaving resolve event may
7075 // return an assembly that does not match, and this can cause recursive resource lookups during error
7076 // reporting. The CoreLib satellite assembly is loaded from relative locations based on the culture, see
7077 // AssemblySpec::Bind().
7078 if (!pSpec->IsMscorlibSatellite())
7080 // Trigger the resolve event also for non-throw situation.
7081 // However, this code path will behave as if the resolve handler has thrown,
7082 // that is, not trigger an MDA.
7084 AssemblySpec NewSpec(this);
7085 AssemblySpec *pFailedSpec = NULL;
7087 fForceReThrow = TRUE; // Managed resolve event handler can throw
7089 // Purposly ignore return value
7090 PostBindResolveAssembly(pSpec, &NewSpec, hrBindResult, &pFailedSpec);
7098 Exception *ex = GET_EXCEPTION();
7100 AssemblySpec NewSpec(this);
7101 AssemblySpec *pFailedSpec = NULL;
7103 // Let transient exceptions or managed resolve event handler exceptions propagate
7104 if (ex->IsTransient() || fForceReThrow)
7110 // This is not executed for SO exceptions so we need to disable the backout
7111 // stack validation to prevent false violations from being reported.
7112 DISABLE_BACKOUT_STACK_VALIDATION;
7114 BOOL fFailure = PostBindResolveAssembly(pSpec, &NewSpec, ex->GetHR(), &pFailedSpec);
7117 BOOL bFileNotFoundException =
7118 (EEFileLoadException::GetFileLoadKind(ex->GetHR()) == kFileNotFoundException);
7120 if (!bFileNotFoundException)
7122 fFailure = AddExceptionToCache(pFailedSpec, ex);
7123 } // else, fFailure stays TRUE
7124 // Effectively, fFailure == bFileNotFoundException || AddExceptionToCache(pFailedSpec, ex)
7126 // Only throw this exception if we are the first in the cache
7130 // If the BindingFailure MDA is enabled, trigger one for this failure
7131 // Note: TryResolveAssembly() can also throw if an AssemblyResolve event subscriber throws
7132 // and the MDA isn't sent in this case (or for transient failure cases)
7134 #ifdef MDA_SUPPORTED
7135 MdaBindingFailure* pProbe = MDA_GET_ASSISTANT(BindingFailure);
7138 // Transition to cooperative GC mode before using any OBJECTREFs.
7141 OBJECTREF exceptionObj = GET_THROWABLE();
7142 GCPROTECT_BEGIN(exceptionObj)
7144 pProbe->BindFailed(pFailedSpec, &exceptionObj);
7150 // In the same cases as for the MDA, store the failure information for DAC to read
7151 if (IsDebuggerAttached()) {
7152 FailedAssembly *pFailed = new FailedAssembly();
7153 pFailed->Initialize(pFailedSpec, ex);
7154 IfFailThrow(m_failedAssemblies.Append(pFailed));
7157 if (!bFileNotFoundException || fThrowOnFileNotFound)
7160 // V1.1 App-compatibility workaround. See VSW530166 if you want to whine about it.
7162 // In Everett, if we failed to download an assembly because of a broken network cable,
7163 // we returned a FileNotFoundException with a COR_E_FILENOTFOUND hr embedded inside
7164 // (which would be exposed when marshaled to native.)
7166 // In Whidbey, we now set the more appropriate INET_E_RESOURCE_NOT_FOUND hr. But
7167 // the online/offline switch code in VSTO for Everett hardcoded a check for
7168 // COR_E_FILENOTFOUND.
7170 // So now, to keep that code from breaking, we have to remap INET_E_RESOURCE_NOT_FOUND
7171 // back to COR_E_FILENOTFOUND. We're doing it here rather down in Fusion so as to affect
7172 // the least number of callers.
7174 if (ex->GetHR() == INET_E_RESOURCE_NOT_FOUND)
7176 EEFileLoadException::Throw(pFailedSpec, COR_E_FILENOTFOUND, ex);
7179 if (EEFileLoadException::CheckType(ex))
7181 if (pFailedSpec == pSpec)
7183 EX_RETHROW; //preserve the information
7187 StackSString exceptionDisplayName, failedSpecDisplayName;
7189 ((EEFileLoadException*)ex)->GetName(exceptionDisplayName);
7190 pFailedSpec->GetFileOrDisplayName(0, failedSpecDisplayName);
7192 if (exceptionDisplayName.CompareCaseInsensitive(failedSpecDisplayName) == 0)
7194 EX_RETHROW; // Throw the original exception. Otherwise, we'd throw an exception that contains the same message twice.
7199 EEFileLoadException::Throw(pFailedSpec, ex->GetHR(), ex);
7206 EX_END_CATCH(RethrowTerminalExceptions);
7208 // Now, if it's a cacheable bind we need to re-fetch the result from the cache, as we may have been racing with another
7209 // thread to store our result. Note that we may throw from here, if there is a cached exception.
7210 // This will release the refcount of the current result holder (if any), and will replace
7211 // it with a non-addref'ed result
7212 if (pSpec->CanUseWithBindingCache() && (result== NULL || result->CanUseWithBindingCache()))
7214 result = FindCachedFile(pSpec);
7220 return result.Extract();
7224 // Unsupported content type
7225 if (fThrowOnFileNotFound)
7227 ThrowHR(COR_E_BADIMAGEFORMAT);
7231 } // AppDomain::BindAssemblySpec
7235 PEAssembly *AppDomain::TryResolveAssembly(AssemblySpec *pSpec, BOOL fPreBind)
7237 STATIC_CONTRACT_THROWS;
7238 STATIC_CONTRACT_GC_TRIGGERS;
7239 STATIC_CONTRACT_MODE_ANY;
7241 PEAssembly *result = NULL;
7245 result = pSpec->ResolveAssemblyFile(this, fPreBind);
7249 Exception *pEx = GET_EXCEPTION();
7251 if (!pEx->IsTransient())
7253 AddExceptionToCache(pSpec, pEx);
7254 if (!EEFileLoadException::CheckType(pEx))
7255 EEFileLoadException::Throw(pSpec, pEx->GetHR(), pEx);
7264 ULONG AppDomain::AddRef()
7266 LIMITED_METHOD_CONTRACT;
7267 return InterlockedIncrement(&m_cRef);
7270 ULONG AppDomain::Release()
7277 PRECONDITION(m_cRef > 0);
7281 ULONG cRef = InterlockedDecrement(&m_cRef);
7284 _ASSERTE (m_Stage == STAGE_CREATING || m_Stage == STAGE_CLOSED);
7287 TESTHOOKCALL(AppDomainDestroyed(adid.m_dwId));
7293 AppDomain* AppDomain::s_pAppDomainToRaiseUnloadEvent;
7294 BOOL AppDomain::s_fProcessUnloadDomainEvent = FALSE;
7296 #ifndef CROSSGEN_COMPILE
7298 void AppDomain::RaiseUnloadDomainEvent_Wrapper(LPVOID ptr)
7305 INJECT_FAULT(COMPlusThrowOM(););
7310 AppDomain* pDomain = (AppDomain *) ptr;
7311 pDomain->RaiseUnloadDomainEvent();
7314 void AppDomain::ProcessUnloadDomainEventOnFinalizeThread()
7323 Thread *pThread = GetThread();
7324 _ASSERTE (pThread && IsFinalizerThread());
7326 // if we are not unloading domain now, do not process the event
7327 if (SystemDomain::AppDomainBeingUnloaded() == NULL)
7329 s_pAppDomainToRaiseUnloadEvent->SetStage(STAGE_UNLOAD_REQUESTED);
7330 s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
7331 s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7332 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
7335 FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, TRUE);
7336 AppDomain::EnableADUnloadWorkerForFinalizer();
7337 pThread->SetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
7338 s_pAppDomainToRaiseUnloadEvent->RaiseUnloadDomainEvent();
7339 pThread->ResetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
7340 s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
7341 s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7342 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
7343 FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, FALSE);
7345 if (pThread->IsAbortRequested())
7347 pThread->UnmarkThreadForAbort(Thread::TAR_Thread);
7351 void AppDomain::RaiseUnloadDomainEvent()
7362 Thread *pThread = GetThread();
7363 if (this != pThread->GetDomain())
7365 pThread->DoADCallBack(this, AppDomain::RaiseUnloadDomainEvent_Wrapper, this,ADV_FINALIZER|ADV_COMPILATION);
7371 APPDOMAINREF Domain;
7374 ZeroMemory(&gc, sizeof(gc));
7376 GCPROTECT_BEGIN(gc);
7377 gc.Domain = (APPDOMAINREF) GetRawExposedObject();
7378 if (gc.Domain != NULL)
7380 gc.Delegate = gc.Domain->m_pDomainUnloadEventHandler;
7381 if (gc.Delegate != NULL)
7382 DistributeEvent(&gc.Delegate, (OBJECTREF *) &gc.Domain);
7388 void AppDomain::RaiseLoadingAssemblyEvent(DomainAssembly *pAssembly)
7394 PRECONDITION(this == GetAppDomain());
7401 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
7406 APPDOMAINREF AppDomainRef;
7409 ZeroMemory(&gc, sizeof(gc));
7411 if ((gc.AppDomainRef = (APPDOMAINREF) GetRawExposedObject()) != NULL) {
7412 if (gc.AppDomainRef->m_pAssemblyEventHandler != NULL)
7415 GCPROTECT_BEGIN(gc);
7417 gc.orThis = pAssembly->GetExposedAssemblyObject();
7419 MethodDescCallSite onAssemblyLoad(METHOD__APP_DOMAIN__ON_ASSEMBLY_LOAD, &gc.orThis);
7421 // GetExposedAssemblyObject may cause a gc, so call this before filling args[0]
7422 args[1] = ObjToArgSlot(gc.orThis);
7423 args[0] = ObjToArgSlot(gc.AppDomainRef);
7425 onAssemblyLoad.Call(args);
7434 EX_END_CATCH(SwallowAllExceptions);
7438 BOOL AppDomain::OnUnhandledException(OBJECTREF *pThrowable, BOOL isTerminating/*=TRUE*/)
7440 STATIC_CONTRACT_NOTHROW;
7441 STATIC_CONTRACT_GC_TRIGGERS;
7442 STATIC_CONTRACT_MODE_ANY;
7448 // The Everett behavior was to send the unhandled exception event only to the Default
7449 // AppDomain (since that's the only place that exceptions actually went unhandled).
7451 // During Whidbey development, we broadcast the event to all AppDomains in the process.
7453 // But the official shipping Whidbey behavior is that the unhandled exception event is
7454 // sent to the Default AppDomain and to whatever AppDomain the exception went unhandled
7455 // in. To achieve this, we declare the exception to be unhandled *BEFORE* we marshal
7456 // it back to the Default AppDomain at the base of the Finalizer, threadpool and managed
7459 // The rationale for sending the event to the Default AppDomain as well as the one the
7460 // exception went unhandled in is:
7462 // 1) This is compatible with the pre-Whidbey behavior, where only the Default AppDomain
7463 // received the notification.
7465 // 2) This is convenient for hosts, which don't want to bother injecting listeners into
7466 // every single AppDomain.
7468 AppDomain *pAppDomain = GetAppDomain();
7469 OBJECTREF orSender = 0;
7471 GCPROTECT_BEGIN(orSender);
7473 orSender = pAppDomain->GetRawExposedObject();
7475 retVal = pAppDomain->RaiseUnhandledExceptionEventNoThrow(&orSender, pThrowable, isTerminating);
7483 // Move outside of the AppDomain iteration, to avoid issues with the GC Frames being outside
7484 // the domain transition. This is a chronic issue that causes us to report roots for an AppDomain
7485 // after we have left it. This causes problems with AppDomain unloading that we only find
7486 // with stress coverage..
7487 void AppDomain::RaiseOneExitProcessEvent()
7499 APPDOMAINREF Domain;
7502 ZeroMemory(&gc, sizeof(gc));
7504 GCPROTECT_BEGIN(gc);
7505 gc.Domain = (APPDOMAINREF) SystemDomain::GetCurrentDomain()->GetRawExposedObject();
7506 if (gc.Domain != NULL)
7508 gc.Delegate = gc.Domain->m_pProcessExitEventHandler;
7509 if (gc.Delegate != NULL)
7510 DistributeEvent(&gc.Delegate, (OBJECTREF *) &gc.Domain);
7515 // Local wrapper used in AppDomain::RaiseExitProcessEvent,
7516 // introduced solely to avoid stack overflow because of _alloca in the loop.
7517 // It's just factored out body of the loop, but it has to be a member method of AppDomain,
7518 // because it calls private RaiseOneExitProcessEvent
7519 /*static*/ void AppDomain::RaiseOneExitProcessEvent_Wrapper(AppDomainIterator* pi)
7521 STATIC_CONTRACT_MODE_COOPERATIVE;
7522 STATIC_CONTRACT_THROWS;
7523 STATIC_CONTRACT_GC_TRIGGERS;
7525 ENTER_DOMAIN_PTR(pi->GetDomain(), ADV_ITERATOR)
7526 AppDomain::RaiseOneExitProcessEvent();
7527 END_DOMAIN_TRANSITION;
7530 static LONG s_ProcessedExitProcessEventCount = 0;
7532 LONG GetProcessedExitProcessEventCount()
7534 LIMITED_METHOD_CONTRACT;
7535 return s_ProcessedExitProcessEventCount;
7538 void AppDomain::RaiseExitProcessEvent()
7543 STATIC_CONTRACT_MODE_COOPERATIVE;
7544 STATIC_CONTRACT_THROWS;
7545 STATIC_CONTRACT_GC_TRIGGERS;
7547 // Only finalizer thread during shutdown can call this function.
7548 _ASSERTE ((g_fEEShutDown&ShutDown_Finalize1) && GetThread() == FinalizerThread::GetFinalizerThread());
7550 _ASSERTE (GetThread()->PreemptiveGCDisabled());
7552 _ASSERTE (GetThread()->GetDomain()->IsDefaultDomain());
7554 AppDomainIterator i(TRUE);
7557 RaiseOneExitProcessEvent_Wrapper(&i);
7558 FastInterlockIncrement(&s_ProcessedExitProcessEventCount);
7564 AppDomain::RaiseUnhandledExceptionEventNoThrow(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating)
7577 bRetVal = RaiseUnhandledExceptionEvent(pSender, pThrowable, isTerminating);
7582 EX_END_CATCH(SwallowAllExceptions) // Swallow any errors.
7588 AppDomain::HasUnhandledExceptionEventHandler()
7593 GC_NOTRIGGER; //essential
7597 if (!CanThreadEnter(GetThread()))
7599 if (GetRawExposedObject()==NULL)
7601 return (((APPDOMAINREF)GetRawExposedObject())->m_pUnhandledExceptionEventHandler!=NULL);
7605 AppDomain::RaiseUnhandledExceptionEvent(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating)
7612 INJECT_FAULT(COMPlusThrowOM(););
7616 if (!HasUnhandledExceptionEventHandler())
7619 BOOL result = FALSE;
7621 _ASSERTE(pThrowable != NULL && IsProtectedByGCFrame(pThrowable));
7622 _ASSERTE(pSender != NULL && IsProtectedByGCFrame(pSender));
7624 _ASSERTE(this == GetThread()->GetDomain());
7627 OBJECTREF orDelegate = NULL;
7629 GCPROTECT_BEGIN(orDelegate);
7631 APPDOMAINREF orAD = (APPDOMAINREF) GetAppDomain()->GetRawExposedObject();
7635 orDelegate = orAD->m_pUnhandledExceptionEventHandler;
7636 if (orDelegate != NULL)
7639 DistributeUnhandledExceptionReliably(&orDelegate, pSender, pThrowable, isTerminating);
7648 #endif // CROSSGEN_COMPILE
7650 // You must be in the correct context before calling this
7651 // routine. Therefore, it is only good for initializing the
7653 void AppDomain::InitializeDomainContext(BOOL allowRedirects,
7662 INJECT_FAULT(COMPlusThrowOM(););
7666 if (NingenEnabled())
7669 CreateFusionContext();
7674 #ifndef CROSSGEN_COMPILE
7676 STRINGREF pFilePath;
7679 PTRARRAYREF propertyNames;
7680 PTRARRAYREF propertyValues;
7682 ZeroMemory(&gc, sizeof(gc));
7684 GCPROTECT_BEGIN(gc);
7687 gc.pFilePath = StringObject::NewString(pwszPath);
7692 gc.pConfig = StringObject::NewString(pwszConfig);
7696 if ((gc.ref = GetExposedObject()) != NULL)
7698 MethodDescCallSite setupDomain(METHOD__APP_DOMAIN__SETUP_DOMAIN);
7702 ObjToArgSlot(gc.ref),
7703 BoolToArgSlot(allowRedirects),
7704 ObjToArgSlot(gc.pFilePath),
7705 ObjToArgSlot(gc.pConfig),
7706 ObjToArgSlot(gc.propertyNames),
7707 ObjToArgSlot(gc.propertyValues)
7709 setupDomain.Call(args);
7713 CacheStringsForDAC();
7714 #endif // CROSSGEN_COMPILE
7718 IUnknown *AppDomain::CreateFusionContext()
7720 CONTRACT(IUnknown *)
7725 POSTCONDITION(CheckPointer(RETVAL));
7726 INJECT_FAULT(COMPlusThrowOM(););
7730 if (!m_pFusionContext)
7732 ETWOnStartup (FusionAppCtx_V1, FusionAppCtxEnd_V1);
7733 CLRPrivBinderCoreCLR *pTPABinder = NULL;
7737 // Initialize the assembly binder for the default context loads for CoreCLR.
7738 IfFailThrow(CCoreCLRBinderHelper::DefaultBinderSetupContext(GetId().m_dwId, &pTPABinder));
7739 m_pFusionContext = reinterpret_cast<IUnknown *>(pTPABinder);
7741 // By default, initial binding context setup for CoreCLR is also the TPABinding context
7742 (m_pTPABinderContext = pTPABinder)->AddRef();
7746 RETURN m_pFusionContext;
7751 //---------------------------------------------------------------------------------------
7753 // AppDomain::IsDebuggerAttached - is a debugger attached to this process
7759 // TRUE if a debugger is attached to this process, FALSE otherwise.
7762 // This is identical to CORDebuggerAttached. This exists idependantly for legacy reasons - we used to
7763 // support attaching to individual AppDomains. This should probably go away eventually.
7766 BOOL AppDomain::IsDebuggerAttached()
7768 LIMITED_METHOD_CONTRACT;
7770 if (CORDebuggerAttached())
7780 #ifdef DEBUGGING_SUPPORTED
7782 // This is called from the debugger to request notification events from
7783 // Assemblies, Modules, Types in this appdomain.
7784 BOOL AppDomain::NotifyDebuggerLoad(int flags, BOOL attaching)
7786 WRAPPER_NO_CONTRACT;
7787 BOOL result = FALSE;
7789 if (!attaching && !IsDebuggerAttached())
7794 // Attach to our assemblies
7795 LOG((LF_CORDB, LL_INFO100, "AD::NDA: Iterating assemblies\n"));
7796 i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution));
7797 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7798 while (i.Next(pDomainAssembly.This()))
7800 result = (pDomainAssembly->NotifyDebuggerLoad(flags, attaching) ||
7807 void AppDomain::NotifyDebuggerUnload()
7809 WRAPPER_NO_CONTRACT;
7810 if (!IsDebuggerAttached())
7813 LOG((LF_CORDB, LL_INFO10, "AD::NDD domain [%d] %#08x %ls\n",
7814 GetId().m_dwId, this, GetFriendlyNameForLogging()));
7816 LOG((LF_CORDB, LL_INFO100, "AD::NDD: Interating domain bound assemblies\n"));
7817 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution));
7818 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7820 // Detach from our assemblies
7821 while (i.Next(pDomainAssembly.This()))
7823 LOG((LF_CORDB, LL_INFO100, "AD::NDD: Iterating assemblies\n"));
7824 pDomainAssembly->NotifyDebuggerUnload();
7827 #endif // DEBUGGING_SUPPORTED
7829 void AppDomain::SetSystemAssemblyLoadEventSent(BOOL fFlag)
7831 LIMITED_METHOD_CONTRACT;
7833 m_dwFlags |= LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
7835 m_dwFlags &= ~LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
7838 BOOL AppDomain::WasSystemAssemblyLoadEventSent(void)
7840 LIMITED_METHOD_CONTRACT;
7841 return ((m_dwFlags & LOAD_SYSTEM_ASSEMBLY_EVENT_SENT) == 0) ? FALSE : TRUE;
7844 #ifndef CROSSGEN_COMPILE
7845 // U->M thunks created in this domain and not associated with a delegate.
7846 UMEntryThunkCache *AppDomain::GetUMEntryThunkCache()
7853 INJECT_FAULT(COMPlusThrowOM(););
7857 if (!m_pUMEntryThunkCache)
7859 UMEntryThunkCache *pUMEntryThunkCache = new UMEntryThunkCache(this);
7861 if (FastInterlockCompareExchangePointer(&m_pUMEntryThunkCache, pUMEntryThunkCache, NULL) != NULL)
7863 // some thread swooped in and set the field
7864 delete pUMEntryThunkCache;
7867 _ASSERTE(m_pUMEntryThunkCache);
7868 return m_pUMEntryThunkCache;
7871 #ifdef FEATURE_COMINTEROP
7873 ComCallWrapperCache *AppDomain::GetComCallWrapperCache()
7880 INJECT_FAULT(COMPlusThrowOM(););
7884 if (! m_pComCallWrapperCache)
7886 BaseDomain::LockHolder lh(this);
7888 if (! m_pComCallWrapperCache)
7889 m_pComCallWrapperCache = ComCallWrapperCache::Create(this);
7891 _ASSERTE(m_pComCallWrapperCache);
7892 return m_pComCallWrapperCache;
7895 RCWRefCache *AppDomain::GetRCWRefCache()
7897 CONTRACT(RCWRefCache*)
7902 POSTCONDITION(CheckPointer(RETVAL));
7906 if (!m_pRCWRefCache) {
7907 NewHolder<RCWRefCache> pRCWRefCache = new RCWRefCache(this);
7908 if (FastInterlockCompareExchangePointer(&m_pRCWRefCache, (RCWRefCache *)pRCWRefCache, NULL) == NULL)
7910 pRCWRefCache.SuppressRelease();
7913 RETURN m_pRCWRefCache;
7916 RCWCache *AppDomain::CreateRCWCache()
7923 INJECT_FAULT(COMPlusThrowOM(););
7924 POSTCONDITION(CheckPointer(RETVAL));
7928 // Initialize the global RCW cleanup list here as well. This is so that it
7929 // it guaranteed to exist if any RCW's are created, but it is not created
7931 if (!g_pRCWCleanupList)
7933 SystemDomain::LockHolder lh;
7935 if (!g_pRCWCleanupList)
7936 g_pRCWCleanupList = new RCWCleanupList();
7938 _ASSERTE(g_pRCWCleanupList);
7941 BaseDomain::LockHolder lh(this);
7944 m_pRCWCache = new RCWCache(this);
7950 void AppDomain::ReleaseRCWs(LPVOID pCtxCookie)
7952 WRAPPER_NO_CONTRACT;
7954 m_pRCWCache->ReleaseWrappersWorker(pCtxCookie);
7956 RemoveWinRTFactoryObjects(pCtxCookie);
7959 void AppDomain::DetachRCWs()
7961 WRAPPER_NO_CONTRACT;
7963 m_pRCWCache->DetachWrappersWorker();
7966 #endif // FEATURE_COMINTEROP
7968 BOOL AppDomain::CanThreadEnter(Thread *pThread)
7970 WRAPPER_NO_CONTRACT;
7972 if (m_Stage < STAGE_EXITED)
7975 if (pThread == SystemDomain::System()->GetUnloadingThread())
7976 return m_Stage < STAGE_FINALIZING;
7977 if (pThread == FinalizerThread::GetFinalizerThread())
7978 return m_Stage < STAGE_FINALIZED;
7983 void AppDomain::AllowThreadEntrance(AppDomain * pApp)
7991 PRECONDITION(CheckPointer(pApp));
7995 if (pApp->GetUnloadRequestThread() == NULL)
7997 // This is asynchonous unload, either by a host, or by AppDomain.Unload from AD unload event.
7998 if (!pApp->IsUnloadingFromUnloadEvent())
8000 pApp->SetStage(STAGE_UNLOAD_REQUESTED);
8001 pApp->EnableADUnloadWorker(
8002 pApp->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
8007 SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
8009 #ifdef FEATURE_COMINTEROP
8010 if (pApp->m_pComCallWrapperCache)
8011 pApp->m_pComCallWrapperCache->ResetDomainIsUnloading();
8012 #endif // FEATURE_COMINTEROP
8014 pApp->SetStage(STAGE_OPEN);
8017 void AppDomain::RestrictThreadEntrance(AppDomain * pApp)
8022 DISABLED(GC_TRIGGERS);
8024 DISABLED(FORBID_FAULT);
8025 PRECONDITION(CheckPointer(pApp));
8029 #ifdef FEATURE_COMINTEROP
8030 // Set the flag on our CCW cache so stubs won't enter
8031 if (pApp->m_pComCallWrapperCache)
8032 pApp->m_pComCallWrapperCache->SetDomainIsUnloading();
8033 #endif // FEATURE_COMINTEROP
8035 SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
8036 // Release our ID so remoting and thread pool won't enter
8037 pApp->SetStage(STAGE_EXITED);
8040 void AppDomain::Exit(BOOL fRunFinalizers, BOOL fAsyncExit)
8050 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Exiting domain [%d] %#08x %ls\n",
8051 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8053 RestrictEnterHolder RestrictEnter(this);
8056 SystemDomain::LockHolder lh; // we don't want to close appdomain if other thread can be preparing to unload it
8057 SetStage(STAGE_EXITING); // Note that we're trying to exit
8060 // Raise the event indicating the domain is being unloaded.
8061 if (GetDefaultContext())
8063 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, this);
8065 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8066 //if (timeout == INFINITE)
8068 // timeout = 20000; // 20 seconds
8070 DWORD timeoutForFinalizer = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
8071 ULONGLONG curTime = CLRGetTickCount64();
8072 ULONGLONG endTime = 0;
8073 if (timeout != INFINITE)
8075 endTime = curTime + timeout;
8076 // We will try to kill AD unload event if it takes too long, and then we move on to the next registered caller.
8080 while (s_pAppDomainToRaiseUnloadEvent != NULL)
8082 FinalizerThread::FinalizerThreadWait(s_fProcessUnloadDomainEvent?timeout:timeoutForFinalizer);
8083 if (endTime != 0 && s_pAppDomainToRaiseUnloadEvent != NULL)
8085 if (CLRGetTickCount64() >= endTime)
8088 sThreadId.Printf(W("%x"), FinalizerThread::GetFinalizerThread()->GetThreadId());
8089 COMPlusThrow(kCannotUnloadAppDomainException,
8090 IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD,
8097 // Tell the tiered compilation manager to stop initiating any new work for background
8098 // jit optimization. Its possible the standard thread unwind mechanisms would pre-emptively
8099 // evacuate the jit threadpool worker threads from the domain on their own, but I see no reason
8100 // to take the risk of relying on them when we can easily augment with a cooperative
8101 // shutdown check. This notification only initiates the process of evacuating the threads
8102 // and then the UnwindThreads() call below is where blocking will occur to ensure the threads
8103 // have exited the domain.
8105 #ifdef FEATURE_TIERED_COMPILATION
8106 m_tieredCompilationManager.Shutdown(FALSE);
8110 // Set up blocks so no threads can enter except for the finalizer and the thread
8111 // doing the unload.
8114 RestrictThreadEntrance(this);
8116 // Cause existing threads to abort out of this domain. This should ensure all
8117 // normal threads are outside the domain, and we've already ensured that no new threads
8120 PerAppDomainTPCountList::AppDomainUnloadingHolder tpAdUnloadHolder(GetTPIndex());
8123 if (!NingenEnabled())
8128 TESTHOOKCALL(UnwoundThreads(GetId().m_dwId)) ;
8129 ProcessEventForHost(Event_DomainUnload, (PVOID)(UINT_PTR)GetId().m_dwId);
8131 RestrictEnter.SuppressRelease(); //after this point we don't guarantee appdomain consistency
8132 #ifdef PROFILING_SUPPORTED
8133 // Signal profile if present.
8135 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
8137 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) this);
8140 #endif // PROFILING_SUPPORTED
8141 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains--);
8142 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomainsUnloaded++);
8144 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is exited.\n",
8145 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8147 // Send ETW events for this domain's unload and potentially iterate through this
8148 // domain's modules & assemblies to send events for their unloads as well. This
8149 // needs to occur before STAGE_FINALIZED (to ensure everything is there), so we do
8150 // this before any finalization occurs at all.
8151 ETW::LoaderLog::DomainUnload(this);
8153 CodeVersionManager::OnAppDomainExit(this);
8156 // Spin running finalizers until we flush them all. We need to make multiple passes
8157 // in case the finalizers create more finalizable objects. This is important to clear
8158 // the finalizable objects as roots, as well as to actually execute the finalizers. This
8159 // will only finalize instances instances of types that aren't potentially agile becuase we can't
8160 // risk finalizing agile objects. So we will be left with instances of potentially agile types
8161 // in handles or statics.
8163 // <TODO>@todo: Need to ensure this will terminate in a reasonable amount of time. Eventually
8164 // we should probably start passing FALSE for fRunFinalizers. Also I'm not sure we
8165 // guarantee that FinalizerThreadWait will ever terminate in general.</TODO>
8168 SetStage(STAGE_FINALIZING);
8170 // Flush finalizers now.
8171 FinalizerThread::UnloadAppDomain(this, fRunFinalizers);
8173 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8174 ULONGLONG startTime = CLRGetTickCount64();
8175 ULONGLONG elapsedTime = 0;
8176 DWORD finalizerWait = 0;
8178 while (FinalizerThread::GetUnloadingAppDomain() != NULL)
8181 if (timeout != INFINITE)
8183 elapsedTime = CLRGetTickCount64() - startTime;
8185 if (timeout > elapsedTime)
8187 finalizerWait = timeout - static_cast<DWORD>(elapsedTime);
8189 FinalizerThread::FinalizerThreadWait(finalizerWait); //will set stage to finalized
8190 if (timeout != INFINITE && FinalizerThread::GetUnloadingAppDomain() != NULL)
8192 elapsedTime = CLRGetTickCount64() - startTime;
8193 if (timeout <= elapsedTime)
8196 // TODO: Consider escalation from RudeAppDomain
8202 tpAdUnloadHolder.SuppressRelease();
8203 PerAppDomainTPCountList::ResetAppDomainTPCounts(GetTPIndex());
8205 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is finalized.\n",
8206 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8209 AppDomainRefHolder This(this);
8210 AddRef(); // Hold a reference so CloseDomain won't delete us yet
8211 CloseDomain(); // Remove ourself from the list of app domains
8213 // This needs to be done prior to destroying the handle tables below.
8214 ReleaseDomainBoundInfo();
8217 // It should be impossible to run non-mscorlib code in this domain now.
8218 // Cleanup all of our roots except the handles. We do this to allow as many
8219 // finalizers as possible to run correctly. If we delete the handles, they
8222 if (!NingenEnabled())
8229 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is cleared.\n",
8230 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8232 if (fAsyncExit && fRunFinalizers)
8235 m_AssemblyCache.Clear();
8236 ClearFusionContext();
8238 if (!NingenEnabled())
8240 AddMemoryPressure();
8243 SystemDomain::System()->AddToDelayedUnloadList(this, fAsyncExit);
8244 SystemDomain::SetUnloadDomainCleared();
8245 if (m_dwId.m_dwId!=0)
8246 SystemDomain::ReleaseAppDomainId(m_dwId);
8247 #ifdef PROFILING_SUPPORTED
8248 // Always signal profile if present, even when failed.
8250 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
8252 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) this, S_OK);
8255 #endif // PROFILING_SUPPORTED
8259 void AppDomain::Close()
8268 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is collected.\n",
8269 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8272 #if CHECK_APP_DOMAIN_LEAKS
8273 if (g_pConfig->AppDomainLeaks())
8274 // at this point shouldn't have any non-agile objects in the heap because we finalized all the non-agile ones.
8275 SyncBlockCache::GetSyncBlockCache()->CheckForUnloadedInstances(GetIndex());
8276 #endif // CHECK_APP_DOMAIN_LEAKS
8279 RemoveMemoryPressure();
8281 _ASSERTE(m_cRef>0); //should be alive at this point otherwise iterator can revive us and crash
8283 SystemDomain::LockHolder lh; // Avoid races with AppDomainIterator
8284 SetStage(STAGE_CLOSED);
8287 // CONSIDER: move releasing remoting cache from managed code to here.
8291 void AppDomain::ResetUnloadRequestThread(ADID Id)
8297 PRECONDITION(!IsADUnloadHelperThread());
8302 AppDomainFromIDHolder ad(Id, TRUE);
8303 if(!ad.IsUnloaded() && ad->m_Stage < STAGE_UNLOAD_REQUESTED)
8305 Thread *pThread = ad->GetUnloadRequestThread();
8306 if(pThread==GetThread())
8308 ad->m_dwThreadsStillInAppDomain=(ULONG)-1;
8312 if (pThread->GetUnloadBoundaryFrame() && pThread->IsBeingAbortedForADUnload())
8314 pThread->UnmarkThreadForAbort(Thread::TAR_ADUnload);
8316 ad->GetUnloadRequestThread()->ResetUnloadBoundaryFrame();
8317 pThread->ResetBeginAbortedForADUnload();
8320 ad->SetUnloadRequestThread(NULL);
8326 int g_fADUnloadWorkerOK = -1;
8328 HRESULT AppDomain::UnloadById(ADID dwId, BOOL fSync,BOOL fExceptionsPassThrough)
8332 if(fExceptionsPassThrough) {THROWS;} else {NOTHROW;}
8334 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
8339 if (dwId==(ADID)DefaultADID)
8340 return COR_E_CANNOTUNLOADAPPDOMAIN;
8342 Thread *pThread = GetThread();
8344 // Finalizer thread can not wait until AD unload is done,
8345 // because AD unload is going to wait for Finalizer Thread.
8346 if (fSync && pThread == FinalizerThread::GetFinalizerThread() &&
8347 !pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent))
8348 return COR_E_CANNOTUNLOADAPPDOMAIN;
8351 // AD unload helper thread should have been created.
8352 _ASSERTE (g_fADUnloadWorkerOK == 1);
8354 _ASSERTE (!IsADUnloadHelperThread());
8356 BOOL fIsRaisingUnloadEvent = (pThread != NULL && pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent));
8358 if (fIsRaisingUnloadEvent)
8360 AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_GC);
8362 if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
8363 return COR_E_APPDOMAINUNLOADED;
8365 pApp->EnableADUnloadWorker();
8371 ADUnloadSinkHolder pSink;
8374 SystemDomain::LockHolder ulh;
8376 AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_ADLock);
8378 if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
8379 return COR_E_APPDOMAINUNLOADED;
8381 if (g_fADUnloadWorkerOK != 1)
8384 return E_UNEXPECTED;
8389 pApp->EnableADUnloadWorker();
8393 pSink = pApp->PrepareForWaitUnloadCompletion();
8395 pApp->EnableADUnloadWorker();
8397 // release the holders - we don't care anymore if the appdomain is gone
8400 #ifdef FEATURE_TESTHOOKS
8401 if (fExceptionsPassThrough)
8403 CONTRACT_VIOLATION(FaultViolation);
8404 return UnloadWaitNoCatch(dwId,pSink);
8408 return UnloadWait(dwId,pSink);
8411 HRESULT AppDomain::UnloadWait(ADID Id, ADUnloadSink * pSink)
8417 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
8424 // IF you ever try to change this to something not using events, please address the fact that
8425 // AppDomain::StopEEAndUnwindThreads relies on that events are used.
8427 pSink->WaitUnloadCompletion();
8429 EX_CATCH_HRESULT(hr);
8432 hr=pSink->GetUnloadResult();
8436 ResetUnloadRequestThread(Id);
8441 #ifdef FEATURE_TESTHOOKS
8442 HRESULT AppDomain::UnloadWaitNoCatch(ADID Id, ADUnloadSink * pSink)
8444 STATIC_CONTRACT_THROWS;
8445 STATIC_CONTRACT_MODE_ANY;
8447 Holder<ADID, DoNothing<ADID>, AppDomain::ResetUnloadRequestThread> resetUnloadHolder(Id);
8449 // IF you ever try to change this to something not using events, please address the fact that
8450 // AppDomain::StopEEAndUnwindThreads relies on that events are used.
8451 pSink->WaitUnloadCompletion();
8453 HRESULT hr = pSink->GetUnloadResult();
8456 resetUnloadHolder.SuppressRelease();
8462 void AppDomain::Unload(BOOL fForceUnload)
8469 INJECT_FAULT(COMPlusThrowOM(););
8473 #ifdef FEATURE_MULTICOREJIT
8475 // Avoid profiling file is partially written in ASP.net scenarios, call it earlier
8476 GetMulticoreJitManager().StopProfile(true);
8480 Thread *pThread = GetThread();
8483 if (! fForceUnload && !g_pConfig->AppDomainUnload())
8486 EPolicyAction action;
8487 EClrOperation operation;
8488 if (!IsRudeUnload())
8490 operation = OPR_AppDomainUnload;
8494 operation = OPR_AppDomainRudeUnload;
8496 action = GetEEPolicy()->GetDefaultAction(operation,NULL);
8497 GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
8501 case eUnloadAppDomain:
8503 case eRudeUnloadAppDomain:
8507 case eFastExitProcess:
8508 case eRudeExitProcess:
8509 case eDisableRuntime:
8510 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_ADUNLOAD);
8511 _ASSERTE (!"Should not get here");
8517 #if (defined(_DEBUG) || defined(BREAK_ON_UNLOAD) || defined(AD_LOG_MEMORY) || defined(AD_SNAPSHOT))
8518 static int unloadCount = 0;
8521 #ifdef AD_LOG_MEMORY
8524 static int logMemory = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADLogMemory);
8525 typedef void (__cdecl *LogItFcn) ( int );
8526 static LogItFcn pLogIt = NULL;
8528 if (logMemory && ! pLogIt)
8530 HMODULE hMod = CLRLoadLibrary(W("mpdh.dll"));
8533 pLogIt = (LogItFcn)GetProcAddress(hMod, "logIt");
8542 #endif // AD_LOG_MEMORY
8544 if (IsDefaultDomain() && !IsSingleAppDomain())
8545 COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_DEFAULT);
8547 _ASSERTE(CanUnload());
8549 if (pThread == FinalizerThread::GetFinalizerThread() || GetUnloadRequestThread() == FinalizerThread::GetFinalizerThread())
8550 COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_IN_FINALIZER);
8552 _ASSERTE(! SystemDomain::AppDomainBeingUnloaded());
8554 // should not be running in this AD because unload spawned thread in default domain
8555 if (!NingenEnabled())
8557 _ASSERTE(!pThread->IsRunningIn(this, NULL));
8561 #ifdef APPDOMAIN_STATE
8562 _ASSERTE_ALL_BUILDS("clr/src/VM/AppDomain.cpp", pThread->GetDomain()->IsDefaultDomain());
8565 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Unloading domain [%d] %#08x %ls\n", GetId().m_dwId, this, GetFriendlyName()));
8567 STRESS_LOG3 (LF_APPDOMAIN, LL_INFO100, "Unload domain [%d, %d] %p\n", GetId().m_dwId, GetIndex().m_dwIndex, this);
8569 UnloadHolder hold(this);
8571 SystemDomain::System()->SetUnloadRequestingThread(GetUnloadRequestThread());
8572 SystemDomain::System()->SetUnloadingThread(pThread);
8576 static int dumpSB = -1;
8579 dumpSB = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADDumpSB);
8583 LogSpewAlways("Starting unload %3.3d\n", unloadCount);
8584 DumpSyncBlockCache();
8588 BOOL bForceGC=m_bForceGCOnUnload;
8590 #ifdef AD_LOG_MEMORY
8593 #endif // AD_LOG_MEMORY
8596 static int takeSnapShot = -1;
8598 if (takeSnapShot == -1)
8599 takeSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeSnapShot);
8603 #endif // AD_SNAPSHOT
8609 static int cfgForceGC = -1;
8611 if (cfgForceGC == -1)
8612 cfgForceGC =!CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ADULazyMemoryRelease);
8614 bForceGC=bForceGC||cfgForceGC;
8615 AppDomainRefHolder This(this);
8618 // Do the actual unloading
8620 // We do not want other threads to abort the current one.
8621 ThreadPreventAsyncHolder preventAsync;
8622 Exit(TRUE, !bForceGC);
8626 GCHeapUtilities::GetGCHeap()->GarbageCollect();
8627 FinalizerThread::FinalizerThreadWait();
8628 SetStage(STAGE_COLLECTED);
8632 #ifdef AD_LOG_MEMORY
8636 pLogIt(unloadCount);
8638 #endif // AD_LOG_MEMORY
8644 sprintf_s(buffer, _countof(buffer), "vadump -p %d -o > vadump.%d", GetCurrentProcessId(), unloadCount);
8646 sprintf_s(buffer, _countof(buffer), "umdh -p:%d -d -i:1 -f:umdh.%d", GetCurrentProcessId(), unloadCount);
8648 int takeDHSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeDHSnapShot);
8651 sprintf_s(buffer, _countof(buffer), "dh -p %d -s -g -h -b -f dh.%d", GetCurrentProcessId(), unloadCount);
8655 #endif // AD_SNAPSHOT
8660 // do extra finalizer wait to remove any leftover sb entries
8661 FinalizerThread::FinalizerThreadWait();
8662 GCHeapUtilities::GetGCHeap()->GarbageCollect();
8663 FinalizerThread::FinalizerThreadWait();
8664 LogSpewAlways("Done unload %3.3d\n", unloadCount);
8665 DumpSyncBlockCache();
8668 swprintf_s(buffer, NumItems(buffer), W("DumpSB.%d"), unloadCount);
8669 _ASSERTE(WszMoveFileEx(W("COMPLUS.LOG"), buffer, MOVEFILE_REPLACE_EXISTING));
8670 // this will open a new file
8676 void AppDomain::ExceptionUnwind(Frame *pFrame)
8680 DISABLED(GC_TRIGGERS); // EEResourceException
8681 DISABLED(THROWS); // EEResourceException
8686 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind for %8.8x\n", pFrame));
8688 printf("%x AppDomain::ExceptionUnwind for %8.8p\n", GetThread()->GetThreadId(), pFrame);
8690 Thread *pThread = GetThread();
8693 if (! pThread->ShouldChangeAbortToUnload(pFrame))
8695 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: not first transition or abort\n"));
8699 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: changing to unload\n"));
8702 OBJECTREF throwable = NULL;
8703 EEResourceException e(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded_ThreadUnwound"));
8704 throwable = e.GetThrowable();
8706 // reset the exception to an AppDomainUnloadedException
8707 if (throwable != NULL)
8709 GetThread()->SafeSetThrowables(throwable);
8713 BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread)
8724 Thread *pThread = NULL;
8725 DWORD nThreadsNeedMoreWork=0;
8726 if (retryCount != (unsigned int)-1 && retryCount < g_pConfig->AppDomainUnloadRetryCount())
8728 Thread *pCurThread = GetThread();
8729 if (pCurThread->CatchAtSafePoint())
8730 pCurThread->PulseGCMode();
8733 // We know which thread is not in the domain now. We just need to
8734 // work on those threads. We do not need to suspend the runtime.
8735 ThreadStoreLockHolder tsl;
8737 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8739 if (pThread == pCurThread)
8744 if (pThread == FinalizerThread::GetFinalizerThread())
8749 if (pThread->GetUnloadBoundaryFrame() == NULL)
8754 // A thread may have UnloadBoundaryFrame set if
8755 // 1. Being unloaded by AD unload helper thread
8756 // 2. Escalation from OOM or SO triggers AD unload
8757 // Here we only need to work on threads that are in the domain. If we work on other threads,
8758 // those threads may be stucked in a finally, and we will not be able to escalate for them,
8759 // therefore AD unload is blocked.
8760 if (pThread->IsBeingAbortedForADUnload() ||
8761 pThread == SystemDomain::System()->GetUnloadRequestingThread())
8763 nThreadsNeedMoreWork++;
8766 if (!(IsRudeUnload() ||
8767 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())))
8772 if ((pThread == SystemDomain::System()->GetUnloadRequestingThread()) && *pFMarkUnloadRequestThread)
8774 // Mark thread for abortion only once; later on interrupt only
8775 *pFMarkUnloadRequestThread = FALSE;
8776 pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
8780 if (pThread->m_State & Thread::TS_Interruptible)
8782 pThread->UserInterrupt(Thread::TI_Abort);
8786 if (pThread->PreemptiveGCDisabledOther())
8788 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
8789 Thread::SuspendThreadResult str = pThread->SuspendThread();
8790 if (str == Thread::STR_Success)
8792 if (pThread->PreemptiveGCDisabledOther() &&
8793 (!pThread->IsAbortInitiated() || pThread->IsRudeAbort()))
8795 pThread->HandleJITCaseForAbort();
8797 pThread->ResumeThread();
8802 } // ThreadStoreLockHolder
8804 m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
8805 return !nThreadsNeedMoreWork;
8808 // For now piggyback on the GC's suspend EE mechanism
8809 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
8811 // <TODO>@todo: what to do with any threads that didn't stop?</TODO>
8812 _ASSERTE(ThreadStore::s_pThreadStore->DbgBackgroundThreadCount() > 0);
8815 int totalADCount = 0;
8816 int finalizerADCount = 0;
8819 RuntimeExceptionKind reKind = kLastException;
8821 SmallStackSString ssThreadId;
8823 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8825 // we already checked that we're not running in the unload domain
8826 if (pThread == GetThread())
8832 void PrintStackTraceWithADToLog(Thread *pThread);
8833 if (LoggingOn(LF_APPDOMAIN, LL_INFO100)) {
8834 LOG((LF_APPDOMAIN, LL_INFO100, "\nStackTrace for %x\n", pThread->GetThreadId()));
8835 PrintStackTraceWithADToLog(pThread);
8839 Frame *pFrame = pThread->GetFirstTransitionInto(this, &count);
8841 _ASSERTE(count == 0);
8842 if (pThread->IsBeingAbortedForADUnload())
8844 pThread->ResetBeginAbortedForADUnload();
8849 if (pThread != FinalizerThread::GetFinalizerThread())
8851 totalADCount += count;
8852 nThreadsNeedMoreWork++;
8853 pThread->SetUnloadBoundaryFrame(pFrame);
8857 finalizerADCount = count;
8860 // don't setup the exception info for the unloading thread unless it's the last one in
8861 if (retryCount != ((unsigned int) -1) && retryCount > g_pConfig->AppDomainUnloadRetryCount() && reKind == kLastException &&
8862 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft()))
8864 #ifdef AD_BREAK_ON_CANNOT_UNLOAD
8865 static int breakOnCannotUnload = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADBreakOnCannotUnload);
8866 if (breakOnCannotUnload)
8867 _ASSERTE(!"Cannot unload AD");
8868 #endif // AD_BREAK_ON_CANNOT_UNLOAD
8869 reKind = kCannotUnloadAppDomainException;
8870 resId = IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD;
8871 ssThreadId.Printf(W("%x"), pThread->GetThreadId());
8872 STRESS_LOG2(LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads cannot stop thread %x with %d transitions\n", pThread->GetThreadId(), count);
8873 // don't break out of this early or the assert totalADCount == (int)m_dwThreadEnterCount below will fire
8874 // it's better to chew a little extra time here and make sure our counts are consistent
8876 // only abort the thread requesting the unload if it's the last one in, that way it will get
8877 // notification that the unload failed for some other thread not being aborted. And don't abort
8878 // the finalizer thread - let it finish it's work as it's allowed to be in there. If it won't finish,
8879 // then we will eventually get a CannotUnloadException on it.
8881 if (pThread != FinalizerThread::GetFinalizerThread() &&
8882 // If the domain is rudely unloaded, we will unwind the requesting thread out
8883 // Rude unload is going to succeed, or escalated to disable runtime or higher.
8885 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())
8890 STRESS_LOG2(LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count);
8891 LOG((LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count));
8893 printf("AppDomain::UnwindThreads %x stopping %x with first frame %8.8p\n", GetThread()->GetThreadId(), pThread->GetThreadId(), pFrame);
8895 if (pThread == SystemDomain::System()->GetUnloadRequestingThread())
8897 // Mark thread for abortion only once; later on interrupt only
8898 *pFMarkUnloadRequestThread = FALSE;
8900 pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
8902 TESTHOOKCALL(UnwindingThreads(GetId().m_dwId)) ;
8904 _ASSERTE(totalADCount + finalizerADCount == (int)m_dwThreadEnterCount);
8906 //@TODO: This is intended to catch a stress bug. Remove when no longer needed.
8907 if (totalADCount + finalizerADCount != (int)m_dwThreadEnterCount)
8908 FreeBuildDebugBreak();
8910 // if our count did get messed up, set it to whatever count we actually found in the domain to avoid looping
8911 // or other problems related to incorrect count. This is very much a bug if this happens - a thread should always
8912 // exit the domain gracefully.
8913 // m_dwThreadEnterCount = totalADCount;
8915 if (reKind != kLastException)
8918 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8920 if (pThread->IsBeingAbortedForADUnload())
8922 pThread->ResetBeginAbortedForADUnload();
8927 // CommonTripThread will handle the abort for any threads that we've marked
8928 ThreadSuspend::RestartEE(FALSE, TRUE);
8929 if (reKind != kLastException)
8930 COMPlusThrow(reKind, resId, ssThreadId.GetUnicode());
8932 _ASSERTE((totalADCount==0 && nThreadsNeedMoreWork==0) ||(totalADCount!=0 && nThreadsNeedMoreWork!=0));
8934 m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
8935 return (totalADCount == 0);
8938 void AppDomain::UnwindThreads()
8940 // This function should guarantee appdomain
8941 // consistency even if it fails. Everything that is going
8942 // to make the appdomain impossible to reenter
8943 // should be factored out
8945 // <TODO>@todo: need real synchronization here!!!</TODO>
8954 int retryCount = -1;
8955 m_dwThreadsStillInAppDomain=(ULONG)-1;
8956 ULONGLONG startTime = CLRGetTickCount64();
8958 if (GetEEPolicy()->GetDefaultAction(OPR_AppDomainUnload, NULL) == eRudeUnloadAppDomain &&
8961 GetEEPolicy()->NotifyHostOnDefaultAction(OPR_AppDomainUnload, eRudeUnloadAppDomain);
8965 // Force threads to go through slow path during AD unload.
8966 TSSuspendHolder shTrap;
8968 BOOL fCurrentUnloadMode = IsRudeUnload();
8969 BOOL fMarkUnloadRequestThread = TRUE;
8971 // now wait for all the threads running in our AD to get out
8974 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8975 EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, NULL);
8976 if (timeout != INFINITE && action > eUnloadAppDomain) {
8977 // Escalation policy specified.
8978 ULONGLONG curTime = CLRGetTickCount64();
8979 ULONGLONG elapseTime = curTime - startTime;
8980 if (elapseTime > timeout)
8985 case eRudeUnloadAppDomain:
8986 GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
8988 STRESS_LOG1(LF_APPDOMAIN, LL_INFO100,"Escalating to RADU, adid=%d",GetId().m_dwId);
8991 case eFastExitProcess:
8992 case eRudeExitProcess:
8993 case eDisableRuntime:
8994 GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
8995 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
8996 _ASSERTE (!"Should not reach here");
9004 if (LoggingOn(LF_APPDOMAIN, LL_INFO100))
9005 DumpADThreadTrack();
9007 BOOL fNextUnloadMode = IsRudeUnload();
9008 if (fCurrentUnloadMode != fNextUnloadMode)
9010 // We have changed from normal unload to rude unload. We need to mark the thread
9011 // with RudeAbort, but we can only do this safely if the runtime is suspended.
9012 fCurrentUnloadMode = fNextUnloadMode;
9015 if (StopEEAndUnwindThreads(retryCount, &fMarkUnloadRequestThread))
9017 if (timeout != INFINITE)
9019 // Turn off the timeout used by AD.
9024 // GCStress takes a long time to unwind, due to expensive creation of
9025 // a threadabort exception.
9026 if (!GCStress<cfg_any>::IsEnabled())
9028 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount));
9030 printf("AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount);
9034 if (m_dwThreadEnterCount != 0)
9037 GetThread()->UserSleep(20);
9039 GetThread()->UserSleep(10);
9046 void AppDomain::ClearGCHandles()
9056 SetStage(STAGE_HANDLETABLE_NOACCESS);
9058 GCHeapUtilities::GetGCHeap()->WaitUntilConcurrentGCComplete();
9060 // Keep async pin handles alive by moving them to default domain
9061 HandleAsyncPinHandles();
9063 // Remove our handle store as a source of GC roots
9064 m_handleStore->Uproot();
9067 // When an AD is unloaded, we will release all objects in this AD.
9068 // If a future asynchronous operation, like io completion port function,
9069 // we need to keep the memory space fixed so that the gc heap is not corrupted.
9070 void AppDomain::HandleAsyncPinHandles()
9080 IGCHandleStore *pBucket = m_handleStore;
9082 // IO completion port picks IO job using FIFO. Here is how we know which AsyncPinHandle can be freed.
9083 // 1. We mark all non-pending AsyncPinHandle with READYTOCLEAN.
9084 // 2. We queue a dump Overlapped to the IO completion as a marker.
9085 // 3. When the Overlapped is picked up by completion port, we wait until all previous IO jobs are processed.
9086 // 4. Then we can delete all AsyncPinHandle marked with READYTOCLEAN.
9087 IGCHandleStore *pBucketInDefault = SystemDomain::System()->DefaultDomain()->m_handleStore;
9089 pBucket->RelocateAsyncPinnedHandles(pBucketInDefault);
9091 OverlappedDataObject::RequestCleanup();
9094 void AppDomain::ClearGCRoots()
9104 Thread *pThread = NULL;
9105 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
9107 // Tell the JIT managers to delete any entries in their structures. All the cooperative mode threads are stopped at
9108 // this point, so only need to synchronize the preemptive mode threads.
9109 ExecutionManager::Unload(GetLoaderAllocator());
9111 while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL)
9113 // Delete the thread local static store
9114 pThread->DeleteThreadStaticData(this);
9116 // <TODO>@TODO: A pre-allocated AppDomainUnloaded exception might be better.</TODO>
9117 if (m_handleStore->ContainsHandle(pThread->m_LastThrownObjectHandle))
9119 // Never delete a handle to a preallocated exception object.
9120 if (!CLRException::IsPreallocatedExceptionHandle(pThread->m_LastThrownObjectHandle))
9122 DestroyHandle(pThread->m_LastThrownObjectHandle);
9125 pThread->m_LastThrownObjectHandle = NULL;
9128 // Clear out the exceptions objects held by a thread.
9129 pThread->GetExceptionState()->ClearThrowablesForUnload(m_handleStore);
9132 //delete them while we still have the runtime suspended
9133 // This must be deleted before the loader heaps are deleted.
9134 if (m_pMarshalingData != NULL)
9136 delete m_pMarshalingData;
9137 m_pMarshalingData = NULL;
9140 if (m_pLargeHeapHandleTable != NULL)
9142 delete m_pLargeHeapHandleTable;
9143 m_pLargeHeapHandleTable = NULL;
9146 ThreadSuspend::RestartEE(FALSE, TRUE);
9151 void AppDomain::TrackADThreadEnter(Thread *pThread, Frame *pFrame)
9158 PRECONDITION(CheckPointer(pThread));
9159 PRECONDITION(pFrame != (Frame*)(size_t) INVALID_POINTER_CD);
9163 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9165 if (m_pThreadTrackInfoList == NULL)
9166 m_pThreadTrackInfoList = new (nothrow) ThreadTrackInfoList;
9167 // If we don't assert here, we will AV in the for loop below
9168 _ASSERTE(m_pThreadTrackInfoList);
9170 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9172 ThreadTrackInfo *pTrack = NULL;
9174 for (i=0; i < pTrackList->Count(); i++) {
9175 if ((*(pTrackList->Get(i)))->pThread == pThread) {
9176 pTrack = *(pTrackList->Get(i));
9181 pTrack = new (nothrow) ThreadTrackInfo;
9182 // If we don't assert here, we will AV in the for loop below.
9184 pTrack->pThread = pThread;
9185 ThreadTrackInfo **pSlot = pTrackList->Append();
9189 InterlockedIncrement((LONG*)&m_dwThreadEnterCount);
9193 pSlot = pTrack->frameStack.Insert(0);
9197 for (i=0; i < pTrackList->Count(); i++)
9198 totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
9199 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9201 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9205 void AppDomain::TrackADThreadExit(Thread *pThread, Frame *pFrame)
9209 if (GetThread()) {MODE_COOPERATIVE;}
9215 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9217 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9218 _ASSERTE(pTrackList);
9219 ThreadTrackInfo *pTrack = NULL;
9221 for (i=0; i < pTrackList->Count(); i++)
9223 if ((*(pTrackList->Get(i)))->pThread == pThread)
9225 pTrack = *(pTrackList->Get(i));
9230 _ASSERTE(*(pTrack->frameStack.Get(0)) == pFrame);
9231 pTrack->frameStack.Delete(0);
9232 InterlockedDecrement((LONG*)&m_dwThreadEnterCount);
9235 for (i=0; i < pTrackList->Count(); i++)
9236 totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
9237 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9239 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9242 void AppDomain::DumpADThreadTrack()
9252 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9254 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9259 LOG((LF_APPDOMAIN, LL_INFO10000, "\nThread dump of %d threads for [%d] %#08x %S\n",
9260 m_dwThreadEnterCount, GetId().m_dwId, this, GetFriendlyNameForLogging()));
9262 for (int i=0; i < pTrackList->Count(); i++)
9264 ThreadTrackInfo *pTrack = *(pTrackList->Get(i));
9265 if (pTrack->frameStack.Count()==0)
9267 LOG((LF_APPDOMAIN, LL_INFO100, " ADEnterCount for %x is %d\n", pTrack->pThread->GetThreadId(), pTrack->frameStack.Count()));
9268 totThreads += pTrack->frameStack.Count();
9269 for (int j=0; j < pTrack->frameStack.Count(); j++)
9270 LOG((LF_APPDOMAIN, LL_INFO100, " frame %8.8x\n", *(pTrack->frameStack.Get(j))));
9272 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9275 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9280 #endif // CROSSGEN_COMPILE
9282 void *SharedDomain::operator new(size_t size, void *pInPlace)
9284 LIMITED_METHOD_CONTRACT;
9288 void SharedDomain::operator delete(void *pMem)
9290 LIMITED_METHOD_CONTRACT;
9291 // Do nothing - new() was in-place
9295 void SharedDomain::Attach()
9302 INJECT_FAULT(COMPlusThrowOM(););
9306 // Create the global SharedDomain and initialize it.
9307 m_pSharedDomain = new (&g_pSharedDomainMemory[0]) SharedDomain();
9308 SystemDomain::GetGlobalLoaderAllocator()->m_pDomain = m_pSharedDomain;
9309 // This cannot fail since g_pSharedDomainMemory is a static array.
9310 CONSISTENCY_CHECK(CheckPointer(m_pSharedDomain));
9312 LOG((LF_CLASSLOADER,
9314 "Created shared domain at %p\n",
9317 // We need to initialize the memory pools etc. for the system domain.
9318 m_pSharedDomain->Init(); // Setup the memory heaps
9320 // allocate a Virtual Call Stub Manager for the shared domain
9321 m_pSharedDomain->InitVSD();
9324 #ifndef CROSSGEN_COMPILE
9325 void SharedDomain::Detach()
9327 if (m_pSharedDomain)
9329 m_pSharedDomain->Terminate();
9330 delete m_pSharedDomain;
9331 m_pSharedDomain = NULL;
9334 #endif // CROSSGEN_COMPILE
9336 #endif // !DACCESS_COMPILE
9338 SharedDomain *SharedDomain::GetDomain()
9340 LIMITED_METHOD_DAC_CONTRACT;
9342 return m_pSharedDomain;
9345 #ifndef DACCESS_COMPILE
9347 #define INITIAL_ASSEMBLY_MAP_SIZE 17
9348 void SharedDomain::Init()
9355 INJECT_FAULT(COMPlusThrowOM(););
9361 #ifdef FEATURE_LOADER_OPTIMIZATION
9362 m_FileCreateLock.Init(CrstSharedAssemblyCreate, CRST_DEFAULT,TRUE);
9364 LockOwner lock = { &m_DomainCrst, IsOwnerOfCrst };
9365 m_assemblyMap.Init(INITIAL_ASSEMBLY_MAP_SIZE, CompareSharedAssembly, TRUE, &lock);
9366 #endif // FEATURE_LOADER_OPTIMIZATION
9368 ETW::LoaderLog::DomainLoad(this);
9371 #ifndef CROSSGEN_COMPILE
9372 void SharedDomain::Terminate()
9374 // make sure we delete the StringLiteralMap before unloading
9375 // the asemblies since the string literal map entries can
9376 // point to metadata string literals.
9377 GetLoaderAllocator()->CleanupStringLiteralMap();
9379 #ifdef FEATURE_LOADER_OPTIMIZATION
9380 PtrHashMap::PtrIterator i = m_assemblyMap.begin();
9384 Assembly *pAssembly = (Assembly*) i.GetValue();
9389 ListLockEntry* pElement;
9390 pElement = m_FileCreateLock.Pop(TRUE);
9393 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
9394 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
9397 pElement = (FileLoadLock*) m_FileCreateLock.Pop(TRUE);
9399 m_FileCreateLock.Destroy();
9400 #endif // FEATURE_LOADER_OPTIMIZATION
9401 BaseDomain::Terminate();
9403 #endif // CROSSGEN_COMPILE
9407 #ifdef FEATURE_LOADER_OPTIMIZATION
9409 BOOL SharedDomain::CompareSharedAssembly(UPTR u1, UPTR u2)
9419 // This is the input to the lookup
9420 SharedAssemblyLocator *pLocator = (SharedAssemblyLocator *) (u1<<1);
9422 // This is the value stored in the table
9423 Assembly *pAssembly = (Assembly *) u2;
9424 if (pLocator->GetType()==SharedAssemblyLocator::DOMAINASSEMBLY)
9426 if (!pAssembly->GetManifestFile()->Equals(pLocator->GetDomainAssembly()->GetFile()))
9429 return pAssembly->CanBeShared(pLocator->GetDomainAssembly());
9432 if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLY)
9433 return pAssembly->GetManifestFile()->Equals(pLocator->GetPEAssembly());
9435 if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLYEXACT)
9436 return pAssembly->GetManifestFile() == pLocator->GetPEAssembly();
9437 _ASSERTE(!"Unexpected type of assembly locator");
9441 DWORD SharedAssemblyLocator::Hash()
9448 INJECT_FAULT(COMPlusThrowOM(););
9451 if (m_type==DOMAINASSEMBLY)
9452 return GetDomainAssembly()->HashIdentity();
9453 if (m_type==PEASSEMBLY||m_type==PEASSEMBLYEXACT)
9454 return GetPEAssembly()->HashIdentity();
9455 _ASSERTE(!"Unexpected type of assembly locator");
9459 Assembly * SharedDomain::FindShareableAssembly(SharedAssemblyLocator * pLocator)
9466 INJECT_FAULT(COMPlusThrowOM(););
9470 Assembly * match= (Assembly *) m_assemblyMap.LookupValue(pLocator->Hash(), pLocator);
9471 if (match != (Assembly *) INVALIDENTRY)
9477 SIZE_T SharedDomain::GetShareableAssemblyCount()
9479 LIMITED_METHOD_CONTRACT;
9481 return m_assemblyMap.GetCount();
9484 void SharedDomain::AddShareableAssembly(Assembly * pAssembly)
9491 INJECT_FAULT(COMPlusThrowOM(););
9495 // We have a lock on the file. There should be no races to add the same assembly.
9498 LockHolder holder(this);
9502 pAssembly->SetIsTenured();
9503 m_assemblyMap.InsertValue(pAssembly->HashIdentity(), pAssembly);
9507 // There was an error adding the assembly to the assembly hash (probably an OOM),
9508 // so we need to unset the tenured bit so that correct cleanup can happen.
9509 pAssembly->UnsetIsTenured();
9514 LOG((LF_CODESHARING,
9516 "Successfully added shareable assembly \"%s\".\n",
9517 pAssembly->GetManifestFile()->GetSimpleName()));
9520 #endif // FEATURE_LOADER_OPTIMIZATION
9521 #endif // !DACCESS_COMPILE
9523 DWORD DomainLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex /*=(DWORD)-1*/)
9531 { // SO tolerance exception for debug-only assertion.
9532 CONTRACT_VIOLATION(SOToleranceViolation);
9533 CONSISTENCY_CHECK(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9536 if (pMT->IsDynamicStatics())
9538 _ASSERTE(!pMT->ContainsGenericVariables());
9539 DWORD dynamicClassID = pMT->GetModuleDynamicEntryID();
9540 if(m_aDynamicEntries <= dynamicClassID)
9542 return (m_pDynamicClassTable[dynamicClassID].m_dwFlags);
9546 if (iClassIndex == (DWORD)-1)
9547 iClassIndex = pMT->GetClassIndex();
9548 return GetPrecomputedStaticsClassData()[iClassIndex];
9552 #ifndef DACCESS_COMPILE
9554 void DomainLocalModule::SetClassInitialized(MethodTable* pMT)
9564 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9566 _ASSERTE(!IsClassInitialized(pMT));
9567 _ASSERTE(!IsClassInitError(pMT));
9569 SetClassFlags(pMT, ClassInitFlags::INITIALIZED_FLAG);
9572 void DomainLocalModule::SetClassInitError(MethodTable* pMT)
9574 WRAPPER_NO_CONTRACT;
9576 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9578 SetClassFlags(pMT, ClassInitFlags::ERROR_FLAG);
9581 void DomainLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags)
9586 PRECONDITION(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9587 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9588 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9591 if (pMT->IsDynamicStatics())
9593 _ASSERTE(!pMT->ContainsGenericVariables());
9594 DWORD dwID = pMT->GetModuleDynamicEntryID();
9595 EnsureDynamicClassIndex(dwID);
9596 m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags;
9600 GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags;
9604 void DomainLocalModule::EnsureDynamicClassIndex(DWORD dwID)
9611 INJECT_FAULT(COMPlusThrowOM(););
9612 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9613 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9617 if (dwID < m_aDynamicEntries)
9619 _ASSERTE(m_pDynamicClassTable.Load() != NULL);
9623 SIZE_T aDynamicEntries = max(16, m_aDynamicEntries.Load());
9624 while (aDynamicEntries <= dwID)
9626 aDynamicEntries *= 2;
9629 DynamicClassInfo* pNewDynamicClassTable;
9630 pNewDynamicClassTable = (DynamicClassInfo*)
9631 (void*)GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
9632 S_SIZE_T(sizeof(DynamicClassInfo)) * S_SIZE_T(aDynamicEntries));
9634 memcpy(pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * m_aDynamicEntries);
9636 // Note: Memory allocated on loader heap is zero filled
9637 // memset(pNewDynamicClassTable + m_aDynamicEntries, 0, (aDynamicEntries - m_aDynamicEntries) * sizeof(DynamicClassInfo));
9639 _ASSERTE(m_aDynamicEntries%2 == 0);
9641 // Commit new dynamic table. The lock-free helpers depend on the order.
9643 m_pDynamicClassTable = pNewDynamicClassTable;
9645 m_aDynamicEntries = aDynamicEntries;
9648 #ifndef CROSSGEN_COMPILE
9649 void DomainLocalModule::AllocateDynamicClass(MethodTable *pMT)
9655 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9656 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9660 _ASSERTE(!pMT->ContainsGenericVariables());
9661 _ASSERTE(!pMT->IsSharedByGenericInstantiations());
9662 _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9663 _ASSERTE(pMT->IsDynamicStatics());
9665 DWORD dynamicEntryIDIndex = pMT->GetModuleDynamicEntryID();
9667 EnsureDynamicClassIndex(dynamicEntryIDIndex);
9669 _ASSERTE(m_aDynamicEntries > dynamicEntryIDIndex);
9671 EEClass *pClass = pMT->GetClass();
9673 DWORD dwStaticBytes = pClass->GetNonGCRegularStaticFieldBytes();
9674 DWORD dwNumHandleStatics = pClass->GetNumHandleRegularStatics();
9676 _ASSERTE(!IsClassAllocated(pMT));
9677 _ASSERTE(!IsClassInitialized(pMT));
9678 _ASSERTE(!IsClassInitError(pMT));
9680 DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry;
9682 // We need this check because maybe a class had a cctor but no statics
9683 if (dwStaticBytes > 0 || dwNumHandleStatics > 0)
9685 if (pDynamicStatics == NULL)
9687 LoaderHeap * pLoaderAllocator = GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap();
9689 if (pMT->Collectible())
9691 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(sizeof(CollectibleDynamicEntry)));
9695 SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes;
9697 #ifdef FEATURE_64BIT_ALIGNMENT
9698 // Allocate memory with extra alignment only if it is really necessary
9699 if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
9701 static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0);
9702 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE);
9706 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(dynamicEntrySize));
9709 // Note: Memory allocated on loader heap is zero filled
9711 m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry = pDynamicStatics;
9714 if (pMT->Collectible() && (dwStaticBytes != 0))
9717 OBJECTREF nongcStaticsArray = NULL;
9718 GCPROTECT_BEGIN(nongcStaticsArray);
9719 #ifdef FEATURE_64BIT_ALIGNMENT
9720 // Allocate memory with extra alignment only if it is really necessary
9721 if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
9722 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8)-1)) / (sizeof(CLR_I8)));
9725 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes);
9726 ((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray);
9729 if (dwNumHandleStatics > 0)
9731 if (!pMT->Collectible())
9733 GetAppDomain()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
9734 &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics);
9739 OBJECTREF gcStaticsArray = NULL;
9740 GCPROTECT_BEGIN(gcStaticsArray);
9741 gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass);
9742 ((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(gcStaticsArray);
9750 void DomainLocalModule::PopulateClass(MethodTable *pMT)
9759 _ASSERTE(!pMT->ContainsGenericVariables());
9761 // <todo> the only work actually done here for non-dynamics is the freezing related work.
9762 // See if we can eliminate this and make this a dynamic-only path </todo>
9763 DWORD iClassIndex = pMT->GetClassIndex();
9765 if (!IsClassAllocated(pMT, iClassIndex))
9767 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9769 if (!IsClassAllocated(pMT, iClassIndex))
9771 // Allocate dynamic space if necessary
9772 if (pMT->IsDynamicStatics())
9773 AllocateDynamicClass(pMT);
9775 // determine flags to set on the statics block
9776 DWORD dwFlags = ClassInitFlags::ALLOCATECLASS_FLAG;
9778 if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics())
9780 _ASSERTE(!IsClassInitialized(pMT));
9781 _ASSERTE(!IsClassInitError(pMT));
9782 dwFlags |= ClassInitFlags::INITIALIZED_FLAG;
9785 if (pMT->Collectible())
9787 dwFlags |= ClassInitFlags::COLLECTIBLE_FLAG;
9790 // Set all flags at the same time to avoid races
9791 SetClassFlags(pMT, dwFlags);
9797 #endif // CROSSGEN_COMPILE
9799 void DomainLocalBlock::EnsureModuleIndex(ModuleIndex index)
9806 INJECT_FAULT(COMPlusThrowOM(););
9807 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9808 PRECONDITION(m_pDomain->OwnDomainLocalBlockLock());
9812 if (m_aModuleIndices > index.m_dwIndex)
9814 _ASSERTE(m_pModuleSlots != NULL);
9818 SIZE_T aModuleIndices = max(16, m_aModuleIndices);
9819 while (aModuleIndices <= index.m_dwIndex)
9821 aModuleIndices *= 2;
9824 PTR_DomainLocalModule* pNewModuleSlots = (PTR_DomainLocalModule*) (void*)m_pDomain->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(PTR_DomainLocalModule)) * S_SIZE_T(aModuleIndices));
9826 memcpy(pNewModuleSlots, m_pModuleSlots, sizeof(SIZE_T)*m_aModuleIndices);
9828 // Note: Memory allocated on loader heap is zero filled
9829 // memset(pNewModuleSlots + m_aModuleIndices, 0 , (aModuleIndices - m_aModuleIndices)*sizeof(PTR_DomainLocalModule) );
9831 // Commit new table. The lock-free helpers depend on the order.
9833 m_pModuleSlots = pNewModuleSlots;
9835 m_aModuleIndices = aModuleIndices;
9839 void DomainLocalBlock::SetModuleSlot(ModuleIndex index, PTR_DomainLocalModule pLocalModule)
9841 // Need to synchronize with table growth in this domain
9842 BaseDomain::DomainLocalBlockLockHolder lh(m_pDomain);
9844 EnsureModuleIndex(index);
9846 _ASSERTE(index.m_dwIndex < m_aModuleIndices);
9848 // We would like this assert here, unfortunately, loading a module in this appdomain can fail
9849 // after here and we will keep the module around and reuse the slot when we retry (if
9850 // the failure happened due to a transient error, such as OOM). In that case the slot wont
9852 //_ASSERTE(m_pModuleSlots[index.m_dwIndex] == 0);
9854 m_pModuleSlots[index.m_dwIndex] = pLocalModule;
9857 #ifndef CROSSGEN_COMPILE
9859 DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef)
9866 INJECT_FAULT(COMPlusThrowOM(););
9870 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
9873 DomainAssembly* pResolvedAssembly = NULL;
9874 _ASSERTE(strcmp(szName, g_AppDomainClassName));
9879 OBJECTREF AppDomainRef;
9880 OBJECTREF AssemblyRef;
9883 ZeroMemory(&gc, sizeof(gc));
9885 GCPROTECT_BEGIN(gc);
9886 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9888 if (pAssembly != NULL)
9889 gc.AssemblyRef = pAssembly->GetExposedAssemblyObject();
9891 MethodDescCallSite onTypeResolve(METHOD__APP_DOMAIN__ON_TYPE_RESOLVE, &gc.AppDomainRef);
9893 gc.str = StringObject::NewString(szName);
9896 ObjToArgSlot(gc.AppDomainRef),
9897 ObjToArgSlot(gc.AssemblyRef),
9898 ObjToArgSlot(gc.str)
9900 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onTypeResolve.Call_RetOBJECTREF(args);
9902 if (ResultingAssemblyRef != NULL)
9904 pResolvedAssembly = ResultingAssemblyRef->GetDomainAssembly();
9906 if (pResultingAssemblyRef)
9907 *pResultingAssemblyRef = ResultingAssemblyRef;
9910 if (pResolvedAssembly->IsCollectible())
9912 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
9919 return pResolvedAssembly;
9923 Assembly* AppDomain::RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName)
9930 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9931 INJECT_FAULT(COMPlusThrowOM(););
9935 Assembly* pResolvedAssembly = NULL;
9940 OBJECTREF AppDomainRef;
9941 OBJECTREF AssemblyRef;
9944 ZeroMemory(&gc, sizeof(gc));
9946 GCPROTECT_BEGIN(gc);
9947 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9949 if (pAssembly != NULL)
9950 gc.AssemblyRef=pAssembly->GetExposedAssemblyObject();
9952 MethodDescCallSite onResourceResolve(METHOD__APP_DOMAIN__ON_RESOURCE_RESOLVE, &gc.AppDomainRef);
9953 gc.str = StringObject::NewString(szName);
9956 ObjToArgSlot(gc.AppDomainRef),
9957 ObjToArgSlot(gc.AssemblyRef),
9958 ObjToArgSlot(gc.str)
9960 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onResourceResolve.Call_RetOBJECTREF(args);
9961 if (ResultingAssemblyRef != NULL)
9963 pResolvedAssembly = ResultingAssemblyRef->GetAssembly();
9964 if (pResolvedAssembly->IsCollectible())
9966 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
9972 RETURN pResolvedAssembly;
9977 AppDomain::RaiseAssemblyResolveEvent(
9978 AssemblySpec * pSpec,
9979 BOOL fIntrospection,
9987 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9988 INJECT_FAULT(COMPlusThrowOM(););
9992 BinderMethodID methodId;
9993 StackSString ssName;
9994 pSpec->GetFileOrDisplayName(0, ssName);
9998 methodId = METHOD__APP_DOMAIN__ON_ASSEMBLY_RESOLVE; // post-bind execution event (the classic V1.0 event)
10006 // Elevate threads allowed loading level. This allows the host to load an assembly even in a restricted
10007 // condition. Note, however, that this exposes us to possible recursion failures, if the host tries to
10008 // load the assemblies currently being loaded. (Such cases would then throw an exception.)
10010 OVERRIDE_LOAD_LEVEL_LIMIT(FILE_ACTIVE);
10011 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
10015 Assembly* pAssembly = NULL;
10018 OBJECTREF AppDomainRef;
10019 OBJECTREF AssemblyRef;
10022 ZeroMemory(&gc, sizeof(gc));
10024 GCPROTECT_BEGIN(gc);
10025 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
10027 if (pSpec->GetParentAssembly() != NULL)
10030 gc.AssemblyRef=pSpec->GetParentAssembly()->GetExposedAssemblyObject();
10033 MethodDescCallSite onAssemblyResolve(methodId, &gc.AppDomainRef);
10035 gc.str = StringObject::NewString(ssName);
10036 ARG_SLOT args[3] = {
10037 ObjToArgSlot(gc.AppDomainRef),
10038 ObjToArgSlot(gc.AssemblyRef),
10039 ObjToArgSlot(gc.str)
10042 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onAssemblyResolve.Call_RetOBJECTREF(args);
10044 if (ResultingAssemblyRef != NULL)
10046 pAssembly = ResultingAssemblyRef->GetAssembly();
10047 if (pAssembly->IsCollectible())
10049 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
10055 if (pAssembly != NULL)
10057 if ((!(pAssembly->IsIntrospectionOnly())) != (!fIntrospection))
10059 // Cannot return an introspection assembly from an execution callback or vice-versa
10060 COMPlusThrow(kFileLoadException, pAssembly->IsIntrospectionOnly() ? IDS_CLASSLOAD_ASSEMBLY_RESOLVE_RETURNED_INTROSPECTION : IDS_CLASSLOAD_ASSEMBLY_RESOLVE_RETURNED_EXECUTION);
10063 // Check that the public key token matches the one specified in the spec
10064 // MatchPublicKeys throws as appropriate
10065 pSpec->MatchPublicKeys(pAssembly);
10069 } // AppDomain::RaiseAssemblyResolveEvent
10072 //---------------------------------------------------------------------------------------
10074 // Determine the type of AppDomainManager to use for the default AppDomain
10077 // v2.0 of the CLR used environment variables APPDOMAIN_MANAGER_ASM and APPDOMAIN_MANAGER_TYPE to set the
10078 // domain manager. For compatibility these are still supported, along with appDomainManagerAsm and
10079 // appDomainManagerType config file switches. If the config switches are supplied, the entry point must be
10083 void AppDomain::InitializeDefaultDomainManager()
10090 INJECT_FAULT(COMPlusThrowOM(););
10091 PRECONDITION(GetId().m_dwId == DefaultADID);
10095 OBJECTREF orThis = GetExposedObject();
10096 GCPROTECT_BEGIN(orThis);
10098 MethodDescCallSite initCompatFlags(METHOD__APP_DOMAIN__INITIALIZE_COMPATIBILITY_FLAGS);
10101 ObjToArgSlot(orThis)
10104 initCompatFlags.Call(args);
10109 CLREvent * AppDomain::g_pUnloadStartEvent;
10111 void AppDomain::CreateADUnloadWorker()
10113 STANDARD_VM_CONTRACT;
10115 // Do not create adUnload thread if there is only default domain
10116 if(IsSingleAppDomain())
10120 BOOL fCreator = FALSE;
10121 if (FastInterlockCompareExchange((LONG *)&g_fADUnloadWorkerOK,-2,-1)==-1) //we're first
10123 #ifdef _TARGET_X86_ // use the smallest possible stack on X86
10124 DWORD stackSize = 128 * 1024;
10126 DWORD stackSize = 512 * 1024; // leave X64 unchanged since we have plenty of VM
10128 Thread *pThread = SetupUnstartedThread();
10129 if (pThread->CreateNewThread(stackSize, ADUnloadThreadStart, pThread))
10133 dwRet = pThread->StartThread();
10135 // When running under a user mode native debugger there is a race
10136 // between the moment we've created the thread (in CreateNewThread) and
10137 // the moment we resume it (in StartThread); the debugger may receive
10138 // the "ct" (create thread) notification, and it will attempt to
10139 // suspend/resume all threads in the process. Now imagine the debugger
10140 // resumes this thread first, and only later does it try to resume the
10141 // newly created thread (the ADU worker thread). In these conditions our
10142 // call to ResumeThread may come before the debugger's call to ResumeThread
10143 // actually causing dwRet to equal 2.
10144 // We cannot use IsDebuggerPresent() in the condition below because the
10145 // debugger may have been detached between the time it got the notification
10146 // and the moment we execute the test below.
10147 _ASSERTE(dwRet == 1 || dwRet == 2);
10151 pThread->DecExternalCount(FALSE);
10152 FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK, -1);
10153 ThrowOutOfMemory();
10157 YIELD_WHILE (g_fADUnloadWorkerOK == -2);
10159 if (g_fADUnloadWorkerOK == -1) {
10162 ThrowOutOfMemory();
10171 /*static*/ void AppDomain::ADUnloadWorkerHelper(AppDomain *pDomain)
10173 STATIC_CONTRACT_NOTHROW;
10174 STATIC_CONTRACT_GC_TRIGGERS;
10175 STATIC_CONTRACT_MODE_COOPERATIVE;
10176 ADUnloadSink* pADUnloadSink=pDomain->GetADUnloadSinkForUnload();
10181 pDomain->Unload(FALSE);
10183 EX_CATCH_HRESULT(hr);
10187 SystemDomain::LockHolder lh;
10188 pADUnloadSink->ReportUnloadResult(hr,NULL);
10189 pADUnloadSink->Release();
10193 void AppDomain::DoADUnloadWork()
10200 INJECT_FAULT(COMPlusThrowOM(););
10207 AppDomain *pDomainToUnload = NULL;
10210 // Take the lock so that no domain can be added or removed from the system domain
10211 SystemDomain::LockHolder lh;
10213 DWORD numDomain = SystemDomain::GetCurrentAppDomainMaxIndex();
10214 for (; i <= numDomain; i ++) {
10215 AppDomain * pDomain = SystemDomain::TestGetAppDomainAtIndex(ADIndex(i));
10217 // @todo: We used to also select a domain if pDomain->IsUnload() returned true. But that causes
10218 // problems when we've failed to completely unload the AD in the past. If we've reached the CLEARED
10219 // stage, for instance, then there will be no default context and AppDomain::Exit() will simply crash.
10221 if (pDomain && pDomain->IsUnloadRequested())
10223 pDomainToUnload = pDomain;
10230 if (!pDomainToUnload) {
10234 // We are the only thread that can unload domains so no one else can delete the appdomain
10235 ADUnloadWorkerHelper(pDomainToUnload);
10239 static void DoADUnloadWorkHelper()
10241 STATIC_CONTRACT_NOTHROW;
10242 STATIC_CONTRACT_GC_TRIGGERS;
10243 STATIC_CONTRACT_MODE_COOPERATIVE;
10246 AppDomain::DoADUnloadWork();
10251 EX_END_CATCH(SwallowAllExceptions);
10254 ULONGLONG g_ObjFinalizeStartTime = 0;
10255 Volatile<BOOL> g_FinalizerIsRunning = FALSE;
10256 Volatile<ULONG> g_FinalizerLoopCount = 0;
10258 ULONGLONG GetObjFinalizeStartTime()
10260 LIMITED_METHOD_CONTRACT;
10261 return g_ObjFinalizeStartTime;
10264 void FinalizerThreadAbortOnTimeout()
10266 STATIC_CONTRACT_NOTHROW;
10267 STATIC_CONTRACT_MODE_COOPERATIVE;
10268 STATIC_CONTRACT_GC_TRIGGERS;
10271 // If finalizer thread is blocked because scheduler is running another task,
10272 // or it is waiting for another thread, we first see if we get finalizer thread
10274 Thread::ThreadAbortWatchDog();
10279 Thread *pFinalizerThread = FinalizerThread::GetFinalizerThread();
10280 EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(OPR_FinalizerRun, pFinalizerThread);
10284 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10285 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10288 Thread::UAC_FinalizerTimeout);
10290 case eRudeAbortThread:
10291 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10292 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10295 Thread::UAC_FinalizerTimeout);
10297 case eUnloadAppDomain:
10299 AppDomain *pDomain = pFinalizerThread->GetDomain();
10300 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10303 Thread::UAC_FinalizerTimeout);
10304 if (!pDomain->IsDefaultDomain())
10306 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10307 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
10311 case eRudeUnloadAppDomain:
10313 AppDomain *pDomain = pFinalizerThread->GetDomain();
10314 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10317 Thread::UAC_FinalizerTimeout);
10318 if (!pDomain->IsDefaultDomain())
10320 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10321 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
10326 case eFastExitProcess:
10327 case eRudeExitProcess:
10328 case eDisableRuntime:
10329 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10330 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
10331 _ASSERTE (!"Should not get here");
10340 EX_END_CATCH(SwallowAllExceptions);
10345 WT_UnloadDomain = 0x1,
10346 WT_ThreadAbort = 0x2,
10347 WT_FinalizerThread = 0x4,
10348 WT_ClearCollectedDomains=0x8
10351 static Volatile<DWORD> s_WorkType = 0;
10354 DWORD WINAPI AppDomain::ADUnloadThreadStart(void *args)
10359 DISABLED(GC_TRIGGERS);
10361 // This function will always be at the very bottom of the stack. The only
10362 // user code it calls is the AppDomainUnload notifications which we will
10363 // not be hardenning for Whidbey.
10369 BEGIN_ENTRYPOINT_NOTHROW;
10371 ClrFlsSetThreadType (ThreadType_ADUnloadHelper);
10373 Thread *pThread = (Thread*)args;
10374 bool fOK = (pThread->HasStarted() != 0);
10377 GCX_MAYBE_PREEMP(fOK);
10379 _ASSERTE (g_fADUnloadWorkerOK == -2);
10381 FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK,fOK?1:-1);
10385 DestroyThread(pThread);
10389 pThread->SetBackground(TRUE);
10391 pThread->SetThreadStateNC(Thread::TSNC_ADUnloadHelper);
10394 DWORD TAtimeout = INFINITE;
10395 ULONGLONG endTime = Thread::GetNextSelfAbortEndTime();
10396 ULONGLONG curTime = CLRGetTickCount64();
10397 if (endTime <= curTime) {
10402 ULONGLONG diff = endTime - curTime;
10403 if (diff < MAXULONG)
10405 TAtimeout = (DWORD)diff;
10408 ULONGLONG finalizeStartTime = GetObjFinalizeStartTime();
10409 DWORD finalizeTimeout = INFINITE;
10410 DWORD finalizeTimeoutSetting = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
10411 if (finalizeTimeoutSetting != INFINITE && g_FinalizerIsRunning)
10413 if (finalizeStartTime == 0)
10415 finalizeTimeout = finalizeTimeoutSetting;
10419 endTime = finalizeStartTime + finalizeTimeoutSetting;
10420 if (endTime <= curTime) {
10421 finalizeTimeout = 0;
10425 ULONGLONG diff = endTime - curTime;
10426 if (diff < MAXULONG)
10428 finalizeTimeout = (DWORD)diff;
10434 if (AppDomain::HasWorkForFinalizerThread())
10436 if (finalizeTimeout > finalizeTimeoutSetting)
10438 finalizeTimeout = finalizeTimeoutSetting;
10442 DWORD timeout = INFINITE;
10443 if (finalizeTimeout <= TAtimeout)
10445 timeout = finalizeTimeout;
10449 timeout = TAtimeout;
10454 LOG((LF_APPDOMAIN, LL_INFO10, "Waiting to start unload\n"));
10455 g_pUnloadStartEvent->Wait(timeout,FALSE);
10458 if (finalizeTimeout != INFINITE || (s_WorkType & WT_FinalizerThread) != 0)
10460 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for Finalizer thread\n");
10461 FastInterlockAnd(&s_WorkType, ~WT_FinalizerThread);
10462 // only watch finalizer thread is finalizer method or unloadevent is being processed
10463 if (GetObjFinalizeStartTime() == finalizeStartTime && finalizeStartTime != 0 && g_FinalizerIsRunning)
10465 if (CLRGetTickCount64() >= finalizeStartTime+finalizeTimeoutSetting)
10468 FinalizerThreadAbortOnTimeout();
10471 if (s_fProcessUnloadDomainEvent && g_FinalizerIsRunning)
10474 FinalizerThreadAbortOnTimeout();
10478 if (TAtimeout != INFINITE || (s_WorkType & WT_ThreadAbort) != 0)
10480 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for thread abort\n");
10481 FastInterlockAnd(&s_WorkType, ~WT_ThreadAbort);
10483 Thread::ThreadAbortWatchDog();
10486 if ((s_WorkType & WT_UnloadDomain) != 0 && !AppDomain::HasWorkForFinalizerThread())
10488 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD unload\n");
10489 FastInterlockAnd(&s_WorkType, ~WT_UnloadDomain);
10491 DoADUnloadWorkHelper();
10494 if ((s_WorkType & WT_ClearCollectedDomains) != 0)
10496 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD cleanup\n");
10497 FastInterlockAnd(&s_WorkType, ~WT_ClearCollectedDomains);
10499 SystemDomain::System()->ClearCollectedDomains();
10506 END_ENTRYPOINT_NOTHROW;
10511 void AppDomain::EnableADUnloadWorker()
10517 SO_TOLERANT; // Called during a SO
10521 EEPolicy::AppDomainUnloadTypes type = EEPolicy::ADU_Safe;
10524 DWORD hostTestADUnload = g_pConfig->GetHostTestADUnload();
10525 if (hostTestADUnload == 2) {
10526 type = EEPolicy::ADU_Rude;
10530 EnableADUnloadWorker(type);
10533 void AppDomain::EnableADUnloadWorker(EEPolicy::AppDomainUnloadTypes type, BOOL fHasStack)
10539 SO_TOLERANT; // Called during a SO
10543 FastInterlockOr (&s_WorkType, WT_UnloadDomain);
10545 LONG stage = m_Stage;
10546 static_assert_no_msg(sizeof(m_Stage) == sizeof(int));
10548 _ASSERTE(!IsDefaultDomain());
10550 // Mark unload requested.
10551 if (type == EEPolicy::ADU_Rude) {
10554 while (stage < STAGE_UNLOAD_REQUESTED) {
10555 stage = FastInterlockCompareExchange((LONG*)&m_Stage,STAGE_UNLOAD_REQUESTED,stage);
10560 // Can not call Set due to limited stack.
10563 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker\n"));
10564 g_pUnloadStartEvent->Set();
10567 void AppDomain::EnableADUnloadWorkerForThreadAbort()
10569 LIMITED_METHOD_CONTRACT;
10570 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "Enabling unload worker for thread abort\n");
10571 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for thread abort\n"));
10572 FastInterlockOr (&s_WorkType, WT_ThreadAbort);
10573 g_pUnloadStartEvent->Set();
10577 void AppDomain::EnableADUnloadWorkerForFinalizer()
10579 LIMITED_METHOD_CONTRACT;
10580 if (GetEEPolicy()->GetTimeout(OPR_FinalizerRun) != INFINITE)
10582 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for Finalizer Thread\n"));
10583 FastInterlockOr (&s_WorkType, WT_FinalizerThread);
10584 g_pUnloadStartEvent->Set();
10588 void AppDomain::EnableADUnloadWorkerForCollectedADCleanup()
10590 LIMITED_METHOD_CONTRACT;
10591 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for collected domains\n"));
10592 FastInterlockOr (&s_WorkType, WT_ClearCollectedDomains);
10593 g_pUnloadStartEvent->Set();
10597 void SystemDomain::ClearCollectedDomains()
10607 AppDomain* pDomainsToClear=NULL;
10609 CrstHolder lh(&m_DelayedUnloadCrst);
10610 for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
10612 if ((*ppDomain)->m_Stage==AppDomain::STAGE_COLLECTED)
10614 AppDomain* pAppDomain=*ppDomain;
10615 *ppDomain=(*ppDomain)->m_pNextInDelayedUnloadList;
10616 pAppDomain->m_pNextInDelayedUnloadList=pDomainsToClear;
10617 pDomainsToClear=pAppDomain;
10620 ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
10624 for (AppDomain* pDomain=pDomainsToClear;pDomain!=NULL;)
10626 AppDomain* pNext=pDomain->m_pNextInDelayedUnloadList;
10627 pDomain->Close(); //NOTHROW!
10628 pDomain->Release();
10633 void SystemDomain::ProcessClearingDomains()
10642 CrstHolder lh(&m_DelayedUnloadCrst);
10644 for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
10646 if ((*ppDomain)->m_Stage==AppDomain::STAGE_HANDLETABLE_NOACCESS)
10648 AppDomain* pAppDomain=*ppDomain;
10649 pAppDomain->SetStage(AppDomain::STAGE_CLEARED);
10651 ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
10654 if (!m_UnloadIsAsync)
10656 // For synchronous mode, we are now done with the list.
10657 m_pDelayedUnloadList = NULL;
10661 void SystemDomain::ProcessDelayedUnloadDomains()
10671 int iGCRefPoint=GCHeapUtilities::GetGCHeap()->CollectionCount(GCHeapUtilities::GetGCHeap()->GetMaxGeneration());
10672 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCInProgress())
10675 BOOL bAppDomainToCleanup = FALSE;
10676 LoaderAllocator * pAllocatorsToDelete = NULL;
10679 CrstHolder lh(&m_DelayedUnloadCrst);
10681 for (AppDomain* pDomain=m_pDelayedUnloadList; pDomain!=NULL; pDomain=pDomain->m_pNextInDelayedUnloadList)
10683 if (pDomain->m_Stage==AppDomain::STAGE_CLEARED)
10685 // Compare with 0 to handle overflows gracefully
10686 if (0 < iGCRefPoint - pDomain->GetGCRefPoint())
10688 bAppDomainToCleanup=TRUE;
10689 pDomain->SetStage(AppDomain::STAGE_COLLECTED);
10694 LoaderAllocator ** ppAllocator=&m_pDelayedUnloadListOfLoaderAllocators;
10695 while (*ppAllocator!= NULL)
10697 LoaderAllocator * pAllocator = *ppAllocator;
10698 if (0 < iGCRefPoint - pAllocator->GetGCRefPoint())
10700 *ppAllocator = pAllocator->m_pLoaderAllocatorDestroyNext;
10702 pAllocator->m_pLoaderAllocatorDestroyNext = pAllocatorsToDelete;
10703 pAllocatorsToDelete = pAllocator;
10707 ppAllocator = &pAllocator->m_pLoaderAllocatorDestroyNext;
10712 if (bAppDomainToCleanup)
10713 AppDomain::EnableADUnloadWorkerForCollectedADCleanup();
10715 // Delete collected loader allocators on the finalizer thread. We cannot offload it to appdomain unload thread because of
10716 // there is not guaranteed to be one, and it is not that expensive operation anyway.
10717 while (pAllocatorsToDelete != NULL)
10719 LoaderAllocator * pAllocator = pAllocatorsToDelete;
10720 pAllocatorsToDelete = pAllocator->m_pLoaderAllocatorDestroyNext;
10725 #endif // CROSSGEN_COMPILE
10727 AppDomainFromIDHolder::AppDomainFromIDHolder(ADID adId, BOOL bUnsafePoint, SyncType synctype)
10729 WRAPPER_NO_CONTRACT;
10730 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
10737 Assign(adId, bUnsafePoint);
10740 AppDomainFromIDHolder::AppDomainFromIDHolder(SyncType synctype)
10742 LIMITED_METHOD_CONTRACT;
10743 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
10752 #ifndef CROSSGEN_COMPILE
10753 void ADUnloadSink::ReportUnloadResult (HRESULT hr, OBJECTREF* pException)
10759 PRECONDITION(CheckPointer(this));
10760 PRECONDITION(m_UnloadCompleteEvent.IsValid());
10764 //pException is unused;
10766 m_UnloadCompleteEvent.Set();
10769 void ADUnloadSink::WaitUnloadCompletion()
10775 PRECONDITION(CheckPointer(this));
10776 PRECONDITION(m_UnloadCompleteEvent.IsValid());
10780 CONTRACT_VIOLATION(FaultViolation);
10781 m_UnloadCompleteEvent.WaitEx(INFINITE, (WaitMode)(WaitMode_Alertable | WaitMode_ADUnload));
10784 ADUnloadSink* AppDomain::PrepareForWaitUnloadCompletion()
10790 PRECONDITION(SystemDomain::IsUnderDomainLock());
10795 ADUnloadSink* pADSink=GetADUnloadSink();
10796 PREFIX_ASSUME(pADSink!=NULL);
10797 if (m_Stage < AppDomain::STAGE_UNLOAD_REQUESTED) //we're first
10800 SetUnloadRequestThread(GetThread());
10805 ADUnloadSink::ADUnloadSink()
10813 INJECT_FAULT(COMPlusThrowOM(););
10818 m_UnloadCompleteEvent.CreateManualEvent(FALSE);
10819 m_UnloadResult=S_OK;
10822 ADUnloadSink::~ADUnloadSink()
10832 m_UnloadCompleteEvent.CloseEvent();
10837 ULONG ADUnloadSink::AddRef()
10839 LIMITED_METHOD_CONTRACT;
10840 return InterlockedIncrement(&m_cRef);
10843 ULONG ADUnloadSink::Release()
10845 LIMITED_METHOD_CONTRACT;
10846 ULONG ulRef = InterlockedDecrement(&m_cRef);
10854 void ADUnloadSink::Reset()
10856 LIMITED_METHOD_CONTRACT;
10857 m_UnloadResult=S_OK;
10858 m_UnloadCompleteEvent.Reset();
10861 ADUnloadSink* AppDomain::GetADUnloadSink()
10863 LIMITED_METHOD_CONTRACT;
10864 _ASSERTE(SystemDomain::IsUnderDomainLock());
10866 m_ADUnloadSink->AddRef();
10867 return m_ADUnloadSink;
10870 ADUnloadSink* AppDomain::GetADUnloadSinkForUnload()
10872 // unload thread only. Doesn't need to have AD lock
10873 LIMITED_METHOD_CONTRACT;
10875 m_ADUnloadSink->AddRef();
10876 return m_ADUnloadSink;
10878 #endif // CROSSGEN_COMPILE
10880 void AppDomain::EnumStaticGCRefs(promote_func* fn, ScanContext* sc)
10889 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
10890 GCHeapUtilities::IsServerHeap() &&
10891 IsGCSpecialThread());
10893 AppDomain::AssemblyIterator asmIterator = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution));
10894 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
10895 while (asmIterator.Next(pDomainAssembly.This()))
10897 // @TODO: Review when DomainAssemblies get added.
10898 _ASSERTE(pDomainAssembly != NULL);
10899 pDomainAssembly->EnumStaticGCRefs(fn, sc);
10905 #endif // !DACCESS_COMPILE
10907 //------------------------------------------------------------------------
10908 UINT32 BaseDomain::GetTypeID(PTR_MethodTable pMT) {
10912 PRECONDITION(pMT->GetDomain() == this);
10915 return m_typeIDMap.GetTypeID(pMT);
10918 //------------------------------------------------------------------------
10919 // Returns the ID of the type if found. If not found, returns INVALID_TYPE_ID
10920 UINT32 BaseDomain::LookupTypeID(PTR_MethodTable pMT)
10925 WRAPPER(GC_TRIGGERS);
10926 PRECONDITION(pMT->GetDomain() == this);
10929 return m_typeIDMap.LookupTypeID(pMT);
10932 //------------------------------------------------------------------------
10933 PTR_MethodTable BaseDomain::LookupType(UINT32 id) {
10937 WRAPPER(GC_TRIGGERS);
10938 CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS);
10941 PTR_MethodTable pMT = m_typeIDMap.LookupType(id);
10942 if (pMT == NULL && !IsSharedDomain()) {
10943 pMT = SharedDomain::GetDomain()->LookupType(id);
10946 CONSISTENCY_CHECK(CheckPointer(pMT));
10947 CONSISTENCY_CHECK(pMT->IsInterface());
10951 #ifndef DACCESS_COMPILE
10954 //------------------------------------------------------------------------
10955 BOOL GetCompatibilityFlag(CompatibilityFlag flag)
10965 #endif // !DACCESS_COMPILE
10967 //---------------------------------------------------------------------------------------
10970 AppDomain::AssemblyIterator::Next(
10971 CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
10975 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
10979 CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
10980 return Next_Unlocked(pDomainAssemblyHolder);
10983 //---------------------------------------------------------------------------------------
10985 // Note: Does not lock the assembly list, but locks collectible assemblies for adding references.
10988 AppDomain::AssemblyIterator::Next_Unlocked(
10989 CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
10997 #ifndef DACCESS_COMPILE
10998 _ASSERTE(m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
11001 while (m_Iterator.Next())
11003 // Get element from the list/iterator (without adding reference to the assembly)
11004 DomainAssembly * pDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
11005 if (pDomainAssembly == NULL)
11010 if (pDomainAssembly->IsError())
11012 if (m_assemblyIterationFlags & kIncludeFailedToLoad)
11014 *pDomainAssemblyHolder = pDomainAssembly;
11017 continue; // reject
11020 // First, reject DomainAssemblies whose load status is not to be included in
11023 if (pDomainAssembly->IsAvailableToProfilers() &&
11024 (m_assemblyIterationFlags & kIncludeAvailableToProfilers))
11026 // The assembly has reached the state at which we would notify profilers,
11027 // and we're supposed to include such assemblies in the enumeration. So
11028 // don't reject it (i.e., noop here, and don't bother with the rest of
11029 // the load status checks). Check for this first, since
11030 // kIncludeAvailableToProfilers contains some loaded AND loading
11033 else if (pDomainAssembly->IsLoaded())
11035 // A loaded assembly
11036 if (!(m_assemblyIterationFlags & kIncludeLoaded))
11038 continue; // reject
11043 // A loading assembly
11044 if (!(m_assemblyIterationFlags & kIncludeLoading))
11046 continue; // reject
11050 // Next, reject DomainAssemblies whose execution / introspection status is
11051 // not to be included in the enumeration
11053 if (pDomainAssembly->IsIntrospectionOnly())
11055 // introspection assembly
11056 if (!(m_assemblyIterationFlags & kIncludeIntrospection))
11058 continue; // reject
11063 // execution assembly
11064 if (!(m_assemblyIterationFlags & kIncludeExecution))
11066 continue; // reject
11070 // Next, reject collectible assemblies
11071 if (pDomainAssembly->IsCollectible())
11073 if (m_assemblyIterationFlags & kExcludeCollectible)
11075 _ASSERTE(!(m_assemblyIterationFlags & kIncludeCollected));
11076 continue; // reject
11079 // Un-tenured collectible assemblies should not be returned. (This can only happen in a brief
11080 // window during collectible assembly creation. No thread should need to have a pointer
11081 // to the just allocated DomainAssembly at this stage.)
11082 if (!pDomainAssembly->GetAssembly()->GetManifestModule()->IsTenured())
11084 continue; // reject
11087 if (pDomainAssembly->GetLoaderAllocator()->AddReferenceIfAlive())
11088 { // The assembly is alive
11090 // Set the holder value (incl. increasing ref-count)
11091 *pDomainAssemblyHolder = pDomainAssembly;
11093 // Now release the reference we took in the if-condition
11094 pDomainAssembly->GetLoaderAllocator()->Release();
11097 // The assembly is not alive anymore (and we didn't increase its ref-count in the
11100 if (!(m_assemblyIterationFlags & kIncludeCollected))
11102 continue; // reject
11104 // Set the holder value to assembly with 0 ref-count without increasing the ref-count (won't
11105 // call Release either)
11106 pDomainAssemblyHolder->Assign(pDomainAssembly, FALSE);
11110 *pDomainAssemblyHolder = pDomainAssembly;
11114 *pDomainAssemblyHolder = NULL;
11116 } // AppDomain::AssemblyIterator::Next_Unlocked
11118 #ifndef DACCESS_COMPILE
11120 //---------------------------------------------------------------------------------------
11122 // Can be called only from AppDomain shutdown code:AppDomain::ShutdownAssemblies.
11123 // Does not add-ref collectible assemblies (as the LoaderAllocator might not be reachable from the
11124 // DomainAssembly anymore).
11127 AppDomain::AssemblyIterator::Next_UnsafeNoAddRef(
11128 DomainAssembly ** ppDomainAssembly)
11136 // Make sure we are iterating all assemblies (see the only caller code:AppDomain::ShutdownAssemblies)
11137 _ASSERTE(m_assemblyIterationFlags ==
11138 (kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
11139 // It also means that we do not exclude anything
11140 _ASSERTE((m_assemblyIterationFlags & kExcludeCollectible) == 0);
11142 // We are on shutdown path, so lock shouldn't be neccessary, but all _Unlocked methods on AssemblyList
11143 // have asserts that the lock is held, so why not to take it ...
11144 CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
11146 while (m_Iterator.Next())
11148 // Get element from the list/iterator (without adding reference to the assembly)
11149 *ppDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
11150 if (*ppDomainAssembly == NULL)
11158 *ppDomainAssembly = NULL;
11160 } // AppDomain::AssemblyIterator::Next_UnsafeNoAddRef
11163 //---------------------------------------------------------------------------------------
11165 BOOL AppDomain::IsImageFromTrustedPath(PEImage* pPEImage)
11172 PRECONDITION(CheckPointer(pPEImage));
11176 const SString &sImagePath = pPEImage->GetPath();
11178 return !sImagePath.IsEmpty();
11181 #endif //!DACCESS_COMPILE
11183 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
11185 // Returns a BOOL indicating if the binding model has been locked for the AppDomain
11186 BOOL AppDomain::IsBindingModelLocked()
11196 return m_fIsBindingModelLocked.Load();
11199 // Marks the binding model locked for AppDomain
11200 BOOL AppDomain::LockBindingModel()
11202 LIMITED_METHOD_CONTRACT;
11204 BOOL fDidWeLockBindingModel = FALSE;
11206 if (InterlockedCompareExchangeT<BOOL>(&m_fIsBindingModelLocked, TRUE, FALSE) == FALSE)
11208 fDidWeLockBindingModel = TRUE;
11211 return fDidWeLockBindingModel;
11214 BOOL AppDomain::IsHostAssemblyResolverInUse()
11216 LIMITED_METHOD_CONTRACT;
11218 return (GetFusionContext() != GetTPABinderContext());
11221 // Helper used by the assembly binder to check if the specified AppDomain can use apppath assembly resolver
11222 BOOL RuntimeCanUseAppPathAssemblyResolver(DWORD adid)
11226 NOTHROW; // Cannot throw since it is invoked by the Binder that expects to get a hresult
11234 // We need to be in COOP mode to get the AppDomain*
11237 AppDomain *pTargetDomain = SystemDomain::GetAppDomainFromId(id, ADV_CURRENTAD);
11238 _ASSERTE(pTargetDomain != NULL);
11240 pTargetDomain->LockBindingModel();
11242 return !pTargetDomain->IsHostAssemblyResolverInUse();
11245 // Returns S_OK if the assembly was successfully loaded
11246 HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, IAssemblyName *pIAssemblyName, CLRPrivBinderCoreCLR *pTPABinder, BINDER_SPACE::AssemblyName *pAssemblyName, ICLRPrivAssembly **ppLoadedAssembly)
11253 PRECONDITION(ppLoadedAssembly != NULL);
11257 HRESULT hr = E_FAIL;
11259 // DevDiv #933506: Exceptions thrown during AssemblyLoadContext.Load should propagate
11262 // Switch to COOP mode since we are going to work with managed references
11267 ASSEMBLYNAMEREF oRefAssemblyName;
11268 ASSEMBLYREF oRefLoadedAssembly;
11271 ZeroMemory(&_gcRefs, sizeof(_gcRefs));
11273 GCPROTECT_BEGIN(_gcRefs);
11275 ICLRPrivAssembly *pAssemblyBindingContext = NULL;
11277 bool fInvokedForTPABinder = (pTPABinder == NULL)?true:false;
11279 // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.Resolve method.
11281 // First, initialize an assembly spec for the requested assembly
11284 hr = spec.Init(pIAssemblyName);
11287 bool fResolvedAssembly = false;
11288 bool fResolvedAssemblyViaTPALoadContext = false;
11290 // Allocate an AssemblyName managed object
11291 _gcRefs.oRefAssemblyName = (ASSEMBLYNAMEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME));
11293 // Initialize the AssemblyName object from the AssemblySpec
11294 spec.AssemblyNameInit(&_gcRefs.oRefAssemblyName, NULL);
11296 if (!fInvokedForTPABinder)
11298 // Step 2 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName) - Invoke Load method
11299 // This is not invoked for TPA Binder since it always returns NULL.
11301 // Finally, setup arguments for invocation
11302 BinderMethodID idHAR_Resolve = METHOD__ASSEMBLYLOADCONTEXT__RESOLVE;
11303 MethodDescCallSite methLoadAssembly(idHAR_Resolve);
11305 // Setup the arguments for the call
11308 PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
11309 ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
11313 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
11314 if (_gcRefs.oRefLoadedAssembly != NULL)
11316 fResolvedAssembly = true;
11319 // Step 3 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
11320 if (!fResolvedAssembly)
11322 // If we could not resolve the assembly using Load method, then attempt fallback with TPA Binder.
11323 // Since TPA binder cannot fallback to itself, this fallback does not happen for binds within TPA binder.
11325 // Switch to pre-emp mode before calling into the binder
11327 ICLRPrivAssembly *pCoreCLRFoundAssembly = NULL;
11328 hr = pTPABinder->BindAssemblyByName(pIAssemblyName, &pCoreCLRFoundAssembly);
11331 pAssemblyBindingContext = pCoreCLRFoundAssembly;
11332 fResolvedAssembly = true;
11333 fResolvedAssemblyViaTPALoadContext = true;
11338 if (!fResolvedAssembly)
11340 // Step 4 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
11342 // If we couldnt resolve the assembly using TPA LoadContext as well, then
11343 // attempt to resolve it using the Resolving event.
11344 // Finally, setup arguments for invocation
11345 BinderMethodID idHAR_ResolveUsingEvent = METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUSINGEVENT;
11346 MethodDescCallSite methLoadAssembly(idHAR_ResolveUsingEvent);
11348 // Setup the arguments for the call
11351 PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
11352 ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
11356 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
11357 if (_gcRefs.oRefLoadedAssembly != NULL)
11359 // Set the flag indicating we found the assembly
11360 fResolvedAssembly = true;
11364 if (fResolvedAssembly && !fResolvedAssemblyViaTPALoadContext)
11366 // If we are here, assembly was successfully resolved via Load or Resolving events.
11367 _ASSERTE(_gcRefs.oRefLoadedAssembly != NULL);
11369 // We were able to get the assembly loaded. Now, get its name since the host could have
11370 // performed the resolution using an assembly with different name.
11371 DomainAssembly *pDomainAssembly = _gcRefs.oRefLoadedAssembly->GetDomainAssembly();
11372 PEAssembly *pLoadedPEAssembly = NULL;
11373 bool fFailLoad = false;
11374 if (!pDomainAssembly)
11376 // Reflection emitted assemblies will not have a domain assembly.
11381 pLoadedPEAssembly = pDomainAssembly->GetFile();
11382 if (pLoadedPEAssembly->HasHostAssembly() != true)
11384 // Reflection emitted assemblies will not have a domain assembly.
11389 // The loaded assembly's ICLRPrivAssembly* is saved as HostAssembly in PEAssembly
11393 spec.GetFileOrDisplayName(0, name);
11394 COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_DYNAMICALLY_EMITTED_ASSEMBLIES_UNSUPPORTED, name);
11397 // Is the assembly already bound using a binding context that will be incompatible?
11398 // An example is attempting to consume an assembly bound to WinRT binder.
11399 pAssemblyBindingContext = pLoadedPEAssembly->GetHostAssembly();
11402 #ifdef FEATURE_COMINTEROP
11403 if (AreSameBinderInstance(pAssemblyBindingContext, GetAppDomain()->GetWinRtBinder()))
11405 // It is invalid to return an assembly bound to an incompatible binder
11406 *ppLoadedAssembly = NULL;
11408 spec.GetFileOrDisplayName(0, name);
11409 COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_BINDING_CONTEXT, name);
11411 #endif // FEATURE_COMINTEROP
11413 // Get the ICLRPrivAssembly reference to return back to.
11414 *ppLoadedAssembly = clr::SafeAddRef(pAssemblyBindingContext);
11420 // EX_CATCH_HRESULT(hr);
11425 #endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
11427 //approximate size of loader data
11428 //maintained for each assembly
11429 #define APPROX_LOADER_DATA_PER_ASSEMBLY 8196
11431 size_t AppDomain::EstimateSize()
11441 size_t retval = sizeof(AppDomain);
11442 retval += GetLoaderAllocator()->EstimateSize();
11443 //very rough estimate
11444 retval += GetAssemblyCount() * APPROX_LOADER_DATA_PER_ASSEMBLY;
11448 #ifdef DACCESS_COMPILE
11451 DomainLocalModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
11455 // Enumerate the DomainLocalModule itself. DLMs are allocated to be larger than
11456 // sizeof(DomainLocalModule) to make room for ClassInit flags and non-GC statics.
11457 // "DAC_ENUM_DTHIS()" probably does not account for this, so we might not enumerate
11458 // all of the ClassInit flags and non-GC statics.
11459 // sizeof(DomainLocalModule) == 0x28
11462 if (m_pDomainFile.IsValid())
11464 m_pDomainFile->EnumMemoryRegions(flags);
11467 if (m_pDynamicClassTable.Load().IsValid())
11469 DacEnumMemoryRegion(dac_cast<TADDR>(m_pDynamicClassTable.Load()),
11470 m_aDynamicEntries * sizeof(DynamicClassInfo));
11472 for (SIZE_T i = 0; i < m_aDynamicEntries; i++)
11474 PTR_DynamicEntry entry = dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[i].m_pDynamicEntry.Load());
11475 if (entry.IsValid())
11477 // sizeof(DomainLocalModule::DynamicEntry) == 8
11485 DomainLocalBlock::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
11488 // Block is contained in AppDomain, don't enum this.
11490 if (m_pModuleSlots.IsValid())
11492 DacEnumMemoryRegion(dac_cast<TADDR>(m_pModuleSlots),
11493 m_aModuleIndices * sizeof(TADDR));
11495 for (SIZE_T i = 0; i < m_aModuleIndices; i++)
11497 PTR_DomainLocalModule domMod = m_pModuleSlots[i];
11498 if (domMod.IsValid())
11500 domMod->EnumMemoryRegions(flags);
11507 BaseDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11513 // This is wrong. Don't do it.
11514 // BaseDomain cannot be instantiated.
11515 // The only thing this code can hope to accomplish is to potentially break
11516 // memory enumeration walking through the derived class if we
11517 // explicitly call the base class enum first.
11518 // DAC_ENUM_VTHIS();
11521 EMEM_OUT(("MEM: %p BaseDomain\n", dac_cast<TADDR>(this)));
11525 AppDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11532 //sizeof(AppDomain) == 0xeb0
11535 BaseDomain::EnumMemoryRegions(flags, false);
11537 // We don't need AppDomain name in triage dumps.
11538 if (flags != CLRDATA_ENUM_MEM_TRIAGE)
11540 m_friendlyName.EnumMemoryRegions(flags);
11543 m_Assemblies.EnumMemoryRegions(flags);
11544 AssemblyIterator assem = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution | kIncludeIntrospection));
11545 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
11547 while (assem.Next(pDomainAssembly.This()))
11549 pDomainAssembly->EnumMemoryRegions(flags);
11552 m_sDomainLocalBlock.EnumMemoryRegions(flags);
11554 m_LoaderAllocator.EnumMemoryRegions(flags);
11558 SystemDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11566 BaseDomain::EnumMemoryRegions(flags, false);
11568 if (m_pSystemFile.IsValid())
11570 m_pSystemFile->EnumMemoryRegions(flags);
11572 if (m_pSystemAssembly.IsValid())
11574 m_pSystemAssembly->EnumMemoryRegions(flags);
11576 if (m_pDefaultDomain.IsValid())
11578 m_pDefaultDomain->EnumMemoryRegions(flags, true);
11581 m_appDomainIndexList.EnumMem();
11582 (&m_appDomainIndexList)->EnumMemoryRegions(flags);
11586 SharedDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11594 BaseDomain::EnumMemoryRegions(flags, false);
11595 #ifdef FEATURE_LOADER_OPTIMIZATION
11596 m_assemblyMap.EnumMemoryRegions(flags);
11597 SharedAssemblyIterator assem;
11598 while (assem.Next())
11600 assem.GetAssembly()->EnumMemoryRegions(flags);
11605 #endif //DACCESS_COMPILE
11608 PTR_LoaderAllocator SystemDomain::GetGlobalLoaderAllocator()
11610 return PTR_LoaderAllocator(PTR_HOST_MEMBER_TADDR(SystemDomain,System(),m_GlobalAllocator));
11613 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
11615 #ifndef CROSSGEN_COMPILE
11616 // Return the total processor time (user and kernel) used by threads executing in this AppDomain so far. The
11617 // result is in 100ns units.
11618 ULONGLONG AppDomain::QueryProcessorUsage()
11628 #ifndef DACCESS_COMPILE
11629 Thread *pThread = NULL;
11631 // Need to update our accumulated processor time count with current values from each thread that is
11632 // currently executing in this domain.
11634 // Take the thread store lock while we enumerate threads.
11635 ThreadStoreLockHolder tsl;
11636 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
11638 // Skip unstarted and dead threads and those that are currently executing in a different AppDomain.
11639 if (pThread->IsUnstarted() || pThread->IsDead() || pThread->GetDomain(INDEBUG(TRUE)) != this)
11642 // Add the amount of time spent by the thread in the AppDomain since the last time we asked (calling
11643 // Thread::QueryThreadProcessorUsage() will reset the thread's counter).
11644 UpdateProcessorUsage(pThread->QueryThreadProcessorUsage());
11646 #endif // !DACCESS_COMPILE
11648 // Return the updated total.
11649 return m_ullTotalProcessorUsage;
11652 // Add to the current count of processor time used by threads within this AppDomain. This API is called by
11653 // threads transitioning between AppDomains.
11654 void AppDomain::UpdateProcessorUsage(ULONGLONG ullAdditionalUsage)
11656 LIMITED_METHOD_CONTRACT;
11658 // Need to be careful to synchronize here, multiple threads could be racing to update this count.
11659 ULONGLONG ullOldValue;
11660 ULONGLONG ullNewValue;
11663 ullOldValue = m_ullTotalProcessorUsage;
11664 ullNewValue = ullOldValue + ullAdditionalUsage;
11665 } while (InterlockedCompareExchange64((LONGLONG*)&m_ullTotalProcessorUsage,
11666 (LONGLONG)ullNewValue,
11667 (LONGLONG)ullOldValue) != (LONGLONG)ullOldValue);
11669 #endif // CROSSGEN_COMPILE
11671 #endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
11673 #if defined(FEATURE_TYPEEQUIVALENCE)
11675 #ifndef DACCESS_COMPILE
11676 TypeEquivalenceHashTable * AppDomain::GetTypeEquivalenceCache()
11682 INJECT_FAULT(COMPlusThrowOM());
11687 // Take the critical section all of the time in debug builds to ensure that it is safe to take
11688 // the critical section in the unusual times when it may actually be needed in retail builds
11690 CrstHolder ch(&m_TypeEquivalenceCrst);
11693 if (m_pTypeEquivalenceTable.Load() == NULL)
11696 CrstHolder ch(&m_TypeEquivalenceCrst);
11698 if (m_pTypeEquivalenceTable.Load() == NULL)
11700 m_pTypeEquivalenceTable = TypeEquivalenceHashTable::Create(this, 12, &m_TypeEquivalenceCrst);
11703 return m_pTypeEquivalenceTable;
11705 #endif //!DACCESS_COMPILE
11707 #endif //FEATURE_TYPEEQUIVALENCE
11709 #if !defined(DACCESS_COMPILE)
11711 //---------------------------------------------------------------------------------------------------------------------
11712 void AppDomain::PublishHostedAssembly(
11713 DomainAssembly * pDomainAssembly)
11723 if (pDomainAssembly->GetFile()->HasHostAssembly())
11725 // We have to serialize all Add operations
11726 CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
11727 _ASSERTE(m_hostAssemblyMap.Lookup(pDomainAssembly->GetFile()->GetHostAssembly()) == nullptr);
11729 // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
11730 HostAssemblyMap::AddPhases addCall;
11732 // 1. Preallocate one element
11733 addCall.PreallocateForAdd(&m_hostAssemblyMap);
11735 // 2. Take the reader lock which can be taken during stack walking
11736 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
11737 ForbidSuspendThreadHolder suspend;
11739 CrstHolder lock(&m_crstHostAssemblyMap);
11740 // 3. Add the element to the hash table (no call out into host)
11741 addCall.Add(pDomainAssembly);
11744 // 4. Cleanup the old memory (if any)
11745 addCall.DeleteOldTable();
11752 //---------------------------------------------------------------------------------------------------------------------
11753 void AppDomain::UpdatePublishHostedAssembly(
11754 DomainAssembly * pAssembly,
11766 if (pAssembly->GetFile()->HasHostAssembly())
11768 // We have to serialize all Add operations
11769 CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
11771 // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
11772 OriginalFileHostAssemblyMap::AddPhases addCall;
11773 bool fAddOrigFile = false;
11775 // For cases where the pefile is being updated
11776 // 1. Preallocate one element
11777 if (pFile != pAssembly->GetFile())
11779 addCall.PreallocateForAdd(&m_hostAssemblyMapForOrigFile);
11780 fAddOrigFile = true;
11784 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
11785 ForbidSuspendThreadHolder suspend;
11787 CrstHolder lock(&m_crstHostAssemblyMap);
11789 // Remove from hash table.
11790 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
11791 m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
11793 // Update PEFile on DomainAssembly. (This may cause the key for the hash to change, which is why we need this function)
11794 pAssembly->UpdatePEFileWorker(pFile);
11796 _ASSERTE(fAddOrigFile == (pAssembly->GetOriginalFile() != pAssembly->GetFile()));
11799 // Add to the orig file hash table if we might be in a case where we've cached the original pefile and not the final pe file (for use during GetAssemblyIfLoaded)
11800 addCall.Add(pAssembly);
11803 // Add back to the hashtable (the call to Remove above guarantees that we will not call into host for table reallocation)
11804 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) == nullptr);
11805 m_hostAssemblyMap.Add(pAssembly);
11809 // 4. Cleanup the old memory (if any)
11811 addCall.DeleteOldTable();
11817 pAssembly->UpdatePEFileWorker(pFile);
11821 //---------------------------------------------------------------------------------------------------------------------
11822 void AppDomain::UnPublishHostedAssembly(
11823 DomainAssembly * pAssembly)
11834 if (pAssembly->GetFile()->HasHostAssembly())
11836 ForbidSuspendThreadHolder suspend;
11838 CrstHolder lock(&m_crstHostAssemblyMap);
11839 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
11840 m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
11842 // We also have an entry in m_hostAssemblyMapForOrigFile. Handle that case.
11843 if (pAssembly->GetOriginalFile() != pAssembly->GetFile())
11845 m_hostAssemblyMapForOrigFile.Remove(pAssembly->GetOriginalFile()->GetHostAssembly());
11851 // In AppX processes, all PEAssemblies that are reach this stage should have host binders.
11852 _ASSERTE(!AppX::IsAppXProcess());
11856 #if defined(FEATURE_COMINTEROP)
11857 HRESULT AppDomain::SetWinrtApplicationContext(SString &appLocalWinMD)
11859 STANDARD_VM_CONTRACT;
11861 _ASSERTE(WinRTSupported());
11862 _ASSERTE(m_pWinRtBinder != nullptr);
11864 _ASSERTE(GetTPABinderContext() != NULL);
11865 BINDER_SPACE::ApplicationContext *pApplicationContext = GetTPABinderContext()->GetAppContext();
11866 _ASSERTE(pApplicationContext != NULL);
11868 return m_pWinRtBinder->SetApplicationContext(pApplicationContext, appLocalWinMD);
11871 #endif // FEATURE_COMINTEROP
11873 #endif //!DACCESS_COMPILE
11875 //---------------------------------------------------------------------------------------------------------------------
11876 PTR_DomainAssembly AppDomain::FindAssembly(PTR_ICLRPrivAssembly pHostAssembly)
11887 if (pHostAssembly == nullptr)
11891 ForbidSuspendThreadHolder suspend;
11893 CrstHolder lock(&m_crstHostAssemblyMap);
11894 PTR_DomainAssembly returnValue = m_hostAssemblyMap.Lookup(pHostAssembly);
11895 if (returnValue == NULL)
11897 // If not found in the m_hostAssemblyMap, look in the m_hostAssemblyMapForOrigFile
11898 // This is necessary as it may happen during in a second AppDomain that the PEFile
11899 // first discovered in the AppDomain may not be used by the DomainFile, but the CLRPrivBinderFusion
11900 // will in some cases find the pHostAssembly associated with this no longer used PEFile
11901 // instead of the PEFile that was finally decided upon.
11902 returnValue = m_hostAssemblyMapForOrigFile.Lookup(pHostAssembly);
11905 return returnValue;
11910 #if !defined(DACCESS_COMPILE) && defined(FEATURE_NATIVE_IMAGE_GENERATION)
11912 void ZapperSetBindingPaths(ICorCompilationDomain *pDomain, SString &trustedPlatformAssemblies, SString &platformResourceRoots, SString &appPaths, SString &appNiPaths)
11914 CLRPrivBinderCoreCLR *pBinder = static_cast<CLRPrivBinderCoreCLR*>(((CompilationDomain *)pDomain)->GetFusionContext());
11915 _ASSERTE(pBinder != NULL);
11916 pBinder->SetupBindingPaths(trustedPlatformAssemblies, platformResourceRoots, appPaths, appNiPaths);
11917 #ifdef FEATURE_COMINTEROP
11918 SString emptString;
11919 ((CompilationDomain*)pDomain)->SetWinrtApplicationContext(emptString);
11925 #if !defined(CROSSGEN_COMPILE)
11926 bool IsSingleAppDomain()
11928 STARTUP_FLAGS flags = CorHost2::GetStartupFlags();
11929 if(flags & STARTUP_SINGLE_APPDOMAIN)
11935 bool IsSingleAppDomain()