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"
82 #pragma warning(disable:4324)
86 // this file handles string conversion errors for itself
87 #undef MAKE_TRANSLATIONFAILED
89 // Define these macro's to do strict validation for jit lock and class
90 // init entry leaks. This defines determine if the asserts that
91 // verify for these leaks are defined or not. These asserts can
92 // sometimes go off even if no entries have been leaked so this
93 // defines should be used with caution.
95 // If we are inside a .cctor when the application shut's down then the
96 // class init lock's head will be set and this will cause the assert
99 // If we are jitting a method when the application shut's down then
100 // the jit lock's head will be set causing the assert to go off.
102 //#define STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
104 static const WCHAR DEFAULT_DOMAIN_FRIENDLY_NAME[] = W("DefaultDomain");
105 static const WCHAR OTHER_DOMAIN_FRIENDLY_NAME_PREFIX[] = W("Domain");
107 #define STATIC_OBJECT_TABLE_BUCKET_SIZE 1020
109 #define MAX_URL_LENGTH 2084 // same as INTERNET_MAX_URL_LENGTH
111 //#define _DEBUG_ADUNLOAD 1
113 HRESULT RunDllMain(MethodDesc *pMD, HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved); // clsload.cpp
121 SPTR_IMPL(SystemDomain, SystemDomain, m_pSystemDomain);
122 SVAL_IMPL(ArrayListStatic, SystemDomain, m_appDomainIndexList);
123 SPTR_IMPL(SharedDomain, SharedDomain, m_pSharedDomain);
124 SVAL_IMPL(BOOL, SystemDomain, s_fForceDebug);
125 SVAL_IMPL(BOOL, SystemDomain, s_fForceProfiling);
126 SVAL_IMPL(BOOL, SystemDomain, s_fForceInstrument);
128 #ifndef DACCESS_COMPILE
130 // Base Domain Statics
131 CrstStatic BaseDomain::m_SpecialStaticsCrst;
133 int BaseDomain::m_iNumberOfProcessors = 0;
135 // Shared Domain Statics
137 static BYTE g_pSharedDomainMemory[sizeof(SharedDomain)];
139 // System Domain Statics
140 GlobalStringLiteralMap* SystemDomain::m_pGlobalStringLiteralMap = NULL;
143 static BYTE g_pSystemDomainMemory[sizeof(SystemDomain)];
145 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
146 size_t SystemDomain::m_totalSurvivedBytes = 0;
147 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
149 CrstStatic SystemDomain::m_SystemDomainCrst;
150 CrstStatic SystemDomain::m_DelayedUnloadCrst;
152 ULONG SystemDomain::s_dNumAppDomains = 0;
154 AppDomain * SystemDomain::m_pAppDomainBeingUnloaded = NULL;
155 ADIndex SystemDomain::m_dwIndexOfAppDomainBeingUnloaded;
156 Thread *SystemDomain::m_pAppDomainUnloadRequestingThread = 0;
157 Thread *SystemDomain::m_pAppDomainUnloadingThread = 0;
159 ArrayListStatic SystemDomain::m_appDomainIdList;
161 DWORD SystemDomain::m_dwLowestFreeIndex = 0;
165 // comparison function to be used for matching clsids in our clsid hash table
166 BOOL CompareCLSID(UPTR u1, UPTR u2)
174 INJECT_FAULT(COMPlusThrowOM(););
178 GUID *pguid = (GUID *)(u1 << 1);
179 _ASSERTE(pguid != NULL);
181 MethodTable *pMT= (MethodTable *)u2;
182 _ASSERTE(pMT!= NULL);
185 pMT->GetGuid(&guid, TRUE);
186 if (!IsEqualIID(guid, *pguid))
192 #ifndef CROSSGEN_COMPILE
193 // Constructor for the LargeHeapHandleBucket class.
194 LargeHeapHandleBucket::LargeHeapHandleBucket(LargeHeapHandleBucket *pNext, DWORD Size, BaseDomain *pDomain, BOOL bCrossAD)
198 , m_CurrentEmbeddedFreePos(0) // hint for where to start a search for an embedded free item
205 PRECONDITION(CheckPointer(pDomain));
206 INJECT_FAULT(COMPlusThrowOM(););
210 PTRARRAYREF HandleArrayObj;
212 // Allocate the array in the large object heap.
215 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
216 HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, TRUE);
220 // During AD creation we don't want to assign the handle array to the currently running AD but
221 // to the AD being created. Ensure that AllocateArrayEx doesn't set the AD and then set it here.
222 AppDomain *pAD = pDomain->AsAppDomain();
224 _ASSERTE(pAD->IsBeingCreated());
228 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
229 array = AllocateArrayEx(
230 ClassLoader::LoadArrayTypeThrowing(g_pObjectClass),
237 array->SetAppDomain(pAD);
239 HandleArrayObj = (PTRARRAYREF)array;
242 // Retrieve the pointer to the data inside the array. This is legal since the array
243 // is located in the large object heap and is guaranteed not to move.
244 m_pArrayDataPtr = (OBJECTREF *)HandleArrayObj->GetDataPtr();
246 // Store the array in a strong handle to keep it alive.
247 m_hndHandleArray = pDomain->CreatePinningHandle((OBJECTREF)HandleArrayObj);
251 // Destructor for the LargeHeapHandleBucket class.
252 LargeHeapHandleBucket::~LargeHeapHandleBucket()
261 if (m_hndHandleArray)
263 DestroyPinningHandle(m_hndHandleArray);
264 m_hndHandleArray = NULL;
269 // Allocate handles from the bucket.
270 OBJECTREF *LargeHeapHandleBucket::AllocateHandles(DWORD nRequested)
280 _ASSERTE(nRequested > 0 && nRequested <= GetNumRemainingHandles());
281 _ASSERTE(m_pArrayDataPtr == (OBJECTREF*)((PTRARRAYREF)ObjectFromHandle(m_hndHandleArray))->GetDataPtr());
283 // Store the handles in the buffer that was passed in
284 OBJECTREF* ret = &m_pArrayDataPtr[m_CurrentPos];
285 m_CurrentPos += nRequested;
290 // look for a free item embedded in the table
291 OBJECTREF *LargeHeapHandleBucket::TryAllocateEmbeddedFreeHandle()
301 OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
302 _ASSERTE(pPreallocatedSentinalObject != NULL);
304 for (int i = m_CurrentEmbeddedFreePos; i < m_CurrentPos; i++)
306 if (m_pArrayDataPtr[i] == pPreallocatedSentinalObject)
308 m_CurrentEmbeddedFreePos = i;
309 m_pArrayDataPtr[i] = NULL;
310 return &m_pArrayDataPtr[i];
314 // 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)
316 m_CurrentEmbeddedFreePos = 0;
321 // Maximum bucket size will be 64K on 32-bit and 128K on 64-bit.
322 // We subtract out a small amount to leave room for the object
323 // header and length of the array.
325 #define MAX_BUCKETSIZE (16384 - 4)
327 // Constructor for the LargeHeapHandleTable class.
328 LargeHeapHandleTable::LargeHeapHandleTable(BaseDomain *pDomain, DWORD InitialBucketSize)
331 , m_NextBucketSize(InitialBucketSize)
332 , m_pFreeSearchHint(NULL)
340 PRECONDITION(CheckPointer(pDomain));
341 INJECT_FAULT(COMPlusThrowOM(););
351 // Destructor for the LargeHeapHandleTable class.
352 LargeHeapHandleTable::~LargeHeapHandleTable()
361 // Delete the buckets.
364 LargeHeapHandleBucket *pOld = m_pHead;
365 m_pHead = pOld->GetNext();
370 //*****************************************************************************
372 // LOCKING RULES FOR AllocateHandles() and ReleaseHandles() 12/08/2004
375 // These functions are not protected by any locking in this location but rather the callers are
376 // assumed to be doing suitable locking for the handle table. The handle table itself is
377 // behaving rather like a thread-agnostic collection class -- it doesn't want to know
378 // much about the outside world and so it is just doing its job with no awareness of
381 // The instance in question is
382 // There are two locations you can find a LargeHeapHandleTable
383 // 1) there is one in every BaseDomain, it is used to keep track of the static members
385 // 2) there is one in the System Domain that is used for the GlobalStringLiteralMap
387 // the one in (2) is not the same as the one that is in the BaseDomain object that corresponds
388 // to the SystemDomain -- that one is basically stilborn because the string literals don't go
389 // there and of course the System Domain has no code loaded into it -- only regular
390 // AppDomains (like Domain 0) actually execute code. As a result handle tables are in
391 // practice used either for string literals or for static members but never for both.
392 // At least not at this writing.
394 // Now it's useful to consider what the locking discipline is for these classes.
398 // First case: (easiest) is the statics members
400 // Each BaseDomain has its own critical section
402 // BaseDomain::AllocateObjRefPtrsInLargeTable takes a lock with
403 // CrstHolder ch(&m_LargeHeapHandleTableCrst);
405 // it does this before it calls AllocateHandles which suffices. It does not call ReleaseHandles
406 // at any time (although ReleaseHandles may be called via AllocateHandles if the request
407 // doesn't fit in the current block, the remaining handles at the end of the block are released
408 // automatically as part of allocation/recycling)
410 // note: Recycled handles are only used during String Literal allocation because we only try
411 // to recycle handles if the allocation request is for exactly one handle.
413 // The handles in the BaseDomain handle table are released when the Domain is unloaded
414 // as the GC objects become rootless at that time.
416 // This dispenses with all of the Handle tables except the one that is used for string literals
420 // Second case: Allocation for use in a string literal
422 // AppDomainStringLiteralMap::GetStringLiteral
424 // LargeHeapHandleBlockHolder constructor
426 // m_Data = pOwner->AllocateHandles(nCount);
428 // before doing this AppDomainStringLiteralMap::GetStringLiteral takes this lock
430 // CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
432 // which is the lock for the hash table that it owns
434 // STRINGREF *AppDomainStringLiteralMap::GetInternedString
436 // has a similar call path and uses the same approach and the same lock
437 // this covers all the paths which allocate
441 // Third case: Releases for use in a string literal entry
443 // CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
444 // taken in the AppDomainStringLiteralMap functions below protects the 4 ways that this can happen
448 // in an appdomain unload case
450 // AppDomainStringLiteralMap::~AppDomainStringLiteralMap() takes the lock then
452 // StringLiteralEntry::Release
454 // SystemDomain::GetGlobalStringLiteralMapNoCreate()->RemoveStringLiteralEntry(this)
456 // m_LargeHeapHandleTable.ReleaseHandles((OBJECTREF*)pObjRef, 1);
460 // AppDomainStringLiteralMap::GetStringLiteral() can call StringLiteralEntry::Release in some
461 // error cases, leading to the same stack as above
465 // AppDomainStringLiteralMap::GetInternedString() can call StringLiteralEntry::Release in some
466 // error cases, leading to the same stack as above
470 // The same code paths in 3b and 3c and also end up releasing if an exception is thrown
471 // during their processing. Both these paths use a StringLiteralEntryHolder to assist in cleanup,
472 // the StaticRelease method of the StringLiteralEntry gets called, which in turn calls the
476 // Allocate handles from the large heap handle table.
477 OBJECTREF* LargeHeapHandleTable::AllocateHandles(DWORD nRequested, BOOL bCrossAD)
484 PRECONDITION(nRequested > 0);
485 INJECT_FAULT(COMPlusThrowOM(););
489 // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
491 // the lock must be registered and already held by the caller per contract
493 _ASSERTE(m_pCrstDebug != NULL);
494 _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
497 if (nRequested == 1 && m_cEmbeddedFree != 0)
499 // special casing singleton requests to look for slots that can be re-used
501 // we need to do this because string literals are allocated one at a time and then sometimes
502 // released. we do not wish for the number of handles consumed by string literals to
503 // increase forever as assemblies are loaded and unloaded
505 if (m_pFreeSearchHint == NULL)
506 m_pFreeSearchHint = m_pHead;
508 while (m_pFreeSearchHint)
510 OBJECTREF* pObjRef = m_pFreeSearchHint->TryAllocateEmbeddedFreeHandle();
513 // the slot is to have been prepared with a null ready to go
514 _ASSERTE(*pObjRef == NULL);
518 m_pFreeSearchHint = m_pFreeSearchHint->GetNext();
521 // the search doesn't wrap around so it's possible that we might have embedded free items
522 // and not find them but that's ok, we'll get them on the next alloc... all we're trying to do
523 // is to not have big leaks over time.
527 // Retrieve the remaining number of handles in the bucket.
528 DWORD NumRemainingHandlesInBucket = (m_pHead != NULL) ? m_pHead->GetNumRemainingHandles() : 0;
530 // create a new block if this request doesn't fit in the current block
531 if (nRequested > NumRemainingHandlesInBucket)
535 // mark the handles in that remaining region as available for re-use
536 ReleaseHandles(m_pHead->CurrentPos(), NumRemainingHandlesInBucket);
538 // mark what's left as having been used
539 m_pHead->ConsumeRemaining();
542 // create a new bucket for this allocation
544 // We need a block big enough to hold the requested handles
545 DWORD NewBucketSize = max(m_NextBucketSize, nRequested);
547 m_pHead = new LargeHeapHandleBucket(m_pHead, NewBucketSize, m_pDomain, bCrossAD);
549 m_NextBucketSize = min(m_NextBucketSize * 2, MAX_BUCKETSIZE);
552 return m_pHead->AllocateHandles(nRequested);
555 //*****************************************************************************
556 // Release object handles allocated using AllocateHandles().
557 void LargeHeapHandleTable::ReleaseHandles(OBJECTREF *pObjRef, DWORD nReleased)
564 PRECONDITION(CheckPointer(pObjRef));
568 // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
570 // the lock must be registered and already held by the caller per contract
572 _ASSERTE(m_pCrstDebug != NULL);
573 _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
576 OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
577 _ASSERTE(pPreallocatedSentinalObject != NULL);
580 // Add the released handles to the list of available handles.
581 for (DWORD i = 0; i < nReleased; i++)
583 SetObjectReference(&pObjRef[i], pPreallocatedSentinalObject, NULL);
586 m_cEmbeddedFree += nReleased;
592 // Constructor for the ThreadStaticHandleBucket class.
593 ThreadStaticHandleBucket::ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain)
602 PRECONDITION(CheckPointer(pDomain));
603 INJECT_FAULT(COMPlusThrowOM(););
607 PTRARRAYREF HandleArrayObj;
609 // Allocate the array on the GC heap.
610 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
611 HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, FALSE);
613 // Store the array in a strong handle to keep it alive.
614 m_hndHandleArray = pDomain->CreateStrongHandle((OBJECTREF)HandleArrayObj);
617 // Destructor for the ThreadStaticHandleBucket class.
618 ThreadStaticHandleBucket::~ThreadStaticHandleBucket()
628 if (m_hndHandleArray)
630 DestroyStrongHandle(m_hndHandleArray);
631 m_hndHandleArray = NULL;
635 // Allocate handles from the bucket.
636 OBJECTHANDLE ThreadStaticHandleBucket::GetHandles()
646 return m_hndHandleArray;
649 // Constructor for the ThreadStaticHandleTable class.
650 ThreadStaticHandleTable::ThreadStaticHandleTable(BaseDomain *pDomain)
659 PRECONDITION(CheckPointer(pDomain));
664 // Destructor for the ThreadStaticHandleTable class.
665 ThreadStaticHandleTable::~ThreadStaticHandleTable()
674 // Delete the buckets.
677 ThreadStaticHandleBucket *pOld = m_pHead;
678 m_pHead = pOld->GetNext();
683 // Allocate handles from the large heap handle table.
684 OBJECTHANDLE ThreadStaticHandleTable::AllocateHandles(DWORD nRequested)
691 PRECONDITION(nRequested > 0);
692 INJECT_FAULT(COMPlusThrowOM(););
696 // create a new bucket for this allocation
697 m_pHead = new ThreadStaticHandleBucket(m_pHead, nRequested, m_pDomain);
699 return m_pHead->GetHandles();
702 #endif // CROSSGEN_COMPILE
705 //*****************************************************************************
707 //*****************************************************************************
708 void BaseDomain::Attach()
710 m_SpecialStaticsCrst.Init(CrstSpecialStatics);
713 BaseDomain::BaseDomain()
715 // initialize fields so the domain can be safely destructed
716 // shouldn't call anything that can fail here - use ::Init instead
726 m_fDisableInterfaceCache = FALSE;
728 m_pFusionContext = NULL;
729 m_pTPABinderContext = NULL;
731 // Make sure the container is set to NULL so that it gets loaded when it is used.
732 m_pLargeHeapHandleTable = NULL;
734 #ifndef CROSSGEN_COMPILE
735 // Note that m_handleStore is overridden by app domains
736 m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
738 m_handleStore = NULL;
741 m_pMarshalingData = NULL;
743 m_dwContextStatics = 0;
744 #ifdef FEATURE_COMINTEROP
745 m_pMngStdInterfacesInfo = NULL;
746 m_pWinRtBinder = NULL;
748 m_FileLoadLock.PreInit();
750 m_ClassInitLock.PreInit();
751 m_ILStubGenLock.PreInit();
753 #ifdef FEATURE_CODE_VERSIONING
754 m_codeVersionManager.PreInit(this == (BaseDomain *)g_pSharedDomainMemory);
757 } //BaseDomain::BaseDomain
759 //*****************************************************************************
760 void BaseDomain::Init()
767 INJECT_FAULT(COMPlusThrowOM(););
772 // Initialize the domain locks
775 if (this == reinterpret_cast<BaseDomain*>(&g_pSharedDomainMemory[0]))
776 m_DomainCrst.Init(CrstSharedBaseDomain);
777 else if (this == reinterpret_cast<BaseDomain*>(&g_pSystemDomainMemory[0]))
778 m_DomainCrst.Init(CrstSystemBaseDomain);
780 m_DomainCrst.Init(CrstBaseDomain);
782 m_DomainCacheCrst.Init(CrstAppDomainCache);
783 m_DomainLocalBlockCrst.Init(CrstDomainLocalBlock);
785 m_InteropDataCrst.Init(CrstInteropData, CRST_REENTRANCY);
787 m_WinRTFactoryCacheCrst.Init(CrstWinRTFactoryCache, CRST_UNSAFE_COOPGC);
789 // NOTE: CRST_UNSAFE_COOPGC prevents a GC mode switch to preemptive when entering this crst.
790 // If you remove this flag, we will switch to preemptive mode when entering
791 // m_FileLoadLock, which means all functions that enter it will become
792 // GC_TRIGGERS. (This includes all uses of PEFileListLockHolder, LoadLockHolder, etc.) So be sure
793 // to update the contracts if you remove this flag.
794 m_FileLoadLock.Init(CrstAssemblyLoader,
795 CrstFlags(CRST_HOST_BREAKABLE), TRUE);
798 // The JIT lock and the CCtor locks are at the same level (and marked as
799 // UNSAFE_SAME_LEVEL) because they are all part of the same deadlock detection mechanism. We
800 // see through cycles of JITting and .cctor execution and then explicitly allow the cycle to
801 // be broken by giving access to uninitialized classes. If there is no cycle or if the cycle
802 // involves other locks that arent part of this special deadlock-breaking semantics, then
803 // we continue to block.
805 m_JITLock.Init(CrstJit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
806 m_ClassInitLock.Init(CrstClassInit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
808 m_ILStubGenLock.Init(CrstILStubGen, CrstFlags(CRST_REENTRANCY), TRUE);
810 // Large heap handle table CRST.
811 m_LargeHeapHandleTableCrst.Init(CrstAppDomainHandleTable);
813 m_crstLoaderAllocatorReferences.Init(CrstLoaderAllocatorReferences);
814 // Has to switch thread to GC_NOTRIGGER while being held (see code:BaseDomain#AssemblyListLock)
815 m_crstAssemblyList.Init(CrstAssemblyList, CrstFlags(
816 CRST_GC_NOTRIGGER_WHEN_TAKEN | CRST_DEBUGGER_THREAD | CRST_TAKEN_DURING_SHUTDOWN));
818 // Initialize the EE marshaling data to NULL.
819 m_pMarshalingData = NULL;
821 #ifdef FEATURE_COMINTEROP
822 // Allocate the managed standard interfaces information.
823 m_pMngStdInterfacesInfo = new MngStdInterfacesInfo();
826 CLRPrivBinderWinRT::NamespaceResolutionKind fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_WindowsAPI;
827 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DesignerNamespaceResolutionEnabled) != FALSE)
829 fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_DesignerResolveEvent;
831 CLRPrivTypeCacheWinRT * pWinRtTypeCache = CLRPrivTypeCacheWinRT::GetOrCreateTypeCache();
832 m_pWinRtBinder = CLRPrivBinderWinRT::GetOrCreateBinder(pWinRtTypeCache, fNamespaceResolutionKind);
834 #endif // FEATURE_COMINTEROP
836 // Init the COM Interop data hash
838 LockOwner lock = {&m_InteropDataCrst, IsOwnerOfCrst};
839 m_interopDataHash.Init(0, NULL, false, &lock);
842 m_dwSizedRefHandles = 0;
843 if (!m_iNumberOfProcessors)
845 m_iNumberOfProcessors = GetCurrentProcessCpuCount();
849 #undef LOADERHEAP_PROFILE_COUNTER
851 #ifndef CROSSGEN_COMPILE
852 //*****************************************************************************
853 void BaseDomain::Terminate()
863 m_crstLoaderAllocatorReferences.Destroy();
864 m_DomainCrst.Destroy();
865 m_DomainCacheCrst.Destroy();
866 m_DomainLocalBlockCrst.Destroy();
867 m_InteropDataCrst.Destroy();
869 JitListLockEntry* pJitElement;
870 ListLockEntry* pElement;
872 // All the threads that are in this domain had better be stopped by this
875 // We might be jitting or running a .cctor so we need to empty that queue.
876 pJitElement = m_JITLock.Pop(TRUE);
879 #ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
880 _ASSERTE ((m_JITLock.m_pHead->m_dwRefCount == 1
881 && m_JITLock.m_pHead->m_hrResultCode == E_FAIL) ||
882 dbg_fDrasticShutdown || g_fInControlC);
883 #endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
885 pJitElement = m_JITLock.Pop(TRUE);
890 pElement = m_ClassInitLock.Pop(TRUE);
893 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
894 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
897 pElement = m_ClassInitLock.Pop(TRUE);
899 m_ClassInitLock.Destroy();
901 FileLoadLock* pFileElement;
902 pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
905 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
906 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
908 pFileElement->Release();
909 pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
911 m_FileLoadLock.Destroy();
913 pElement = m_ILStubGenLock.Pop(TRUE);
916 #ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
917 _ASSERTE ((m_ILStubGenLock.m_pHead->m_dwRefCount == 1
918 && m_ILStubGenLock.m_pHead->m_hrResultCode == E_FAIL) ||
919 dbg_fDrasticShutdown || g_fInControlC);
920 #endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
922 pElement = m_ILStubGenLock.Pop(TRUE);
924 m_ILStubGenLock.Destroy();
926 m_LargeHeapHandleTableCrst.Destroy();
928 if (m_pLargeHeapHandleTable != NULL)
930 delete m_pLargeHeapHandleTable;
931 m_pLargeHeapHandleTable = NULL;
936 // Kind of a workaround - during unloading, we need to have an EE halt
937 // around deleting this stuff. So it gets deleted in AppDomain::Terminate()
938 // for those things (because there is a convenient place there.)
939 GetLoaderAllocator()->CleanupStringLiteralMap();
942 #ifdef FEATURE_COMINTEROP
943 if (m_pMngStdInterfacesInfo)
945 delete m_pMngStdInterfacesInfo;
946 m_pMngStdInterfacesInfo = NULL;
949 if (m_pWinRtBinder != NULL)
951 m_pWinRtBinder->Release();
953 #endif // FEATURE_COMINTEROP
955 ClearFusionContext();
957 m_dwSizedRefHandles = 0;
959 #endif // CROSSGEN_COMPILE
961 void BaseDomain::InitVSD()
963 STANDARD_VM_CONTRACT;
965 // This is a workaround for gcc, since it fails to successfully resolve
966 // "TypeIDMap::STARTING_SHARED_DOMAIN_ID" when used within the ?: operator.
968 if (IsSharedDomain())
970 startingId = TypeIDMap::STARTING_SHARED_DOMAIN_ID;
974 startingId = TypeIDMap::STARTING_UNSHARED_DOMAIN_ID;
977 // By passing false as the last parameter, interfaces loaded in the
978 // shared domain will not be given fat type ids if RequiresFatDispatchTokens
979 // is set. This is correct, as the fat dispatch tokens are only needed to solve
980 // uniqueness problems involving domain specific types.
981 m_typeIDMap.Init(startingId, 2, !IsSharedDomain());
983 #ifndef CROSSGEN_COMPILE
984 GetLoaderAllocator()->InitVirtualCallStubManager(this);
988 #ifndef CROSSGEN_COMPILE
990 DWORD BaseDomain::AllocateContextStaticsOffset(DWORD* pOffsetSlot)
999 CrstHolder ch(&m_SpecialStaticsCrst);
1001 DWORD dwOffset = *pOffsetSlot;
1003 if (dwOffset == (DWORD)-1)
1005 // Allocate the slot
1006 dwOffset = m_dwContextStatics++;
1007 *pOffsetSlot = dwOffset;
1013 void BaseDomain::ClearFusionContext()
1023 if(m_pFusionContext) {
1024 m_pFusionContext->Release();
1025 m_pFusionContext = NULL;
1027 if (m_pTPABinderContext) {
1028 m_pTPABinderContext->Release();
1029 m_pTPABinderContext = NULL;
1033 #ifdef FEATURE_PREJIT
1034 void AppDomain::DeleteNativeCodeRanges()
1045 // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized
1046 // and yet we are destroying it. (This is the case if we OOM during AppDomain creation.)
1047 if (m_Assemblies.IsEmpty())
1050 // Shutdown assemblies
1051 AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad) );
1052 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1054 while (i.Next(pDomainAssembly.This()))
1056 Assembly * assembly = pDomainAssembly->m_pAssembly;
1057 if ((assembly != NULL) && !assembly->IsDomainNeutral())
1058 assembly->DeleteNativeCodeRanges();
1063 void AppDomain::ShutdownAssemblies()
1073 // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized
1074 // and yet we are destroying it. (This is the case if we OOM during AppDomain creation.)
1075 if (m_Assemblies.IsEmpty())
1078 // Shutdown assemblies
1079 // has two stages because Terminate needs info from the Assembly's dependencies
1081 // Stage 1: call code:Assembly::Terminate
1082 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1083 kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
1084 DomainAssembly * pDomainAssembly = NULL;
1086 while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1088 // Note: cannot use DomainAssembly::GetAssembly() here as it asserts that the assembly has been
1089 // loaded to at least the FILE_LOAD_ALLOCATE level. Since domain shutdown can take place
1090 // asynchronously this property cannot be guaranteed. Access the m_pAssembly field directly instead.
1091 Assembly * assembly = pDomainAssembly->m_pAssembly;
1092 if (assembly && !assembly->IsDomainNeutral())
1093 assembly->Terminate();
1096 // Stage 2: Clear the list of assemblies
1097 i = IterateAssembliesEx((AssemblyIterationFlags)(
1098 kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
1099 while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1101 // We are in shutdown path, no one else can get to the list anymore
1102 delete pDomainAssembly;
1104 m_Assemblies.Clear(this);
1106 // Stage 2: Clear the loader allocators registered for deletion from code:Assembly:Terminate calls in
1108 // Note: It is not clear to me why we cannot delete the loader allocator from within
1109 // code:DomainAssembly::~DomainAssembly
1110 ShutdownFreeLoaderAllocators(FALSE);
1111 } // AppDomain::ShutdownAssemblies
1113 void AppDomain::ShutdownFreeLoaderAllocators(BOOL bFromManagedCode)
1115 // If we're called from managed code (i.e. the finalizer thread) we take a lock in
1116 // LoaderAllocator::CleanupFailedTypeInit, which may throw. Otherwise we're called
1117 // from the app-domain shutdown path in which we can avoid taking the lock.
1121 if (bFromManagedCode) THROWS; else NOTHROW;
1127 CrstHolder ch(GetLoaderAllocatorReferencesLock());
1129 // Shutdown the LoaderAllocators associated with collectible assemblies
1130 while (m_pDelayedLoaderAllocatorUnloadList != NULL)
1132 LoaderAllocator * pCurrentLoaderAllocator = m_pDelayedLoaderAllocatorUnloadList;
1133 // Remove next loader allocator from the list
1134 m_pDelayedLoaderAllocatorUnloadList = m_pDelayedLoaderAllocatorUnloadList->m_pLoaderAllocatorDestroyNext;
1136 if (bFromManagedCode)
1138 // For loader allocator finalization, we need to be careful about cleaning up per-appdomain allocations
1139 // and synchronizing with GC using delay unload list. We need to wait for next Gen2 GC to finish to ensure
1140 // that GC heap does not have any references to the MethodTables being unloaded.
1142 pCurrentLoaderAllocator->CleanupFailedTypeInit();
1144 pCurrentLoaderAllocator->CleanupHandles();
1147 SystemDomain::System()->AddToDelayedUnloadList(pCurrentLoaderAllocator);
1151 // For appdomain unload, delete the loader allocator right away
1152 delete pCurrentLoaderAllocator;
1155 } // AppDomain::ShutdownFreeLoaderAllocators
1157 //---------------------------------------------------------------------------------------
1159 // Register the loader allocator for deletion in code:AppDomain::ShutdownFreeLoaderAllocators.
1161 void AppDomain::RegisterLoaderAllocatorForDeletion(LoaderAllocator * pLoaderAllocator)
1172 CrstHolder ch(GetLoaderAllocatorReferencesLock());
1174 pLoaderAllocator->m_pLoaderAllocatorDestroyNext = m_pDelayedLoaderAllocatorUnloadList;
1175 m_pDelayedLoaderAllocatorUnloadList = pLoaderAllocator;
1178 void AppDomain::ShutdownNativeDllSearchDirectories()
1180 LIMITED_METHOD_CONTRACT;
1181 // Shutdown assemblies
1182 PathIterator i = IterateNativeDllSearchDirectories();
1189 m_NativeDllSearchDirectories.Clear();
1192 void AppDomain::ReleaseDomainBoundInfo()
1201 // Shutdown assemblies
1202 m_AssemblyCache.OnAppDomainUnload();
1204 AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeFailedToLoad) );
1205 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1207 while (i.Next(pDomainAssembly.This()))
1209 pDomainAssembly->ReleaseManagedData();
1213 void AppDomain::ReleaseFiles()
1215 STANDARD_VM_CONTRACT;
1217 // Shutdown assemblies
1218 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1219 kIncludeLoaded | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeLoading));
1220 CollectibleAssemblyHolder<DomainAssembly *> pAsm;
1222 while (i.Next(pAsm.This()))
1224 if (pAsm->GetCurrentAssembly() == NULL)
1226 // Might be domain neutral or not, but should have no live objects as it has not been
1227 // really loaded yet. Just reset it.
1228 _ASSERTE(FitsIn<DWORD>(i.GetIndex()));
1229 m_Assemblies.Set(this, static_cast<DWORD>(i.GetIndex()), NULL);
1230 delete pAsm.Extract();
1234 if (!pAsm->GetCurrentAssembly()->IsDomainNeutral())
1235 pAsm->ReleaseFiles();
1238 } // AppDomain::ReleaseFiles
1241 OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate, BOOL bCrossAD)
1248 PRECONDITION((nRequested > 0));
1249 INJECT_FAULT(COMPlusThrowOM(););
1253 if (ppLazyAllocate && *ppLazyAllocate)
1255 // Allocation already happened
1256 return *ppLazyAllocate;
1259 // Enter preemptive state, take the lock and go back to cooperative mode.
1261 CrstHolder ch(&m_LargeHeapHandleTableCrst);
1264 if (ppLazyAllocate && *ppLazyAllocate)
1266 // Allocation already happened
1267 return *ppLazyAllocate;
1270 // Make sure the large heap handle table is initialized.
1271 if (!m_pLargeHeapHandleTable)
1272 InitLargeHeapHandleTable();
1274 // Allocate the handles.
1275 OBJECTREF* result = m_pLargeHeapHandleTable->AllocateHandles(nRequested, bCrossAD);
1279 *ppLazyAllocate = result;
1285 #endif // CROSSGEN_COMPILE
1287 #endif // !DACCESS_COMPILE
1290 PTR_BaseDomain BaseDomain::ComputeBaseDomain(
1291 BaseDomain * pGenericDefinitionDomain, // the domain that owns the generic type or method
1292 Instantiation classInst, // the type arguments to the type (if any)
1293 Instantiation methodInst) // the type arguments to the method (if any)
1295 CONTRACT(PTR_BaseDomain)
1301 POSTCONDITION(CheckPointer(RETVAL));
1307 if (pGenericDefinitionDomain && pGenericDefinitionDomain->IsAppDomain())
1308 RETURN PTR_BaseDomain(pGenericDefinitionDomain);
1310 for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
1312 PTR_BaseDomain pArgDomain = classInst[i].GetDomain();
1313 if (pArgDomain->IsAppDomain())
1317 for (DWORD i = 0; i < methodInst.GetNumArgs(); i++)
1319 PTR_BaseDomain pArgDomain = methodInst[i].GetDomain();
1320 if (pArgDomain->IsAppDomain())
1323 RETURN (pGenericDefinitionDomain ?
1324 PTR_BaseDomain(pGenericDefinitionDomain) :
1325 PTR_BaseDomain(SystemDomain::System()));
1328 PTR_BaseDomain BaseDomain::ComputeBaseDomain(TypeKey * pKey)
1340 if (pKey->GetKind() == ELEMENT_TYPE_CLASS)
1341 return BaseDomain::ComputeBaseDomain(pKey->GetModule()->GetDomain(),
1342 pKey->GetInstantiation());
1343 else if (pKey->GetKind() != ELEMENT_TYPE_FNPTR)
1344 return pKey->GetElementType().GetDomain();
1346 return BaseDomain::ComputeBaseDomain(NULL,Instantiation(pKey->GetRetAndArgTypes(), pKey->GetNumArgs()+1));
1353 #ifndef DACCESS_COMPILE
1355 // Insert class in the hash table
1356 void AppDomain::InsertClassForCLSID(MethodTable* pMT, BOOL fForceInsert /*=FALSE*/)
1363 INJECT_FAULT(COMPlusThrowOM(););
1369 // Ensure that registered classes are activated for allocation
1370 pMT->EnsureInstanceActive();
1372 // Note that it is possible for multiple classes to claim the same CLSID, and in such a
1373 // case it is arbitrary which one we will return for a future query for a given app domain.
1375 pMT->GetGuid(&cvid, fForceInsert);
1377 if (!IsEqualIID(cvid, GUID_NULL))
1379 //<TODO>@todo get a better key</TODO>
1380 LPVOID val = (LPVOID)pMT;
1382 LockHolder lh(this);
1384 if (LookupClass(cvid) != pMT)
1386 m_clsidHash.InsertValue(GetKeyFromGUID(&cvid), val);
1392 void AppDomain::InsertClassForCLSID(MethodTable* pMT, GUID *pGuid)
1397 PRECONDITION(CheckPointer(pMT));
1398 PRECONDITION(CheckPointer(pGuid));
1402 LPVOID val = (LPVOID)pMT;
1404 LockHolder lh(this);
1407 if (LookupClass(*cvid) != pMT)
1409 m_clsidHash.InsertValue(GetKeyFromGUID(pGuid), val);
1415 #endif // DACCESS_COMPILE
1417 #ifdef FEATURE_COMINTEROP
1419 #ifndef DACCESS_COMPILE
1420 void AppDomain::CacheTypeByName(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1422 WRAPPER_NO_CONTRACT;
1423 LockHolder lh(this);
1424 CacheTypeByNameWorker(ssClassName, vCacheVersion, typeHandle, bFlags, bReplaceExisting);
1427 void AppDomain::CacheTypeByNameWorker(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1433 PRECONDITION(!typeHandle.IsNull());
1437 NewArrayHolder<WCHAR> wzClassName(DuplicateStringThrowing(ssClassName.GetUnicode()));
1439 if (m_vNameToTypeMapVersion != vCacheVersion)
1442 if (m_pNameToTypeMap == nullptr)
1444 m_pNameToTypeMap = new NameToTypeMapTable();
1447 NameToTypeMapEntry e;
1448 e.m_key.m_wzName = wzClassName;
1449 e.m_key.m_cchName = ssClassName.GetCount();
1450 e.m_typeHandle = typeHandle;
1451 e.m_nEpoch = this->m_nEpoch;
1452 e.m_bFlags = bFlags;
1453 if (!bReplaceExisting)
1454 m_pNameToTypeMap->Add(e);
1456 m_pNameToTypeMap->AddOrReplace(e);
1458 wzClassName.SuppressRelease();
1460 #endif // DACCESS_COMPILE
1462 TypeHandle AppDomain::LookupTypeByName(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1464 WRAPPER_NO_CONTRACT;
1465 LockHolder lh(this);
1466 return LookupTypeByNameWorker(ssClassName, pvCacheVersion, pbFlags);
1469 TypeHandle AppDomain::LookupTypeByNameWorker(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1476 PRECONDITION(CheckPointer(pbFlags, NULL_OK));
1480 *pvCacheVersion = m_vNameToTypeMapVersion;
1482 if (m_pNameToTypeMap == nullptr)
1483 return TypeHandle(); // a null TypeHandle
1485 NameToTypeMapEntry::Key key;
1486 key.m_cchName = ssClassName.GetCount();
1487 key.m_wzName = ssClassName.GetUnicode();
1489 const NameToTypeMapEntry * pEntry = m_pNameToTypeMap->LookupPtr(key);
1491 return TypeHandle(); // a null TypeHandle
1493 if (pbFlags != NULL)
1494 *pbFlags = pEntry->m_bFlags;
1496 return pEntry->m_typeHandle;
1499 PTR_MethodTable AppDomain::LookupTypeByGuid(const GUID & guid)
1513 GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1514 sGuid.Append(wszGuid);
1517 TypeHandle th = LookupTypeByName(sGuid, &ver, NULL);
1521 _ASSERTE(!th.IsTypeDesc());
1522 return th.AsMethodTable();
1525 #ifdef FEATURE_PREJIT
1528 // Next look in each ngen'ed image in turn
1529 AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1530 kIncludeLoaded | kIncludeExecution));
1531 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1532 while (assemblyIterator.Next(pDomainAssembly.This()))
1534 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1536 DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1539 Module * pModule = i.GetLoadedModule();
1540 if (!pModule->HasNativeImage())
1542 _ASSERTE(!pModule->IsCollectible());
1543 PTR_MethodTable pMT = pModule->LookupTypeByGuid(guid);
1551 #endif // FEATURE_PREJIT
1555 #ifndef DACCESS_COMPILE
1556 void AppDomain::CacheWinRTTypeByGuid(TypeHandle typeHandle)
1563 PRECONDITION(!typeHandle.IsTypeDesc());
1564 PRECONDITION(CanCacheWinRTTypeByGuid(typeHandle));
1568 PTR_MethodTable pMT = typeHandle.AsMethodTable();
1571 if (pMT->GetGuidForWinRT(&guid))
1577 GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1578 sGuid.Append(wszGuid);
1585 LockHolder lh(this);
1586 th = LookupTypeByNameWorker(sGuid, &vCacheVersion, &bFlags);
1590 // no other entry with the same GUID exists in the cache
1591 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags);
1593 else if (typeHandle.AsMethodTable() != th.AsMethodTable() && th.IsProjectedFromWinRT())
1595 // If we found a native WinRT type cached with the same GUID, replace it.
1596 // Otherwise simply add the new mapping to the cache.
1597 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags, TRUE);
1602 #endif // DACCESS_COMPILE
1604 void AppDomain::GetCachedWinRTTypes(
1605 SArray<PTR_MethodTable> * pTypes,
1606 SArray<GUID> * pGuids,
1619 LockHolder lh(this);
1621 for (auto it = m_pNameToTypeMap->Begin(), end = m_pNameToTypeMap->End();
1625 NameToTypeMapEntry entry = (NameToTypeMapEntry)(*it);
1626 TypeHandle th = entry.m_typeHandle;
1627 if (th.AsMethodTable() != NULL &&
1628 entry.m_key.m_wzName[0] == W('{') &&
1629 entry.m_nEpoch >= minEpoch)
1631 _ASSERTE(!th.IsTypeDesc());
1632 PTR_MethodTable pMT = th.AsMethodTable();
1633 // we're parsing the GUID value from the cache, because projected types do not cache the
1634 // COM GUID in their GetGuid() but rather the legacy GUID
1636 if (LPWSTRToGuid(&iid, entry.m_key.m_wzName, 38) && iid != GUID_NULL)
1638 pTypes->Append(pMT);
1639 pGuids->Append(iid);
1644 #ifdef FEATURE_PREJIT
1645 // Next look in each ngen'ed image in turn
1646 AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1647 kIncludeLoaded | kIncludeExecution));
1648 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1649 while (assemblyIterator.Next(pDomainAssembly.This()))
1651 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1653 DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1656 Module * pModule = i.GetLoadedModule();
1657 if (!pModule->HasNativeImage())
1659 _ASSERTE(!pModule->IsCollectible());
1661 pModule->GetCachedWinRTTypes(pTypes, pGuids);
1664 #endif // FEATURE_PREJIT
1666 if (pCurEpoch != NULL)
1667 *pCurEpoch = m_nEpoch;
1671 #ifndef CROSSGEN_COMPILE
1672 #ifndef DACCESS_COMPILE
1674 void WinRTFactoryCacheTraits::OnDestructPerEntryCleanupAction(const WinRTFactoryCacheEntry& e)
1676 WRAPPER_NO_CONTRACT;
1677 if (e.m_pCtxEntry != NULL)
1679 e.m_pCtxEntry->Release();
1681 // the AD is going away, no need to destroy the OBJECTHANDLE
1684 void AppDomain::CacheWinRTFactoryObject(MethodTable *pClassMT, OBJECTREF *refFactory, LPVOID lpCtxCookie)
1691 PRECONDITION(CheckPointer(pClassMT));
1695 CtxEntryHolder pNewCtxEntry;
1696 if (lpCtxCookie != NULL)
1698 // We don't want to insert the context cookie in the cache because it's just an address
1699 // of an internal COM data structure which will be freed when the apartment is torn down.
1700 // What's worse, if another apartment is later created, its context cookie may have exactly
1701 // the same value leading to incorrect cache hits. We'll use our CtxEntry instead which
1702 // is ref-counted and keeps the COM data structure alive even after the apartment ceases
1704 pNewCtxEntry = CtxEntryCache::GetCtxEntryCache()->FindCtxEntry(lpCtxCookie, GetThread());
1707 WinRTFactoryCacheLockHolder lh(this);
1709 if (m_pWinRTFactoryCache == nullptr)
1711 m_pWinRTFactoryCache = new WinRTFactoryCache();
1714 WinRTFactoryCacheEntry *pEntry = const_cast<WinRTFactoryCacheEntry*>(m_pWinRTFactoryCache->LookupPtr(pClassMT));
1718 // No existing entry for this cache
1721 WinRTFactoryCacheEntry e;
1723 OBJECTHANDLEHolder ohNewHandle(CreateHandle(*refFactory));
1726 e.m_pCtxEntry = pNewCtxEntry;
1727 e.m_ohFactoryObject = ohNewHandle;
1729 m_pWinRTFactoryCache->Add(e);
1731 // suppress release of the CtxEntry and handle after we successfully inserted the new entry
1732 pNewCtxEntry.SuppressRelease();
1733 ohNewHandle.SuppressRelease();
1740 // release the old CtxEntry and update the entry
1741 CtxEntry *pTemp = pNewCtxEntry.Extract();
1742 pNewCtxEntry = pEntry->m_pCtxEntry;
1743 pEntry->m_pCtxEntry = pTemp;
1745 IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
1746 mgr->StoreObjectInHandle(pEntry->m_ohFactoryObject, OBJECTREFToObject(*refFactory));
1750 OBJECTREF AppDomain::LookupWinRTFactoryObject(MethodTable *pClassMT, LPVOID lpCtxCookie)
1757 PRECONDITION(CheckPointer(pClassMT));
1758 PRECONDITION(CheckPointer(m_pWinRTFactoryCache, NULL_OK));
1763 if (m_pWinRTFactoryCache == nullptr)
1767 // Retrieve cached factory
1769 WinRTFactoryCacheLockHolder lh(this);
1771 const WinRTFactoryCacheEntry *pEntry = m_pWinRTFactoryCache->LookupPtr(pClassMT);
1776 // Ignore factories from a different context, unless lpCtxCookie == NULL,
1777 // which means the factory is free-threaded
1778 // Note that we cannot touch the RCW to retrieve cookie at this point
1779 // because the RCW might belong to a STA thread and that STA thread might die
1780 // and take the RCW with it. Therefore we have to save cookie in this cache
1782 if (pEntry->m_pCtxEntry == NULL || pEntry->m_pCtxEntry->GetCtxCookie() == lpCtxCookie)
1783 return ObjectFromHandle(pEntry->m_ohFactoryObject);
1788 void AppDomain::RemoveWinRTFactoryObjects(LPVOID pCtxCookie)
1798 if (m_pWinRTFactoryCache == nullptr)
1801 // helper class for delayed CtxEntry cleanup
1802 class CtxEntryListReleaseHolder
1805 CQuickArrayList<CtxEntry *> m_list;
1807 ~CtxEntryListReleaseHolder()
1817 for (SIZE_T i = 0; i < m_list.Size(); i++)
1819 m_list[i]->Release();
1822 } ctxEntryListReleaseHolder;
1826 WinRTFactoryCacheLockHolder lh(this);
1828 // Go through the hash table and remove items in the given context
1829 for (WinRTFactoryCache::Iterator it = m_pWinRTFactoryCache->Begin(); it != m_pWinRTFactoryCache->End(); it++)
1831 if (it->m_pCtxEntry != NULL && it->m_pCtxEntry->GetCtxCookie() == pCtxCookie)
1833 // Releasing the CtxEntry may trigger GC which we can't do under the lock so we push
1834 // it on our local list and release them all after we're done iterating the hashtable.
1835 ctxEntryListReleaseHolder.m_list.Push(it->m_pCtxEntry);
1837 DestroyHandle(it->m_ohFactoryObject);
1838 m_pWinRTFactoryCache->Remove(it);
1844 OBJECTREF AppDomain::GetMissingObject()
1857 FieldDesc *pValueFD = MscorlibBinder::GetField(FIELD__MISSING__VALUE);
1859 pValueFD->CheckRunClassInitThrowing();
1861 // Retrieve the value static field and store it.
1862 OBJECTHANDLE hndMissing = CreateHandle(pValueFD->GetStaticOBJECTREF());
1864 if (FastInterlockCompareExchangePointer(&m_hndMissing, hndMissing, NULL) != NULL)
1866 // Exchanged failed. The m_hndMissing did not equal NULL and was returned.
1867 DestroyHandle(hndMissing);
1871 return ObjectFromHandle(m_hndMissing);
1874 #endif // DACCESS_COMPILE
1875 #endif //CROSSGEN_COMPILE
1876 #endif // FEATURE_COMINTEROP
1878 #ifndef DACCESS_COMPILE
1880 EEMarshalingData *BaseDomain::GetMarshalingData()
1882 CONTRACT (EEMarshalingData*)
1887 INJECT_FAULT(COMPlusThrowOM());
1888 POSTCONDITION(CheckPointer(m_pMarshalingData));
1892 if (!m_pMarshalingData)
1895 CrstHolder holder(&m_InteropDataCrst);
1897 if (!m_pMarshalingData)
1899 LoaderHeap* pHeap = GetLoaderAllocator()->GetLowFrequencyHeap();
1900 m_pMarshalingData = new (pHeap) EEMarshalingData(this, pHeap, &m_DomainCrst);
1904 RETURN m_pMarshalingData;
1907 void BaseDomain::DeleteMarshalingData()
1917 // We are in shutdown - no need to take any lock
1918 if (m_pMarshalingData)
1920 delete m_pMarshalingData;
1921 m_pMarshalingData = NULL;
1925 #ifndef CROSSGEN_COMPILE
1927 STRINGREF *BaseDomain::IsStringInterned(STRINGREF *pString)
1934 PRECONDITION(CheckPointer(pString));
1935 INJECT_FAULT(COMPlusThrowOM(););
1939 return GetLoaderAllocator()->IsStringInterned(pString);
1942 STRINGREF *BaseDomain::GetOrInternString(STRINGREF *pString)
1949 PRECONDITION(CheckPointer(pString));
1950 INJECT_FAULT(COMPlusThrowOM(););
1954 return GetLoaderAllocator()->GetOrInternString(pString);
1957 void BaseDomain::InitLargeHeapHandleTable()
1964 PRECONDITION(m_pLargeHeapHandleTable==NULL);
1965 INJECT_FAULT(COMPlusThrowOM(););
1969 m_pLargeHeapHandleTable = new LargeHeapHandleTable(this, STATIC_OBJECT_TABLE_BUCKET_SIZE);
1972 m_pLargeHeapHandleTable->RegisterCrstDebug(&m_LargeHeapHandleTableCrst);
1976 #ifdef FEATURE_COMINTEROP
1977 MethodTable* AppDomain::GetLicenseInteropHelperMethodTable()
1986 if(m_pLicenseInteropHelperMT == NULL)
1988 // Do this work outside of the lock so we don't have an unbreakable lock condition
1990 TypeHandle licenseMgrTypeHnd;
1991 MethodDescCallSite loadLM(METHOD__MARSHAL__LOAD_LICENSE_MANAGER);
1993 licenseMgrTypeHnd = (MethodTable*) loadLM.Call_RetLPVOID((ARG_SLOT*)NULL);
1996 // Look up this method by name, because the type is actually declared in System.dll. <TODO>@todo: why?</TODO>
1999 MethodDesc *pGetLIHMD = MemberLoader::FindMethod(licenseMgrTypeHnd.AsMethodTable(),
2000 "GetLicenseInteropHelperType", &gsig_SM_Void_RetIntPtr);
2001 _ASSERTE(pGetLIHMD);
2003 TypeHandle lihTypeHnd;
2005 MethodDescCallSite getLIH(pGetLIHMD);
2006 lihTypeHnd = (MethodTable*) getLIH.Call_RetLPVOID((ARG_SLOT*)NULL);
2008 BaseDomain::LockHolder lh(this);
2010 if(m_pLicenseInteropHelperMT == NULL)
2011 m_pLicenseInteropHelperMT = lihTypeHnd.AsMethodTable();
2013 return m_pLicenseInteropHelperMT;
2016 COMorRemotingFlag AppDomain::GetComOrRemotingFlag()
2026 // 0. check if the value is already been set
2027 if (m_COMorRemotingFlag != COMorRemoting_NotInitialized)
2028 return m_COMorRemotingFlag;
2030 // 1. check whether the process is AppX
2031 if (AppX::IsAppXProcess())
2033 // do not use Remoting in AppX
2034 m_COMorRemotingFlag = COMorRemoting_COM;
2035 return m_COMorRemotingFlag;
2038 // 2. check the xml file
2039 m_COMorRemotingFlag = GetPreferComInsteadOfManagedRemotingFromConfigFile();
2040 if (m_COMorRemotingFlag != COMorRemoting_NotInitialized)
2042 return m_COMorRemotingFlag;
2045 // 3. check the global setting
2046 if (NULL != g_pConfig && g_pConfig->ComInsteadOfManagedRemoting())
2048 m_COMorRemotingFlag = COMorRemoting_COM;
2052 m_COMorRemotingFlag = COMorRemoting_Remoting;
2055 return m_COMorRemotingFlag;
2058 BOOL AppDomain::GetPreferComInsteadOfManagedRemoting()
2060 WRAPPER_NO_CONTRACT;
2062 return (GetComOrRemotingFlag() == COMorRemoting_COM);
2065 STDAPI GetXMLObjectEx(IXMLParser **ppv);
2067 COMorRemotingFlag AppDomain::GetPreferComInsteadOfManagedRemotingFromConfigFile()
2077 return COMorRemoting_COM;
2079 #endif // FEATURE_COMINTEROP
2081 #endif // CROSSGEN_COMPILE
2083 //*****************************************************************************
2084 //*****************************************************************************
2085 //*****************************************************************************
2087 void *SystemDomain::operator new(size_t size, void *pInPlace)
2089 LIMITED_METHOD_CONTRACT;
2094 void SystemDomain::operator delete(void *pMem)
2096 LIMITED_METHOD_CONTRACT;
2097 // Do nothing - new() was in-place
2101 void SystemDomain::SetCompilationOverrides(BOOL fForceDebug,
2102 BOOL fForceProfiling,
2103 BOOL fForceInstrument)
2105 LIMITED_METHOD_CONTRACT;
2106 s_fForceDebug = fForceDebug;
2107 s_fForceProfiling = fForceProfiling;
2108 s_fForceInstrument = fForceInstrument;
2111 #endif //!DACCESS_COMPILE
2113 void SystemDomain::GetCompilationOverrides(BOOL * fForceDebug,
2114 BOOL * fForceProfiling,
2115 BOOL * fForceInstrument)
2117 LIMITED_METHOD_DAC_CONTRACT;
2118 *fForceDebug = s_fForceDebug;
2119 *fForceProfiling = s_fForceProfiling;
2120 *fForceInstrument = s_fForceInstrument;
2123 #ifndef DACCESS_COMPILE
2125 void SystemDomain::Attach()
2132 PRECONDITION(m_pSystemDomain == NULL);
2133 INJECT_FAULT(COMPlusThrowOM(););
2137 #ifndef CROSSGEN_COMPILE
2138 // Initialize stub managers
2139 PrecodeStubManager::Init();
2140 DelegateInvokeStubManager::Init();
2141 JumpStubStubManager::Init();
2142 RangeSectionStubManager::Init();
2143 ILStubManager::Init();
2144 InteropDispatchStubManager::Init();
2145 StubLinkStubManager::Init();
2147 ThunkHeapStubManager::Init();
2149 TailCallStubManager::Init();
2151 PerAppDomainTPCountList::InitAppDomainIndexList();
2152 #endif // CROSSGEN_COMPILE
2154 m_appDomainIndexList.Init();
2155 m_appDomainIdList.Init();
2157 m_SystemDomainCrst.Init(CrstSystemDomain, (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN));
2158 m_DelayedUnloadCrst.Init(CrstSystemDomainDelayedUnloadList, CRST_UNSAFE_COOPGC);
2160 // Initialize the ID dispenser that is used for domain neutral module IDs
2161 g_pModuleIndexDispenser = new IdDispenser();
2163 // Create the global SystemDomain and initialize it.
2164 m_pSystemDomain = new (&g_pSystemDomainMemory[0]) SystemDomain();
2165 // No way it can fail since g_pSystemDomainMemory is a static array.
2166 CONSISTENCY_CHECK(CheckPointer(m_pSystemDomain));
2168 LOG((LF_CLASSLOADER,
2170 "Created system domain at %p\n",
2173 // We need to initialize the memory pools etc. for the system domain.
2174 m_pSystemDomain->BaseDomain::Init(); // Setup the memory heaps
2176 // Create the default domain
2177 m_pSystemDomain->CreateDefaultDomain();
2178 SharedDomain::Attach();
2180 // Each domain gets its own ReJitManager, and ReJitManager has its own static
2181 // initialization to run
2182 ReJitManager::InitStatic();
2185 #ifndef CROSSGEN_COMPILE
2187 void SystemDomain::DetachBegin()
2189 WRAPPER_NO_CONTRACT;
2190 // Shut down the domain and its children (but don't deallocate anything just
2193 // TODO: we should really not running managed DLLMain during process detach.
2194 if (GetThread() == NULL)
2200 m_pSystemDomain->Stop();
2203 void SystemDomain::DetachEnd()
2212 // Shut down the domain and its children (but don't deallocate anything just
2217 m_pSystemDomain->ClearFusionContext();
2218 if (m_pSystemDomain->m_pDefaultDomain)
2219 m_pSystemDomain->m_pDefaultDomain->ClearFusionContext();
2223 void SystemDomain::Stop()
2225 WRAPPER_NO_CONTRACT;
2226 AppDomainIterator i(TRUE);
2229 if (i.GetDomain()->m_Stage < AppDomain::STAGE_CLEARED)
2230 i.GetDomain()->Stop();
2234 void SystemDomain::Terminate() // bNotifyProfiler is ignored
2244 // This ignores the refences and terminates the appdomains
2245 AppDomainIterator i(FALSE);
2249 delete i.GetDomain();
2250 // Keep the iterator from Releasing the current domain
2251 i.m_pCurrent = NULL;
2254 if (m_pSystemFile != NULL) {
2255 m_pSystemFile->Release();
2256 m_pSystemFile = NULL;
2259 m_pSystemAssembly = NULL;
2262 delete[] m_pwDevpath;
2268 if (m_pGlobalStringLiteralMap) {
2269 delete m_pGlobalStringLiteralMap;
2270 m_pGlobalStringLiteralMap = NULL;
2274 SharedDomain::Detach();
2276 BaseDomain::Terminate();
2278 #ifdef FEATURE_COMINTEROP
2279 if (g_pRCWCleanupList != NULL)
2280 delete g_pRCWCleanupList;
2281 #endif // FEATURE_COMINTEROP
2282 m_GlobalAllocator.Terminate();
2286 void SystemDomain::PreallocateSpecialObjects()
2293 INJECT_FAULT(COMPlusThrowOM(););
2297 _ASSERTE(g_pPreallocatedSentinelObject == NULL);
2299 OBJECTREF pPreallocatedSentinalObject = AllocateObject(g_pObjectClass);
2300 #if CHECK_APP_DOMAIN_LEAKS
2301 pPreallocatedSentinalObject->SetSyncBlockAppDomainAgile();
2303 g_pPreallocatedSentinelObject = CreatePinningHandle( pPreallocatedSentinalObject );
2305 #ifdef FEATURE_PREJIT
2306 if (SystemModule()->HasNativeImage())
2308 CORCOMPILE_EE_INFO_TABLE *pEEInfo = SystemModule()->GetNativeImage()->GetNativeEEInfoTable();
2309 pEEInfo->emptyString = (CORINFO_Object **)StringObject::GetEmptyStringRefPtr();
2314 void SystemDomain::CreatePreallocatedExceptions()
2321 INJECT_FAULT(COMPlusThrowOM(););
2325 EXCEPTIONREF pBaseException = (EXCEPTIONREF)AllocateObject(g_pExceptionClass);
2326 pBaseException->SetHResult(COR_E_EXCEPTION);
2327 pBaseException->SetXCode(EXCEPTION_COMPLUS);
2328 _ASSERTE(g_pPreallocatedBaseException == NULL);
2329 g_pPreallocatedBaseException = CreateHandle(pBaseException);
2332 EXCEPTIONREF pOutOfMemory = (EXCEPTIONREF)AllocateObject(g_pOutOfMemoryExceptionClass);
2333 pOutOfMemory->SetHResult(COR_E_OUTOFMEMORY);
2334 pOutOfMemory->SetXCode(EXCEPTION_COMPLUS);
2335 _ASSERTE(g_pPreallocatedOutOfMemoryException == NULL);
2336 g_pPreallocatedOutOfMemoryException = CreateHandle(pOutOfMemory);
2339 EXCEPTIONREF pStackOverflow = (EXCEPTIONREF)AllocateObject(g_pStackOverflowExceptionClass);
2340 pStackOverflow->SetHResult(COR_E_STACKOVERFLOW);
2341 pStackOverflow->SetXCode(EXCEPTION_COMPLUS);
2342 _ASSERTE(g_pPreallocatedStackOverflowException == NULL);
2343 g_pPreallocatedStackOverflowException = CreateHandle(pStackOverflow);
2346 EXCEPTIONREF pExecutionEngine = (EXCEPTIONREF)AllocateObject(g_pExecutionEngineExceptionClass);
2347 pExecutionEngine->SetHResult(COR_E_EXECUTIONENGINE);
2348 pExecutionEngine->SetXCode(EXCEPTION_COMPLUS);
2349 _ASSERTE(g_pPreallocatedExecutionEngineException == NULL);
2350 g_pPreallocatedExecutionEngineException = CreateHandle(pExecutionEngine);
2353 EXCEPTIONREF pRudeAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2354 #if CHECK_APP_DOMAIN_LEAKS
2355 pRudeAbortException->SetSyncBlockAppDomainAgile();
2357 pRudeAbortException->SetHResult(COR_E_THREADABORTED);
2358 pRudeAbortException->SetXCode(EXCEPTION_COMPLUS);
2359 _ASSERTE(g_pPreallocatedRudeThreadAbortException == NULL);
2360 g_pPreallocatedRudeThreadAbortException = CreateHandle(pRudeAbortException);
2363 EXCEPTIONREF pAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2364 #if CHECK_APP_DOMAIN_LEAKS
2365 pAbortException->SetSyncBlockAppDomainAgile();
2367 pAbortException->SetHResult(COR_E_THREADABORTED);
2368 pAbortException->SetXCode(EXCEPTION_COMPLUS);
2369 _ASSERTE(g_pPreallocatedThreadAbortException == NULL);
2370 g_pPreallocatedThreadAbortException = CreateHandle( pAbortException );
2372 #endif // CROSSGEN_COMPILE
2374 void SystemDomain::Init()
2376 STANDARD_VM_CONTRACT;
2384 "sizeof(EEClass) = %d\n"
2385 "sizeof(MethodTable) = %d\n"
2386 "sizeof(MethodDesc)= %d\n"
2387 "sizeof(FieldDesc) = %d\n"
2388 "sizeof(Module) = %d\n",
2390 sizeof(MethodTable),
2397 // The base domain is initialized in SystemDomain::Attach()
2398 // to allow stub caches to use the memory pool. Do not
2399 // initialze it here!
2401 #ifndef CROSSGEN_COMPILE
2403 Context *curCtx = GetCurrentContext();
2406 _ASSERTE(curCtx->GetDomain() != NULL);
2410 g_fVerifierOff = g_pConfig->IsVerifierOff();
2413 #ifdef FEATURE_PREJIT
2414 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapDisable) != 0)
2415 g_fAllowNativeImages = false;
2418 m_pSystemFile = NULL;
2419 m_pSystemAssembly = NULL;
2424 // Get the install directory so we can find mscorlib
2425 hr = GetInternalSystemDirectory(NULL, &size);
2426 if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
2429 // GetInternalSystemDirectory returns a size, including the null!
2430 WCHAR *buffer = m_SystemDirectory.OpenUnicodeBuffer(size-1);
2431 IfFailThrow(GetInternalSystemDirectory(buffer, &size));
2432 m_SystemDirectory.CloseBuffer();
2433 m_SystemDirectory.Normalize();
2435 // At this point m_SystemDirectory should already be canonicalized
2438 m_BaseLibrary.Append(m_SystemDirectory);
2439 if (!m_BaseLibrary.EndsWith(DIRECTORY_SEPARATOR_CHAR_W))
2441 m_BaseLibrary.Append(DIRECTORY_SEPARATOR_CHAR_W);
2443 m_BaseLibrary.Append(g_pwBaseLibrary);
2444 m_BaseLibrary.Normalize();
2446 LoadBaseSystemClasses();
2449 // We are about to start allocating objects, so we must be in cooperative mode.
2450 // However, many of the entrypoints to the system (DllGetClassObject and all
2451 // N/Direct exports) get called multiple times. Sometimes they initialize the EE,
2452 // but generally they remain in preemptive mode. So we really want to push/pop
2456 #ifndef CROSSGEN_COMPILE
2457 if (!NingenEnabled())
2459 CreatePreallocatedExceptions();
2461 PreallocateSpecialObjects();
2465 // Finish loading mscorlib now.
2466 m_pSystemAssembly->GetDomainAssembly()->EnsureActive();
2470 BOOL fPause = EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_PauseOnLoad, FALSE);
2474 ClrSleepEx(20, TRUE);
2479 #ifndef CROSSGEN_COMPILE
2480 void SystemDomain::LazyInitGlobalStringLiteralMap()
2487 INJECT_FAULT(COMPlusThrowOM(););
2491 // Allocate the global string literal map.
2492 NewHolder<GlobalStringLiteralMap> pGlobalStringLiteralMap(new GlobalStringLiteralMap());
2494 // Initialize the global string literal map.
2495 pGlobalStringLiteralMap->Init();
2497 if (InterlockedCompareExchangeT<GlobalStringLiteralMap *>(&m_pGlobalStringLiteralMap, pGlobalStringLiteralMap, NULL) == NULL)
2499 pGlobalStringLiteralMap.SuppressRelease();
2503 void AppDomain::CreateADUnloadStartEvent()
2514 g_pUnloadStartEvent = new CLREvent();
2515 g_pUnloadStartEvent->CreateAutoEvent(FALSE);
2518 /*static*/ void SystemDomain::EnumAllStaticGCRefs(promote_func* fn, ScanContext* sc)
2528 // We don't do a normal AppDomainIterator because we can't take the SystemDomain lock from
2530 // We're only supposed to call this from a Server GC. We're walking here m_appDomainIdList
2531 // m_appDomainIdList will have an AppDomain* or will be NULL. So the only danger is if we
2532 // Fetch an AppDomain and then in some other thread the AppDomain is deleted.
2534 // If the thread deleting the AppDomain (AppDomain::~AppDomain)was in Preemptive mode
2535 // while doing SystemDomain::EnumAllStaticGCRefs we will issue a GCX_COOP(), which will wait
2536 // for the GC to finish, so we are safe
2538 // If the thread is in cooperative mode, it must have been suspended for the GC so a delete
2541 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
2542 GCHeapUtilities::IsServerHeap() &&
2543 IsGCSpecialThread());
2545 SystemDomain* sysDomain = SystemDomain::System();
2549 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2550 for (i = 0 ; i < count ; i++)
2552 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2553 if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
2555 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2558 sc->pCurrentDomain = pAppDomain;
2560 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2561 pAppDomain->EnumStaticGCRefs(fn, sc);
2569 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2570 void SystemDomain::ResetADSurvivedBytes()
2580 _ASSERTE(GCHeapUtilities::IsGCInProgress());
2582 SystemDomain* sysDomain = SystemDomain::System();
2586 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2587 for (i = 0 ; i < count ; i++)
2589 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2590 if (pAppDomain && pAppDomain->IsUserActive())
2592 pAppDomain->ResetSurvivedBytes();
2600 ULONGLONG SystemDomain::GetADSurvivedBytes()
2610 SystemDomain* sysDomain = SystemDomain::System();
2611 ULONGLONG ullTotalADSurvived = 0;
2615 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2616 for (i = 0 ; i < count ; i++)
2618 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2619 if (pAppDomain && pAppDomain->IsUserActive())
2621 ULONGLONG ullSurvived = pAppDomain->GetSurvivedBytes();
2622 ullTotalADSurvived += ullSurvived;
2627 return ullTotalADSurvived;
2630 void SystemDomain::RecordTotalSurvivedBytes(size_t totalSurvivedBytes)
2640 m_totalSurvivedBytes = totalSurvivedBytes;
2642 SystemDomain* sysDomain = SystemDomain::System();
2646 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2647 for (i = 0 ; i < count ; i++)
2649 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2650 if (pAppDomain && pAppDomain->IsUserActive())
2652 FireEtwAppDomainMemSurvived((ULONGLONG)pAppDomain, pAppDomain->GetSurvivedBytes(), totalSurvivedBytes, GetClrInstanceId());
2659 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2661 // Only called when EE is suspended.
2662 DWORD SystemDomain::GetTotalNumSizedRefHandles()
2672 SystemDomain* sysDomain = SystemDomain::System();
2673 DWORD dwTotalNumSizedRefHandles = 0;
2677 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2678 for (i = 0 ; i < count ; i++)
2680 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2681 if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
2683 dwTotalNumSizedRefHandles += pAppDomain->GetNumSizedRefHandles();
2688 return dwTotalNumSizedRefHandles;
2690 #endif // CROSSGEN_COMPILE
2692 void SystemDomain::LoadBaseSystemClasses()
2694 STANDARD_VM_CONTRACT;
2696 ETWOnStartup(LdSysBases_V1, LdSysBasesEnd_V1);
2699 m_pSystemFile = PEAssembly::OpenSystem(NULL);
2701 // Only partially load the system assembly. Other parts of the code will want to access
2702 // the globals in this function before finishing the load.
2703 m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemFile, FILE_LOAD_POST_LOADLIBRARY)->GetCurrentAssembly();
2705 // Set up binder for mscorlib
2706 MscorlibBinder::AttachModule(m_pSystemAssembly->GetManifestModule());
2709 g_pObjectClass = MscorlibBinder::GetClass(CLASS__OBJECT);
2711 // Now that ObjectClass is loaded, we can set up
2712 // the system for finalizers. There is no point in deferring this, since we need
2713 // to know this before we allocate our first object.
2714 g_pObjectFinalizerMD = MscorlibBinder::GetMethod(METHOD__OBJECT__FINALIZE);
2717 g_pCanonMethodTableClass = MscorlibBinder::GetClass(CLASS____CANON);
2719 // NOTE: !!!IMPORTANT!!! ValueType and Enum MUST be loaded one immediately after
2720 // the other, because we have coded MethodTable::IsChildValueType
2721 // in such a way that it depends on this behaviour.
2722 // Load the ValueType class
2723 g_pValueTypeClass = MscorlibBinder::GetClass(CLASS__VALUE_TYPE);
2725 // Load the enum class
2726 g_pEnumClass = MscorlibBinder::GetClass(CLASS__ENUM);
2727 _ASSERTE(!g_pEnumClass->IsValueType());
2729 // Load System.RuntimeType
2730 g_pRuntimeTypeClass = MscorlibBinder::GetClass(CLASS__CLASS);
2731 _ASSERTE(g_pRuntimeTypeClass->IsFullyLoaded());
2734 g_pArrayClass = MscorlibBinder::GetClass(CLASS__ARRAY);
2736 // Calling a method on IList<T> for an array requires redirection to a method on
2737 // the SZArrayHelper class. Retrieving such methods means calling
2738 // GetActualImplementationForArrayGenericIListMethod, which calls FetchMethod for
2739 // the corresponding method on SZArrayHelper. This basically results in a class
2740 // load due to a method call, which the debugger cannot handle, so we pre-load
2741 // the SZArrayHelper class here.
2742 g_pSZArrayHelperClass = MscorlibBinder::GetClass(CLASS__SZARRAYHELPER);
2744 // Load ByReference class
2746 // NOTE: ByReference<T> must be the first by-ref-like system type to be loaded,
2747 // because MethodTable::ClassifyEightBytesWithManagedLayout depends on it.
2748 g_pByReferenceClass = MscorlibBinder::GetClass(CLASS__BYREFERENCE);
2750 // Load Nullable class
2751 g_pNullableClass = MscorlibBinder::GetClass(CLASS__NULLABLE);
2753 // Load the Object array class.
2754 g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pObjectClass)).AsArray();
2756 // We have delayed allocation of mscorlib's static handles until we load the object class
2757 MscorlibBinder::GetModule()->AllocateRegularStaticHandles(DefaultDomain());
2759 g_TypedReferenceMT = MscorlibBinder::GetClass(CLASS__TYPED_REFERENCE);
2761 // Make sure all primitive types are loaded
2762 for (int et = ELEMENT_TYPE_VOID; et <= ELEMENT_TYPE_R8; et++)
2763 MscorlibBinder::LoadPrimitiveType((CorElementType)et);
2765 MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_I);
2766 MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_U);
2768 // unfortunately, the following cannot be delay loaded since the jit
2769 // uses it to compute method attributes within a function that cannot
2770 // handle Complus exception and the following call goes through a path
2771 // where a complus exception can be thrown. It is unfortunate, because
2772 // we know that the delegate class and multidelegate class are always
2773 // guaranteed to be found.
2774 g_pDelegateClass = MscorlibBinder::GetClass(CLASS__DELEGATE);
2775 g_pMulticastDelegateClass = MscorlibBinder::GetClass(CLASS__MULTICAST_DELEGATE);
2777 // used by IsImplicitInterfaceOfSZArray
2778 MscorlibBinder::GetClass(CLASS__IENUMERABLEGENERIC);
2779 MscorlibBinder::GetClass(CLASS__ICOLLECTIONGENERIC);
2780 MscorlibBinder::GetClass(CLASS__ILISTGENERIC);
2781 MscorlibBinder::GetClass(CLASS__IREADONLYCOLLECTIONGENERIC);
2782 MscorlibBinder::GetClass(CLASS__IREADONLYLISTGENERIC);
2785 g_pStringClass = MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_STRING);
2786 _ASSERTE(g_pStringClass->GetBaseSize() == ObjSizeOf(StringObject)+sizeof(WCHAR));
2787 _ASSERTE(g_pStringClass->GetComponentSize() == 2);
2789 // Used by Buffer::BlockCopy
2790 g_pByteArrayMT = ClassLoader::LoadArrayTypeThrowing(
2791 TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1))).AsArray()->GetMethodTable();
2793 #ifndef CROSSGEN_COMPILE
2794 ECall::PopulateManagedStringConstructors();
2795 #endif // CROSSGEN_COMPILE
2797 g_pExceptionClass = MscorlibBinder::GetClass(CLASS__EXCEPTION);
2798 g_pOutOfMemoryExceptionClass = MscorlibBinder::GetException(kOutOfMemoryException);
2799 g_pStackOverflowExceptionClass = MscorlibBinder::GetException(kStackOverflowException);
2800 g_pExecutionEngineExceptionClass = MscorlibBinder::GetException(kExecutionEngineException);
2801 g_pThreadAbortExceptionClass = MscorlibBinder::GetException(kThreadAbortException);
2804 // used by gc to handle predefined agility checking
2805 g_pThreadClass = MscorlibBinder::GetClass(CLASS__THREAD);
2807 #ifdef FEATURE_COMINTEROP
2808 g_pBaseCOMObject = MscorlibBinder::GetClass(CLASS__COM_OBJECT);
2809 g_pBaseRuntimeClass = MscorlibBinder::GetClass(CLASS__RUNTIME_CLASS);
2811 MscorlibBinder::GetClass(CLASS__IDICTIONARYGENERIC);
2812 MscorlibBinder::GetClass(CLASS__IREADONLYDICTIONARYGENERIC);
2813 MscorlibBinder::GetClass(CLASS__ATTRIBUTE);
2814 MscorlibBinder::GetClass(CLASS__EVENT_HANDLERGENERIC);
2816 MscorlibBinder::GetClass(CLASS__IENUMERABLE);
2817 MscorlibBinder::GetClass(CLASS__ICOLLECTION);
2818 MscorlibBinder::GetClass(CLASS__ILIST);
2819 MscorlibBinder::GetClass(CLASS__IDISPOSABLE);
2822 WinRTInterfaceRedirector::VerifyRedirectedInterfaceStubs();
2826 #ifdef FEATURE_ICASTABLE
2827 g_pICastableInterface = MscorlibBinder::GetClass(CLASS__ICASTABLE);
2828 #endif // FEATURE_ICASTABLE
2830 // Load a special marker method used to detect Constrained Execution Regions
2832 g_pExecuteBackoutCodeHelperMethod = MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__EXECUTE_BACKOUT_CODE_HELPER);
2834 // Make sure that FCall mapping for Monitor.Enter is initialized. We need it in case Monitor.Enter is used only as JIT helper.
2835 // For more details, see comment in code:JITutil_MonEnterWorker around "__me = GetEEFuncEntryPointMacro(JIT_MonEnter)".
2836 ECall::GetFCallImpl(MscorlibBinder::GetMethod(METHOD__MONITOR__ENTER));
2838 #ifdef PROFILING_SUPPORTED
2839 // Note that g_profControlBlock.fBaseSystemClassesLoaded must be set to TRUE only after
2840 // all base system classes are loaded. Profilers are not allowed to call any type-loading
2841 // APIs until g_profControlBlock.fBaseSystemClassesLoaded is TRUE. It is important that
2842 // all base system classes need to be loaded before profilers can trigger the type loading.
2843 g_profControlBlock.fBaseSystemClassesLoaded = TRUE;
2844 #endif // PROFILING_SUPPORTED
2846 #if defined(_DEBUG) && !defined(CROSSGEN_COMPILE)
2847 if (!NingenEnabled())
2853 #if defined(HAVE_GCCOVER) && defined(FEATURE_PREJIT)
2854 if (GCStress<cfg_instr_ngen>::IsEnabled())
2856 // Setting up gc coverage requires the base system classes
2857 // to be initialized. So we have deferred it until now for mscorlib.
2858 Module *pModule = MscorlibBinder::GetModule();
2859 _ASSERTE(pModule->IsSystem());
2860 if(pModule->HasNativeImage())
2862 SetupGcCoverageForNativeImage(pModule);
2865 #endif // defined(HAVE_GCCOVER) && !defined(FEATURE_PREJIT)
2869 void SystemDomain::LoadDomain(AppDomain *pDomain)
2876 PRECONDITION(CheckPointer(System()));
2877 INJECT_FAULT(COMPlusThrowOM(););
2881 pDomain->SetCanUnload(); // by default can unload any domain
2882 SystemDomain::System()->AddDomain(pDomain);
2885 ADIndex SystemDomain::GetNewAppDomainIndex(AppDomain *pAppDomain)
2887 STANDARD_VM_CONTRACT;
2889 DWORD count = m_appDomainIndexList.GetCount();
2895 // So that we can keep AD index inside object header.
2896 // We do not want to create syncblock unless needed.
2903 // Look for an unused index. Note that in a checked build,
2904 // we never reuse indexes - this makes it easier to tell
2905 // when we are looking at a stale app domain.
2908 i = m_appDomainIndexList.FindElement(m_dwLowestFreeIndex, NULL);
2909 if (i == (DWORD) ArrayList::NOT_FOUND)
2911 m_dwLowestFreeIndex = i+1;
2913 if (m_dwLowestFreeIndex >= 2000)
2915 m_dwLowestFreeIndex = 0;
2921 IfFailThrow(m_appDomainIndexList.Append(pAppDomain));
2923 m_appDomainIndexList.Set(i, pAppDomain);
2925 _ASSERTE(i < m_appDomainIndexList.GetCount());
2927 // Note that index 0 means domain agile.
2928 return ADIndex(i+1);
2931 void SystemDomain::ReleaseAppDomainIndex(ADIndex index)
2933 WRAPPER_NO_CONTRACT;
2934 SystemDomain::LockHolder lh;
2935 // Note that index 0 means domain agile.
2938 _ASSERTE(m_appDomainIndexList.Get(index.m_dwIndex) != NULL);
2940 m_appDomainIndexList.Set(index.m_dwIndex, NULL);
2943 if (index.m_dwIndex < m_dwLowestFreeIndex)
2944 m_dwLowestFreeIndex = index.m_dwIndex;
2948 #endif // !DACCESS_COMPILE
2950 PTR_AppDomain SystemDomain::GetAppDomainAtIndex(ADIndex index)
2952 LIMITED_METHOD_CONTRACT;
2954 _ASSERTE(index.m_dwIndex != 0);
2956 PTR_AppDomain pAppDomain = TestGetAppDomainAtIndex(index);
2958 _ASSERTE(pAppDomain || !"Attempt to access unloaded app domain");
2963 PTR_AppDomain SystemDomain::TestGetAppDomainAtIndex(ADIndex index)
2965 LIMITED_METHOD_CONTRACT;
2967 _ASSERTE(index.m_dwIndex != 0);
2970 #ifndef DACCESS_COMPILE
2971 _ASSERTE(index.m_dwIndex < (DWORD)m_appDomainIndexList.GetCount());
2972 AppDomain *pAppDomain = (AppDomain*) m_appDomainIndexList.Get(index.m_dwIndex);
2973 #else // DACCESS_COMPILE
2974 PTR_ArrayListStatic pList = &m_appDomainIndexList;
2975 AppDomain *pAppDomain = dac_cast<PTR_AppDomain>(pList->Get(index.m_dwIndex));
2976 #endif // DACCESS_COMPILE
2977 return PTR_AppDomain(pAppDomain);
2980 #ifndef DACCESS_COMPILE
2982 // See also code:SystemDomain::ReleaseAppDomainId
2983 ADID SystemDomain::GetNewAppDomainId(AppDomain *pAppDomain)
2990 INJECT_FAULT(COMPlusThrowOM(););
2994 DWORD i = m_appDomainIdList.GetCount();
2996 IfFailThrow(m_appDomainIdList.Append(pAppDomain));
2998 _ASSERTE(i < m_appDomainIdList.GetCount());
3003 AppDomain *SystemDomain::GetAppDomainAtId(ADID index)
3008 if (!SystemDomain::IsUnderDomainLock() && !IsGCThread()) { MODE_COOPERATIVE;} else { DISABLED(MODE_ANY);}
3016 if(index.m_dwId == 0)
3018 DWORD requestedID = index.m_dwId - 1;
3020 if(requestedID >= (DWORD)m_appDomainIdList.GetCount())
3023 AppDomain * result = (AppDomain *)m_appDomainIdList.Get(requestedID);
3025 #ifndef CROSSGEN_COMPILE
3026 if(result==NULL && GetThread() == FinalizerThread::GetFinalizerThread() &&
3027 SystemDomain::System()->AppDomainBeingUnloaded()!=NULL &&
3028 SystemDomain::System()->AppDomainBeingUnloaded()->GetId()==index)
3029 result=SystemDomain::System()->AppDomainBeingUnloaded();
3030 // If the current thread can't enter the AppDomain, then don't return it.
3031 if (!result || !result->CanThreadEnter(GetThread()))
3033 #endif // CROSSGEN_COMPILE
3038 // Releases an appdomain index. Note that today we have code that depends on these
3039 // indexes not being recycled, so we don't actually shrink m_appDomainIdList, but
3040 // simply zero out an entry. THus we 'leak' the memory associated the slot in
3041 // m_appDomainIdList.
3043 // TODO make this a sparse structure so that we avoid that leak.
3045 void SystemDomain::ReleaseAppDomainId(ADID index)
3047 LIMITED_METHOD_CONTRACT;
3050 _ASSERTE(index.m_dwId < (DWORD)m_appDomainIdList.GetCount());
3052 m_appDomainIdList.Set(index.m_dwId, NULL);
3055 #if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3058 int g_fMainThreadApartmentStateSet = 0;
3061 Thread::ApartmentState SystemDomain::GetEntryPointThreadAptState(IMDInternalImport* pScope, mdMethodDef mdMethod)
3063 STANDARD_VM_CONTRACT;
3066 IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
3067 DEFAULTDOMAIN_MTA_TYPE,
3070 BOOL fIsMTA = FALSE;
3074 IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
3075 DEFAULTDOMAIN_STA_TYPE,
3078 BOOL fIsSTA = FALSE;
3082 if (fIsSTA && fIsMTA)
3083 COMPlusThrowHR(COR_E_CUSTOMATTRIBUTEFORMAT);
3086 return Thread::AS_InSTA;
3088 return Thread::AS_InMTA;
3090 return Thread::AS_Unknown;
3093 void SystemDomain::SetThreadAptState (IMDInternalImport* pScope, Thread::ApartmentState state)
3095 STANDARD_VM_CONTRACT;
3097 BOOL fIsLegacy = FALSE;
3099 // Check for legacy behavior regarding COM Apartment state of the main thread.
3101 #define METAMODEL_MAJOR_VER_WITH_NEW_BEHAVIOR 2
3102 #define METAMODEL_MINOR_VER_WITH_NEW_BEHAVIOR 0
3105 IfFailThrow(pScope->GetVersionString(&pVer));
3107 // Does this look like a version?
3110 // Is it 'vN.' where N is a digit?
3111 if ((pVer[0] == 'v' || pVer[0] == 'V') &&
3112 IS_DIGIT(pVer[1]) &&
3115 // Looks like a version. Is it lesser than v2.0 major version where we start using new behavior?
3116 fIsLegacy = DIGIT_TO_INT(pVer[1]) < METAMODEL_MAJOR_VER_WITH_NEW_BEHAVIOR;
3120 if (!fIsLegacy && g_pConfig != NULL)
3122 fIsLegacy = g_pConfig->LegacyApartmentInitPolicy();
3126 Thread* pThread = GetThread();
3129 if(state == Thread::AS_InSTA)
3131 Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InSTA, TRUE);
3132 _ASSERTE(pState == Thread::AS_InSTA);
3134 else if ((state == Thread::AS_InMTA) || (!fIsLegacy))
3136 // If either MTAThreadAttribute is specified or (if no attribute is specified and we are not
3137 // running in legacy mode), then
3138 // we will set the apartment state to MTA. The reason for this is to ensure the apartment
3139 // state is consistent and reliably set. Without this, the apartment state for the main
3140 // thread would be undefined and would actually be dependent on if the assembly was
3141 // ngen'd, which other type were loaded, etc.
3142 Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InMTA, TRUE);
3143 _ASSERTE(pState == Thread::AS_InMTA);
3147 g_fMainThreadApartmentStateSet++;
3150 #endif // defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3152 // Looks in all the modules for the DefaultDomain attribute
3153 // The order is assembly and then the modules. It is first
3154 // come, first serve.
3155 BOOL SystemDomain::SetGlobalSharePolicyUsingAttribute(IMDInternalImport* pScope, mdMethodDef mdMethod)
3157 STANDARD_VM_CONTRACT;
3163 void SystemDomain::SetupDefaultDomain()
3170 INJECT_FAULT(COMPlusThrowOM(););
3175 Thread *pThread = GetThread();
3179 pDomain = pThread->GetDomain();
3184 ENTER_DOMAIN_PTR(SystemDomain::System()->DefaultDomain(),ADV_DEFAULTAD)
3186 // Push this frame around loading the main assembly to ensure the
3187 // debugger can properly recgonize any managed code that gets run
3188 // as "class initializaion" code.
3189 FrameWithCookie<DebuggerClassInitMarkFrame> __dcimf;
3193 InitializeDefaultDomain(TRUE);
3198 END_DOMAIN_TRANSITION;
3203 HRESULT SystemDomain::SetupDefaultDomainNoThrow()
3216 SystemDomain::SetupDefaultDomain();
3218 EX_CATCH_HRESULT(hr);
3224 int g_fInitializingInitialAD = 0;
3227 // This routine completes the initialization of the default domaine.
3228 // After this call mananged code can be executed.
3229 void SystemDomain::InitializeDefaultDomain(
3230 BOOL allowRedirects,
3231 ICLRPrivBinder * pBinder)
3233 STANDARD_VM_CONTRACT;
3235 WCHAR* pwsConfig = NULL;
3236 WCHAR* pwsPath = NULL;
3238 ETWOnStartup (InitDefaultDomain_V1, InitDefaultDomainEnd_V1);
3241 // Setup the default AppDomain.
3244 g_fInitializingInitialAD++;
3247 AppDomain* pDefaultDomain = SystemDomain::System()->DefaultDomain();
3249 if (pBinder != nullptr)
3251 pDefaultDomain->SetLoadContextHostBinder(pBinder);
3257 pDefaultDomain->InitializeDomainContext(allowRedirects, pwsPath, pwsConfig);
3259 #ifndef CROSSGEN_COMPILE
3260 if (!NingenEnabled())
3263 if (!IsSingleAppDomain())
3265 pDefaultDomain->InitializeDefaultDomainManager();
3268 #endif // CROSSGEN_COMPILE
3271 // DefaultDomain Load event
3272 ETW::LoaderLog::DomainLoad(pDefaultDomain);
3275 g_fInitializingInitialAD--;
3278 TESTHOOKCALL(RuntimeStarted(RTS_DEFAULTADREADY));
3283 #ifndef CROSSGEN_COMPILE
3286 Volatile<LONG> g_fInExecuteMainMethod = 0;
3292 #endif // CROSSGEN_COMPILE
3296 // Helper function to load an assembly. This is called from LoadCOMClass.
3299 Assembly *AppDomain::LoadAssemblyHelper(LPCWSTR wszAssembly,
3300 LPCWSTR wszCodeBase)
3302 CONTRACT(Assembly *)
3305 POSTCONDITION(CheckPointer(RETVAL));
3306 PRECONDITION(wszAssembly || wszCodeBase);
3307 INJECT_FAULT(COMPlusThrowOM(););
3313 #define MAKE_TRANSLATIONFAILED { ThrowOutOfMemory(); }
3314 MAKE_UTF8PTR_FROMWIDE(szAssembly,wszAssembly);
3315 #undef MAKE_TRANSLATIONFAILED
3317 IfFailThrow(spec.Init(szAssembly));
3321 spec.SetCodeBase(wszCodeBase);
3323 RETURN spec.LoadAssembly(FILE_LOADED);
3326 #if defined(FEATURE_CLASSIC_COMINTEROP) && !defined(CROSSGEN_COMPILE)
3328 MethodTable *AppDomain::LoadCOMClass(GUID clsid,
3329 BOOL bLoadRecord/*=FALSE*/,
3330 BOOL* pfAssemblyInReg/*=NULL*/)
3332 // @CORESYSTODO: what to do here?
3336 #endif // FEATURE_CLASSIC_COMINTEROP && !CROSSGEN_COMPILE
3340 bool SystemDomain::IsReflectionInvocationMethod(MethodDesc* pMeth)
3350 MethodTable* pCaller = pMeth->GetMethodTable();
3352 // All Reflection Invocation methods are defined in mscorlib.dll
3353 if (!pCaller->GetModule()->IsSystem())
3356 /* List of types that should be skipped to identify true caller */
3357 static const BinderClassID reflectionInvocationTypes[] = {
3362 CLASS__CONSTRUCTOR_INFO,
3365 CLASS__METHOD_HANDLE,
3366 CLASS__FIELD_HANDLE,
3369 CLASS__RT_FIELD_INFO,
3374 CLASS__PROPERTY_INFO,
3377 CLASS__ASSEMBLYBASE,
3379 CLASS__TYPE_DELEGATOR,
3380 CLASS__RUNTIME_HELPERS,
3381 CLASS__LAZY_INITIALIZER,
3382 CLASS__DYNAMICMETHOD,
3384 CLASS__MULTICAST_DELEGATE,
3388 static const BinderClassID genericReflectionInvocationTypes[] = {
3392 static mdTypeDef genericReflectionInvocationTypeDefs[NumItems(genericReflectionInvocationTypes)];
3394 static bool fInited = false;
3396 if (!VolatileLoad(&fInited))
3398 // Make sure all types are loaded so that we can use faster GetExistingClass()
3399 for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3401 MscorlibBinder::GetClass(reflectionInvocationTypes[i]);
3404 // Make sure all types are loaded so that we can use faster GetExistingClass()
3405 for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypes); i++)
3407 genericReflectionInvocationTypeDefs[i] = MscorlibBinder::GetClass(genericReflectionInvocationTypes[i])->GetCl();
3410 MscorlibBinder::GetClass(CLASS__APP_DOMAIN);
3412 VolatileStore(&fInited, true);
3415 if (pCaller->HasInstantiation())
3417 // For generic types, pCaller will be an instantiated type and never equal to the type definition.
3418 // So we compare their TypeDef tokens instead.
3419 for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypeDefs); i++)
3421 if (pCaller->GetCl() == genericReflectionInvocationTypeDefs[i])
3427 for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3429 if (MscorlibBinder::GetExistingClass(reflectionInvocationTypes[i]) == pCaller)
3437 #ifndef CROSSGEN_COMPILE
3438 struct CallersDataWithStackMark
3440 StackCrawlMark* stackMark;
3442 MethodDesc* pFoundMethod;
3443 MethodDesc* pPrevMethod;
3444 AppDomain* pAppDomain;
3448 MethodDesc* SystemDomain::GetCallersMethod(StackCrawlMark* stackMark,
3449 AppDomain **ppAppDomain/*=NULL*/)
3457 INJECT_FAULT(COMPlusThrowOM(););
3463 CallersDataWithStackMark cdata;
3464 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3465 cdata.stackMark = stackMark;
3467 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3469 if(cdata.pFoundMethod) {
3471 *ppAppDomain = cdata.pAppDomain;
3472 return cdata.pFoundMethod;
3478 MethodTable* SystemDomain::GetCallersType(StackCrawlMark* stackMark,
3479 AppDomain **ppAppDomain/*=NULL*/)
3487 INJECT_FAULT(COMPlusThrowOM(););
3491 CallersDataWithStackMark cdata;
3492 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3493 cdata.stackMark = stackMark;
3495 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3497 if(cdata.pFoundMethod) {
3499 *ppAppDomain = cdata.pAppDomain;
3500 return cdata.pFoundMethod->GetMethodTable();
3506 Module* SystemDomain::GetCallersModule(StackCrawlMark* stackMark,
3507 AppDomain **ppAppDomain/*=NULL*/)
3515 INJECT_FAULT(COMPlusThrowOM(););
3521 CallersDataWithStackMark cdata;
3522 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3523 cdata.stackMark = stackMark;
3525 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3527 if(cdata.pFoundMethod) {
3529 *ppAppDomain = cdata.pAppDomain;
3530 return cdata.pFoundMethod->GetModule();
3538 MethodDesc* pMethod;
3542 Assembly* SystemDomain::GetCallersAssembly(StackCrawlMark *stackMark,
3543 AppDomain **ppAppDomain/*=NULL*/)
3545 WRAPPER_NO_CONTRACT;
3546 Module* mod = GetCallersModule(stackMark, ppAppDomain);
3548 return mod->GetAssembly();
3553 Module* SystemDomain::GetCallersModule(int skip)
3560 INJECT_FAULT(COMPlusThrowOM(););
3567 ZeroMemory(&cdata, sizeof(CallersData));
3570 StackWalkFunctions(GetThread(), CallersMethodCallback, &cdata);
3573 return cdata.pMethod->GetModule();
3579 StackWalkAction SystemDomain::CallersMethodCallbackWithStackMark(CrawlFrame* pCf, VOID* data)
3587 INJECT_FAULT(COMPlusThrowOM(););
3592 MethodDesc *pFunc = pCf->GetFunction();
3594 /* We asked to be called back only for functions */
3597 CallersDataWithStackMark* pCaller = (CallersDataWithStackMark*) data;
3598 if (pCaller->stackMark)
3600 if (!pCf->IsInCalleesFrames(pCaller->stackMark))
3602 // save the current in case it is the one we want
3603 pCaller->pPrevMethod = pFunc;
3604 pCaller->pAppDomain = pCf->GetAppDomain();
3605 return SWA_CONTINUE;
3608 // LookForMe stack crawl marks needn't worry about reflection or
3609 // remoting frames on the stack. Each frame above (newer than) the
3610 // target will be captured by the logic above. Once we transition to
3611 // finding the stack mark below the AofRA, we know that we hit the
3612 // target last time round and immediately exit with the cached result.
3614 if (*(pCaller->stackMark) == LookForMe)
3616 pCaller->pFoundMethod = pCaller->pPrevMethod;
3621 // Skip reflection and remoting frames that could lie between a stack marked
3622 // method and its true caller (or that caller and its own caller). These
3623 // frames are infrastructure and logically transparent to the stack crawling
3626 // Skipping remoting frames. We always skip entire client to server spans
3627 // (though we see them in the order server then client during a stack crawl
3630 // We spot the server dispatcher end because all calls are dispatched
3631 // through a single method: StackBuilderSink._PrivateProcessMessage.
3633 Frame* frame = pCf->GetFrame();
3634 _ASSERTE(pCf->IsFrameless() || frame);
3638 // Skipping reflection frames. We don't need to be quite as exhaustive here
3639 // as the security or reflection stack walking code since we know this logic
3640 // is only invoked for selected methods in mscorlib itself. So we're
3641 // reasonably sure we won't have any sensitive methods late bound invoked on
3642 // constructors, properties or events. This leaves being invoked via
3643 // MethodInfo, Type or Delegate (and depending on which invoke overload is
3644 // being used, several different reflection classes may be involved).
3646 g_IBCLogger.LogMethodDescAccess(pFunc);
3648 if (SystemDomain::IsReflectionInvocationMethod(pFunc))
3649 return SWA_CONTINUE;
3651 if (frame && frame->GetFrameType() == Frame::TYPE_MULTICAST)
3653 // This must be either a secure delegate frame or a true multicast delegate invocation.
3655 _ASSERTE(pFunc->GetMethodTable()->IsDelegate());
3657 DELEGATEREF del = (DELEGATEREF)((SecureDelegateFrame*)frame)->GetThis(); // This can throw.
3659 if (COMDelegate::IsSecureDelegate(del))
3661 if (del->IsWrapperDelegate())
3663 // On ARM, we use secure delegate infrastructure to preserve R4 register.
3664 return SWA_CONTINUE;
3666 // For a secure delegate frame, we should return the delegate creator instead
3667 // of the delegate method itself.
3668 pFunc = (MethodDesc*) del->GetMethodPtrAux();
3672 _ASSERTE(COMDelegate::IsTrueMulticastDelegate(del));
3673 return SWA_CONTINUE;
3677 // Return the first non-reflection/remoting frame if no stack mark was
3679 if (!pCaller->stackMark)
3681 pCaller->pFoundMethod = pFunc;
3682 pCaller->pAppDomain = pCf->GetAppDomain();
3686 // If we got here, we must already be in the frame containing the stack mark and we are not looking for "me".
3687 _ASSERTE(pCaller->stackMark &&
3688 pCf->IsInCalleesFrames(pCaller->stackMark) &&
3689 *(pCaller->stackMark) != LookForMe);
3691 // When looking for caller's caller, we delay returning results for another
3692 // round (the way this is structured, we will still be able to skip
3693 // reflection and remoting frames between the caller and the caller's
3696 if ((*(pCaller->stackMark) == LookForMyCallersCaller) &&
3697 (pCaller->pFoundMethod == NULL))
3699 pCaller->pFoundMethod = pFunc;
3700 return SWA_CONTINUE;
3703 // If remoting is not available, we only set the caller if the crawlframe is from the same domain.
3704 // Why? Because if the callerdomain is different from current domain,
3705 // there have to be interop/native frames in between.
3706 // For example, in the CORECLR, if we find the caller to be in a different domain, then the
3707 // call into reflection is due to an unmanaged call into mscorlib. For that
3708 // case, the caller really is an INTEROP method.
3709 // In general, if the caller is INTEROP, we set the caller/callerdomain to be NULL
3710 // (To be precise: they are already NULL and we don't change them).
3711 if (pCf->GetAppDomain() == GetAppDomain())
3712 // We must either be looking for the caller, or the caller's caller when
3713 // we've already found the caller (we used a non-null value in pFoundMethod
3714 // simply as a flag, the correct method to return in both case is the
3717 pCaller->pFoundMethod = pFunc;
3718 pCaller->pAppDomain = pCf->GetAppDomain();
3725 StackWalkAction SystemDomain::CallersMethodCallback(CrawlFrame* pCf, VOID* data)
3727 LIMITED_METHOD_CONTRACT;
3728 STATIC_CONTRACT_SO_TOLERANT;
3729 MethodDesc *pFunc = pCf->GetFunction();
3731 /* We asked to be called back only for functions */
3734 CallersData* pCaller = (CallersData*) data;
3735 if(pCaller->skip == 0) {
3736 pCaller->pMethod = pFunc;
3741 return SWA_CONTINUE;
3745 #endif // CROSSGEN_COMPILE
3747 #ifdef CROSSGEN_COMPILE
3748 // defined in compile.cpp
3749 extern CompilationDomain * theDomain;
3752 void SystemDomain::CreateDefaultDomain()
3754 STANDARD_VM_CONTRACT;
3756 #ifdef CROSSGEN_COMPILE
3757 AppDomainRefHolder pDomain(theDomain);
3759 AppDomainRefHolder pDomain(new AppDomain());
3762 SystemDomain::LockHolder lh;
3765 // need to make this assignment here since we'll be releasing
3766 // the lock before calling AddDomain. So any other thread
3767 // grabbing this lock after we release it will find that
3768 // the COM Domain has already been created
3769 m_pDefaultDomain = pDomain;
3770 _ASSERTE (pDomain->GetId().m_dwId == DefaultADID);
3772 // allocate a Virtual Call Stub Manager for the default domain
3773 m_pDefaultDomain->InitVSD();
3775 pDomain->SetStage(AppDomain::STAGE_OPEN);
3776 pDomain.SuppressRelease();
3778 LOG((LF_CLASSLOADER | LF_CORDB,
3780 "Created default domain at %p\n", m_pDefaultDomain));
3783 #ifdef DEBUGGING_SUPPORTED
3785 void SystemDomain::PublishAppDomainAndInformDebugger (AppDomain *pDomain)
3789 if(!g_fEEInit) {THROWS;} else {DISABLED(NOTHROW);};
3790 if(!g_fEEInit) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);};
3795 LOG((LF_CORDB, LL_INFO100, "SD::PADAID: Adding 0x%x\n", pDomain));
3797 // Call the publisher API to add this appdomain entry to the list
3798 // The publisher will handle failures, so we don't care if this succeeds or fails.
3799 if (g_pDebugInterface != NULL)
3801 g_pDebugInterface->AddAppDomainToIPC(pDomain);
3805 #endif // DEBUGGING_SUPPORTED
3807 void SystemDomain::AddDomain(AppDomain* pDomain)
3814 PRECONDITION(CheckPointer((pDomain)));
3821 _ASSERTE (pDomain->m_Stage != AppDomain::STAGE_CREATING);
3822 if (pDomain->m_Stage == AppDomain::STAGE_READYFORMANAGEDCODE ||
3823 pDomain->m_Stage == AppDomain::STAGE_ACTIVE)
3825 pDomain->SetStage(AppDomain::STAGE_OPEN);
3826 IncrementNumAppDomains(); // Maintain a count of app domains added to the list.
3830 // Note that if you add another path that can reach here without calling
3831 // PublishAppDomainAndInformDebugger, then you should go back & make sure
3832 // that PADAID gets called. Right after this call, if not sooner.
3833 LOG((LF_CORDB, LL_INFO1000, "SD::AD:Would have added domain here! 0x%x\n",
3837 BOOL SystemDomain::RemoveDomain(AppDomain* pDomain)
3844 PRECONDITION(CheckPointer(pDomain));
3845 PRECONDITION(!pDomain->IsDefaultDomain());
3849 // You can not remove the default domain.
3852 if (!pDomain->IsActive())
3861 #ifdef PROFILING_SUPPORTED
3862 void SystemDomain::NotifyProfilerStartup()
3873 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3875 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System());
3880 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3882 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System(), S_OK);
3887 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3888 _ASSERTE(System()->DefaultDomain());
3889 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System()->DefaultDomain());
3894 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3895 _ASSERTE(System()->DefaultDomain());
3896 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3901 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3902 _ASSERTE(SharedDomain::GetDomain());
3903 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) SharedDomain::GetDomain());
3908 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3909 _ASSERTE(SharedDomain::GetDomain());
3910 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) SharedDomain::GetDomain(), S_OK);
3915 HRESULT SystemDomain::NotifyProfilerShutdown()
3926 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3928 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System());
3933 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3935 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System(), S_OK);
3940 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3941 _ASSERTE(System()->DefaultDomain());
3942 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System()->DefaultDomain());
3947 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3948 _ASSERTE(System()->DefaultDomain());
3949 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3954 #endif // PROFILING_SUPPORTED
3958 struct AppDomain::ThreadTrackInfo {
3960 CDynArray<Frame *> frameStack;
3964 AppDomain::AppDomain()
3966 // initialize fields so the appdomain can be safely destructed
3967 // shouldn't call anything that can fail here - use ::Init instead
3978 m_pNextInDelayedUnloadList = NULL;
3979 m_fRudeUnload = FALSE;
3980 m_pUnloadRequestThread = NULL;
3981 m_ADUnloadSink=NULL;
3984 // Initialize Shared state. Assemblies are loaded
3985 // into each domain by default.
3986 #ifdef FEATURE_LOADER_OPTIMIZATION
3987 m_SharePolicy = SHARE_POLICY_UNSPECIFIED;
3990 m_pRootAssembly = NULL;
3992 m_pwDynamicDir = NULL;
3995 m_pDefaultContext = NULL;
3996 #ifdef FEATURE_COMINTEROP
3997 m_pComCallWrapperCache = NULL;
3999 m_pRCWRefCache = NULL;
4000 m_pLicenseInteropHelperMT = NULL;
4001 m_COMorRemotingFlag = COMorRemoting_NotInitialized;
4002 memset(m_rpCLRTypes, 0, sizeof(m_rpCLRTypes));
4003 #endif // FEATURE_COMINTEROP
4005 m_pUMEntryThunkCache = NULL;
4007 m_pAsyncPool = NULL;
4008 m_handleStore = NULL;
4010 m_ExposedObject = NULL;
4011 m_pComIPForExposedObject = NULL;
4014 m_pThreadTrackInfoList = NULL;
4015 m_TrackSpinLock = 0;
4016 m_Assemblies.Debug_SetAppDomain(this);
4019 m_dwThreadEnterCount = 0;
4020 m_dwThreadsStillInAppDomain = (ULONG)-1;
4022 #ifdef FEATURE_COMINTEROP
4023 m_pRefDispIDCache = NULL;
4024 m_hndMissing = NULL;
4027 m_pRefClassFactHash = NULL;
4028 m_anonymouslyHostedDynamicMethodsAssembly = NULL;
4030 m_ReversePInvokeCanEnter=TRUE;
4031 m_ForceTrivialWaitOperations = false;
4032 m_Stage=STAGE_CREATING;
4034 m_bForceGCOnUnload=FALSE;
4035 m_bUnloadingFromUnloadEvent=FALSE;
4039 m_dwCreationHolders=0;
4042 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4043 m_ullTotalProcessorUsage = 0;
4044 m_pullAllocBytes = NULL;
4045 m_pullSurvivedBytes = NULL;
4046 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4048 #ifdef FEATURE_TYPEEQUIVALENCE
4049 m_pTypeEquivalenceTable = NULL;
4050 #endif // FEATURE_TYPEEQUIVALENCE
4052 #ifdef FEATURE_COMINTEROP
4053 m_pNameToTypeMap = NULL;
4054 m_vNameToTypeMapVersion = 0;
4056 m_pWinRTFactoryCache = NULL;
4057 #endif // FEATURE_COMINTEROP
4059 #ifdef FEATURE_PREJIT
4060 m_pDomainFileWithNativeImageList = NULL;
4063 m_fIsBindingModelLocked.Store(FALSE);
4065 } // AppDomain::AppDomain
4067 AppDomain::~AppDomain()
4077 #ifndef CROSSGEN_COMPILE
4079 _ASSERTE(m_dwCreationHolders == 0);
4081 // release the TPIndex. note that since TPIndex values are recycled the TPIndex
4082 // can only be released once all threads in the AppDomain have exited.
4083 if (GetTPIndex().m_dwIndex != 0)
4084 PerAppDomainTPCountList::ResetAppDomainIndex(GetTPIndex());
4086 if (m_dwId.m_dwId!=0)
4087 SystemDomain::ReleaseAppDomainId(m_dwId);
4089 m_AssemblyCache.Clear();
4092 m_ADUnloadSink->Release();
4100 #ifdef FEATURE_COMINTEROP
4101 if (m_pNameToTypeMap != nullptr)
4103 delete m_pNameToTypeMap;
4104 m_pNameToTypeMap = nullptr;
4106 if (m_pWinRTFactoryCache != nullptr)
4108 delete m_pWinRTFactoryCache;
4109 m_pWinRTFactoryCache = nullptr;
4111 #endif //FEATURE_COMINTEROP
4114 // If we were tracking thread AD transitions, cleanup the list on shutdown
4115 if (m_pThreadTrackInfoList)
4117 while (m_pThreadTrackInfoList->Count() > 0)
4119 // Get the very last element
4120 ThreadTrackInfo *pElem = *(m_pThreadTrackInfoList->Get(m_pThreadTrackInfoList->Count() - 1));
4126 // Remove pointer entry from the list
4127 m_pThreadTrackInfoList->Delete(m_pThreadTrackInfoList->Count() - 1);
4130 // Now delete the list itself
4131 delete m_pThreadTrackInfoList;
4132 m_pThreadTrackInfoList = NULL;
4136 #endif // CROSSGEN_COMPILE
4139 //*****************************************************************************
4140 //*****************************************************************************
4141 //*****************************************************************************
4142 void AppDomain::Init()
4147 PRECONDITION(SystemDomain::IsUnderDomainLock());
4151 m_pDelayedLoaderAllocatorUnloadList = NULL;
4153 SetStage( STAGE_CREATING);
4156 // The lock is taken also during stack walking (GC or profiler)
4157 // - To prevent deadlock with GC thread, we cannot trigger GC while holding the lock
4158 // - To prevent deadlock with profiler thread, we cannot allow thread suspension
4159 m_crstHostAssemblyMap.Init(
4160 CrstHostAssemblyMap,
4161 (CrstFlags)(CRST_GC_NOTRIGGER_WHEN_TAKEN
4162 | CRST_DEBUGGER_THREAD
4163 INDEBUG(| CRST_DEBUG_ONLY_CHECK_FORBID_SUSPEND_THREAD)));
4164 m_crstHostAssemblyMapAdd.Init(CrstHostAssemblyMapAdd);
4166 m_dwId = SystemDomain::GetNewAppDomainId(this);
4168 m_LoaderAllocator.Init(this);
4170 #ifndef CROSSGEN_COMPILE
4171 //Allocate the threadpool entry before the appdomin id list. Otherwise,
4172 //the thread pool list will be out of sync if insertion of id in
4173 //the appdomain fails.
4174 m_tpIndex = PerAppDomainTPCountList::AddNewTPIndex();
4175 #endif // CROSSGEN_COMPILE
4177 m_dwIndex = SystemDomain::GetNewAppDomainIndex(this);
4179 #ifndef CROSSGEN_COMPILE
4180 PerAppDomainTPCountList::SetAppDomainId(m_tpIndex, m_dwId);
4182 m_ADUnloadSink=new ADUnloadSink();
4187 // Set up the IL stub cache
4188 m_ILStubCache.Init(GetLoaderAllocator()->GetHighFrequencyHeap());
4190 // Set up the binding caches
4191 m_AssemblyCache.Init(&m_DomainCacheCrst, GetHighFrequencyHeap());
4192 m_UnmanagedCache.InitializeTable(this, &m_DomainCacheCrst);
4194 m_MemoryPressure = 0;
4196 m_sDomainLocalBlock.Init(this);
4198 #ifndef CROSSGEN_COMPILE
4200 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4201 // NOTE: it's important that we initialize ARM data structures before calling
4202 // Ref_CreateHandleTableBucket, this is because AD::Init() can race with GC
4203 // and once we add ourselves to the handle table map the GC can start walking
4204 // our handles and calling AD::RecordSurvivedBytes() which touches ARM data.
4205 if (GCHeapUtilities::IsServerHeap())
4206 m_dwNumHeaps = CPUGroupInfo::CanEnableGCCPUGroups() ?
4207 CPUGroupInfo::GetNumActiveProcessors() :
4208 GetCurrentProcessCpuCount();
4211 m_pullAllocBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
4212 m_pullSurvivedBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
4213 for (DWORD i = 0; i < m_dwNumHeaps; i++)
4215 m_pullAllocBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
4216 m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
4218 m_ullLastEtwAllocBytes = 0;
4219 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4221 // Default domain reuses the handletablemap that was created during EEStartup since
4222 // default domain cannot be unloaded.
4223 if (GetId().m_dwId == DefaultADID)
4225 m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
4229 m_handleStore = GCHandleUtilities::GetGCHandleManager()->CreateHandleStore((void*)(uintptr_t)m_dwIndex.m_dwIndex);
4237 #endif // CROSSGEN_COMPILE
4239 #ifdef FEATURE_TYPEEQUIVALENCE
4240 m_TypeEquivalenceCrst.Init(CrstTypeEquivalenceMap);
4243 m_ReflectionCrst.Init(CrstReflection, CRST_UNSAFE_ANYMODE);
4244 m_RefClassFactCrst.Init(CrstClassFactInfoHash);
4247 LockOwner lock = {&m_DomainCrst, IsOwnerOfCrst};
4248 m_clsidHash.Init(0,&CompareCLSID,true, &lock); // init hash table
4251 SetStage(STAGE_READYFORMANAGEDCODE);
4253 #ifndef CROSSGEN_COMPILE
4254 m_pDefaultContext = new Context(this);
4256 m_ExposedObject = CreateHandle(NULL);
4258 // Create the Application Security Descriptor
4260 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains++);
4262 #ifdef FEATURE_COMINTEROP
4263 if (!AppX::IsAppXProcess())
4266 #endif //FEATURE_COMINTEROP
4268 #ifdef FEATURE_TIERED_COMPILATION
4269 m_tieredCompilationManager.Init(GetId());
4271 #endif // CROSSGEN_COMPILE
4272 } // AppDomain::Init
4275 /*********************************************************************/
4277 BOOL AppDomain::IsCompilationDomain()
4279 LIMITED_METHOD_CONTRACT;
4281 BOOL isCompilationDomain = (m_dwFlags & COMPILATION_DOMAIN) != 0;
4282 #ifdef FEATURE_PREJIT
4283 _ASSERTE(!isCompilationDomain ||
4284 (IsCompilationProcess() && IsPassiveDomain()));
4285 #endif // FEATURE_PREJIT
4286 return isCompilationDomain;
4289 #ifndef CROSSGEN_COMPILE
4291 extern int g_fADUnloadWorkerOK;
4294 // This helper will send the AppDomain creation notifications for profiler / debugger.
4295 // If it throws, its backout code will also send a notification.
4296 // If it succeeds, then we still need to send a AppDomainCreateFinished notification.
4297 void AppDomain::CreateUnmanagedObject(AppDomainCreationHolder<AppDomain>& pDomain)
4304 INJECT_FAULT(COMPlusThrowOM(););
4310 pDomain.Assign(new AppDomain());
4311 if (g_fADUnloadWorkerOK<0)
4313 AppDomain::CreateADUnloadWorker();
4317 // We addref Appdomain object here and notify a profiler that appdomain
4318 // creation has started, then return to managed code which will call
4319 // the function that releases the appdomain and notifies a profiler that we finished
4320 // creating the appdomain. If an exception is raised while we're in that managed code
4321 // we will leak memory and the profiler will not be notified about the failure
4323 #ifdef PROFILING_SUPPORTED
4324 // Signal profile if present.
4326 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
4327 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) (AppDomain*) pDomain);
4331 #endif // PROFILING_SUPPORTED
4334 SystemDomain::LockHolder lh;
4336 // allocate a Virtual Call Stub Manager for this domain
4340 pDomain->SetCanUnload(); // by default can unload any domain
4342 #ifdef DEBUGGING_SUPPORTED
4343 // Notify the debugger here, before the thread transitions into the
4344 // AD to finish the setup, and before any assemblies are loaded into it.
4345 SystemDomain::PublishAppDomainAndInformDebugger(pDomain);
4346 #endif // DEBUGGING_SUPPORTED
4348 STRESS_LOG2 (LF_APPDOMAIN, LL_INFO100, "Create domain [%d] %p\n", pDomain->GetId().m_dwId, (AppDomain*)pDomain);
4349 pDomain->LoadSystemAssemblies();
4350 pDomain->SetupSharedStatics();
4352 pDomain->SetStage(AppDomain::STAGE_ACTIVE);
4354 #ifdef PROFILING_SUPPORTED
4357 // Need the first assembly loaded in to get any data on an app domain.
4359 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
4360 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID)(AppDomain*) pDomain, GET_EXCEPTION()->GetHR());
4366 // On success, caller must still send the AppDomainCreationFinished notification.
4367 #endif // PROFILING_SUPPORTED
4370 void AppDomain::Stop()
4380 #ifdef FEATURE_MULTICOREJIT
4381 GetMulticoreJitManager().StopProfile(true);
4384 // Set the unloaded flag before notifying the debugger
4385 GetLoaderAllocator()->SetIsUnloaded();
4387 #ifdef DEBUGGING_SUPPORTED
4388 if (IsDebuggerAttached())
4389 NotifyDebuggerUnload();
4390 #endif // DEBUGGING_SUPPORTED
4392 m_pRootAssembly = NULL; // This assembly is in the assembly list;
4394 #ifdef DEBUGGING_SUPPORTED
4395 if (NULL != g_pDebugInterface)
4397 // Call the publisher API to delete this appdomain entry from the list
4398 CONTRACT_VIOLATION(ThrowsViolation);
4399 g_pDebugInterface->RemoveAppDomainFromIPC (this);
4401 #endif // DEBUGGING_SUPPORTED
4404 void AppDomain::Terminate()
4417 _ASSERTE(m_dwThreadEnterCount == 0 || IsDefaultDomain());
4419 if (m_pComIPForExposedObject)
4421 m_pComIPForExposedObject->Release();
4422 m_pComIPForExposedObject = NULL;
4425 delete m_pDefaultContext;
4426 m_pDefaultContext = NULL;
4428 if (m_pUMEntryThunkCache)
4430 delete m_pUMEntryThunkCache;
4431 m_pUMEntryThunkCache = NULL;
4434 #ifdef FEATURE_COMINTEROP
4443 delete m_pRCWRefCache;
4444 m_pRCWRefCache = NULL;
4447 if (m_pComCallWrapperCache)
4449 m_pComCallWrapperCache->Neuter();
4450 m_pComCallWrapperCache->Release();
4453 // if the above released the wrapper cache, then it will call back and reset our
4454 // m_pComCallWrapperCache to null. If not null, then need to set it's domain pointer to
4456 if (! m_pComCallWrapperCache)
4458 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::Terminate ComCallWrapperCache released\n"));
4463 m_pComCallWrapperCache = NULL;
4464 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::Terminate ComCallWrapperCache not released\n"));
4468 #endif // FEATURE_COMINTEROP
4471 if (!IsAtProcessExit())
4473 // if we're not shutting down everything then clean up the string literals associated
4474 // with this appdomain -- note that is no longer needs to happen while suspended
4475 // because the appropriate locks are taken in the GlobalStringLiteralMap
4476 // this is important as this locks have a higher lock number than does the
4477 // thread-store lock which is taken when we suspend.
4478 GetLoaderAllocator()->CleanupStringLiteralMap();
4480 // Suspend the EE to do some clean up that can only occur
4481 // while no threads are running.
4482 GCX_COOP (); // SuspendEE may require current thread to be in Coop mode
4483 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
4486 // Note that this must be performed before restarting the EE. It will clean
4487 // the cache and prevent others from using stale cache entries.
4488 //@TODO: Would be nice to get this back to BaseDomain, but need larger fix for that.
4489 // NOTE: Must have the runtime suspended to unlink managers
4490 // NOTE: May be NULL due to OOM during initialization. Can skip in that case.
4491 GetLoaderAllocator()->UninitVirtualCallStubManager();
4492 MethodTable::ClearMethodDataCache();
4493 ClearJitGenericHandleCache(this);
4495 // @TODO s_TPMethodTableCrst prevents us from from keeping the whole
4496 // assembly shutdown logic here. See if we can do better in the next milestone
4497 #ifdef FEATURE_PREJIT
4498 DeleteNativeCodeRanges();
4501 if (!IsAtProcessExit())
4504 ThreadSuspend::RestartEE(FALSE, TRUE);
4507 ShutdownAssemblies();
4508 ShutdownNativeDllSearchDirectories();
4510 if (m_pRefClassFactHash)
4512 m_pRefClassFactHash->Destroy();
4513 // storage for m_pRefClassFactHash itself is allocated on the loader heap
4516 #ifdef FEATURE_TYPEEQUIVALENCE
4517 m_TypeEquivalenceCrst.Destroy();
4520 m_ReflectionCrst.Destroy();
4521 m_RefClassFactCrst.Destroy();
4523 m_LoaderAllocator.Terminate();
4525 BaseDomain::Terminate();
4529 GCHandleUtilities::GetGCHandleManager()->DestroyHandleStore(m_handleStore);
4530 m_handleStore = NULL;
4533 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4534 if (m_pullAllocBytes)
4536 delete [] m_pullAllocBytes;
4538 if (m_pullSurvivedBytes)
4540 delete [] m_pullSurvivedBytes;
4542 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4544 if(m_dwIndex.m_dwIndex != 0)
4545 SystemDomain::ReleaseAppDomainIndex(m_dwIndex);
4546 } // AppDomain::Terminate
4548 void AppDomain::CloseDomain()
4559 BOOL bADRemoved=FALSE;;
4561 AddRef(); // Hold a reference
4562 AppDomainRefHolder AdHolder(this);
4564 SystemDomain::LockHolder lh;
4566 SystemDomain::System()->DecrementNumAppDomains(); // Maintain a count of app domains added to the list.
4567 bADRemoved = SystemDomain::System()->RemoveDomain(this);
4574 /*********************************************************************/
4576 struct GetExposedObject_Args
4582 static void GetExposedObject_Wrapper(LPVOID ptr)
4591 GetExposedObject_Args *args = (GetExposedObject_Args *) ptr;
4592 *(args->ref) = args->pDomain->GetExposedObject();
4596 OBJECTREF AppDomain::GetExposedObject()
4603 INJECT_FAULT(COMPlusThrowOM(););
4607 OBJECTREF ref = GetRawExposedObject();
4610 APPDOMAINREF obj = NULL;
4612 Thread *pThread = GetThread();
4613 if (pThread->GetDomain() != this)
4615 GCPROTECT_BEGIN(ref);
4616 GetExposedObject_Args args = {this, &ref};
4617 // call through DoCallBack with a domain transition
4618 pThread->DoADCallBack(this,GetExposedObject_Wrapper, &args,ADV_CREATING|ADV_RUNNINGIN);
4622 MethodTable *pMT = MscorlibBinder::GetClass(CLASS__APP_DOMAIN);
4624 // Create the module object
4625 obj = (APPDOMAINREF) AllocateObject(pMT);
4626 obj->SetDomain(this);
4628 if (!StoreFirstObjectInHandle(m_ExposedObject, (OBJECTREF) obj))
4630 obj = (APPDOMAINREF) GetRawExposedObject();
4634 return (OBJECTREF) obj;
4642 OBJECTREF AppDomain::DoSetup(OBJECTREF* setupInfo)
4649 INJECT_FAULT(COMPlusThrowOM(););
4653 ADID adid=GetAppDomain()->GetId();
4655 OBJECTREF retval=NULL;
4656 GCPROTECT_BEGIN(retval);
4658 ENTER_DOMAIN_PTR(this,ADV_CREATING);
4660 MethodDescCallSite setup(METHOD__APP_DOMAIN__SETUP);
4664 args[0]=ObjToArgSlot(*setupInfo);
4666 OBJECTREF activator;
4667 activator=setup.Call_RetOBJECTREF(args);
4668 _ASSERTE(activator==NULL);
4670 #if defined(FEATURE_MULTICOREJIT)
4671 // Disable AutoStartProfile in default domain from this code path.
4672 // It's called from SystemDomain::ExecuteMainMethod for normal program, not needed for SL and Asp.Net
4673 if (! IsDefaultDomain())
4677 GetMulticoreJitManager().AutoStartProfile(this);
4681 END_DOMAIN_TRANSITION;
4686 #endif // !CROSSGEN_COMPILE
4688 #ifdef FEATURE_COMINTEROP
4689 #ifndef CROSSGEN_COMPILE
4690 HRESULT AppDomain::GetComIPForExposedObject(IUnknown **pComIP)
4692 // Assumption: This function is called for AppDomain's that the current
4693 // thread is in or has entered, or the AppDomain is kept alive.
4695 // Assumption: This function can now throw. The caller is responsible for any
4696 // BEGIN_EXTERNAL_ENTRYPOINT, EX_TRY, or other
4697 // techniques to convert to a COM HRESULT protocol.
4707 Thread *pThread = GetThread();
4708 if (m_pComIPForExposedObject)
4710 GCX_PREEMP_THREAD_EXISTS(pThread);
4711 m_pComIPForExposedObject->AddRef();
4712 *pComIP = m_pComIPForExposedObject;
4716 IUnknown* punk = NULL;
4718 OBJECTREF ref = NULL;
4719 GCPROTECT_BEGIN(ref);
4723 ENTER_DOMAIN_PTR(this,ADV_DEFAULTAD)
4725 ref = GetExposedObject();
4726 punk = GetComIPFromObjectRef(&ref);
4727 if (FastInterlockCompareExchangePointer(&m_pComIPForExposedObject, punk, NULL) == NULL)
4729 GCX_PREEMP_THREAD_EXISTS(pThread);
4730 m_pComIPForExposedObject->AddRef();
4733 END_DOMAIN_TRANSITION;
4739 *pComIP = m_pComIPForExposedObject;
4744 #endif //#ifndef CROSSGEN_COMPILE
4746 MethodTable *AppDomain::GetRedirectedType(WinMDAdapter::RedirectedTypeIndex index)
4756 // If we have the type loaded already, use that
4757 if (m_rpCLRTypes[index] != nullptr)
4759 return m_rpCLRTypes[index];
4762 WinMDAdapter::FrameworkAssemblyIndex frameworkAssemblyIndex;
4763 WinMDAdapter::GetRedirectedTypeInfo(index, nullptr, nullptr, nullptr, &frameworkAssemblyIndex, nullptr, nullptr);
4764 MethodTable * pMT = LoadRedirectedType(index, frameworkAssemblyIndex);
4765 m_rpCLRTypes[index] = pMT;
4769 MethodTable* AppDomain::LoadRedirectedType(WinMDAdapter::RedirectedTypeIndex index, WinMDAdapter::FrameworkAssemblyIndex assembly)
4776 PRECONDITION(index < WinMDAdapter::RedirectedTypeIndex_Count);
4780 LPCSTR szClrNamespace;
4782 LPCSTR szFullWinRTName;
4783 WinMDAdapter::FrameworkAssemblyIndex nFrameworkAssemblyIndex;
4785 WinMDAdapter::GetRedirectedTypeInfo(index, &szClrNamespace, &szClrName, &szFullWinRTName, &nFrameworkAssemblyIndex, nullptr, nullptr);
4787 _ASSERTE(nFrameworkAssemblyIndex >= WinMDAdapter::FrameworkAssembly_Mscorlib &&
4788 nFrameworkAssemblyIndex < WinMDAdapter::FrameworkAssembly_Count);
4790 if (assembly != nFrameworkAssemblyIndex)
4792 // The framework type does not live in the assembly we were requested to load redirected types from
4795 else if (nFrameworkAssemblyIndex == WinMDAdapter::FrameworkAssembly_Mscorlib)
4797 return ClassLoader::LoadTypeByNameThrowing(MscorlibBinder::GetModule()->GetAssembly(),
4800 ClassLoader::ThrowIfNotFound,
4801 ClassLoader::LoadTypes,
4802 CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4807 AssemblyMetaDataInternal context;
4808 const BYTE * pbKeyToken;
4809 DWORD cbKeyTokenLength;
4812 WinMDAdapter::GetExtraAssemblyRefProps(nFrameworkAssemblyIndex,
4819 Assembly* pAssembly = AssemblySpec::LoadAssembly(pSimpleName,
4825 return ClassLoader::LoadTypeByNameThrowing(
4829 ClassLoader::ThrowIfNotFound,
4830 ClassLoader::LoadTypes,
4831 CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4834 #endif //FEATURE_COMINTEROP
4836 #endif //!DACCESS_COMPILE
4838 #ifndef DACCESS_COMPILE
4840 bool IsPlatformAssembly(LPCSTR szName, DomainAssembly *pDomainAssembly)
4847 PRECONDITION(CheckPointer(szName));
4848 PRECONDITION(CheckPointer(pDomainAssembly));
4852 PEAssembly *pPEAssembly = pDomainAssembly->GetFile();
4854 if (strcmp(szName, pPEAssembly->GetSimpleName()) != 0)
4860 const BYTE *pbPublicKey = static_cast<const BYTE *>(pPEAssembly->GetPublicKey(&cbPublicKey));
4861 if (pbPublicKey == nullptr)
4866 return StrongNameIsSilverlightPlatformKey(pbPublicKey, cbPublicKey);
4869 void AppDomain::AddAssembly(DomainAssembly * assem)
4876 INJECT_FAULT(COMPlusThrowOM(););
4881 CrstHolder ch(GetAssemblyListLock());
4883 // Attempt to find empty space in assemblies list
4884 DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4885 for (DWORD i = 0; i < asmCount; ++i)
4887 if (m_Assemblies.Get_UnlockedNoReference(i) == NULL)
4889 m_Assemblies.Set_Unlocked(i, assem);
4894 // If empty space not found, simply add to end of list
4895 IfFailThrow(m_Assemblies.Append_Unlocked(assem));
4899 void AppDomain::RemoveAssembly_Unlocked(DomainAssembly * pAsm)
4908 _ASSERTE(GetAssemblyListLock()->OwnedByCurrentThread());
4910 DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4911 for (DWORD i = 0; i < asmCount; ++i)
4913 if (m_Assemblies.Get_UnlockedNoReference(i) == pAsm)
4915 m_Assemblies.Set_Unlocked(i, NULL);
4920 _ASSERTE(!"Unreachable");
4923 BOOL AppDomain::ContainsAssembly(Assembly * assem)
4925 WRAPPER_NO_CONTRACT;
4926 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
4928 (assem->IsIntrospectionOnly() ? kIncludeIntrospection : kIncludeExecution)));
4929 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
4931 while (i.Next(pDomainAssembly.This()))
4933 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
4934 if (pAssembly == assem)
4941 EEClassFactoryInfoHashTable* AppDomain::SetupClassFactHash()
4948 INJECT_FAULT(COMPlusThrowOM(););
4952 CrstHolder ch(&m_ReflectionCrst);
4954 if (m_pRefClassFactHash == NULL)
4956 AllocMemHolder<void> pCache(GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (EEClassFactoryInfoHashTable))));
4957 EEClassFactoryInfoHashTable *tmp = new (pCache) EEClassFactoryInfoHashTable;
4958 LockOwner lock = {&m_RefClassFactCrst,IsOwnerOfCrst};
4959 if (!tmp->Init(20, &lock))
4961 pCache.SuppressRelease();
4962 m_pRefClassFactHash = tmp;
4965 return m_pRefClassFactHash;
4968 #ifdef FEATURE_COMINTEROP
4969 DispIDCache* AppDomain::SetupRefDispIDCache()
4976 INJECT_FAULT(COMPlusThrowOM(););
4980 CrstHolder ch(&m_ReflectionCrst);
4982 if (m_pRefDispIDCache == NULL)
4984 AllocMemHolder<void> pCache = GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (DispIDCache)));
4986 DispIDCache *tmp = new (pCache) DispIDCache;
4989 pCache.SuppressRelease();
4990 m_pRefDispIDCache = tmp;
4993 return m_pRefDispIDCache;
4996 #endif // FEATURE_COMINTEROP
4998 FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
5005 PRECONDITION(pLock->HasLock());
5006 PRECONDITION(pLock->FindFileLock(pFile) == NULL);
5007 INJECT_FAULT(COMPlusThrowOM(););
5011 NewHolder<FileLoadLock> result(new FileLoadLock(pLock, pFile, pDomainFile));
5013 pLock->AddElement(result);
5014 result->AddRef(); // Add one ref on behalf of the ListLock's reference. The corresponding Release() happens in FileLoadLock::CompleteLoadLevel.
5015 return result.Extract();
5018 FileLoadLock::~FileLoadLock()
5028 ((PEFile *) m_data)->Release();
5031 DomainFile *FileLoadLock::GetDomainFile()
5033 LIMITED_METHOD_CONTRACT;
5034 return m_pDomainFile;
5037 FileLoadLevel FileLoadLock::GetLoadLevel()
5039 LIMITED_METHOD_CONTRACT;
5043 ADID FileLoadLock::GetAppDomainId()
5045 LIMITED_METHOD_CONTRACT;
5046 return m_AppDomainId;
5049 // Acquire will return FALSE and not take the lock if the file
5050 // has already been loaded to the target level. Otherwise,
5051 // it will return TRUE and take the lock.
5053 // Note that the taker must release the lock via IncrementLoadLevel.
5055 BOOL FileLoadLock::Acquire(FileLoadLevel targetLevel)
5057 WRAPPER_NO_CONTRACT;
5059 // If we are already loaded to the desired level, the lock is "free".
5060 if (m_level >= targetLevel)
5063 if (!DeadlockAwareEnter())
5065 // We failed to get the lock due to a deadlock.
5069 if (m_level >= targetLevel)
5078 BOOL FileLoadLock::CanAcquire(FileLoadLevel targetLevel)
5080 // If we are already loaded to the desired level, the lock is "free".
5081 if (m_level >= targetLevel)
5084 return CanDeadlockAwareEnter();
5087 #if !defined(DACCESS_COMPILE) && (defined(LOGGING) || defined(STRESS_LOG))
5088 static const char *fileLoadLevelName[] =
5090 "CREATE", // FILE_LOAD_CREATE
5091 "BEGIN", // FILE_LOAD_BEGIN
5092 "FIND_NATIVE_IMAGE", // FILE_LOAD_FIND_NATIVE_IMAGE
5093 "VERIFY_NATIVE_IMAGE_DEPENDENCIES", // FILE_LOAD_VERIFY_NATIVE_IMAGE_DEPENDENCIES
5094 "ALLOCATE", // FILE_LOAD_ALLOCATE
5095 "ADD_DEPENDENCIES", // FILE_LOAD_ADD_DEPENDENCIES
5096 "PRE_LOADLIBRARY", // FILE_LOAD_PRE_LOADLIBRARY
5097 "LOADLIBRARY", // FILE_LOAD_LOADLIBRARY
5098 "POST_LOADLIBRARY", // FILE_LOAD_POST_LOADLIBRARY
5099 "EAGER_FIXUPS", // FILE_LOAD_EAGER_FIXUPS
5100 "VTABLE FIXUPS", // FILE_LOAD_VTABLE_FIXUPS
5101 "DELIVER_EVENTS", // FILE_LOAD_DELIVER_EVENTS
5102 "LOADED", // FILE_LOADED
5103 "VERIFY_EXECUTION", // FILE_LOAD_VERIFY_EXECUTION
5104 "ACTIVE", // FILE_ACTIVE
5106 #endif // !DACCESS_COMPILE && (LOGGING || STRESS_LOG)
5108 BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success)
5115 PRECONDITION(HasLock());
5119 // Increment may happen more than once if reentrancy occurs (e.g. LoadLibrary)
5120 if (level > m_level)
5122 // Must complete each level in turn, unless we have an error
5123 CONSISTENCY_CHECK(m_pDomainFile->IsError() || (level == (m_level+1)));
5124 // Remove the lock from the list if the load is completed
5125 if (level >= FILE_ACTIVE)
5129 PEFileListLockHolder lock((PEFileListLock*)m_pList);
5132 BOOL fDbgOnly_SuccessfulUnlink =
5134 m_pList->Unlink(this);
5135 _ASSERTE(fDbgOnly_SuccessfulUnlink);
5137 m_pDomainFile->ClearLoading();
5139 CONSISTENCY_CHECK(m_dwRefCount >= 2); // Caller (LoadDomainFile) should have 1 refcount and m_pList should have another which was acquired in FileLoadLock::Create.
5141 m_level = (FileLoadLevel)level;
5144 // In AppDomain::IsLoading, if the lock is taken on m_pList and then FindFileLock returns NULL,
5145 // we depend on the DomainFile's load level being up to date. Hence we must update the load
5146 // level while the m_pList lock is held.
5148 m_pDomainFile->SetLoadLevel(level);
5152 Release(); // Release m_pList's refcount on this lock, which was acquired in FileLoadLock::Create
5157 m_level = (FileLoadLevel)level;
5160 m_pDomainFile->SetLoadLevel(level);
5163 #ifndef DACCESS_COMPILE
5166 case FILE_LOAD_ALLOCATE:
5167 case FILE_LOAD_ADD_DEPENDENCIES:
5168 case FILE_LOAD_DELIVER_EVENTS:
5170 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.
5171 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);
5184 void FileLoadLock::SetError(Exception *ex)
5191 PRECONDITION(CheckPointer(ex));
5192 PRECONDITION(HasLock());
5193 INJECT_FAULT(COMPlusThrowOM(););
5197 m_cachedHR = ex->GetHR();
5199 LOG((LF_LOADER, LL_WARNING, "LOADER: %x:***%s*\t!!!Non-transient error 0x%x\n",
5200 m_pDomainFile->GetAppDomain(), m_pDomainFile->GetSimpleName(), m_cachedHR));
5202 m_pDomainFile->SetError(ex);
5204 CompleteLoadLevel(FILE_ACTIVE, FALSE);
5207 void FileLoadLock::AddRef()
5209 LIMITED_METHOD_CONTRACT;
5210 FastInterlockIncrement((LONG *) &m_dwRefCount);
5213 UINT32 FileLoadLock::Release()
5223 LONG count = FastInterlockDecrement((LONG *) &m_dwRefCount);
5230 FileLoadLock::FileLoadLock(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
5231 : ListLockEntry(pLock, pFile, "File load lock"),
5232 m_level((FileLoadLevel) (FILE_LOAD_CREATE)),
5233 m_pDomainFile(pDomainFile),
5235 m_AppDomainId(pDomainFile->GetAppDomain()->GetId())
5237 WRAPPER_NO_CONTRACT;
5241 void FileLoadLock::HolderLeave(FileLoadLock *pThis)
5243 LIMITED_METHOD_CONTRACT;
5253 // Assembly loading:
5255 // Assembly loading is carefully layered to avoid deadlocks in the
5256 // presence of circular loading dependencies.
5257 // A LoadLevel is associated with each assembly as it is being loaded. During the
5258 // act of loading (abstractly, increasing its load level), its lock is
5259 // held, and the current load level is stored on the thread. Any
5260 // recursive loads during that period are automatically restricted to
5261 // only partially load the dependent assembly to the same level as the
5262 // caller (or to one short of that level in the presence of a deadlock
5265 // Each loading stage must be carfully constructed so that
5266 // this constraint is expected and can be dealt with.
5268 // Note that there is one case where this still doesn't handle recursion, and that is the
5269 // security subsytem. The security system runs managed code, and thus must typically fully
5270 // initialize assemblies of permission sets it is trying to use. (And of course, these may be used
5271 // while those assemblies are initializing.) This is dealt with in the historical manner - namely
5272 // the security system passes in a special flag which says that it will deal with null return values
5273 // in the case where a load cannot be safely completed due to such issues.
5276 void AppDomain::LoadSystemAssemblies()
5278 STANDARD_VM_CONTRACT;
5280 // The only reason to make an assembly a "system assembly" is if the EE is caching
5281 // pointers to stuff in the assembly. Because this is going on, we need to preserve
5282 // the invariant that the assembly is loaded into every app domain.
5284 // Right now we have only one system assembly. We shouldn't need to add any more.
5286 LoadAssembly(NULL, SystemDomain::System()->SystemFile(), FILE_ACTIVE);
5289 FileLoadLevel AppDomain::GetDomainFileLoadLevel(DomainFile *pFile)
5299 LoadLockHolder lock(this);
5301 FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5303 if (pLockEntry == NULL)
5304 return pFile->GetLoadLevel();
5306 return pLockEntry->GetLoadLevel();
5309 // This checks if the thread has initiated (or completed) loading at the given level. A false guarantees that
5310 // (a) The current thread (or a thread blocking on the current thread) has not started loading the file
5311 // at the given level, and
5312 // (b) No other thread had started loading the file at this level at the start of this function call.
5314 // Note that another thread may start loading the file at that level in a race with the completion of
5315 // this function. However, the caller still has the guarantee that such a load started after this
5316 // function was called (and e.g. any state in place before the function call will be seen by the other thread.)
5318 // Conversely, a true guarantees that either the current thread has started the load step, or another
5319 // thread has completed the load step.
5322 BOOL AppDomain::IsLoading(DomainFile *pFile, FileLoadLevel level)
5325 if (pFile->GetLoadLevel() < level)
5327 FileLoadLock *pLock = NULL;
5329 LoadLockHolder lock(this);
5331 pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5335 // No thread involved with loading
5336 return pFile->GetLoadLevel() >= level;
5342 FileLoadLockRefHolder lockRef(pLock);
5344 if (pLock->Acquire(level))
5346 // We got the lock - therefore no other thread has started this loading step yet.
5351 // We didn't get the lock - either this thread is already doing the load,
5352 // or else the load has already finished.
5357 // CheckLoading is a weaker form of IsLoading, which will not block on
5358 // other threads waiting for their status. This is appropriate for asserts.
5359 CHECK AppDomain::CheckLoading(DomainFile *pFile, FileLoadLevel level)
5362 if (pFile->GetLoadLevel() < level)
5364 FileLoadLock *pLock = NULL;
5366 LoadLockHolder lock(this);
5368 pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5371 && pLock->CanAcquire(level))
5373 // We can get the lock - therefore no other thread has started this loading step yet.
5374 CHECK_FAILF(("Loading step %d has not been initiated yet", level));
5377 // We didn't get the lock - either this thread is already doing the load,
5378 // or else the load has already finished.
5384 CHECK AppDomain::CheckCanLoadTypes(Assembly *pAssembly)
5393 CHECK_MSG(CheckValidModule(pAssembly->GetManifestModule()),
5394 "Type loading can occur only when executing in the assembly's app domain");
5398 CHECK AppDomain::CheckCanExecuteManagedCode(MethodDesc* pMD)
5408 Module* pModule=pMD->GetModule();
5410 CHECK_MSG(CheckValidModule(pModule),
5411 "Managed code can only run when executing in the module's app domain");
5413 if (!pMD->IsInterface() || pMD->IsStatic()) //interfaces require no activation for instance methods
5415 //cctor could have been interupted by ADU
5416 CHECK_MSG(HasUnloadStarted() || pModule->CheckActivated(),
5417 "Managed code can only run when its module has been activated in the current app domain");
5420 CHECK_MSG(!IsPassiveDomain() || pModule->CanExecuteCode(),
5421 "Executing managed code from an unsafe assembly in a Passive AppDomain");
5426 #endif // !DACCESS_COMPILE
5428 void AppDomain::LoadDomainFile(DomainFile *pFile,
5429 FileLoadLevel targetLevel)
5433 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
5434 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
5435 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM();); }
5436 INJECT_FAULT(COMPlusThrowOM(););
5440 // Quick exit if finished
5441 if (pFile->GetLoadLevel() >= targetLevel)
5444 // Handle the error case
5445 pFile->ThrowIfError(targetLevel);
5448 #ifndef DACCESS_COMPILE
5450 if (pFile->IsLoading())
5454 // Load some more if appropriate
5455 LoadLockHolder lock(this);
5457 FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5458 if (pLockEntry == NULL)
5460 _ASSERTE (!pFile->IsLoading());
5464 pLockEntry->AddRef();
5468 LoadDomainFile(pLockEntry, targetLevel);
5471 #else // DACCESS_COMPILE
5473 #endif // DACCESS_COMPILE
5476 #ifndef DACCESS_COMPILE
5478 FileLoadLevel AppDomain::GetThreadFileLoadLevel()
5480 WRAPPER_NO_CONTRACT;
5481 if (GetThread()->GetLoadLevelLimiter() == NULL)
5484 return (FileLoadLevel)(GetThread()->GetLoadLevelLimiter()->GetLoadLevel()-1);
5488 Assembly *AppDomain::LoadAssembly(AssemblySpec* pIdentity,
5490 FileLoadLevel targetLevel)
5492 CONTRACT(Assembly *)
5497 PRECONDITION(CheckPointer(pFile));
5498 POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // May be NULL in recursive load case
5499 INJECT_FAULT(COMPlusThrowOM(););
5503 DomainAssembly *pAssembly = LoadDomainAssembly(pIdentity, pFile, targetLevel);
5504 PREFIX_ASSUME(pAssembly != NULL);
5506 RETURN pAssembly->GetAssembly();
5509 #ifndef CROSSGEN_COMPILE
5511 class LoadDomainAssemblyStress : APIThreadStress
5515 AssemblySpec* pSpec;
5517 FileLoadLevel targetLevel;
5519 LoadDomainAssemblyStress(AppDomain *pThis, AssemblySpec* pSpec, PEAssembly *pFile, FileLoadLevel targetLevel)
5520 : pThis(pThis), pSpec(pSpec), pFile(pFile), targetLevel(targetLevel) {LIMITED_METHOD_CONTRACT;}
5524 WRAPPER_NO_CONTRACT;
5525 STATIC_CONTRACT_SO_INTOLERANT;
5527 pThis->LoadDomainAssembly(pSpec, pFile, targetLevel);
5530 #endif // CROSSGEN_COMPILE
5532 extern BOOL AreSameBinderInstance(ICLRPrivBinder *pBinderA, ICLRPrivBinder *pBinderB);
5534 DomainAssembly* AppDomain::LoadDomainAssembly( AssemblySpec* pSpec,
5536 FileLoadLevel targetLevel)
5538 STATIC_CONTRACT_THROWS;
5540 if (pSpec == nullptr)
5542 // skip caching, since we don't have anything to base it on
5543 return LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
5546 DomainAssembly* pRetVal = NULL;
5549 pRetVal = LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
5553 Exception* pEx=GET_EXCEPTION();
5554 if (!pEx->IsTransient())
5556 // Setup the binder reference in AssemblySpec from the PEAssembly if one is not already set.
5557 ICLRPrivBinder* pCurrentBindingContext = pSpec->GetBindingContext();
5558 ICLRPrivBinder* pBindingContextFromPEAssembly = pFile->GetBindingContext();
5560 if (pCurrentBindingContext == NULL)
5562 // Set the binding context we got from the PEAssembly if AssemblySpec does not
5563 // have that information
5564 _ASSERTE(pBindingContextFromPEAssembly != NULL);
5565 pSpec->SetBindingContext(pBindingContextFromPEAssembly);
5570 // Binding context in the spec should be the same as the binding context in the PEAssembly
5571 _ASSERTE(AreSameBinderInstance(pCurrentBindingContext, pBindingContextFromPEAssembly));
5575 if (!EEFileLoadException::CheckType(pEx))
5578 pSpec->GetFileOrDisplayName(0, name);
5579 pEx=new EEFileLoadException(name, pEx->GetHR(), NULL, pEx);
5580 AddExceptionToCache(pSpec, pEx);
5581 PAL_CPP_THROW(Exception *, pEx);
5584 AddExceptionToCache(pSpec, pEx);
5593 DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
5595 FileLoadLevel targetLevel)
5597 CONTRACT(DomainAssembly *)
5602 PRECONDITION(CheckPointer(pFile));
5603 PRECONDITION(pFile->IsSystem() || ::GetAppDomain()==this);
5604 POSTCONDITION(CheckPointer(RETVAL));
5605 POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
5606 || RETVAL->GetLoadLevel() >= targetLevel);
5607 POSTCONDITION(RETVAL->CheckNoError(targetLevel));
5608 INJECT_FAULT(COMPlusThrowOM(););
5613 DomainAssembly * result;
5615 #ifndef CROSSGEN_COMPILE
5616 LoadDomainAssemblyStress ts (this, pIdentity, pFile, targetLevel);
5619 // Go into preemptive mode since this may take a while.
5622 // Check for existing fully loaded assembly, or for an assembly which has failed during the loading process.
5623 result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
5627 // Allocate the DomainAssembly a bit early to avoid GC mode problems. We could potentially avoid
5628 // a rare redundant allocation by moving this closer to FileLoadLock::Create, but it's not worth it.
5630 NewHolder<DomainAssembly> pDomainAssembly;
5631 pDomainAssembly = new DomainAssembly(this, pFile, this->GetLoaderAllocator());
5633 LoadLockHolder lock(this);
5635 // Find the list lock entry
5636 FileLoadLock * fileLock = (FileLoadLock *)lock->FindFileLock(pFile);
5637 if (fileLock == NULL)
5639 // Check again in case we were racing
5640 result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
5643 // We are the first one in - create the DomainAssembly
5644 fileLock = FileLoadLock::Create(lock, pFile, pDomainAssembly);
5645 pDomainAssembly.SuppressRelease();
5657 // We pass our ref on fileLock to LoadDomainFile to release.
5659 // Note that if we throw here, we will poison fileLock with an error condition,
5660 // so it will not be removed until app domain unload. So there is no need
5661 // to release our ref count.
5662 result = (DomainAssembly *)LoadDomainFile(fileLock, targetLevel);
5666 result->EnsureLoadLevel(targetLevel);
5670 result->EnsureLoadLevel(targetLevel);
5672 // Malformed metadata may contain a Module reference to what is actually
5673 // an Assembly. In this case we need to throw an exception, since returning
5674 // a DomainModule as a DomainAssembly is a type safety violation.
5675 if (!result->IsAssembly())
5677 ThrowHR(COR_E_ASSEMBLYEXPECTED);
5680 // Cache result in all cases, since found pFile could be from a different AssemblyRef than pIdentity
5681 // Do not cache WindowsRuntime assemblies, they are cached in code:CLRPrivTypeCacheWinRT
5682 if ((pIdentity != NULL) && (pIdentity->CanUseWithBindingCache()) && (result->CanUseWithBindingCache()))
5683 GetAppDomain()->AddAssemblyToCache(pIdentity, result);
5686 } // AppDomain::LoadDomainAssembly
5691 FileLoadLock *pLock;
5692 FileLoadLevel targetLevel;
5696 #ifndef CROSSGEN_COMPILE
5697 static void LoadDomainFile_Wrapper(void *ptr)
5699 WRAPPER_NO_CONTRACT;
5700 STATIC_CONTRACT_SO_INTOLERANT;
5702 LoadFileArgs *args = (LoadFileArgs *) ptr;
5703 args->result = GetAppDomain()->LoadDomainFile(args->pLock, args->targetLevel);
5705 #endif // !CROSSGEN_COMPILE
5707 DomainFile *AppDomain::LoadDomainFile(FileLoadLock *pLock, FileLoadLevel targetLevel)
5709 CONTRACT(DomainFile *)
5712 PRECONDITION(CheckPointer(pLock));
5713 PRECONDITION(pLock->GetDomainFile()->GetAppDomain() == this);
5714 POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
5715 || RETVAL->GetLoadLevel() >= targetLevel);
5716 POSTCONDITION(RETVAL->CheckNoError(targetLevel));
5722 COMPlusThrow(kAppDomainUnloadedException);
5725 APIThreadStress::SyncThreadStress();
5727 DomainFile *pFile = pLock->GetDomainFile();
5729 // Make sure we release the lock on exit
5730 FileLoadLockRefHolder lockRef(pLock);
5732 // We need to perform the early steps of loading mscorlib without a domain transition. This is
5733 // important for bootstrapping purposes - we need to get mscorlib at least partially loaded
5734 // into a domain before we can run serialization code to do the transition.
5736 // Note that we cannot do this in general for all assemblies, because some of the security computations
5737 // require the managed exposed object, which must be created in the correct app domain.
5739 if (this != GetAppDomain()
5740 && pFile->GetFile()->IsSystem()
5741 && targetLevel > FILE_LOAD_ALLOCATE)
5743 // Re-call the routine with a limited load level. This will cause the first part of the load to
5744 // get performed in the current app domain.
5747 LoadDomainFile(pLock, targetLevel > FILE_LOAD_ALLOCATE ? FILE_LOAD_ALLOCATE : targetLevel);
5749 // Now continue on to complete the rest of the load, if any.
5752 // Do a quick out check for the already loaded case.
5753 if (pLock->GetLoadLevel() >= targetLevel)
5755 pFile->ThrowIfError(targetLevel);
5760 #ifndef CROSSGEN_COMPILE
5761 // Make sure we are in the right domain. Many of the load operations require the target domain
5762 // to be the current app domain, most notably anything involving managed code or managed object
5764 if (this != GetAppDomain()
5765 && (!pFile->GetFile()->IsSystem() || targetLevel > FILE_LOAD_ALLOCATE))
5767 // Transition to the correct app domain and perform the load there.
5770 // we will release the lock in the other app domain
5771 lockRef.SuppressRelease();
5773 if(!CanLoadCode() || GetDefaultContext() ==NULL)
5774 COMPlusThrow(kAppDomainUnloadedException);
5775 LoadFileArgs args = {pLock, targetLevel, NULL};
5776 GetThread()->DoADCallBack(this, LoadDomainFile_Wrapper, (void *) &args, ADV_CREATING);
5780 #endif // CROSSGEN_COMPILE
5782 // Initialize a loading queue. This will hold any loads which are triggered recursively but
5783 // which cannot be immediately satisfied due to anti-deadlock constraints.
5785 // PendingLoadQueues are allocated on the stack during a load, and
5786 // shared with all nested loads on the same thread. (Note that we won't use
5787 // "candidate" if we are in a recursive load; that's OK since they are cheap to
5789 FileLoadLevel immediateTargetLevel = targetLevel;
5791 LoadLevelLimiter limit;
5794 // We cannot set a target level higher than that allowed by the limiter currently.
5795 // This is because of anti-deadlock constraints.
5796 if (immediateTargetLevel > limit.GetLoadLevel())
5797 immediateTargetLevel = limit.GetLoadLevel();
5799 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t>>>Load initiated, %s/%s\n",
5800 pFile->GetAppDomain(), pFile->GetSimpleName(),
5801 fileLoadLevelName[immediateTargetLevel], fileLoadLevelName[targetLevel]));
5803 // Now loop and do the load incrementally to the target level.
5804 if (pLock->GetLoadLevel() < immediateTargetLevel)
5807 APIThreadStress::SyncThreadStress();
5809 while (pLock->Acquire(immediateTargetLevel))
5811 FileLoadLevel workLevel;
5813 FileLoadLockHolder fileLock(pLock);
5815 // Work level is next step to do
5816 workLevel = (FileLoadLevel)(fileLock->GetLoadLevel()+1);
5818 // Set up the anti-deadlock constraint: we cannot safely recursively load any assemblies
5819 // on this thread to a higher level than this assembly is being loaded now.
5820 // Note that we do allow work at a parallel level; any deadlocks caused here will
5821 // be resolved by the deadlock detection in the FileLoadLocks.
5822 limit.SetLoadLevel(workLevel);
5825 (workLevel == FILE_LOAD_BEGIN
5826 || workLevel == FILE_LOADED
5827 || workLevel == FILE_ACTIVE)
5828 ? LL_INFO10 : LL_INFO1000,
5829 "LOADER: %p:***%s*\t loading at level %s\n",
5830 this, pFile->GetSimpleName(), fileLoadLevelName[workLevel]));
5832 TryIncrementalLoad(pFile, workLevel, fileLock);
5834 TESTHOOKCALL(CompletedFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5837 if (pLock->GetLoadLevel() == immediateTargetLevel-1)
5839 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load limited due to detected deadlock, %s\n",
5840 pFile->GetAppDomain(), pFile->GetSimpleName(),
5841 fileLoadLevelName[immediateTargetLevel-1]));
5845 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load completed, %s\n",
5846 pFile->GetAppDomain(), pFile->GetSimpleName(),
5847 fileLoadLevelName[pLock->GetLoadLevel()]));
5851 // There may have been an error stored on the domain file by another thread, or from a previous load
5852 pFile->ThrowIfError(targetLevel);
5854 // There are two normal results from the above loop.
5856 // 1. We succeeded in loading the file to the current thread's load level.
5857 // 2. We succeeded in loading the file to the current thread's load level - 1, due
5858 // to deadlock condition with another thread loading the same assembly.
5860 // Either of these are considered satisfactory results, as code inside a load must expect
5861 // a parial load result.
5863 // However, if load level elevation has occurred, then it is possible for a deadlock to
5864 // prevent us from loading an assembly which was loading before the elevation at a radically
5865 // lower level. In such a case, we throw an exception which transiently fails the current
5866 // load, since it is likely we have not satisfied the caller.
5867 // (An alternate, and possibly preferable, strategy here would be for all callers to explicitly
5868 // identify the minimum load level acceptable via CheckLoadDomainFile and throw from there.)
5870 pFile->RequireLoadLevel((FileLoadLevel)(immediateTargetLevel-1));
5876 void AppDomain::TryIncrementalLoad(DomainFile *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder)
5878 STANDARD_VM_CONTRACT;
5880 // This is factored out so we don't call EX_TRY in a loop (EX_TRY can _alloca)
5882 BOOL released = FALSE;
5883 FileLoadLock* pLoadLock = lockHolder.GetValue();
5888 // Special case: for LoadLibrary, we cannot hold the lock during the
5889 // actual LoadLibrary call, because we might get a callback from _CorDllMain on any
5890 // other thread. (Note that this requires DomainFile's LoadLibrary to be independently threadsafe.)
5892 if (workLevel == FILE_LOAD_LOADLIBRARY)
5894 lockHolder.Release();
5899 TESTHOOKCALL(NextFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5900 BOOL success = pFile->DoIncrementalLoad(workLevel);
5901 TESTHOOKCALL(CompletingFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5904 // Reobtain lock to increment level. (Note that another thread may
5905 // have already done it which is OK.
5906 if (pLoadLock->Acquire(workLevel))
5908 // note lockHolder.Acquire isn't wired up to actually take the lock
5909 lockHolder = pLoadLock;
5916 // Complete the level.
5917 if (pLoadLock->CompleteLoadLevel(workLevel, success) &&
5918 pLoadLock->GetLoadLevel()==FILE_LOAD_DELIVER_EVENTS)
5920 lockHolder.Release();
5922 pFile->DeliverAsyncEvents();
5928 Exception *pEx = GET_EXCEPTION();
5931 //We will cache this error and wire this load to forever fail,
5932 // unless the exception is transient or the file is loaded OK but just cannot execute
5933 if (!pEx->IsTransient() && !pFile->IsLoaded())
5938 // Reobtain lock to increment level. (Note that another thread may
5939 // have already done it which is OK.
5940 if (pLoadLock->Acquire(workLevel)) // note pLockHolder->Acquire isn't wired up to actually take the lock
5942 // note lockHolder.Acquire isn't wired up to actually take the lock
5943 lockHolder = pLoadLock;
5950 // Report the error in the lock
5951 pLoadLock->SetError(pEx);
5954 if (!EEFileLoadException::CheckType(pEx))
5955 EEFileLoadException::Throw(pFile->GetFile(), pEx->GetHR(), pEx);
5958 // Otherwise, we simply abort this load, and can retry later on.
5959 // @todo cleanup: make sure that each level is restartable after an exception, and
5960 // leaves no bad side effects
5965 // Checks whether the module is valid to be in the given app domain (need not be yet loaded)
5966 CHECK AppDomain::CheckValidModule(Module * pModule)
5976 if (pModule->FindDomainFile(this) != NULL)
5981 Assembly * pAssembly = pModule->GetAssembly();
5983 CCHECK(pAssembly->IsDomainNeutral());
5984 #ifdef FEATURE_LOADER_OPTIMIZATION
5985 Assembly * pSharedAssembly = NULL;
5986 _ASSERTE(this == ::GetAppDomain());
5988 SharedAssemblyLocator locator(pAssembly->GetManifestFile());
5989 pSharedAssembly = SharedDomain::GetDomain()->FindShareableAssembly(&locator);
5992 CCHECK(pAssembly == pSharedAssembly);
6000 #ifdef FEATURE_LOADER_OPTIMIZATION
6001 // Loads an existing Module into an AppDomain
6002 // WARNING: this can only be done in a very limited scenario - the Module must be an unloaded domain neutral
6003 // dependency in the app domain in question. Normal code should not call this!
6004 DomainFile *AppDomain::LoadDomainNeutralModuleDependency(Module *pModule, FileLoadLevel targetLevel)
6006 CONTRACT(DomainFile *)
6011 PRECONDITION(::GetAppDomain()==this);
6012 PRECONDITION(CheckPointer(pModule));
6013 POSTCONDITION(CheckValidModule(pModule));
6014 POSTCONDITION(CheckPointer(RETVAL));
6015 POSTCONDITION(RETVAL->GetModule() == pModule);
6019 DomainFile *pDomainFile = pModule->FindDomainFile(this);
6021 STRESS_LOG3(LF_CLASSLOADER, LL_INFO100,"LDNMD: DomainFile %p for module %p in AppDomain %i\n",pDomainFile,pModule,GetId().m_dwId);
6023 if (pDomainFile == NULL)
6027 Assembly *pAssembly = pModule->GetAssembly();
6029 DomainAssembly *pDomainAssembly = pAssembly->FindDomainAssembly(this);
6030 if (pDomainAssembly == NULL)
6032 AssemblySpec spec(this);
6033 spec.InitializeSpec(pAssembly->GetManifestFile());
6035 pDomainAssembly = spec.LoadDomainAssembly(targetLevel);
6039 //if the domain assembly already exists, we need to load it to the target level
6040 pDomainAssembly->EnsureLoadLevel (targetLevel);
6043 if(pAssembly != pDomainAssembly->GetAssembly())
6045 ThrowHR(SECURITY_E_INCOMPATIBLE_SHARE);
6048 _ASSERTE (pModule == pAssembly->GetManifestModule());
6049 pDomainFile = pDomainAssembly;
6053 // If the DomainFile already exists, we need to load it to the target level.
6054 pDomainFile->EnsureLoadLevel (targetLevel);
6060 AppDomain::SharePolicy AppDomain::GetSharePolicy()
6062 LIMITED_METHOD_CONTRACT;
6064 return SHARE_POLICY_NEVER;
6066 #endif // FEATURE_LOADER_OPTIMIZATION
6069 void AppDomain::CheckForMismatchedNativeImages(AssemblySpec * pSpec, const GUID * pGuid)
6071 STANDARD_VM_CONTRACT;
6074 // The native images are ever used only for trusted images in CoreCLR.
6075 // We don't wish to open the IL file at runtime so we just forgo any
6076 // eager consistency checking. But we still want to prevent mistmatched
6077 // NGen images from being used. We record all mappings between assembly
6078 // names and MVID, and fail once we detect mismatch.
6081 if (pSpec->IsStrongNamed() && pSpec->HasPublicKey())
6083 pSpec->ConvertPublicKeyToToken();
6087 // CoreCLR binder unifies assembly versions. Ignore assembly version here to
6088 // detect more types of potential mismatches.
6090 AssemblyMetaDataInternal * pContext = pSpec->GetContext();
6091 pContext->usMajorVersion = (USHORT)-1;
6092 pContext->usMinorVersion = (USHORT)-1;
6093 pContext->usBuildNumber = (USHORT)-1;
6094 pContext->usRevisionNumber = (USHORT)-1;
6096 // Ignore the WinRT type while considering if two assemblies have the same identity.
6097 pSpec->SetWindowsRuntimeType(NULL, NULL);
6099 CrstHolder ch(&m_DomainCrst);
6101 const NativeImageDependenciesEntry * pEntry = m_NativeImageDependencies.Lookup(pSpec);
6105 if (*pGuid != pEntry->m_guidMVID)
6108 msg.Printf("ERROR: Native images generated against multiple versions of assembly %s. ", pSpec->GetName());
6109 WszOutputDebugString(msg.GetUnicode());
6110 COMPlusThrowNonLocalized(kFileLoadException, msg.GetUnicode());
6116 // No entry yet - create one
6118 AllocMemTracker amTracker;
6119 AllocMemTracker *pamTracker = &amTracker;
6121 NativeImageDependenciesEntry * pNewEntry =
6122 new (pamTracker->Track(GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(NativeImageDependenciesEntry)))))
6123 NativeImageDependenciesEntry();
6125 pNewEntry->m_AssemblySpec.CopyFrom(pSpec);
6126 pNewEntry->m_AssemblySpec.CloneFieldsToLoaderHeap(AssemblySpec::ALL_OWNED, GetLowFrequencyHeap(), pamTracker);
6128 pNewEntry->m_guidMVID = *pGuid;
6130 m_NativeImageDependencies.Add(pNewEntry);
6131 amTracker.SuppressRelease();
6136 void AppDomain::SetupSharedStatics()
6143 INJECT_FAULT(COMPlusThrowOM(););
6147 #ifndef CROSSGEN_COMPILE
6148 if (NingenEnabled())
6151 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: SetupSharedStatics()"));
6153 // don't do any work in init stage. If not init only do work in non-shared case if are default domain
6154 _ASSERTE(!g_fEEInit);
6156 // Because we are allocating/referencing objects, need to be in cooperative mode
6159 static OBJECTHANDLE hSharedStaticsHandle = NULL;
6161 if (hSharedStaticsHandle == NULL) {
6162 // Note that there is no race here since the default domain is always set up first
6163 _ASSERTE(IsDefaultDomain());
6165 MethodTable *pMT = MscorlibBinder::GetClass(CLASS__SHARED_STATICS);
6166 _ASSERTE(pMT->IsClassPreInited());
6168 hSharedStaticsHandle = CreateGlobalHandle(AllocateObject(pMT));
6171 DomainLocalModule *pLocalModule;
6173 if (IsSingleAppDomain())
6175 pLocalModule = MscorlibBinder::GetModule()->GetDomainLocalModule();
6179 pLocalModule = GetDomainLocalBlock()->GetModuleSlot(
6180 MscorlibBinder::GetModule()->GetModuleIndex());
6183 FieldDesc *pFD = MscorlibBinder::GetField(FIELD__SHARED_STATICS__SHARED_STATICS);
6185 OBJECTREF* pHandle = (OBJECTREF*)
6186 ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pFD->GetOffset());
6187 SetObjectReference( pHandle, ObjectFromHandle(hSharedStaticsHandle), this );
6189 // This is a convenient place to initialize String.Empty.
6190 // It is treated as intrinsic by the JIT as so the static constructor would never run.
6191 // Leaving it uninitialized would confuse debuggers.
6193 // String should not have any static constructors.
6194 _ASSERTE(g_pStringClass->IsClassPreInited());
6196 FieldDesc * pEmptyStringFD = MscorlibBinder::GetField(FIELD__STRING__EMPTY);
6197 OBJECTREF* pEmptyStringHandle = (OBJECTREF*)
6198 ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pEmptyStringFD->GetOffset());
6199 SetObjectReference( pEmptyStringHandle, StringObject::GetEmptyString(), this );
6200 #endif // CROSSGEN_COMPILE
6203 DomainAssembly * AppDomain::FindAssembly(PEAssembly * pFile, FindAssemblyOptions options/* = FindAssemblyOptions_None*/)
6210 INJECT_FAULT(COMPlusThrowOM(););
6214 const bool includeFailedToLoad = (options & FindAssemblyOptions_IncludeFailedToLoad) != 0;
6216 if (pFile->HasHostAssembly())
6218 DomainAssembly * pDA = FindAssembly(pFile->GetHostAssembly());
6219 if (pDA != nullptr && (pDA->IsLoaded() || (includeFailedToLoad && pDA->IsError())))
6226 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
6228 (includeFailedToLoad ? kIncludeFailedToLoad : 0) |
6229 (pFile->IsIntrospectionOnly() ? kIncludeIntrospection : kIncludeExecution)));
6230 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
6232 while (i.Next(pDomainAssembly.This()))
6234 PEFile * pManifestFile = pDomainAssembly->GetFile();
6235 if (pManifestFile &&
6236 !pManifestFile->IsResource() &&
6237 pManifestFile->Equals(pFile))
6239 // Caller already has PEAssembly, so we can give DomainAssembly away freely without AddRef
6240 return pDomainAssembly.Extract();
6246 static const AssemblyIterationFlags STANDARD_IJW_ITERATOR_FLAGS =
6247 (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kExcludeCollectible);
6250 void AppDomain::SetFriendlyName(LPCWSTR pwzFriendlyName, BOOL fDebuggerCares/*=TRUE*/)
6255 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6257 INJECT_FAULT(COMPlusThrowOM(););
6261 // Do all computations into a temporary until we're ensured of success
6262 SString tmpFriendlyName;
6265 if (pwzFriendlyName)
6266 tmpFriendlyName.Set(pwzFriendlyName);
6269 // If there is an assembly, try to get the name from it.
6270 // If no assembly, but if it's the DefaultDomain, then give it a name
6272 if (m_pRootAssembly)
6274 tmpFriendlyName.SetUTF8(m_pRootAssembly->GetSimpleName());
6276 SString::Iterator i = tmpFriendlyName.End();
6277 if (tmpFriendlyName.FindBack(i, '.'))
6278 tmpFriendlyName.Truncate(i);
6282 if (IsDefaultDomain())
6283 tmpFriendlyName.Set(DEFAULT_DOMAIN_FRIENDLY_NAME);
6285 // This is for the profiler - if they call GetFriendlyName on an AppdomainCreateStarted
6286 // event, then we want to give them a temporary name they can use.
6287 else if (GetId().m_dwId != 0)
6289 tmpFriendlyName.Clear();
6290 tmpFriendlyName.Printf(W("%s %d"), OTHER_DOMAIN_FRIENDLY_NAME_PREFIX, GetId().m_dwId);
6296 tmpFriendlyName.Normalize();
6299 m_friendlyName = tmpFriendlyName;
6300 m_friendlyName.Normalize();
6302 if(g_pDebugInterface)
6304 // update the name in the IPC publishing block
6305 if (SUCCEEDED(g_pDebugInterface->UpdateAppDomainEntryInIPC(this)))
6307 // inform the attached debugger that the name of this appdomain has changed.
6308 if (IsDebuggerAttached() && fDebuggerCares)
6309 g_pDebugInterface->NameChangeEvent(this, NULL);
6314 void AppDomain::ResetFriendlyName(BOOL fDebuggerCares/*=TRUE*/)
6316 WRAPPER_NO_CONTRACT;
6317 SetFriendlyName(NULL, fDebuggerCares);
6320 LPCWSTR AppDomain::GetFriendlyName(BOOL fDebuggerCares/*=TRUE*/)
6325 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6327 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6328 INJECT_FAULT(COMPlusThrowOM(););
6333 // Handle NULL this pointer - this happens sometimes when printing log messages
6334 // but in general shouldn't occur in real code
6339 if (m_friendlyName.IsEmpty())
6340 SetFriendlyName(NULL, fDebuggerCares);
6342 RETURN m_friendlyName;
6345 LPCWSTR AppDomain::GetFriendlyNameForLogging()
6352 POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
6356 // Handle NULL this pointer - this happens sometimes when printing log messages
6357 // but in general shouldn't occur in real code
6361 RETURN (m_friendlyName.IsEmpty() ?W(""):(LPCWSTR)m_friendlyName);
6364 LPCWSTR AppDomain::GetFriendlyNameForDebugger()
6369 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6371 POSTCONDITION(CheckPointer(RETVAL));
6376 if (m_friendlyName.IsEmpty())
6378 BOOL fSuccess = FALSE;
6382 SetFriendlyName(NULL);
6388 // Gobble all exceptions.
6390 EX_END_CATCH(SwallowAllExceptions);
6398 RETURN m_friendlyName;
6402 #endif // !DACCESS_COMPILE
6404 #ifdef DACCESS_COMPILE
6406 PVOID AppDomain::GetFriendlyNameNoSet(bool* isUtf8)
6410 if (!m_friendlyName.IsEmpty())
6413 return m_friendlyName.DacGetRawContent();
6415 else if (m_pRootAssembly)
6418 return (PVOID)m_pRootAssembly->GetSimpleName();
6420 else if (dac_cast<TADDR>(this) ==
6421 dac_cast<TADDR>(SystemDomain::System()->DefaultDomain()))
6424 return (PVOID)DEFAULT_DOMAIN_FRIENDLY_NAME;
6432 #endif // DACCESS_COMPILE
6434 void AppDomain::CacheStringsForDAC()
6445 // If the application base, private bin paths, and configuration file are
6446 // available, cache them so DAC can read them out of memory
6450 #ifndef DACCESS_COMPILE
6452 BOOL AppDomain::AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAllowFailure)
6459 PRECONDITION(CheckPointer(pSpec));
6460 // Hosted fusion binder makes an exception here, so we cannot assert.
6461 //PRECONDITION(pSpec->CanUseWithBindingCache());
6462 //PRECONDITION(pFile->CanUseWithBindingCache());
6463 INJECT_FAULT(COMPlusThrowOM(););
6467 CrstHolder holder(&m_DomainCacheCrst);
6468 // !!! suppress exceptions
6469 if(!m_AssemblyCache.StoreFile(pSpec, pFile) && !fAllowFailure)
6471 // TODO: Disabling the below assertion as currently we experience
6472 // inconsistency on resolving the Microsoft.Office.Interop.MSProject.dll
6473 // This causes below assertion to fire and crashes the VS. This issue
6474 // is being tracked with Dev10 Bug 658555. Brought back it when this bug
6478 EEFileLoadException::Throw(pSpec, FUSION_E_CACHEFILE_FAILED, NULL);
6484 BOOL AppDomain::AddAssemblyToCache(AssemblySpec* pSpec, DomainAssembly *pAssembly)
6491 PRECONDITION(CheckPointer(pSpec));
6492 PRECONDITION(CheckPointer(pAssembly));
6493 PRECONDITION(pSpec->CanUseWithBindingCache());
6494 PRECONDITION(pAssembly->CanUseWithBindingCache());
6495 INJECT_FAULT(COMPlusThrowOM(););
6499 CrstHolder holder(&m_DomainCacheCrst);
6500 // !!! suppress exceptions
6501 BOOL bRetVal = m_AssemblyCache.StoreAssembly(pSpec, pAssembly);
6505 BOOL AppDomain::AddExceptionToCache(AssemblySpec* pSpec, Exception *ex)
6512 PRECONDITION(CheckPointer(pSpec));
6513 PRECONDITION(pSpec->CanUseWithBindingCache());
6514 INJECT_FAULT(COMPlusThrowOM(););
6518 if (ex->IsTransient())
6521 CrstHolder holder(&m_DomainCacheCrst);
6522 // !!! suppress exceptions
6523 return m_AssemblyCache.StoreException(pSpec, ex);
6526 void AppDomain::AddUnmanagedImageToCache(LPCWSTR libraryName, HMODULE hMod)
6533 PRECONDITION(CheckPointer(libraryName));
6534 INJECT_FAULT(COMPlusThrowOM(););
6540 spec.SetCodeBase(libraryName);
6541 m_UnmanagedCache.InsertEntry(&spec, hMod);
6547 HMODULE AppDomain::FindUnmanagedImageInCache(LPCWSTR libraryName)
6554 PRECONDITION(CheckPointer(libraryName,NULL_OK));
6555 POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
6556 INJECT_FAULT(COMPlusThrowOM(););
6559 if(libraryName == NULL) RETURN NULL;
6562 spec.SetCodeBase(libraryName);
6563 RETURN (HMODULE) m_UnmanagedCache.LookupEntry(&spec, 0);
6567 BOOL AppDomain::IsCached(AssemblySpec *pSpec)
6569 WRAPPER_NO_CONTRACT;
6571 // Check to see if this fits our rather loose idea of a reference to mscorlib.
6572 // If so, don't use fusion to bind it - do it ourselves.
6573 if (pSpec->IsMscorlib())
6576 return m_AssemblyCache.Contains(pSpec);
6579 void AppDomain::GetCacheAssemblyList(SetSHash<PTR_DomainAssembly>& assemblyList)
6581 CrstHolder holder(&m_DomainCacheCrst);
6582 m_AssemblyCache.GetAllAssemblies(assemblyList);
6585 PEAssembly* AppDomain::FindCachedFile(AssemblySpec* pSpec, BOOL fThrow /*=TRUE*/)
6601 // Check to see if this fits our rather loose idea of a reference to mscorlib.
6602 // If so, don't use fusion to bind it - do it ourselves.
6603 if (fThrow && pSpec->IsMscorlib())
6605 CONSISTENCY_CHECK(SystemDomain::System()->SystemAssembly() != NULL);
6606 PEAssembly *pFile = SystemDomain::System()->SystemFile();
6611 return m_AssemblyCache.LookupFile(pSpec, fThrow);
6615 BOOL AppDomain::PostBindResolveAssembly(AssemblySpec *pPrePolicySpec,
6616 AssemblySpec *pPostPolicySpec,
6617 HRESULT hrBindResult,
6618 AssemblySpec **ppFailedSpec)
6620 STATIC_CONTRACT_THROWS;
6621 STATIC_CONTRACT_GC_TRIGGERS;
6622 PRECONDITION(CheckPointer(pPrePolicySpec));
6623 PRECONDITION(CheckPointer(pPostPolicySpec));
6624 PRECONDITION(CheckPointer(ppFailedSpec));
6626 BOOL fFailure = TRUE;
6627 *ppFailedSpec = pPrePolicySpec;
6630 PEAssemblyHolder result;
6632 if ((EEFileLoadException::GetFileLoadKind(hrBindResult) == kFileNotFoundException) ||
6633 (hrBindResult == FUSION_E_REF_DEF_MISMATCH) ||
6634 (hrBindResult == FUSION_E_INVALID_NAME))
6636 result = TryResolveAssembly(*ppFailedSpec, FALSE /* fPreBind */);
6638 if (result != NULL && pPrePolicySpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
6642 // Given the post-policy resolve event construction of the CLR binder,
6643 // chained managed resolve events can race with each other, therefore we do allow
6644 // the adding of the result to fail. Checking for already chached specs
6645 // is not an option as it would introduce another race window.
6646 // The binder does a re-fetch of the
6647 // orignal binding spec and therefore will not cause inconsistency here.
6648 // For the purposes of the resolve event, failure to add to the cache still is a success.
6649 AddFileToCache(pPrePolicySpec, result, TRUE /* fAllowFailure */);
6650 if (*ppFailedSpec != pPrePolicySpec && pPostPolicySpec->CanUseWithBindingCache())
6652 AddFileToCache(pPostPolicySpec, result, TRUE /* fAllowFailure */ );
6660 //----------------------------------------------------------------------------------------
6661 // Helper class for hosted binder
6663 class PEAssemblyAsPrivAssemblyInfo : public IUnknownCommon<ICLRPrivAssemblyInfo>
6666 //------------------------------------------------------------------------------------
6669 PEAssemblyAsPrivAssemblyInfo(PEAssembly *pPEAssembly)
6671 LIMITED_METHOD_CONTRACT;
6672 STATIC_CONTRACT_THROWS;
6674 if (pPEAssembly == nullptr)
6675 ThrowHR(E_UNEXPECTED);
6677 pPEAssembly->AddRef();
6678 m_pPEAssembly = pPEAssembly;
6681 //------------------------------------------------------------------------------------
6682 // ICLRPrivAssemblyInfo methods
6684 //------------------------------------------------------------------------------------
6685 STDMETHOD(GetAssemblyName)(
6686 __in DWORD cchBuffer,
6687 __out_opt LPDWORD pcchBuffer,
6688 __out_ecount_part_opt(cchBuffer, *pcchBuffer) LPWSTR wzBuffer)
6700 if ((cchBuffer == 0) != (wzBuffer == nullptr))
6702 return E_INVALIDARG;
6705 LPCUTF8 szName = m_pPEAssembly->GetSimpleName();
6709 IfFailRet(FString::Utf8_Unicode_Length(szName, &bIsAscii, &cchName));
6711 if (cchBuffer < cchName + 1)
6713 if (pcchBuffer != nullptr)
6715 *pcchBuffer = cchName + 1;
6717 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6721 IfFailRet(FString::Utf8_Unicode(szName, bIsAscii, wzBuffer, cchName));
6722 if (pcchBuffer != nullptr)
6724 *pcchBuffer = cchName;
6730 //------------------------------------------------------------------------------------
6731 STDMETHOD(GetAssemblyVersion)(
6737 WRAPPER_NO_CONTRACT;
6738 return m_pPEAssembly->GetVersion(pMajor, pMinor, pBuild, pRevision);
6741 //------------------------------------------------------------------------------------
6742 STDMETHOD(GetAssemblyPublicKey)(
6747 STATIC_CONTRACT_LIMITED_METHOD;
6748 STATIC_CONTRACT_CAN_TAKE_LOCK;
6750 VALIDATE_PTR_RET(pcbBuffer);
6751 VALIDATE_CONDITION((pbBuffer == nullptr) == (cbBuffer == 0), return E_INVALIDARG);
6757 // Note: PEAssembly::GetPublicKey will return bogus data pointer when *pcbBuffer == 0
6758 LPCVOID pbKey = m_pPEAssembly->GetPublicKey(pcbBuffer);
6760 if (*pcbBuffer != 0)
6762 if (pbBuffer != nullptr && cbBuffer >= *pcbBuffer)
6764 memcpy(pbBuffer, pbKey, *pcbBuffer);
6769 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6774 hr = S_FALSE; // ==> No public key
6777 EX_CATCH_HRESULT(hr);
6783 ReleaseHolder<PEAssembly> m_pPEAssembly;
6786 //-----------------------------------------------------------------------------------------------------------------
6787 static HRESULT VerifyBindHelper(
6788 ICLRPrivAssembly *pPrivAssembly,
6789 IAssemblyName *pAssemblyName,
6790 PEAssembly *pPEAssembly)
6792 STATIC_CONTRACT_THROWS;
6793 STATIC_CONTRACT_GC_TRIGGERS;
6796 // Create an ICLRPrivAssemblyInfo to call to ICLRPrivAssembly::VerifyBind
6797 NewHolder<PEAssemblyAsPrivAssemblyInfo> pPrivAssemblyInfoImpl = new PEAssemblyAsPrivAssemblyInfo(pPEAssembly);
6798 ReleaseHolder<ICLRPrivAssemblyInfo> pPrivAssemblyInfo;
6799 IfFailRet(pPrivAssemblyInfoImpl->QueryInterface(__uuidof(ICLRPrivAssemblyInfo), (LPVOID *)&pPrivAssemblyInfo));
6800 pPrivAssemblyInfoImpl.SuppressRelease();
6802 // Call VerifyBind to give the host a chance to reject the bind based on assembly image contents.
6803 IfFailRet(pPrivAssembly->VerifyBind(pAssemblyName, pPrivAssembly, pPrivAssemblyInfo));
6808 //-----------------------------------------------------------------------------------------------------------------
6809 HRESULT AppDomain::BindAssemblySpecForHostedBinder(
6810 AssemblySpec * pSpec,
6811 IAssemblyName * pAssemblyName,
6812 ICLRPrivBinder * pBinder,
6813 PEAssembly ** ppAssembly)
6815 STANDARD_VM_CONTRACT;
6817 PRECONDITION(CheckPointer(pSpec));
6818 PRECONDITION(pSpec->GetAppDomain() == this);
6819 PRECONDITION(CheckPointer(ppAssembly));
6820 PRECONDITION(pSpec->GetCodeBase() == nullptr);
6825 // The Fusion binder can throw (to preserve compat, since it will actually perform an assembly
6826 // load as part of it's bind), so we need to be careful here to catch any FileNotFoundException
6827 // objects if fThrowIfNotFound is false.
6828 ReleaseHolder<ICLRPrivAssembly> pPrivAssembly;
6830 // We return HRESULTs here on failure instead of throwing as failures here are not necessarily indicative
6831 // of an actual application problem. Returning an error code is substantially faster than throwing, and
6832 // should be used when possible.
6833 IfFailRet(pBinder->BindAssemblyByName(pAssemblyName, &pPrivAssembly));
6835 IfFailRet(BindHostedPrivAssembly(nullptr, pPrivAssembly, pAssemblyName, ppAssembly));
6841 //-----------------------------------------------------------------------------------------------------------------
6843 AppDomain::BindHostedPrivAssembly(
6844 PEAssembly * pParentAssembly,
6845 ICLRPrivAssembly * pPrivAssembly,
6846 IAssemblyName * pAssemblyName,
6847 PEAssembly ** ppAssembly,
6848 BOOL fIsIntrospectionOnly) // = FALSE
6850 STANDARD_VM_CONTRACT;
6852 PRECONDITION(CheckPointer(pPrivAssembly));
6853 PRECONDITION(CheckPointer(ppAssembly));
6857 *ppAssembly = nullptr;
6859 // See if result has been previously loaded.
6861 DomainAssembly* pDomainAssembly = FindAssembly(pPrivAssembly);
6862 if (pDomainAssembly != nullptr)
6864 *ppAssembly = clr::SafeAddRef(pDomainAssembly->GetFile());
6868 if (*ppAssembly != nullptr)
6869 { // Already exists: ask the binder to verify and return the assembly.
6870 return VerifyBindHelper(pPrivAssembly, pAssemblyName, *ppAssembly);
6873 // Get the IL PEFile.
6874 PEImageHolder pPEImageIL;
6876 // Does not already exist, so get the resource for the assembly and load it.
6878 ReleaseHolder<ICLRPrivResource> pIResourceIL;
6880 IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_IL, &dwImageType, &pIResourceIL));
6881 _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_IL);
6883 pPEImageIL = PEImage::OpenImage(pIResourceIL, MDInternalImport_Default);
6886 // See if an NI is available.
6887 DWORD dwAvailableImages;
6888 IfFailRet(pPrivAssembly->GetAvailableImageTypes(&dwAvailableImages));
6889 _ASSERTE(dwAvailableImages & ASSEMBLY_IMAGE_TYPE_IL); // Just double checking that IL bit is always set.
6891 // Get the NI PEFile if available.
6892 PEImageHolder pPEImageNI;
6893 if (dwAvailableImages & ASSEMBLY_IMAGE_TYPE_NATIVE)
6896 ReleaseHolder<ICLRPrivResource> pIResourceNI;
6898 IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_NATIVE, &dwImageType, &pIResourceNI));
6899 _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_NATIVE || FAILED(hr));
6901 pPEImageNI = PEImage::OpenImage(pIResourceNI, MDInternalImport_TrustedNativeImage);
6903 _ASSERTE(pPEImageIL != nullptr);
6905 // Create a PEAssembly using the IL and NI images.
6906 PEAssemblyHolder pPEAssembly = PEAssembly::Open(pParentAssembly, pPEImageIL, pPEImageNI, pPrivAssembly, fIsIntrospectionOnly);
6909 // Ask the binder to verify.
6910 IfFailRet(VerifyBindHelper(pPrivAssembly, pAssemblyName, pPEAssembly));
6913 *ppAssembly = pPEAssembly.Extract();
6916 } // AppDomain::BindHostedPrivAssembly
6918 //---------------------------------------------------------------------------------------------------------------------
6919 PEAssembly * AppDomain::BindAssemblySpec(
6920 AssemblySpec * pSpec,
6921 BOOL fThrowOnFileNotFound,
6922 BOOL fRaisePrebindEvents,
6923 StackCrawlMark * pCallerStackMark,
6924 BOOL fUseHostBinderIfAvailable)
6926 STATIC_CONTRACT_THROWS;
6927 STATIC_CONTRACT_GC_TRIGGERS;
6928 PRECONDITION(CheckPointer(pSpec));
6929 PRECONDITION(pSpec->GetAppDomain() == this);
6930 PRECONDITION(this==::GetAppDomain());
6934 BOOL fForceReThrow = FALSE;
6936 #if defined(FEATURE_COMINTEROP)
6937 // Handle WinRT assemblies in the classic/hybrid scenario. If this is an AppX process,
6938 // then this case will be handled by the previous block as part of the full set of
6939 // available binding hosts.
6940 if (pSpec->IsContentType_WindowsRuntime())
6944 // Get the assembly display name.
6945 ReleaseHolder<IAssemblyName> pAssemblyName;
6947 IfFailThrow(pSpec->CreateFusionName(&pAssemblyName, TRUE, TRUE));
6950 PEAssemblyHolder pAssembly;
6954 hr = BindAssemblySpecForHostedBinder(pSpec, pAssemblyName, m_pWinRtBinder, &pAssembly);
6956 goto EndTry2; // Goto end of try block.
6959 // The combination of this conditional catch/ the following if statement which will throw reduces the count of exceptions
6960 // thrown in scenarios where the exception does not escape the method. We cannot get rid of the try/catch block, as
6961 // there are cases within some of the clrpriv binder's which throw.
6962 // Note: In theory, FileNotFound should always come here as HRESULT, never as exception.
6963 EX_CATCH_HRESULT_IF(hr,
6964 !fThrowOnFileNotFound && Assembly::FileNotFound(hr))
6966 if (FAILED(hr) && (fThrowOnFileNotFound || !Assembly::FileNotFound(hr)))
6968 if (Assembly::FileNotFound(hr))
6970 _ASSERTE(fThrowOnFileNotFound);
6971 // Uses defaultScope
6972 EEFileLoadException::Throw(pSpec, hr);
6975 // WinRT type bind failures
6976 _ASSERTE(pSpec->IsContentType_WindowsRuntime());
6977 if (hr == HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE)) // Returned by RoResolveNamespace when using 3rd party WinRT types in classic process
6979 if (fThrowOnFileNotFound)
6980 { // Throw NotSupportedException (with custom message) wrapped by TypeLoadException to give user type name for diagnostics
6981 // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6982 EEMessageException ex(kNotSupportedException, IDS_EE_WINRT_THIRDPARTY_NOTSUPPORTED);
6983 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
6986 else if ((hr == CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT) || // Returned e.g. for WinRT type name without namespace
6987 (hr == COR_E_PLATFORMNOTSUPPORTED)) // Using WinRT on pre-Win8 OS
6989 if (fThrowOnFileNotFound)
6990 { // Throw ArgumentException/PlatformNotSupportedException wrapped by TypeLoadException to give user type name for diagnostics
6991 // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6992 EEMessageException ex(hr);
6993 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
7001 _ASSERTE((FAILED(hr) && !fThrowOnFileNotFound) || pAssembly != nullptr);
7003 return pAssembly.Extract();
7006 #endif // FEATURE_COMINTEROP
7007 if (pSpec->HasUniqueIdentity())
7009 HRESULT hrBindResult = S_OK;
7010 PEAssemblyHolder result;
7015 if (!IsCached(pSpec))
7019 bool fAddFileToCache = false;
7021 BOOL fIsWellKnown = FALSE;
7023 // Use CoreClr's fusion alternative
7024 CoreBindResult bindResult;
7026 pSpec->Bind(this, fThrowOnFileNotFound, &bindResult, FALSE /* fNgenExplicitBind */, FALSE /* fExplicitBindToNativeImage */, pCallerStackMark);
7027 hrBindResult = bindResult.GetHRBindResult();
7029 if (bindResult.Found())
7031 if (SystemDomain::SystemFile() && bindResult.IsMscorlib())
7033 // Avoid rebinding to another copy of mscorlib
7034 result = SystemDomain::SystemFile();
7035 result.SuppressRelease(); // Didn't get a refcount
7039 // IsSystem on the PEFile should be false, even for mscorlib satellites
7040 result = PEAssembly::Open(&bindResult,
7041 FALSE, pSpec->IsIntrospectionOnly());
7043 fAddFileToCache = true;
7045 // Setup the reference to the binder, which performed the bind, into the AssemblySpec
7046 ICLRPrivBinder* pBinder = result->GetBindingContext();
7047 _ASSERTE(pBinder != NULL);
7048 pSpec->SetBindingContext(pBinder);
7052 if (fAddFileToCache)
7056 if (pSpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
7058 // Failure to add simply means someone else beat us to it. In that case
7059 // the FindCachedFile call below (after catch block) will update result
7060 // to the cached value.
7061 AddFileToCache(pSpec, result, TRUE /*fAllowFailure*/);
7064 else if (!fIsWellKnown)
7066 _ASSERTE(fThrowOnFileNotFound == FALSE);
7068 // Don't trigger the resolve event for the CoreLib satellite assembly. A misbehaving resolve event may
7069 // return an assembly that does not match, and this can cause recursive resource lookups during error
7070 // reporting. The CoreLib satellite assembly is loaded from relative locations based on the culture, see
7071 // AssemblySpec::Bind().
7072 if (!pSpec->IsMscorlibSatellite())
7074 // Trigger the resolve event also for non-throw situation.
7075 // However, this code path will behave as if the resolve handler has thrown,
7076 // that is, not trigger an MDA.
7078 AssemblySpec NewSpec(this);
7079 AssemblySpec *pFailedSpec = NULL;
7081 fForceReThrow = TRUE; // Managed resolve event handler can throw
7083 // Purposly ignore return value
7084 PostBindResolveAssembly(pSpec, &NewSpec, hrBindResult, &pFailedSpec);
7092 Exception *ex = GET_EXCEPTION();
7094 AssemblySpec NewSpec(this);
7095 AssemblySpec *pFailedSpec = NULL;
7097 // Let transient exceptions or managed resolve event handler exceptions propagate
7098 if (ex->IsTransient() || fForceReThrow)
7104 // This is not executed for SO exceptions so we need to disable the backout
7105 // stack validation to prevent false violations from being reported.
7106 DISABLE_BACKOUT_STACK_VALIDATION;
7108 BOOL fFailure = PostBindResolveAssembly(pSpec, &NewSpec, ex->GetHR(), &pFailedSpec);
7111 BOOL bFileNotFoundException =
7112 (EEFileLoadException::GetFileLoadKind(ex->GetHR()) == kFileNotFoundException);
7114 if (!bFileNotFoundException)
7116 fFailure = AddExceptionToCache(pFailedSpec, ex);
7117 } // else, fFailure stays TRUE
7118 // Effectively, fFailure == bFileNotFoundException || AddExceptionToCache(pFailedSpec, ex)
7120 // Only throw this exception if we are the first in the cache
7124 // If the BindingFailure MDA is enabled, trigger one for this failure
7125 // Note: TryResolveAssembly() can also throw if an AssemblyResolve event subscriber throws
7126 // and the MDA isn't sent in this case (or for transient failure cases)
7128 #ifdef MDA_SUPPORTED
7129 MdaBindingFailure* pProbe = MDA_GET_ASSISTANT(BindingFailure);
7132 // Transition to cooperative GC mode before using any OBJECTREFs.
7135 OBJECTREF exceptionObj = GET_THROWABLE();
7136 GCPROTECT_BEGIN(exceptionObj)
7138 pProbe->BindFailed(pFailedSpec, &exceptionObj);
7144 // In the same cases as for the MDA, store the failure information for DAC to read
7145 if (IsDebuggerAttached()) {
7146 FailedAssembly *pFailed = new FailedAssembly();
7147 pFailed->Initialize(pFailedSpec, ex);
7148 IfFailThrow(m_failedAssemblies.Append(pFailed));
7151 if (!bFileNotFoundException || fThrowOnFileNotFound)
7154 // V1.1 App-compatibility workaround. See VSW530166 if you want to whine about it.
7156 // In Everett, if we failed to download an assembly because of a broken network cable,
7157 // we returned a FileNotFoundException with a COR_E_FILENOTFOUND hr embedded inside
7158 // (which would be exposed when marshaled to native.)
7160 // In Whidbey, we now set the more appropriate INET_E_RESOURCE_NOT_FOUND hr. But
7161 // the online/offline switch code in VSTO for Everett hardcoded a check for
7162 // COR_E_FILENOTFOUND.
7164 // So now, to keep that code from breaking, we have to remap INET_E_RESOURCE_NOT_FOUND
7165 // back to COR_E_FILENOTFOUND. We're doing it here rather down in Fusion so as to affect
7166 // the least number of callers.
7168 if (ex->GetHR() == INET_E_RESOURCE_NOT_FOUND)
7170 EEFileLoadException::Throw(pFailedSpec, COR_E_FILENOTFOUND, ex);
7173 if (EEFileLoadException::CheckType(ex))
7175 if (pFailedSpec == pSpec)
7177 EX_RETHROW; //preserve the information
7181 StackSString exceptionDisplayName, failedSpecDisplayName;
7183 ((EEFileLoadException*)ex)->GetName(exceptionDisplayName);
7184 pFailedSpec->GetFileOrDisplayName(0, failedSpecDisplayName);
7186 if (exceptionDisplayName.CompareCaseInsensitive(failedSpecDisplayName) == 0)
7188 EX_RETHROW; // Throw the original exception. Otherwise, we'd throw an exception that contains the same message twice.
7193 EEFileLoadException::Throw(pFailedSpec, ex->GetHR(), ex);
7200 EX_END_CATCH(RethrowTerminalExceptions);
7202 // 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
7203 // thread to store our result. Note that we may throw from here, if there is a cached exception.
7204 // This will release the refcount of the current result holder (if any), and will replace
7205 // it with a non-addref'ed result
7206 if (pSpec->CanUseWithBindingCache() && (result== NULL || result->CanUseWithBindingCache()))
7208 result = FindCachedFile(pSpec);
7214 return result.Extract();
7218 // Unsupported content type
7219 if (fThrowOnFileNotFound)
7221 ThrowHR(COR_E_BADIMAGEFORMAT);
7225 } // AppDomain::BindAssemblySpec
7229 PEAssembly *AppDomain::TryResolveAssembly(AssemblySpec *pSpec, BOOL fPreBind)
7231 STATIC_CONTRACT_THROWS;
7232 STATIC_CONTRACT_GC_TRIGGERS;
7233 STATIC_CONTRACT_MODE_ANY;
7235 PEAssembly *result = NULL;
7239 result = pSpec->ResolveAssemblyFile(this, fPreBind);
7243 Exception *pEx = GET_EXCEPTION();
7245 if (!pEx->IsTransient())
7247 AddExceptionToCache(pSpec, pEx);
7248 if (!EEFileLoadException::CheckType(pEx))
7249 EEFileLoadException::Throw(pSpec, pEx->GetHR(), pEx);
7258 ULONG AppDomain::AddRef()
7260 LIMITED_METHOD_CONTRACT;
7261 return InterlockedIncrement(&m_cRef);
7264 ULONG AppDomain::Release()
7271 PRECONDITION(m_cRef > 0);
7275 ULONG cRef = InterlockedDecrement(&m_cRef);
7278 _ASSERTE (m_Stage == STAGE_CREATING || m_Stage == STAGE_CLOSED);
7281 TESTHOOKCALL(AppDomainDestroyed(adid.m_dwId));
7287 AppDomain* AppDomain::s_pAppDomainToRaiseUnloadEvent;
7288 BOOL AppDomain::s_fProcessUnloadDomainEvent = FALSE;
7290 #ifndef CROSSGEN_COMPILE
7292 void AppDomain::RaiseUnloadDomainEvent_Wrapper(LPVOID ptr)
7299 INJECT_FAULT(COMPlusThrowOM(););
7304 AppDomain* pDomain = (AppDomain *) ptr;
7305 pDomain->RaiseUnloadDomainEvent();
7308 void AppDomain::ProcessUnloadDomainEventOnFinalizeThread()
7317 Thread *pThread = GetThread();
7318 _ASSERTE (pThread && IsFinalizerThread());
7320 // if we are not unloading domain now, do not process the event
7321 if (SystemDomain::AppDomainBeingUnloaded() == NULL)
7323 s_pAppDomainToRaiseUnloadEvent->SetStage(STAGE_UNLOAD_REQUESTED);
7324 s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
7325 s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7326 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
7329 FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, TRUE);
7330 AppDomain::EnableADUnloadWorkerForFinalizer();
7331 pThread->SetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
7332 s_pAppDomainToRaiseUnloadEvent->RaiseUnloadDomainEvent();
7333 pThread->ResetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
7334 s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
7335 s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7336 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
7337 FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, FALSE);
7339 if (pThread->IsAbortRequested())
7341 pThread->UnmarkThreadForAbort(Thread::TAR_Thread);
7345 void AppDomain::RaiseUnloadDomainEvent()
7356 Thread *pThread = GetThread();
7357 if (this != pThread->GetDomain())
7359 pThread->DoADCallBack(this, AppDomain::RaiseUnloadDomainEvent_Wrapper, this,ADV_FINALIZER|ADV_COMPILATION);
7365 APPDOMAINREF Domain;
7368 ZeroMemory(&gc, sizeof(gc));
7370 GCPROTECT_BEGIN(gc);
7371 gc.Domain = (APPDOMAINREF) GetRawExposedObject();
7372 if (gc.Domain != NULL)
7374 gc.Delegate = gc.Domain->m_pDomainUnloadEventHandler;
7375 if (gc.Delegate != NULL)
7376 DistributeEvent(&gc.Delegate, (OBJECTREF *) &gc.Domain);
7382 void AppDomain::RaiseLoadingAssemblyEvent(DomainAssembly *pAssembly)
7388 PRECONDITION(this == GetAppDomain());
7395 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
7400 APPDOMAINREF AppDomainRef;
7403 ZeroMemory(&gc, sizeof(gc));
7405 if ((gc.AppDomainRef = (APPDOMAINREF) GetRawExposedObject()) != NULL) {
7406 if (gc.AppDomainRef->m_pAssemblyEventHandler != NULL)
7409 GCPROTECT_BEGIN(gc);
7411 gc.orThis = pAssembly->GetExposedAssemblyObject();
7413 MethodDescCallSite onAssemblyLoad(METHOD__APP_DOMAIN__ON_ASSEMBLY_LOAD, &gc.orThis);
7415 // GetExposedAssemblyObject may cause a gc, so call this before filling args[0]
7416 args[1] = ObjToArgSlot(gc.orThis);
7417 args[0] = ObjToArgSlot(gc.AppDomainRef);
7419 onAssemblyLoad.Call(args);
7428 EX_END_CATCH(SwallowAllExceptions);
7432 BOOL AppDomain::OnUnhandledException(OBJECTREF *pThrowable, BOOL isTerminating/*=TRUE*/)
7434 STATIC_CONTRACT_NOTHROW;
7435 STATIC_CONTRACT_GC_TRIGGERS;
7436 STATIC_CONTRACT_MODE_ANY;
7442 // The Everett behavior was to send the unhandled exception event only to the Default
7443 // AppDomain (since that's the only place that exceptions actually went unhandled).
7445 // During Whidbey development, we broadcast the event to all AppDomains in the process.
7447 // But the official shipping Whidbey behavior is that the unhandled exception event is
7448 // sent to the Default AppDomain and to whatever AppDomain the exception went unhandled
7449 // in. To achieve this, we declare the exception to be unhandled *BEFORE* we marshal
7450 // it back to the Default AppDomain at the base of the Finalizer, threadpool and managed
7453 // The rationale for sending the event to the Default AppDomain as well as the one the
7454 // exception went unhandled in is:
7456 // 1) This is compatible with the pre-Whidbey behavior, where only the Default AppDomain
7457 // received the notification.
7459 // 2) This is convenient for hosts, which don't want to bother injecting listeners into
7460 // every single AppDomain.
7462 AppDomain *pAppDomain = GetAppDomain();
7463 OBJECTREF orSender = 0;
7465 GCPROTECT_BEGIN(orSender);
7467 orSender = pAppDomain->GetRawExposedObject();
7469 retVal = pAppDomain->RaiseUnhandledExceptionEventNoThrow(&orSender, pThrowable, isTerminating);
7477 // Move outside of the AppDomain iteration, to avoid issues with the GC Frames being outside
7478 // the domain transition. This is a chronic issue that causes us to report roots for an AppDomain
7479 // after we have left it. This causes problems with AppDomain unloading that we only find
7480 // with stress coverage..
7481 void AppDomain::RaiseOneExitProcessEvent()
7493 APPDOMAINREF Domain;
7496 ZeroMemory(&gc, sizeof(gc));
7498 GCPROTECT_BEGIN(gc);
7499 gc.Domain = (APPDOMAINREF) SystemDomain::GetCurrentDomain()->GetRawExposedObject();
7500 if (gc.Domain != NULL)
7502 gc.Delegate = gc.Domain->m_pProcessExitEventHandler;
7503 if (gc.Delegate != NULL)
7504 DistributeEvent(&gc.Delegate, (OBJECTREF *) &gc.Domain);
7509 // Local wrapper used in AppDomain::RaiseExitProcessEvent,
7510 // introduced solely to avoid stack overflow because of _alloca in the loop.
7511 // It's just factored out body of the loop, but it has to be a member method of AppDomain,
7512 // because it calls private RaiseOneExitProcessEvent
7513 /*static*/ void AppDomain::RaiseOneExitProcessEvent_Wrapper(AppDomainIterator* pi)
7515 STATIC_CONTRACT_MODE_COOPERATIVE;
7516 STATIC_CONTRACT_THROWS;
7517 STATIC_CONTRACT_GC_TRIGGERS;
7519 ENTER_DOMAIN_PTR(pi->GetDomain(), ADV_ITERATOR)
7520 AppDomain::RaiseOneExitProcessEvent();
7521 END_DOMAIN_TRANSITION;
7524 static LONG s_ProcessedExitProcessEventCount = 0;
7526 LONG GetProcessedExitProcessEventCount()
7528 LIMITED_METHOD_CONTRACT;
7529 return s_ProcessedExitProcessEventCount;
7532 void AppDomain::RaiseExitProcessEvent()
7537 STATIC_CONTRACT_MODE_COOPERATIVE;
7538 STATIC_CONTRACT_THROWS;
7539 STATIC_CONTRACT_GC_TRIGGERS;
7541 // Only finalizer thread during shutdown can call this function.
7542 _ASSERTE ((g_fEEShutDown&ShutDown_Finalize1) && GetThread() == FinalizerThread::GetFinalizerThread());
7544 _ASSERTE (GetThread()->PreemptiveGCDisabled());
7546 _ASSERTE (GetThread()->GetDomain()->IsDefaultDomain());
7548 AppDomainIterator i(TRUE);
7551 RaiseOneExitProcessEvent_Wrapper(&i);
7552 FastInterlockIncrement(&s_ProcessedExitProcessEventCount);
7558 AppDomain::RaiseUnhandledExceptionEventNoThrow(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating)
7571 bRetVal = RaiseUnhandledExceptionEvent(pSender, pThrowable, isTerminating);
7576 EX_END_CATCH(SwallowAllExceptions) // Swallow any errors.
7582 AppDomain::HasUnhandledExceptionEventHandler()
7587 GC_NOTRIGGER; //essential
7591 if (!CanThreadEnter(GetThread()))
7593 if (GetRawExposedObject()==NULL)
7595 return (((APPDOMAINREF)GetRawExposedObject())->m_pUnhandledExceptionEventHandler!=NULL);
7599 AppDomain::RaiseUnhandledExceptionEvent(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating)
7606 INJECT_FAULT(COMPlusThrowOM(););
7610 if (!HasUnhandledExceptionEventHandler())
7613 BOOL result = FALSE;
7615 _ASSERTE(pThrowable != NULL && IsProtectedByGCFrame(pThrowable));
7616 _ASSERTE(pSender != NULL && IsProtectedByGCFrame(pSender));
7618 _ASSERTE(this == GetThread()->GetDomain());
7621 OBJECTREF orDelegate = NULL;
7623 GCPROTECT_BEGIN(orDelegate);
7625 APPDOMAINREF orAD = (APPDOMAINREF) GetAppDomain()->GetRawExposedObject();
7629 orDelegate = orAD->m_pUnhandledExceptionEventHandler;
7630 if (orDelegate != NULL)
7633 DistributeUnhandledExceptionReliably(&orDelegate, pSender, pThrowable, isTerminating);
7642 #endif // CROSSGEN_COMPILE
7644 // You must be in the correct context before calling this
7645 // routine. Therefore, it is only good for initializing the
7647 void AppDomain::InitializeDomainContext(BOOL allowRedirects,
7656 INJECT_FAULT(COMPlusThrowOM(););
7660 if (NingenEnabled())
7663 CreateFusionContext();
7668 #ifndef CROSSGEN_COMPILE
7670 STRINGREF pFilePath;
7673 PTRARRAYREF propertyNames;
7674 PTRARRAYREF propertyValues;
7676 ZeroMemory(&gc, sizeof(gc));
7678 GCPROTECT_BEGIN(gc);
7681 gc.pFilePath = StringObject::NewString(pwszPath);
7686 gc.pConfig = StringObject::NewString(pwszConfig);
7690 if ((gc.ref = GetExposedObject()) != NULL)
7692 MethodDescCallSite setupDomain(METHOD__APP_DOMAIN__SETUP_DOMAIN);
7696 ObjToArgSlot(gc.ref),
7697 BoolToArgSlot(allowRedirects),
7698 ObjToArgSlot(gc.pFilePath),
7699 ObjToArgSlot(gc.pConfig),
7700 ObjToArgSlot(gc.propertyNames),
7701 ObjToArgSlot(gc.propertyValues)
7703 setupDomain.Call(args);
7707 CacheStringsForDAC();
7708 #endif // CROSSGEN_COMPILE
7712 IUnknown *AppDomain::CreateFusionContext()
7714 CONTRACT(IUnknown *)
7719 POSTCONDITION(CheckPointer(RETVAL));
7720 INJECT_FAULT(COMPlusThrowOM(););
7724 if (!m_pFusionContext)
7726 ETWOnStartup (FusionAppCtx_V1, FusionAppCtxEnd_V1);
7727 CLRPrivBinderCoreCLR *pTPABinder = NULL;
7731 // Initialize the assembly binder for the default context loads for CoreCLR.
7732 IfFailThrow(CCoreCLRBinderHelper::DefaultBinderSetupContext(GetId().m_dwId, &pTPABinder));
7733 m_pFusionContext = reinterpret_cast<IUnknown *>(pTPABinder);
7735 // By default, initial binding context setup for CoreCLR is also the TPABinding context
7736 (m_pTPABinderContext = pTPABinder)->AddRef();
7740 RETURN m_pFusionContext;
7745 //---------------------------------------------------------------------------------------
7747 // AppDomain::IsDebuggerAttached - is a debugger attached to this process
7753 // TRUE if a debugger is attached to this process, FALSE otherwise.
7756 // This is identical to CORDebuggerAttached. This exists idependantly for legacy reasons - we used to
7757 // support attaching to individual AppDomains. This should probably go away eventually.
7760 BOOL AppDomain::IsDebuggerAttached()
7762 LIMITED_METHOD_CONTRACT;
7764 if (CORDebuggerAttached())
7774 #ifdef DEBUGGING_SUPPORTED
7776 // This is called from the debugger to request notification events from
7777 // Assemblies, Modules, Types in this appdomain.
7778 BOOL AppDomain::NotifyDebuggerLoad(int flags, BOOL attaching)
7780 WRAPPER_NO_CONTRACT;
7781 BOOL result = FALSE;
7783 if (!attaching && !IsDebuggerAttached())
7788 // Attach to our assemblies
7789 LOG((LF_CORDB, LL_INFO100, "AD::NDA: Iterating assemblies\n"));
7790 i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution));
7791 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7792 while (i.Next(pDomainAssembly.This()))
7794 result = (pDomainAssembly->NotifyDebuggerLoad(flags, attaching) ||
7801 void AppDomain::NotifyDebuggerUnload()
7803 WRAPPER_NO_CONTRACT;
7804 if (!IsDebuggerAttached())
7807 LOG((LF_CORDB, LL_INFO10, "AD::NDD domain [%d] %#08x %ls\n",
7808 GetId().m_dwId, this, GetFriendlyNameForLogging()));
7810 LOG((LF_CORDB, LL_INFO100, "AD::NDD: Interating domain bound assemblies\n"));
7811 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution));
7812 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7814 // Detach from our assemblies
7815 while (i.Next(pDomainAssembly.This()))
7817 LOG((LF_CORDB, LL_INFO100, "AD::NDD: Iterating assemblies\n"));
7818 pDomainAssembly->NotifyDebuggerUnload();
7821 #endif // DEBUGGING_SUPPORTED
7823 void AppDomain::SetSystemAssemblyLoadEventSent(BOOL fFlag)
7825 LIMITED_METHOD_CONTRACT;
7827 m_dwFlags |= LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
7829 m_dwFlags &= ~LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
7832 BOOL AppDomain::WasSystemAssemblyLoadEventSent(void)
7834 LIMITED_METHOD_CONTRACT;
7835 return ((m_dwFlags & LOAD_SYSTEM_ASSEMBLY_EVENT_SENT) == 0) ? FALSE : TRUE;
7838 #ifndef CROSSGEN_COMPILE
7839 // U->M thunks created in this domain and not associated with a delegate.
7840 UMEntryThunkCache *AppDomain::GetUMEntryThunkCache()
7847 INJECT_FAULT(COMPlusThrowOM(););
7851 if (!m_pUMEntryThunkCache)
7853 UMEntryThunkCache *pUMEntryThunkCache = new UMEntryThunkCache(this);
7855 if (FastInterlockCompareExchangePointer(&m_pUMEntryThunkCache, pUMEntryThunkCache, NULL) != NULL)
7857 // some thread swooped in and set the field
7858 delete pUMEntryThunkCache;
7861 _ASSERTE(m_pUMEntryThunkCache);
7862 return m_pUMEntryThunkCache;
7865 #ifdef FEATURE_COMINTEROP
7867 ComCallWrapperCache *AppDomain::GetComCallWrapperCache()
7874 INJECT_FAULT(COMPlusThrowOM(););
7878 if (! m_pComCallWrapperCache)
7880 BaseDomain::LockHolder lh(this);
7882 if (! m_pComCallWrapperCache)
7883 m_pComCallWrapperCache = ComCallWrapperCache::Create(this);
7885 _ASSERTE(m_pComCallWrapperCache);
7886 return m_pComCallWrapperCache;
7889 RCWRefCache *AppDomain::GetRCWRefCache()
7891 CONTRACT(RCWRefCache*)
7896 POSTCONDITION(CheckPointer(RETVAL));
7900 if (!m_pRCWRefCache) {
7901 NewHolder<RCWRefCache> pRCWRefCache = new RCWRefCache(this);
7902 if (FastInterlockCompareExchangePointer(&m_pRCWRefCache, (RCWRefCache *)pRCWRefCache, NULL) == NULL)
7904 pRCWRefCache.SuppressRelease();
7907 RETURN m_pRCWRefCache;
7910 RCWCache *AppDomain::CreateRCWCache()
7917 INJECT_FAULT(COMPlusThrowOM(););
7918 POSTCONDITION(CheckPointer(RETVAL));
7922 // Initialize the global RCW cleanup list here as well. This is so that it
7923 // it guaranteed to exist if any RCW's are created, but it is not created
7925 if (!g_pRCWCleanupList)
7927 SystemDomain::LockHolder lh;
7929 if (!g_pRCWCleanupList)
7930 g_pRCWCleanupList = new RCWCleanupList();
7932 _ASSERTE(g_pRCWCleanupList);
7935 BaseDomain::LockHolder lh(this);
7938 m_pRCWCache = new RCWCache(this);
7944 void AppDomain::ReleaseRCWs(LPVOID pCtxCookie)
7946 WRAPPER_NO_CONTRACT;
7948 m_pRCWCache->ReleaseWrappersWorker(pCtxCookie);
7950 RemoveWinRTFactoryObjects(pCtxCookie);
7953 void AppDomain::DetachRCWs()
7955 WRAPPER_NO_CONTRACT;
7957 m_pRCWCache->DetachWrappersWorker();
7960 #endif // FEATURE_COMINTEROP
7962 BOOL AppDomain::CanThreadEnter(Thread *pThread)
7964 WRAPPER_NO_CONTRACT;
7966 if (m_Stage < STAGE_EXITED)
7969 if (pThread == SystemDomain::System()->GetUnloadingThread())
7970 return m_Stage < STAGE_FINALIZING;
7971 if (pThread == FinalizerThread::GetFinalizerThread())
7972 return m_Stage < STAGE_FINALIZED;
7977 void AppDomain::AllowThreadEntrance(AppDomain * pApp)
7985 PRECONDITION(CheckPointer(pApp));
7989 if (pApp->GetUnloadRequestThread() == NULL)
7991 // This is asynchonous unload, either by a host, or by AppDomain.Unload from AD unload event.
7992 if (!pApp->IsUnloadingFromUnloadEvent())
7994 pApp->SetStage(STAGE_UNLOAD_REQUESTED);
7995 pApp->EnableADUnloadWorker(
7996 pApp->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
8001 SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
8003 #ifdef FEATURE_COMINTEROP
8004 if (pApp->m_pComCallWrapperCache)
8005 pApp->m_pComCallWrapperCache->ResetDomainIsUnloading();
8006 #endif // FEATURE_COMINTEROP
8008 pApp->SetStage(STAGE_OPEN);
8011 void AppDomain::RestrictThreadEntrance(AppDomain * pApp)
8016 DISABLED(GC_TRIGGERS);
8018 DISABLED(FORBID_FAULT);
8019 PRECONDITION(CheckPointer(pApp));
8023 #ifdef FEATURE_COMINTEROP
8024 // Set the flag on our CCW cache so stubs won't enter
8025 if (pApp->m_pComCallWrapperCache)
8026 pApp->m_pComCallWrapperCache->SetDomainIsUnloading();
8027 #endif // FEATURE_COMINTEROP
8029 SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
8030 // Release our ID so remoting and thread pool won't enter
8031 pApp->SetStage(STAGE_EXITED);
8034 void AppDomain::Exit(BOOL fRunFinalizers, BOOL fAsyncExit)
8044 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Exiting domain [%d] %#08x %ls\n",
8045 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8047 RestrictEnterHolder RestrictEnter(this);
8050 SystemDomain::LockHolder lh; // we don't want to close appdomain if other thread can be preparing to unload it
8051 SetStage(STAGE_EXITING); // Note that we're trying to exit
8054 // Raise the event indicating the domain is being unloaded.
8055 if (GetDefaultContext())
8057 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, this);
8059 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8060 //if (timeout == INFINITE)
8062 // timeout = 20000; // 20 seconds
8064 DWORD timeoutForFinalizer = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
8065 ULONGLONG curTime = CLRGetTickCount64();
8066 ULONGLONG endTime = 0;
8067 if (timeout != INFINITE)
8069 endTime = curTime + timeout;
8070 // We will try to kill AD unload event if it takes too long, and then we move on to the next registered caller.
8074 while (s_pAppDomainToRaiseUnloadEvent != NULL)
8076 FinalizerThread::FinalizerThreadWait(s_fProcessUnloadDomainEvent?timeout:timeoutForFinalizer);
8077 if (endTime != 0 && s_pAppDomainToRaiseUnloadEvent != NULL)
8079 if (CLRGetTickCount64() >= endTime)
8082 sThreadId.Printf(W("%x"), FinalizerThread::GetFinalizerThread()->GetThreadId());
8083 COMPlusThrow(kCannotUnloadAppDomainException,
8084 IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD,
8091 // Tell the tiered compilation manager to stop initiating any new work for background
8092 // jit optimization. Its possible the standard thread unwind mechanisms would pre-emptively
8093 // evacuate the jit threadpool worker threads from the domain on their own, but I see no reason
8094 // to take the risk of relying on them when we can easily augment with a cooperative
8095 // shutdown check. This notification only initiates the process of evacuating the threads
8096 // and then the UnwindThreads() call below is where blocking will occur to ensure the threads
8097 // have exited the domain.
8099 #ifdef FEATURE_TIERED_COMPILATION
8100 m_tieredCompilationManager.Shutdown(FALSE);
8104 // Set up blocks so no threads can enter except for the finalizer and the thread
8105 // doing the unload.
8108 RestrictThreadEntrance(this);
8110 // Cause existing threads to abort out of this domain. This should ensure all
8111 // normal threads are outside the domain, and we've already ensured that no new threads
8114 PerAppDomainTPCountList::AppDomainUnloadingHolder tpAdUnloadHolder(GetTPIndex());
8117 if (!NingenEnabled())
8122 TESTHOOKCALL(UnwoundThreads(GetId().m_dwId)) ;
8123 ProcessEventForHost(Event_DomainUnload, (PVOID)(UINT_PTR)GetId().m_dwId);
8125 RestrictEnter.SuppressRelease(); //after this point we don't guarantee appdomain consistency
8126 #ifdef PROFILING_SUPPORTED
8127 // Signal profile if present.
8129 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
8131 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) this);
8134 #endif // PROFILING_SUPPORTED
8135 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains--);
8136 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomainsUnloaded++);
8138 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is exited.\n",
8139 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8141 // Send ETW events for this domain's unload and potentially iterate through this
8142 // domain's modules & assemblies to send events for their unloads as well. This
8143 // needs to occur before STAGE_FINALIZED (to ensure everything is there), so we do
8144 // this before any finalization occurs at all.
8145 ETW::LoaderLog::DomainUnload(this);
8147 CodeVersionManager::OnAppDomainExit(this);
8150 // Spin running finalizers until we flush them all. We need to make multiple passes
8151 // in case the finalizers create more finalizable objects. This is important to clear
8152 // the finalizable objects as roots, as well as to actually execute the finalizers. This
8153 // will only finalize instances instances of types that aren't potentially agile becuase we can't
8154 // risk finalizing agile objects. So we will be left with instances of potentially agile types
8155 // in handles or statics.
8157 // <TODO>@todo: Need to ensure this will terminate in a reasonable amount of time. Eventually
8158 // we should probably start passing FALSE for fRunFinalizers. Also I'm not sure we
8159 // guarantee that FinalizerThreadWait will ever terminate in general.</TODO>
8162 SetStage(STAGE_FINALIZING);
8164 // Flush finalizers now.
8165 FinalizerThread::UnloadAppDomain(this, fRunFinalizers);
8167 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8168 ULONGLONG startTime = CLRGetTickCount64();
8169 ULONGLONG elapsedTime = 0;
8170 DWORD finalizerWait = 0;
8172 while (FinalizerThread::GetUnloadingAppDomain() != NULL)
8175 if (timeout != INFINITE)
8177 elapsedTime = CLRGetTickCount64() - startTime;
8179 if (timeout > elapsedTime)
8181 finalizerWait = timeout - static_cast<DWORD>(elapsedTime);
8183 FinalizerThread::FinalizerThreadWait(finalizerWait); //will set stage to finalized
8184 if (timeout != INFINITE && FinalizerThread::GetUnloadingAppDomain() != NULL)
8186 elapsedTime = CLRGetTickCount64() - startTime;
8187 if (timeout <= elapsedTime)
8190 // TODO: Consider escalation from RudeAppDomain
8196 tpAdUnloadHolder.SuppressRelease();
8197 PerAppDomainTPCountList::ResetAppDomainTPCounts(GetTPIndex());
8199 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is finalized.\n",
8200 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8203 AppDomainRefHolder This(this);
8204 AddRef(); // Hold a reference so CloseDomain won't delete us yet
8205 CloseDomain(); // Remove ourself from the list of app domains
8207 // This needs to be done prior to destroying the handle tables below.
8208 ReleaseDomainBoundInfo();
8211 // It should be impossible to run non-mscorlib code in this domain now.
8212 // Cleanup all of our roots except the handles. We do this to allow as many
8213 // finalizers as possible to run correctly. If we delete the handles, they
8216 if (!NingenEnabled())
8223 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is cleared.\n",
8224 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8226 if (fAsyncExit && fRunFinalizers)
8229 m_AssemblyCache.Clear();
8230 ClearFusionContext();
8232 if (!NingenEnabled())
8234 AddMemoryPressure();
8237 SystemDomain::System()->AddToDelayedUnloadList(this, fAsyncExit);
8238 SystemDomain::SetUnloadDomainCleared();
8239 if (m_dwId.m_dwId!=0)
8240 SystemDomain::ReleaseAppDomainId(m_dwId);
8241 #ifdef PROFILING_SUPPORTED
8242 // Always signal profile if present, even when failed.
8244 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
8246 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) this, S_OK);
8249 #endif // PROFILING_SUPPORTED
8253 void AppDomain::Close()
8262 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is collected.\n",
8263 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8266 #if CHECK_APP_DOMAIN_LEAKS
8267 if (g_pConfig->AppDomainLeaks())
8268 // at this point shouldn't have any non-agile objects in the heap because we finalized all the non-agile ones.
8269 SyncBlockCache::GetSyncBlockCache()->CheckForUnloadedInstances(GetIndex());
8270 #endif // CHECK_APP_DOMAIN_LEAKS
8273 RemoveMemoryPressure();
8275 _ASSERTE(m_cRef>0); //should be alive at this point otherwise iterator can revive us and crash
8277 SystemDomain::LockHolder lh; // Avoid races with AppDomainIterator
8278 SetStage(STAGE_CLOSED);
8281 // CONSIDER: move releasing remoting cache from managed code to here.
8285 void AppDomain::ResetUnloadRequestThread(ADID Id)
8291 PRECONDITION(!IsADUnloadHelperThread());
8296 AppDomainFromIDHolder ad(Id, TRUE);
8297 if(!ad.IsUnloaded() && ad->m_Stage < STAGE_UNLOAD_REQUESTED)
8299 Thread *pThread = ad->GetUnloadRequestThread();
8300 if(pThread==GetThread())
8302 ad->m_dwThreadsStillInAppDomain=(ULONG)-1;
8306 if (pThread->GetUnloadBoundaryFrame() && pThread->IsBeingAbortedForADUnload())
8308 pThread->UnmarkThreadForAbort(Thread::TAR_ADUnload);
8310 ad->GetUnloadRequestThread()->ResetUnloadBoundaryFrame();
8311 pThread->ResetBeginAbortedForADUnload();
8314 ad->SetUnloadRequestThread(NULL);
8320 int g_fADUnloadWorkerOK = -1;
8322 HRESULT AppDomain::UnloadById(ADID dwId, BOOL fSync,BOOL fExceptionsPassThrough)
8326 if(fExceptionsPassThrough) {THROWS;} else {NOTHROW;}
8328 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
8333 if (dwId==(ADID)DefaultADID)
8334 return COR_E_CANNOTUNLOADAPPDOMAIN;
8336 Thread *pThread = GetThread();
8338 // Finalizer thread can not wait until AD unload is done,
8339 // because AD unload is going to wait for Finalizer Thread.
8340 if (fSync && pThread == FinalizerThread::GetFinalizerThread() &&
8341 !pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent))
8342 return COR_E_CANNOTUNLOADAPPDOMAIN;
8345 // AD unload helper thread should have been created.
8346 _ASSERTE (g_fADUnloadWorkerOK == 1);
8348 _ASSERTE (!IsADUnloadHelperThread());
8350 BOOL fIsRaisingUnloadEvent = (pThread != NULL && pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent));
8352 if (fIsRaisingUnloadEvent)
8354 AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_GC);
8356 if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
8357 return COR_E_APPDOMAINUNLOADED;
8359 pApp->EnableADUnloadWorker();
8365 ADUnloadSinkHolder pSink;
8368 SystemDomain::LockHolder ulh;
8370 AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_ADLock);
8372 if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
8373 return COR_E_APPDOMAINUNLOADED;
8375 if (g_fADUnloadWorkerOK != 1)
8378 return E_UNEXPECTED;
8383 pApp->EnableADUnloadWorker();
8387 pSink = pApp->PrepareForWaitUnloadCompletion();
8389 pApp->EnableADUnloadWorker();
8391 // release the holders - we don't care anymore if the appdomain is gone
8394 #ifdef FEATURE_TESTHOOKS
8395 if (fExceptionsPassThrough)
8397 CONTRACT_VIOLATION(FaultViolation);
8398 return UnloadWaitNoCatch(dwId,pSink);
8402 return UnloadWait(dwId,pSink);
8405 HRESULT AppDomain::UnloadWait(ADID Id, ADUnloadSink * pSink)
8411 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
8418 // IF you ever try to change this to something not using events, please address the fact that
8419 // AppDomain::StopEEAndUnwindThreads relies on that events are used.
8421 pSink->WaitUnloadCompletion();
8423 EX_CATCH_HRESULT(hr);
8426 hr=pSink->GetUnloadResult();
8430 ResetUnloadRequestThread(Id);
8435 #ifdef FEATURE_TESTHOOKS
8436 HRESULT AppDomain::UnloadWaitNoCatch(ADID Id, ADUnloadSink * pSink)
8438 STATIC_CONTRACT_THROWS;
8439 STATIC_CONTRACT_MODE_ANY;
8441 Holder<ADID, DoNothing<ADID>, AppDomain::ResetUnloadRequestThread> resetUnloadHolder(Id);
8443 // IF you ever try to change this to something not using events, please address the fact that
8444 // AppDomain::StopEEAndUnwindThreads relies on that events are used.
8445 pSink->WaitUnloadCompletion();
8447 HRESULT hr = pSink->GetUnloadResult();
8450 resetUnloadHolder.SuppressRelease();
8456 void AppDomain::Unload(BOOL fForceUnload)
8463 INJECT_FAULT(COMPlusThrowOM(););
8467 #ifdef FEATURE_MULTICOREJIT
8469 // Avoid profiling file is partially written in ASP.net scenarios, call it earlier
8470 GetMulticoreJitManager().StopProfile(true);
8474 Thread *pThread = GetThread();
8477 if (! fForceUnload && !g_pConfig->AppDomainUnload())
8480 EPolicyAction action;
8481 EClrOperation operation;
8482 if (!IsRudeUnload())
8484 operation = OPR_AppDomainUnload;
8488 operation = OPR_AppDomainRudeUnload;
8490 action = GetEEPolicy()->GetDefaultAction(operation,NULL);
8491 GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
8495 case eUnloadAppDomain:
8497 case eRudeUnloadAppDomain:
8501 case eFastExitProcess:
8502 case eRudeExitProcess:
8503 case eDisableRuntime:
8504 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_ADUNLOAD);
8505 _ASSERTE (!"Should not get here");
8511 #if (defined(_DEBUG) || defined(BREAK_ON_UNLOAD) || defined(AD_LOG_MEMORY) || defined(AD_SNAPSHOT))
8512 static int unloadCount = 0;
8515 #ifdef AD_LOG_MEMORY
8518 static int logMemory = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADLogMemory);
8519 typedef void (__cdecl *LogItFcn) ( int );
8520 static LogItFcn pLogIt = NULL;
8522 if (logMemory && ! pLogIt)
8524 HMODULE hMod = CLRLoadLibrary(W("mpdh.dll"));
8527 pLogIt = (LogItFcn)GetProcAddress(hMod, "logIt");
8536 #endif // AD_LOG_MEMORY
8538 if (IsDefaultDomain() && !IsSingleAppDomain())
8539 COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_DEFAULT);
8541 _ASSERTE(CanUnload());
8543 if (pThread == FinalizerThread::GetFinalizerThread() || GetUnloadRequestThread() == FinalizerThread::GetFinalizerThread())
8544 COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_IN_FINALIZER);
8546 _ASSERTE(! SystemDomain::AppDomainBeingUnloaded());
8548 // should not be running in this AD because unload spawned thread in default domain
8549 if (!NingenEnabled())
8551 _ASSERTE(!pThread->IsRunningIn(this, NULL));
8555 #ifdef APPDOMAIN_STATE
8556 _ASSERTE_ALL_BUILDS("clr/src/VM/AppDomain.cpp", pThread->GetDomain()->IsDefaultDomain());
8559 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Unloading domain [%d] %#08x %ls\n", GetId().m_dwId, this, GetFriendlyName()));
8561 STRESS_LOG3 (LF_APPDOMAIN, LL_INFO100, "Unload domain [%d, %d] %p\n", GetId().m_dwId, GetIndex().m_dwIndex, this);
8563 UnloadHolder hold(this);
8565 SystemDomain::System()->SetUnloadRequestingThread(GetUnloadRequestThread());
8566 SystemDomain::System()->SetUnloadingThread(pThread);
8570 static int dumpSB = -1;
8573 dumpSB = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADDumpSB);
8577 LogSpewAlways("Starting unload %3.3d\n", unloadCount);
8578 DumpSyncBlockCache();
8582 BOOL bForceGC=m_bForceGCOnUnload;
8584 #ifdef AD_LOG_MEMORY
8587 #endif // AD_LOG_MEMORY
8590 static int takeSnapShot = -1;
8592 if (takeSnapShot == -1)
8593 takeSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeSnapShot);
8597 #endif // AD_SNAPSHOT
8603 static int cfgForceGC = -1;
8605 if (cfgForceGC == -1)
8606 cfgForceGC =!CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ADULazyMemoryRelease);
8608 bForceGC=bForceGC||cfgForceGC;
8609 AppDomainRefHolder This(this);
8612 // Do the actual unloading
8614 // We do not want other threads to abort the current one.
8615 ThreadPreventAsyncHolder preventAsync;
8616 Exit(TRUE, !bForceGC);
8620 GCHeapUtilities::GetGCHeap()->GarbageCollect();
8621 FinalizerThread::FinalizerThreadWait();
8622 SetStage(STAGE_COLLECTED);
8626 #ifdef AD_LOG_MEMORY
8630 pLogIt(unloadCount);
8632 #endif // AD_LOG_MEMORY
8638 sprintf_s(buffer, _countof(buffer), "vadump -p %d -o > vadump.%d", GetCurrentProcessId(), unloadCount);
8640 sprintf_s(buffer, _countof(buffer), "umdh -p:%d -d -i:1 -f:umdh.%d", GetCurrentProcessId(), unloadCount);
8642 int takeDHSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeDHSnapShot);
8645 sprintf_s(buffer, _countof(buffer), "dh -p %d -s -g -h -b -f dh.%d", GetCurrentProcessId(), unloadCount);
8649 #endif // AD_SNAPSHOT
8654 // do extra finalizer wait to remove any leftover sb entries
8655 FinalizerThread::FinalizerThreadWait();
8656 GCHeapUtilities::GetGCHeap()->GarbageCollect();
8657 FinalizerThread::FinalizerThreadWait();
8658 LogSpewAlways("Done unload %3.3d\n", unloadCount);
8659 DumpSyncBlockCache();
8662 swprintf_s(buffer, NumItems(buffer), W("DumpSB.%d"), unloadCount);
8663 _ASSERTE(WszMoveFileEx(W("COMPLUS.LOG"), buffer, MOVEFILE_REPLACE_EXISTING));
8664 // this will open a new file
8670 void AppDomain::ExceptionUnwind(Frame *pFrame)
8674 DISABLED(GC_TRIGGERS); // EEResourceException
8675 DISABLED(THROWS); // EEResourceException
8680 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind for %8.8x\n", pFrame));
8682 printf("%x AppDomain::ExceptionUnwind for %8.8p\n", GetThread()->GetThreadId(), pFrame);
8684 Thread *pThread = GetThread();
8687 if (! pThread->ShouldChangeAbortToUnload(pFrame))
8689 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: not first transition or abort\n"));
8693 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: changing to unload\n"));
8696 OBJECTREF throwable = NULL;
8697 EEResourceException e(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded_ThreadUnwound"));
8698 throwable = e.GetThrowable();
8700 // reset the exception to an AppDomainUnloadedException
8701 if (throwable != NULL)
8703 GetThread()->SafeSetThrowables(throwable);
8707 BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread)
8718 Thread *pThread = NULL;
8719 DWORD nThreadsNeedMoreWork=0;
8720 if (retryCount != (unsigned int)-1 && retryCount < g_pConfig->AppDomainUnloadRetryCount())
8722 Thread *pCurThread = GetThread();
8723 if (pCurThread->CatchAtSafePoint())
8724 pCurThread->PulseGCMode();
8727 // We know which thread is not in the domain now. We just need to
8728 // work on those threads. We do not need to suspend the runtime.
8729 ThreadStoreLockHolder tsl;
8731 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8733 if (pThread == pCurThread)
8738 if (pThread == FinalizerThread::GetFinalizerThread())
8743 if (pThread->GetUnloadBoundaryFrame() == NULL)
8748 // A thread may have UnloadBoundaryFrame set if
8749 // 1. Being unloaded by AD unload helper thread
8750 // 2. Escalation from OOM or SO triggers AD unload
8751 // Here we only need to work on threads that are in the domain. If we work on other threads,
8752 // those threads may be stucked in a finally, and we will not be able to escalate for them,
8753 // therefore AD unload is blocked.
8754 if (pThread->IsBeingAbortedForADUnload() ||
8755 pThread == SystemDomain::System()->GetUnloadRequestingThread())
8757 nThreadsNeedMoreWork++;
8760 if (!(IsRudeUnload() ||
8761 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())))
8766 if ((pThread == SystemDomain::System()->GetUnloadRequestingThread()) && *pFMarkUnloadRequestThread)
8768 // Mark thread for abortion only once; later on interrupt only
8769 *pFMarkUnloadRequestThread = FALSE;
8770 pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
8774 if (pThread->m_State & Thread::TS_Interruptible)
8776 pThread->UserInterrupt(Thread::TI_Abort);
8780 if (pThread->PreemptiveGCDisabledOther())
8782 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
8783 Thread::SuspendThreadResult str = pThread->SuspendThread();
8784 if (str == Thread::STR_Success)
8786 if (pThread->PreemptiveGCDisabledOther() &&
8787 (!pThread->IsAbortInitiated() || pThread->IsRudeAbort()))
8789 pThread->HandleJITCaseForAbort();
8791 pThread->ResumeThread();
8796 } // ThreadStoreLockHolder
8798 m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
8799 return !nThreadsNeedMoreWork;
8802 // For now piggyback on the GC's suspend EE mechanism
8803 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
8805 // <TODO>@todo: what to do with any threads that didn't stop?</TODO>
8806 _ASSERTE(ThreadStore::s_pThreadStore->DbgBackgroundThreadCount() > 0);
8809 int totalADCount = 0;
8810 int finalizerADCount = 0;
8813 RuntimeExceptionKind reKind = kLastException;
8815 SmallStackSString ssThreadId;
8817 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8819 // we already checked that we're not running in the unload domain
8820 if (pThread == GetThread())
8826 void PrintStackTraceWithADToLog(Thread *pThread);
8827 if (LoggingOn(LF_APPDOMAIN, LL_INFO100)) {
8828 LOG((LF_APPDOMAIN, LL_INFO100, "\nStackTrace for %x\n", pThread->GetThreadId()));
8829 PrintStackTraceWithADToLog(pThread);
8833 Frame *pFrame = pThread->GetFirstTransitionInto(this, &count);
8835 _ASSERTE(count == 0);
8836 if (pThread->IsBeingAbortedForADUnload())
8838 pThread->ResetBeginAbortedForADUnload();
8843 if (pThread != FinalizerThread::GetFinalizerThread())
8845 totalADCount += count;
8846 nThreadsNeedMoreWork++;
8847 pThread->SetUnloadBoundaryFrame(pFrame);
8851 finalizerADCount = count;
8854 // don't setup the exception info for the unloading thread unless it's the last one in
8855 if (retryCount != ((unsigned int) -1) && retryCount > g_pConfig->AppDomainUnloadRetryCount() && reKind == kLastException &&
8856 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft()))
8858 #ifdef AD_BREAK_ON_CANNOT_UNLOAD
8859 static int breakOnCannotUnload = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADBreakOnCannotUnload);
8860 if (breakOnCannotUnload)
8861 _ASSERTE(!"Cannot unload AD");
8862 #endif // AD_BREAK_ON_CANNOT_UNLOAD
8863 reKind = kCannotUnloadAppDomainException;
8864 resId = IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD;
8865 ssThreadId.Printf(W("%x"), pThread->GetThreadId());
8866 STRESS_LOG2(LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads cannot stop thread %x with %d transitions\n", pThread->GetThreadId(), count);
8867 // don't break out of this early or the assert totalADCount == (int)m_dwThreadEnterCount below will fire
8868 // it's better to chew a little extra time here and make sure our counts are consistent
8870 // only abort the thread requesting the unload if it's the last one in, that way it will get
8871 // notification that the unload failed for some other thread not being aborted. And don't abort
8872 // the finalizer thread - let it finish it's work as it's allowed to be in there. If it won't finish,
8873 // then we will eventually get a CannotUnloadException on it.
8875 if (pThread != FinalizerThread::GetFinalizerThread() &&
8876 // If the domain is rudely unloaded, we will unwind the requesting thread out
8877 // Rude unload is going to succeed, or escalated to disable runtime or higher.
8879 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())
8884 STRESS_LOG2(LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count);
8885 LOG((LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count));
8887 printf("AppDomain::UnwindThreads %x stopping %x with first frame %8.8p\n", GetThread()->GetThreadId(), pThread->GetThreadId(), pFrame);
8889 if (pThread == SystemDomain::System()->GetUnloadRequestingThread())
8891 // Mark thread for abortion only once; later on interrupt only
8892 *pFMarkUnloadRequestThread = FALSE;
8894 pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
8896 TESTHOOKCALL(UnwindingThreads(GetId().m_dwId)) ;
8898 _ASSERTE(totalADCount + finalizerADCount == (int)m_dwThreadEnterCount);
8900 //@TODO: This is intended to catch a stress bug. Remove when no longer needed.
8901 if (totalADCount + finalizerADCount != (int)m_dwThreadEnterCount)
8902 FreeBuildDebugBreak();
8904 // if our count did get messed up, set it to whatever count we actually found in the domain to avoid looping
8905 // or other problems related to incorrect count. This is very much a bug if this happens - a thread should always
8906 // exit the domain gracefully.
8907 // m_dwThreadEnterCount = totalADCount;
8909 if (reKind != kLastException)
8912 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8914 if (pThread->IsBeingAbortedForADUnload())
8916 pThread->ResetBeginAbortedForADUnload();
8921 // CommonTripThread will handle the abort for any threads that we've marked
8922 ThreadSuspend::RestartEE(FALSE, TRUE);
8923 if (reKind != kLastException)
8924 COMPlusThrow(reKind, resId, ssThreadId.GetUnicode());
8926 _ASSERTE((totalADCount==0 && nThreadsNeedMoreWork==0) ||(totalADCount!=0 && nThreadsNeedMoreWork!=0));
8928 m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
8929 return (totalADCount == 0);
8932 void AppDomain::UnwindThreads()
8934 // This function should guarantee appdomain
8935 // consistency even if it fails. Everything that is going
8936 // to make the appdomain impossible to reenter
8937 // should be factored out
8939 // <TODO>@todo: need real synchronization here!!!</TODO>
8948 int retryCount = -1;
8949 m_dwThreadsStillInAppDomain=(ULONG)-1;
8950 ULONGLONG startTime = CLRGetTickCount64();
8952 if (GetEEPolicy()->GetDefaultAction(OPR_AppDomainUnload, NULL) == eRudeUnloadAppDomain &&
8955 GetEEPolicy()->NotifyHostOnDefaultAction(OPR_AppDomainUnload, eRudeUnloadAppDomain);
8959 // Force threads to go through slow path during AD unload.
8960 TSSuspendHolder shTrap;
8962 BOOL fCurrentUnloadMode = IsRudeUnload();
8963 BOOL fMarkUnloadRequestThread = TRUE;
8965 // now wait for all the threads running in our AD to get out
8968 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8969 EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, NULL);
8970 if (timeout != INFINITE && action > eUnloadAppDomain) {
8971 // Escalation policy specified.
8972 ULONGLONG curTime = CLRGetTickCount64();
8973 ULONGLONG elapseTime = curTime - startTime;
8974 if (elapseTime > timeout)
8979 case eRudeUnloadAppDomain:
8980 GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
8982 STRESS_LOG1(LF_APPDOMAIN, LL_INFO100,"Escalating to RADU, adid=%d",GetId().m_dwId);
8985 case eFastExitProcess:
8986 case eRudeExitProcess:
8987 case eDisableRuntime:
8988 GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
8989 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
8990 _ASSERTE (!"Should not reach here");
8998 if (LoggingOn(LF_APPDOMAIN, LL_INFO100))
8999 DumpADThreadTrack();
9001 BOOL fNextUnloadMode = IsRudeUnload();
9002 if (fCurrentUnloadMode != fNextUnloadMode)
9004 // We have changed from normal unload to rude unload. We need to mark the thread
9005 // with RudeAbort, but we can only do this safely if the runtime is suspended.
9006 fCurrentUnloadMode = fNextUnloadMode;
9009 if (StopEEAndUnwindThreads(retryCount, &fMarkUnloadRequestThread))
9011 if (timeout != INFINITE)
9013 // Turn off the timeout used by AD.
9018 // GCStress takes a long time to unwind, due to expensive creation of
9019 // a threadabort exception.
9020 if (!GCStress<cfg_any>::IsEnabled())
9022 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount));
9024 printf("AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount);
9028 if (m_dwThreadEnterCount != 0)
9031 GetThread()->UserSleep(20);
9033 GetThread()->UserSleep(10);
9040 void AppDomain::ClearGCHandles()
9050 SetStage(STAGE_HANDLETABLE_NOACCESS);
9052 GCHeapUtilities::GetGCHeap()->WaitUntilConcurrentGCComplete();
9054 // Keep async pin handles alive by moving them to default domain
9055 HandleAsyncPinHandles();
9057 // Remove our handle store as a source of GC roots
9058 m_handleStore->Uproot();
9061 // When an AD is unloaded, we will release all objects in this AD.
9062 // If a future asynchronous operation, like io completion port function,
9063 // we need to keep the memory space fixed so that the gc heap is not corrupted.
9064 void AppDomain::HandleAsyncPinHandles()
9074 IGCHandleStore *pBucket = m_handleStore;
9076 // IO completion port picks IO job using FIFO. Here is how we know which AsyncPinHandle can be freed.
9077 // 1. We mark all non-pending AsyncPinHandle with READYTOCLEAN.
9078 // 2. We queue a dump Overlapped to the IO completion as a marker.
9079 // 3. When the Overlapped is picked up by completion port, we wait until all previous IO jobs are processed.
9080 // 4. Then we can delete all AsyncPinHandle marked with READYTOCLEAN.
9081 IGCHandleStore *pBucketInDefault = SystemDomain::System()->DefaultDomain()->m_handleStore;
9083 pBucket->RelocateAsyncPinnedHandles(pBucketInDefault);
9085 OverlappedDataObject::RequestCleanup();
9088 void AppDomain::ClearGCRoots()
9098 Thread *pThread = NULL;
9099 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
9101 // Tell the JIT managers to delete any entries in their structures. All the cooperative mode threads are stopped at
9102 // this point, so only need to synchronize the preemptive mode threads.
9103 ExecutionManager::Unload(GetLoaderAllocator());
9105 while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL)
9107 // Delete the thread local static store
9108 pThread->DeleteThreadStaticData(this);
9110 // <TODO>@TODO: A pre-allocated AppDomainUnloaded exception might be better.</TODO>
9111 if (m_handleStore->ContainsHandle(pThread->m_LastThrownObjectHandle))
9113 // Never delete a handle to a preallocated exception object.
9114 if (!CLRException::IsPreallocatedExceptionHandle(pThread->m_LastThrownObjectHandle))
9116 DestroyHandle(pThread->m_LastThrownObjectHandle);
9119 pThread->m_LastThrownObjectHandle = NULL;
9122 // Clear out the exceptions objects held by a thread.
9123 pThread->GetExceptionState()->ClearThrowablesForUnload(m_handleStore);
9126 //delete them while we still have the runtime suspended
9127 // This must be deleted before the loader heaps are deleted.
9128 if (m_pMarshalingData != NULL)
9130 delete m_pMarshalingData;
9131 m_pMarshalingData = NULL;
9134 if (m_pLargeHeapHandleTable != NULL)
9136 delete m_pLargeHeapHandleTable;
9137 m_pLargeHeapHandleTable = NULL;
9140 ThreadSuspend::RestartEE(FALSE, TRUE);
9145 void AppDomain::TrackADThreadEnter(Thread *pThread, Frame *pFrame)
9152 PRECONDITION(CheckPointer(pThread));
9153 PRECONDITION(pFrame != (Frame*)(size_t) INVALID_POINTER_CD);
9157 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9159 if (m_pThreadTrackInfoList == NULL)
9160 m_pThreadTrackInfoList = new (nothrow) ThreadTrackInfoList;
9161 // If we don't assert here, we will AV in the for loop below
9162 _ASSERTE(m_pThreadTrackInfoList);
9164 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9166 ThreadTrackInfo *pTrack = NULL;
9168 for (i=0; i < pTrackList->Count(); i++) {
9169 if ((*(pTrackList->Get(i)))->pThread == pThread) {
9170 pTrack = *(pTrackList->Get(i));
9175 pTrack = new (nothrow) ThreadTrackInfo;
9176 // If we don't assert here, we will AV in the for loop below.
9178 pTrack->pThread = pThread;
9179 ThreadTrackInfo **pSlot = pTrackList->Append();
9183 InterlockedIncrement((LONG*)&m_dwThreadEnterCount);
9187 pSlot = pTrack->frameStack.Insert(0);
9191 for (i=0; i < pTrackList->Count(); i++)
9192 totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
9193 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9195 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9199 void AppDomain::TrackADThreadExit(Thread *pThread, Frame *pFrame)
9203 if (GetThread()) {MODE_COOPERATIVE;}
9209 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9211 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9212 _ASSERTE(pTrackList);
9213 ThreadTrackInfo *pTrack = NULL;
9215 for (i=0; i < pTrackList->Count(); i++)
9217 if ((*(pTrackList->Get(i)))->pThread == pThread)
9219 pTrack = *(pTrackList->Get(i));
9224 _ASSERTE(*(pTrack->frameStack.Get(0)) == pFrame);
9225 pTrack->frameStack.Delete(0);
9226 InterlockedDecrement((LONG*)&m_dwThreadEnterCount);
9229 for (i=0; i < pTrackList->Count(); i++)
9230 totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
9231 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9233 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9236 void AppDomain::DumpADThreadTrack()
9246 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9248 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9253 LOG((LF_APPDOMAIN, LL_INFO10000, "\nThread dump of %d threads for [%d] %#08x %S\n",
9254 m_dwThreadEnterCount, GetId().m_dwId, this, GetFriendlyNameForLogging()));
9256 for (int i=0; i < pTrackList->Count(); i++)
9258 ThreadTrackInfo *pTrack = *(pTrackList->Get(i));
9259 if (pTrack->frameStack.Count()==0)
9261 LOG((LF_APPDOMAIN, LL_INFO100, " ADEnterCount for %x is %d\n", pTrack->pThread->GetThreadId(), pTrack->frameStack.Count()));
9262 totThreads += pTrack->frameStack.Count();
9263 for (int j=0; j < pTrack->frameStack.Count(); j++)
9264 LOG((LF_APPDOMAIN, LL_INFO100, " frame %8.8x\n", *(pTrack->frameStack.Get(j))));
9266 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9269 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9274 #endif // CROSSGEN_COMPILE
9276 void *SharedDomain::operator new(size_t size, void *pInPlace)
9278 LIMITED_METHOD_CONTRACT;
9282 void SharedDomain::operator delete(void *pMem)
9284 LIMITED_METHOD_CONTRACT;
9285 // Do nothing - new() was in-place
9289 void SharedDomain::Attach()
9296 INJECT_FAULT(COMPlusThrowOM(););
9300 // Create the global SharedDomain and initialize it.
9301 m_pSharedDomain = new (&g_pSharedDomainMemory[0]) SharedDomain();
9302 SystemDomain::GetGlobalLoaderAllocator()->m_pDomain = m_pSharedDomain;
9303 // This cannot fail since g_pSharedDomainMemory is a static array.
9304 CONSISTENCY_CHECK(CheckPointer(m_pSharedDomain));
9306 LOG((LF_CLASSLOADER,
9308 "Created shared domain at %p\n",
9311 // We need to initialize the memory pools etc. for the system domain.
9312 m_pSharedDomain->Init(); // Setup the memory heaps
9314 // allocate a Virtual Call Stub Manager for the shared domain
9315 m_pSharedDomain->InitVSD();
9318 #ifndef CROSSGEN_COMPILE
9319 void SharedDomain::Detach()
9321 if (m_pSharedDomain)
9323 m_pSharedDomain->Terminate();
9324 delete m_pSharedDomain;
9325 m_pSharedDomain = NULL;
9328 #endif // CROSSGEN_COMPILE
9330 #endif // !DACCESS_COMPILE
9332 SharedDomain *SharedDomain::GetDomain()
9334 LIMITED_METHOD_DAC_CONTRACT;
9336 return m_pSharedDomain;
9339 #ifndef DACCESS_COMPILE
9341 #define INITIAL_ASSEMBLY_MAP_SIZE 17
9342 void SharedDomain::Init()
9349 INJECT_FAULT(COMPlusThrowOM(););
9355 #ifdef FEATURE_LOADER_OPTIMIZATION
9356 m_FileCreateLock.Init(CrstSharedAssemblyCreate, CRST_DEFAULT,TRUE);
9358 LockOwner lock = { &m_DomainCrst, IsOwnerOfCrst };
9359 m_assemblyMap.Init(INITIAL_ASSEMBLY_MAP_SIZE, CompareSharedAssembly, TRUE, &lock);
9360 #endif // FEATURE_LOADER_OPTIMIZATION
9362 ETW::LoaderLog::DomainLoad(this);
9365 #ifndef CROSSGEN_COMPILE
9366 void SharedDomain::Terminate()
9368 // make sure we delete the StringLiteralMap before unloading
9369 // the asemblies since the string literal map entries can
9370 // point to metadata string literals.
9371 GetLoaderAllocator()->CleanupStringLiteralMap();
9373 #ifdef FEATURE_LOADER_OPTIMIZATION
9374 PtrHashMap::PtrIterator i = m_assemblyMap.begin();
9378 Assembly *pAssembly = (Assembly*) i.GetValue();
9383 ListLockEntry* pElement;
9384 pElement = m_FileCreateLock.Pop(TRUE);
9387 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
9388 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
9391 pElement = (FileLoadLock*) m_FileCreateLock.Pop(TRUE);
9393 m_FileCreateLock.Destroy();
9394 #endif // FEATURE_LOADER_OPTIMIZATION
9395 BaseDomain::Terminate();
9397 #endif // CROSSGEN_COMPILE
9401 #ifdef FEATURE_LOADER_OPTIMIZATION
9403 BOOL SharedDomain::CompareSharedAssembly(UPTR u1, UPTR u2)
9413 // This is the input to the lookup
9414 SharedAssemblyLocator *pLocator = (SharedAssemblyLocator *) (u1<<1);
9416 // This is the value stored in the table
9417 Assembly *pAssembly = (Assembly *) u2;
9418 if (pLocator->GetType()==SharedAssemblyLocator::DOMAINASSEMBLY)
9420 if (!pAssembly->GetManifestFile()->Equals(pLocator->GetDomainAssembly()->GetFile()))
9423 return pAssembly->CanBeShared(pLocator->GetDomainAssembly());
9426 if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLY)
9427 return pAssembly->GetManifestFile()->Equals(pLocator->GetPEAssembly());
9429 if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLYEXACT)
9430 return pAssembly->GetManifestFile() == pLocator->GetPEAssembly();
9431 _ASSERTE(!"Unexpected type of assembly locator");
9435 DWORD SharedAssemblyLocator::Hash()
9442 INJECT_FAULT(COMPlusThrowOM(););
9445 if (m_type==DOMAINASSEMBLY)
9446 return GetDomainAssembly()->HashIdentity();
9447 if (m_type==PEASSEMBLY||m_type==PEASSEMBLYEXACT)
9448 return GetPEAssembly()->HashIdentity();
9449 _ASSERTE(!"Unexpected type of assembly locator");
9453 Assembly * SharedDomain::FindShareableAssembly(SharedAssemblyLocator * pLocator)
9460 INJECT_FAULT(COMPlusThrowOM(););
9464 Assembly * match= (Assembly *) m_assemblyMap.LookupValue(pLocator->Hash(), pLocator);
9465 if (match != (Assembly *) INVALIDENTRY)
9471 SIZE_T SharedDomain::GetShareableAssemblyCount()
9473 LIMITED_METHOD_CONTRACT;
9475 return m_assemblyMap.GetCount();
9478 void SharedDomain::AddShareableAssembly(Assembly * pAssembly)
9485 INJECT_FAULT(COMPlusThrowOM(););
9489 // We have a lock on the file. There should be no races to add the same assembly.
9492 LockHolder holder(this);
9496 pAssembly->SetIsTenured();
9497 m_assemblyMap.InsertValue(pAssembly->HashIdentity(), pAssembly);
9501 // There was an error adding the assembly to the assembly hash (probably an OOM),
9502 // so we need to unset the tenured bit so that correct cleanup can happen.
9503 pAssembly->UnsetIsTenured();
9508 LOG((LF_CODESHARING,
9510 "Successfully added shareable assembly \"%s\".\n",
9511 pAssembly->GetManifestFile()->GetSimpleName()));
9514 #endif // FEATURE_LOADER_OPTIMIZATION
9515 #endif // !DACCESS_COMPILE
9517 DWORD DomainLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex /*=(DWORD)-1*/)
9525 { // SO tolerance exception for debug-only assertion.
9526 CONTRACT_VIOLATION(SOToleranceViolation);
9527 CONSISTENCY_CHECK(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9530 if (pMT->IsDynamicStatics())
9532 _ASSERTE(!pMT->ContainsGenericVariables());
9533 DWORD dynamicClassID = pMT->GetModuleDynamicEntryID();
9534 if(m_aDynamicEntries <= dynamicClassID)
9536 return (m_pDynamicClassTable[dynamicClassID].m_dwFlags);
9540 if (iClassIndex == (DWORD)-1)
9541 iClassIndex = pMT->GetClassIndex();
9542 return GetPrecomputedStaticsClassData()[iClassIndex];
9546 #ifndef DACCESS_COMPILE
9548 void DomainLocalModule::SetClassInitialized(MethodTable* pMT)
9558 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9560 _ASSERTE(!IsClassInitialized(pMT));
9561 _ASSERTE(!IsClassInitError(pMT));
9563 SetClassFlags(pMT, ClassInitFlags::INITIALIZED_FLAG);
9566 void DomainLocalModule::SetClassInitError(MethodTable* pMT)
9568 WRAPPER_NO_CONTRACT;
9570 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9572 SetClassFlags(pMT, ClassInitFlags::ERROR_FLAG);
9575 void DomainLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags)
9580 PRECONDITION(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9581 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9582 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9585 if (pMT->IsDynamicStatics())
9587 _ASSERTE(!pMT->ContainsGenericVariables());
9588 DWORD dwID = pMT->GetModuleDynamicEntryID();
9589 EnsureDynamicClassIndex(dwID);
9590 m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags;
9594 GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags;
9598 void DomainLocalModule::EnsureDynamicClassIndex(DWORD dwID)
9605 INJECT_FAULT(COMPlusThrowOM(););
9606 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9607 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9611 if (dwID < m_aDynamicEntries)
9613 _ASSERTE(m_pDynamicClassTable.Load() != NULL);
9617 SIZE_T aDynamicEntries = max(16, m_aDynamicEntries.Load());
9618 while (aDynamicEntries <= dwID)
9620 aDynamicEntries *= 2;
9623 DynamicClassInfo* pNewDynamicClassTable;
9624 pNewDynamicClassTable = (DynamicClassInfo*)
9625 (void*)GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
9626 S_SIZE_T(sizeof(DynamicClassInfo)) * S_SIZE_T(aDynamicEntries));
9628 memcpy(pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * m_aDynamicEntries);
9630 // Note: Memory allocated on loader heap is zero filled
9631 // memset(pNewDynamicClassTable + m_aDynamicEntries, 0, (aDynamicEntries - m_aDynamicEntries) * sizeof(DynamicClassInfo));
9633 _ASSERTE(m_aDynamicEntries%2 == 0);
9635 // Commit new dynamic table. The lock-free helpers depend on the order.
9637 m_pDynamicClassTable = pNewDynamicClassTable;
9639 m_aDynamicEntries = aDynamicEntries;
9642 #ifndef CROSSGEN_COMPILE
9643 void DomainLocalModule::AllocateDynamicClass(MethodTable *pMT)
9649 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9650 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9654 _ASSERTE(!pMT->ContainsGenericVariables());
9655 _ASSERTE(!pMT->IsSharedByGenericInstantiations());
9656 _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9657 _ASSERTE(pMT->IsDynamicStatics());
9659 DWORD dynamicEntryIDIndex = pMT->GetModuleDynamicEntryID();
9661 EnsureDynamicClassIndex(dynamicEntryIDIndex);
9663 _ASSERTE(m_aDynamicEntries > dynamicEntryIDIndex);
9665 EEClass *pClass = pMT->GetClass();
9667 DWORD dwStaticBytes = pClass->GetNonGCRegularStaticFieldBytes();
9668 DWORD dwNumHandleStatics = pClass->GetNumHandleRegularStatics();
9670 _ASSERTE(!IsClassAllocated(pMT));
9671 _ASSERTE(!IsClassInitialized(pMT));
9672 _ASSERTE(!IsClassInitError(pMT));
9674 DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry;
9676 // We need this check because maybe a class had a cctor but no statics
9677 if (dwStaticBytes > 0 || dwNumHandleStatics > 0)
9679 if (pDynamicStatics == NULL)
9681 LoaderHeap * pLoaderAllocator = GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap();
9683 if (pMT->Collectible())
9685 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(sizeof(CollectibleDynamicEntry)));
9689 SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes;
9691 #ifdef FEATURE_64BIT_ALIGNMENT
9692 // Allocate memory with extra alignment only if it is really necessary
9693 if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
9695 static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0);
9696 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE);
9700 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(dynamicEntrySize));
9703 // Note: Memory allocated on loader heap is zero filled
9705 m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry = pDynamicStatics;
9708 if (pMT->Collectible() && (dwStaticBytes != 0))
9711 OBJECTREF nongcStaticsArray = NULL;
9712 GCPROTECT_BEGIN(nongcStaticsArray);
9713 #ifdef FEATURE_64BIT_ALIGNMENT
9714 // Allocate memory with extra alignment only if it is really necessary
9715 if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
9716 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8)-1)) / (sizeof(CLR_I8)));
9719 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes);
9720 ((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray);
9723 if (dwNumHandleStatics > 0)
9725 if (!pMT->Collectible())
9727 GetAppDomain()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
9728 &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics);
9733 OBJECTREF gcStaticsArray = NULL;
9734 GCPROTECT_BEGIN(gcStaticsArray);
9735 gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass);
9736 ((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(gcStaticsArray);
9744 void DomainLocalModule::PopulateClass(MethodTable *pMT)
9753 _ASSERTE(!pMT->ContainsGenericVariables());
9755 // <todo> the only work actually done here for non-dynamics is the freezing related work.
9756 // See if we can eliminate this and make this a dynamic-only path </todo>
9757 DWORD iClassIndex = pMT->GetClassIndex();
9759 if (!IsClassAllocated(pMT, iClassIndex))
9761 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9763 if (!IsClassAllocated(pMT, iClassIndex))
9765 // Allocate dynamic space if necessary
9766 if (pMT->IsDynamicStatics())
9767 AllocateDynamicClass(pMT);
9769 // determine flags to set on the statics block
9770 DWORD dwFlags = ClassInitFlags::ALLOCATECLASS_FLAG;
9772 if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics())
9774 _ASSERTE(!IsClassInitialized(pMT));
9775 _ASSERTE(!IsClassInitError(pMT));
9776 dwFlags |= ClassInitFlags::INITIALIZED_FLAG;
9779 if (pMT->Collectible())
9781 dwFlags |= ClassInitFlags::COLLECTIBLE_FLAG;
9784 // Set all flags at the same time to avoid races
9785 SetClassFlags(pMT, dwFlags);
9791 #endif // CROSSGEN_COMPILE
9793 void DomainLocalBlock::EnsureModuleIndex(ModuleIndex index)
9800 INJECT_FAULT(COMPlusThrowOM(););
9801 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9802 PRECONDITION(m_pDomain->OwnDomainLocalBlockLock());
9806 if (m_aModuleIndices > index.m_dwIndex)
9808 _ASSERTE(m_pModuleSlots != NULL);
9812 SIZE_T aModuleIndices = max(16, m_aModuleIndices);
9813 while (aModuleIndices <= index.m_dwIndex)
9815 aModuleIndices *= 2;
9818 PTR_DomainLocalModule* pNewModuleSlots = (PTR_DomainLocalModule*) (void*)m_pDomain->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(PTR_DomainLocalModule)) * S_SIZE_T(aModuleIndices));
9820 memcpy(pNewModuleSlots, m_pModuleSlots, sizeof(SIZE_T)*m_aModuleIndices);
9822 // Note: Memory allocated on loader heap is zero filled
9823 // memset(pNewModuleSlots + m_aModuleIndices, 0 , (aModuleIndices - m_aModuleIndices)*sizeof(PTR_DomainLocalModule) );
9825 // Commit new table. The lock-free helpers depend on the order.
9827 m_pModuleSlots = pNewModuleSlots;
9829 m_aModuleIndices = aModuleIndices;
9833 void DomainLocalBlock::SetModuleSlot(ModuleIndex index, PTR_DomainLocalModule pLocalModule)
9835 // Need to synchronize with table growth in this domain
9836 BaseDomain::DomainLocalBlockLockHolder lh(m_pDomain);
9838 EnsureModuleIndex(index);
9840 _ASSERTE(index.m_dwIndex < m_aModuleIndices);
9842 // We would like this assert here, unfortunately, loading a module in this appdomain can fail
9843 // after here and we will keep the module around and reuse the slot when we retry (if
9844 // the failure happened due to a transient error, such as OOM). In that case the slot wont
9846 //_ASSERTE(m_pModuleSlots[index.m_dwIndex] == 0);
9848 m_pModuleSlots[index.m_dwIndex] = pLocalModule;
9851 #ifndef CROSSGEN_COMPILE
9853 DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef)
9860 INJECT_FAULT(COMPlusThrowOM(););
9864 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
9867 DomainAssembly* pResolvedAssembly = NULL;
9868 _ASSERTE(strcmp(szName, g_AppDomainClassName));
9873 OBJECTREF AppDomainRef;
9874 OBJECTREF AssemblyRef;
9877 ZeroMemory(&gc, sizeof(gc));
9879 GCPROTECT_BEGIN(gc);
9880 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9882 if (pAssembly != NULL)
9883 gc.AssemblyRef = pAssembly->GetExposedAssemblyObject();
9885 MethodDescCallSite onTypeResolve(METHOD__APP_DOMAIN__ON_TYPE_RESOLVE, &gc.AppDomainRef);
9887 gc.str = StringObject::NewString(szName);
9890 ObjToArgSlot(gc.AppDomainRef),
9891 ObjToArgSlot(gc.AssemblyRef),
9892 ObjToArgSlot(gc.str)
9894 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onTypeResolve.Call_RetOBJECTREF(args);
9896 if (ResultingAssemblyRef != NULL)
9898 pResolvedAssembly = ResultingAssemblyRef->GetDomainAssembly();
9900 if (pResultingAssemblyRef)
9901 *pResultingAssemblyRef = ResultingAssemblyRef;
9904 if (pResolvedAssembly->IsCollectible())
9906 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
9913 return pResolvedAssembly;
9917 Assembly* AppDomain::RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName)
9924 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9925 INJECT_FAULT(COMPlusThrowOM(););
9929 Assembly* pResolvedAssembly = NULL;
9934 OBJECTREF AppDomainRef;
9935 OBJECTREF AssemblyRef;
9938 ZeroMemory(&gc, sizeof(gc));
9940 GCPROTECT_BEGIN(gc);
9941 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9943 if (pAssembly != NULL)
9944 gc.AssemblyRef=pAssembly->GetExposedAssemblyObject();
9946 MethodDescCallSite onResourceResolve(METHOD__APP_DOMAIN__ON_RESOURCE_RESOLVE, &gc.AppDomainRef);
9947 gc.str = StringObject::NewString(szName);
9950 ObjToArgSlot(gc.AppDomainRef),
9951 ObjToArgSlot(gc.AssemblyRef),
9952 ObjToArgSlot(gc.str)
9954 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onResourceResolve.Call_RetOBJECTREF(args);
9955 if (ResultingAssemblyRef != NULL)
9957 pResolvedAssembly = ResultingAssemblyRef->GetAssembly();
9958 if (pResolvedAssembly->IsCollectible())
9960 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
9966 RETURN pResolvedAssembly;
9971 AppDomain::RaiseAssemblyResolveEvent(
9972 AssemblySpec * pSpec,
9973 BOOL fIntrospection,
9981 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9982 INJECT_FAULT(COMPlusThrowOM(););
9986 BinderMethodID methodId;
9987 StackSString ssName;
9988 pSpec->GetFileOrDisplayName(0, ssName);
9992 methodId = METHOD__APP_DOMAIN__ON_ASSEMBLY_RESOLVE; // post-bind execution event (the classic V1.0 event)
10000 // Elevate threads allowed loading level. This allows the host to load an assembly even in a restricted
10001 // condition. Note, however, that this exposes us to possible recursion failures, if the host tries to
10002 // load the assemblies currently being loaded. (Such cases would then throw an exception.)
10004 OVERRIDE_LOAD_LEVEL_LIMIT(FILE_ACTIVE);
10005 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
10009 Assembly* pAssembly = NULL;
10012 OBJECTREF AppDomainRef;
10013 OBJECTREF AssemblyRef;
10016 ZeroMemory(&gc, sizeof(gc));
10018 GCPROTECT_BEGIN(gc);
10019 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
10021 if (pSpec->GetParentAssembly() != NULL)
10024 gc.AssemblyRef=pSpec->GetParentAssembly()->GetExposedAssemblyObject();
10027 MethodDescCallSite onAssemblyResolve(methodId, &gc.AppDomainRef);
10029 gc.str = StringObject::NewString(ssName);
10030 ARG_SLOT args[3] = {
10031 ObjToArgSlot(gc.AppDomainRef),
10032 ObjToArgSlot(gc.AssemblyRef),
10033 ObjToArgSlot(gc.str)
10036 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onAssemblyResolve.Call_RetOBJECTREF(args);
10038 if (ResultingAssemblyRef != NULL)
10040 pAssembly = ResultingAssemblyRef->GetAssembly();
10041 if (pAssembly->IsCollectible())
10043 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
10049 if (pAssembly != NULL)
10051 if ((!(pAssembly->IsIntrospectionOnly())) != (!fIntrospection))
10053 // Cannot return an introspection assembly from an execution callback or vice-versa
10054 COMPlusThrow(kFileLoadException, pAssembly->IsIntrospectionOnly() ? IDS_CLASSLOAD_ASSEMBLY_RESOLVE_RETURNED_INTROSPECTION : IDS_CLASSLOAD_ASSEMBLY_RESOLVE_RETURNED_EXECUTION);
10057 // Check that the public key token matches the one specified in the spec
10058 // MatchPublicKeys throws as appropriate
10059 pSpec->MatchPublicKeys(pAssembly);
10063 } // AppDomain::RaiseAssemblyResolveEvent
10066 //---------------------------------------------------------------------------------------
10068 // Determine the type of AppDomainManager to use for the default AppDomain
10071 // v2.0 of the CLR used environment variables APPDOMAIN_MANAGER_ASM and APPDOMAIN_MANAGER_TYPE to set the
10072 // domain manager. For compatibility these are still supported, along with appDomainManagerAsm and
10073 // appDomainManagerType config file switches. If the config switches are supplied, the entry point must be
10077 void AppDomain::InitializeDefaultDomainManager()
10084 INJECT_FAULT(COMPlusThrowOM(););
10085 PRECONDITION(GetId().m_dwId == DefaultADID);
10089 OBJECTREF orThis = GetExposedObject();
10090 GCPROTECT_BEGIN(orThis);
10092 MethodDescCallSite initCompatFlags(METHOD__APP_DOMAIN__INITIALIZE_COMPATIBILITY_FLAGS);
10095 ObjToArgSlot(orThis)
10098 initCompatFlags.Call(args);
10103 CLREvent * AppDomain::g_pUnloadStartEvent;
10105 void AppDomain::CreateADUnloadWorker()
10107 STANDARD_VM_CONTRACT;
10109 // Do not create adUnload thread if there is only default domain
10110 if(IsSingleAppDomain())
10114 BOOL fCreator = FALSE;
10115 if (FastInterlockCompareExchange((LONG *)&g_fADUnloadWorkerOK,-2,-1)==-1) //we're first
10117 #ifdef _TARGET_X86_ // use the smallest possible stack on X86
10118 DWORD stackSize = 128 * 1024;
10120 DWORD stackSize = 512 * 1024; // leave X64 unchanged since we have plenty of VM
10122 Thread *pThread = SetupUnstartedThread();
10123 if (pThread->CreateNewThread(stackSize, ADUnloadThreadStart, pThread))
10127 dwRet = pThread->StartThread();
10129 // When running under a user mode native debugger there is a race
10130 // between the moment we've created the thread (in CreateNewThread) and
10131 // the moment we resume it (in StartThread); the debugger may receive
10132 // the "ct" (create thread) notification, and it will attempt to
10133 // suspend/resume all threads in the process. Now imagine the debugger
10134 // resumes this thread first, and only later does it try to resume the
10135 // newly created thread (the ADU worker thread). In these conditions our
10136 // call to ResumeThread may come before the debugger's call to ResumeThread
10137 // actually causing dwRet to equal 2.
10138 // We cannot use IsDebuggerPresent() in the condition below because the
10139 // debugger may have been detached between the time it got the notification
10140 // and the moment we execute the test below.
10141 _ASSERTE(dwRet == 1 || dwRet == 2);
10145 pThread->DecExternalCount(FALSE);
10146 FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK, -1);
10147 ThrowOutOfMemory();
10151 YIELD_WHILE (g_fADUnloadWorkerOK == -2);
10153 if (g_fADUnloadWorkerOK == -1) {
10156 ThrowOutOfMemory();
10165 /*static*/ void AppDomain::ADUnloadWorkerHelper(AppDomain *pDomain)
10167 STATIC_CONTRACT_NOTHROW;
10168 STATIC_CONTRACT_GC_TRIGGERS;
10169 STATIC_CONTRACT_MODE_COOPERATIVE;
10170 ADUnloadSink* pADUnloadSink=pDomain->GetADUnloadSinkForUnload();
10175 pDomain->Unload(FALSE);
10177 EX_CATCH_HRESULT(hr);
10181 SystemDomain::LockHolder lh;
10182 pADUnloadSink->ReportUnloadResult(hr,NULL);
10183 pADUnloadSink->Release();
10187 void AppDomain::DoADUnloadWork()
10194 INJECT_FAULT(COMPlusThrowOM(););
10201 AppDomain *pDomainToUnload = NULL;
10204 // Take the lock so that no domain can be added or removed from the system domain
10205 SystemDomain::LockHolder lh;
10207 DWORD numDomain = SystemDomain::GetCurrentAppDomainMaxIndex();
10208 for (; i <= numDomain; i ++) {
10209 AppDomain * pDomain = SystemDomain::TestGetAppDomainAtIndex(ADIndex(i));
10211 // @todo: We used to also select a domain if pDomain->IsUnload() returned true. But that causes
10212 // problems when we've failed to completely unload the AD in the past. If we've reached the CLEARED
10213 // stage, for instance, then there will be no default context and AppDomain::Exit() will simply crash.
10215 if (pDomain && pDomain->IsUnloadRequested())
10217 pDomainToUnload = pDomain;
10224 if (!pDomainToUnload) {
10228 // We are the only thread that can unload domains so no one else can delete the appdomain
10229 ADUnloadWorkerHelper(pDomainToUnload);
10233 static void DoADUnloadWorkHelper()
10235 STATIC_CONTRACT_NOTHROW;
10236 STATIC_CONTRACT_GC_TRIGGERS;
10237 STATIC_CONTRACT_MODE_COOPERATIVE;
10240 AppDomain::DoADUnloadWork();
10245 EX_END_CATCH(SwallowAllExceptions);
10248 ULONGLONG g_ObjFinalizeStartTime = 0;
10249 Volatile<BOOL> g_FinalizerIsRunning = FALSE;
10250 Volatile<ULONG> g_FinalizerLoopCount = 0;
10252 ULONGLONG GetObjFinalizeStartTime()
10254 LIMITED_METHOD_CONTRACT;
10255 return g_ObjFinalizeStartTime;
10258 void FinalizerThreadAbortOnTimeout()
10260 STATIC_CONTRACT_NOTHROW;
10261 STATIC_CONTRACT_MODE_COOPERATIVE;
10262 STATIC_CONTRACT_GC_TRIGGERS;
10265 // If finalizer thread is blocked because scheduler is running another task,
10266 // or it is waiting for another thread, we first see if we get finalizer thread
10268 Thread::ThreadAbortWatchDog();
10273 Thread *pFinalizerThread = FinalizerThread::GetFinalizerThread();
10274 EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(OPR_FinalizerRun, pFinalizerThread);
10278 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10279 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10282 Thread::UAC_FinalizerTimeout);
10284 case eRudeAbortThread:
10285 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10286 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10289 Thread::UAC_FinalizerTimeout);
10291 case eUnloadAppDomain:
10293 AppDomain *pDomain = pFinalizerThread->GetDomain();
10294 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10297 Thread::UAC_FinalizerTimeout);
10298 if (!pDomain->IsDefaultDomain())
10300 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10301 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
10305 case eRudeUnloadAppDomain:
10307 AppDomain *pDomain = pFinalizerThread->GetDomain();
10308 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10311 Thread::UAC_FinalizerTimeout);
10312 if (!pDomain->IsDefaultDomain())
10314 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10315 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
10320 case eFastExitProcess:
10321 case eRudeExitProcess:
10322 case eDisableRuntime:
10323 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10324 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
10325 _ASSERTE (!"Should not get here");
10334 EX_END_CATCH(SwallowAllExceptions);
10339 WT_UnloadDomain = 0x1,
10340 WT_ThreadAbort = 0x2,
10341 WT_FinalizerThread = 0x4,
10342 WT_ClearCollectedDomains=0x8
10345 static Volatile<DWORD> s_WorkType = 0;
10348 DWORD WINAPI AppDomain::ADUnloadThreadStart(void *args)
10353 DISABLED(GC_TRIGGERS);
10355 // This function will always be at the very bottom of the stack. The only
10356 // user code it calls is the AppDomainUnload notifications which we will
10357 // not be hardenning for Whidbey.
10363 BEGIN_ENTRYPOINT_NOTHROW;
10365 ClrFlsSetThreadType (ThreadType_ADUnloadHelper);
10367 Thread *pThread = (Thread*)args;
10368 bool fOK = (pThread->HasStarted() != 0);
10371 GCX_MAYBE_PREEMP(fOK);
10373 _ASSERTE (g_fADUnloadWorkerOK == -2);
10375 FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK,fOK?1:-1);
10379 DestroyThread(pThread);
10383 pThread->SetBackground(TRUE);
10385 pThread->SetThreadStateNC(Thread::TSNC_ADUnloadHelper);
10388 DWORD TAtimeout = INFINITE;
10389 ULONGLONG endTime = Thread::GetNextSelfAbortEndTime();
10390 ULONGLONG curTime = CLRGetTickCount64();
10391 if (endTime <= curTime) {
10396 ULONGLONG diff = endTime - curTime;
10397 if (diff < MAXULONG)
10399 TAtimeout = (DWORD)diff;
10402 ULONGLONG finalizeStartTime = GetObjFinalizeStartTime();
10403 DWORD finalizeTimeout = INFINITE;
10404 DWORD finalizeTimeoutSetting = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
10405 if (finalizeTimeoutSetting != INFINITE && g_FinalizerIsRunning)
10407 if (finalizeStartTime == 0)
10409 finalizeTimeout = finalizeTimeoutSetting;
10413 endTime = finalizeStartTime + finalizeTimeoutSetting;
10414 if (endTime <= curTime) {
10415 finalizeTimeout = 0;
10419 ULONGLONG diff = endTime - curTime;
10420 if (diff < MAXULONG)
10422 finalizeTimeout = (DWORD)diff;
10428 if (AppDomain::HasWorkForFinalizerThread())
10430 if (finalizeTimeout > finalizeTimeoutSetting)
10432 finalizeTimeout = finalizeTimeoutSetting;
10436 DWORD timeout = INFINITE;
10437 if (finalizeTimeout <= TAtimeout)
10439 timeout = finalizeTimeout;
10443 timeout = TAtimeout;
10448 LOG((LF_APPDOMAIN, LL_INFO10, "Waiting to start unload\n"));
10449 g_pUnloadStartEvent->Wait(timeout,FALSE);
10452 if (finalizeTimeout != INFINITE || (s_WorkType & WT_FinalizerThread) != 0)
10454 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for Finalizer thread\n");
10455 FastInterlockAnd(&s_WorkType, ~WT_FinalizerThread);
10456 // only watch finalizer thread is finalizer method or unloadevent is being processed
10457 if (GetObjFinalizeStartTime() == finalizeStartTime && finalizeStartTime != 0 && g_FinalizerIsRunning)
10459 if (CLRGetTickCount64() >= finalizeStartTime+finalizeTimeoutSetting)
10462 FinalizerThreadAbortOnTimeout();
10465 if (s_fProcessUnloadDomainEvent && g_FinalizerIsRunning)
10468 FinalizerThreadAbortOnTimeout();
10472 if (TAtimeout != INFINITE || (s_WorkType & WT_ThreadAbort) != 0)
10474 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for thread abort\n");
10475 FastInterlockAnd(&s_WorkType, ~WT_ThreadAbort);
10477 Thread::ThreadAbortWatchDog();
10480 if ((s_WorkType & WT_UnloadDomain) != 0 && !AppDomain::HasWorkForFinalizerThread())
10482 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD unload\n");
10483 FastInterlockAnd(&s_WorkType, ~WT_UnloadDomain);
10485 DoADUnloadWorkHelper();
10488 if ((s_WorkType & WT_ClearCollectedDomains) != 0)
10490 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD cleanup\n");
10491 FastInterlockAnd(&s_WorkType, ~WT_ClearCollectedDomains);
10493 SystemDomain::System()->ClearCollectedDomains();
10500 END_ENTRYPOINT_NOTHROW;
10505 void AppDomain::EnableADUnloadWorker()
10511 SO_TOLERANT; // Called during a SO
10515 EEPolicy::AppDomainUnloadTypes type = EEPolicy::ADU_Safe;
10518 DWORD hostTestADUnload = g_pConfig->GetHostTestADUnload();
10519 if (hostTestADUnload == 2) {
10520 type = EEPolicy::ADU_Rude;
10524 EnableADUnloadWorker(type);
10527 void AppDomain::EnableADUnloadWorker(EEPolicy::AppDomainUnloadTypes type, BOOL fHasStack)
10533 SO_TOLERANT; // Called during a SO
10537 FastInterlockOr (&s_WorkType, WT_UnloadDomain);
10539 LONG stage = m_Stage;
10540 static_assert_no_msg(sizeof(m_Stage) == sizeof(int));
10542 _ASSERTE(!IsDefaultDomain());
10544 // Mark unload requested.
10545 if (type == EEPolicy::ADU_Rude) {
10548 while (stage < STAGE_UNLOAD_REQUESTED) {
10549 stage = FastInterlockCompareExchange((LONG*)&m_Stage,STAGE_UNLOAD_REQUESTED,stage);
10554 // Can not call Set due to limited stack.
10557 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker\n"));
10558 g_pUnloadStartEvent->Set();
10561 void AppDomain::EnableADUnloadWorkerForThreadAbort()
10563 LIMITED_METHOD_CONTRACT;
10564 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "Enabling unload worker for thread abort\n");
10565 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for thread abort\n"));
10566 FastInterlockOr (&s_WorkType, WT_ThreadAbort);
10567 g_pUnloadStartEvent->Set();
10571 void AppDomain::EnableADUnloadWorkerForFinalizer()
10573 LIMITED_METHOD_CONTRACT;
10574 if (GetEEPolicy()->GetTimeout(OPR_FinalizerRun) != INFINITE)
10576 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for Finalizer Thread\n"));
10577 FastInterlockOr (&s_WorkType, WT_FinalizerThread);
10578 g_pUnloadStartEvent->Set();
10582 void AppDomain::EnableADUnloadWorkerForCollectedADCleanup()
10584 LIMITED_METHOD_CONTRACT;
10585 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for collected domains\n"));
10586 FastInterlockOr (&s_WorkType, WT_ClearCollectedDomains);
10587 g_pUnloadStartEvent->Set();
10591 void SystemDomain::ClearCollectedDomains()
10601 AppDomain* pDomainsToClear=NULL;
10603 CrstHolder lh(&m_DelayedUnloadCrst);
10604 for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
10606 if ((*ppDomain)->m_Stage==AppDomain::STAGE_COLLECTED)
10608 AppDomain* pAppDomain=*ppDomain;
10609 *ppDomain=(*ppDomain)->m_pNextInDelayedUnloadList;
10610 pAppDomain->m_pNextInDelayedUnloadList=pDomainsToClear;
10611 pDomainsToClear=pAppDomain;
10614 ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
10618 for (AppDomain* pDomain=pDomainsToClear;pDomain!=NULL;)
10620 AppDomain* pNext=pDomain->m_pNextInDelayedUnloadList;
10621 pDomain->Close(); //NOTHROW!
10622 pDomain->Release();
10627 void SystemDomain::ProcessClearingDomains()
10636 CrstHolder lh(&m_DelayedUnloadCrst);
10638 for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
10640 if ((*ppDomain)->m_Stage==AppDomain::STAGE_HANDLETABLE_NOACCESS)
10642 AppDomain* pAppDomain=*ppDomain;
10643 pAppDomain->SetStage(AppDomain::STAGE_CLEARED);
10645 ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
10648 if (!m_UnloadIsAsync)
10650 // For synchronous mode, we are now done with the list.
10651 m_pDelayedUnloadList = NULL;
10655 void SystemDomain::ProcessDelayedUnloadDomains()
10665 int iGCRefPoint=GCHeapUtilities::GetGCHeap()->CollectionCount(GCHeapUtilities::GetGCHeap()->GetMaxGeneration());
10666 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCInProgress())
10669 BOOL bAppDomainToCleanup = FALSE;
10670 LoaderAllocator * pAllocatorsToDelete = NULL;
10673 CrstHolder lh(&m_DelayedUnloadCrst);
10675 for (AppDomain* pDomain=m_pDelayedUnloadList; pDomain!=NULL; pDomain=pDomain->m_pNextInDelayedUnloadList)
10677 if (pDomain->m_Stage==AppDomain::STAGE_CLEARED)
10679 // Compare with 0 to handle overflows gracefully
10680 if (0 < iGCRefPoint - pDomain->GetGCRefPoint())
10682 bAppDomainToCleanup=TRUE;
10683 pDomain->SetStage(AppDomain::STAGE_COLLECTED);
10688 LoaderAllocator ** ppAllocator=&m_pDelayedUnloadListOfLoaderAllocators;
10689 while (*ppAllocator!= NULL)
10691 LoaderAllocator * pAllocator = *ppAllocator;
10692 if (0 < iGCRefPoint - pAllocator->GetGCRefPoint())
10694 *ppAllocator = pAllocator->m_pLoaderAllocatorDestroyNext;
10696 pAllocator->m_pLoaderAllocatorDestroyNext = pAllocatorsToDelete;
10697 pAllocatorsToDelete = pAllocator;
10701 ppAllocator = &pAllocator->m_pLoaderAllocatorDestroyNext;
10706 if (bAppDomainToCleanup)
10707 AppDomain::EnableADUnloadWorkerForCollectedADCleanup();
10709 // Delete collected loader allocators on the finalizer thread. We cannot offload it to appdomain unload thread because of
10710 // there is not guaranteed to be one, and it is not that expensive operation anyway.
10711 while (pAllocatorsToDelete != NULL)
10713 LoaderAllocator * pAllocator = pAllocatorsToDelete;
10714 pAllocatorsToDelete = pAllocator->m_pLoaderAllocatorDestroyNext;
10719 #endif // CROSSGEN_COMPILE
10721 AppDomainFromIDHolder::AppDomainFromIDHolder(ADID adId, BOOL bUnsafePoint, SyncType synctype)
10723 WRAPPER_NO_CONTRACT;
10724 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
10731 Assign(adId, bUnsafePoint);
10734 AppDomainFromIDHolder::AppDomainFromIDHolder(SyncType synctype)
10736 LIMITED_METHOD_CONTRACT;
10737 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
10746 #ifndef CROSSGEN_COMPILE
10747 void ADUnloadSink::ReportUnloadResult (HRESULT hr, OBJECTREF* pException)
10753 PRECONDITION(CheckPointer(this));
10754 PRECONDITION(m_UnloadCompleteEvent.IsValid());
10758 //pException is unused;
10760 m_UnloadCompleteEvent.Set();
10763 void ADUnloadSink::WaitUnloadCompletion()
10769 PRECONDITION(CheckPointer(this));
10770 PRECONDITION(m_UnloadCompleteEvent.IsValid());
10774 CONTRACT_VIOLATION(FaultViolation);
10775 m_UnloadCompleteEvent.WaitEx(INFINITE, (WaitMode)(WaitMode_Alertable | WaitMode_ADUnload));
10778 ADUnloadSink* AppDomain::PrepareForWaitUnloadCompletion()
10784 PRECONDITION(SystemDomain::IsUnderDomainLock());
10789 ADUnloadSink* pADSink=GetADUnloadSink();
10790 PREFIX_ASSUME(pADSink!=NULL);
10791 if (m_Stage < AppDomain::STAGE_UNLOAD_REQUESTED) //we're first
10794 SetUnloadRequestThread(GetThread());
10799 ADUnloadSink::ADUnloadSink()
10807 INJECT_FAULT(COMPlusThrowOM(););
10812 m_UnloadCompleteEvent.CreateManualEvent(FALSE);
10813 m_UnloadResult=S_OK;
10816 ADUnloadSink::~ADUnloadSink()
10826 m_UnloadCompleteEvent.CloseEvent();
10831 ULONG ADUnloadSink::AddRef()
10833 LIMITED_METHOD_CONTRACT;
10834 return InterlockedIncrement(&m_cRef);
10837 ULONG ADUnloadSink::Release()
10839 LIMITED_METHOD_CONTRACT;
10840 ULONG ulRef = InterlockedDecrement(&m_cRef);
10848 void ADUnloadSink::Reset()
10850 LIMITED_METHOD_CONTRACT;
10851 m_UnloadResult=S_OK;
10852 m_UnloadCompleteEvent.Reset();
10855 ADUnloadSink* AppDomain::GetADUnloadSink()
10857 LIMITED_METHOD_CONTRACT;
10858 _ASSERTE(SystemDomain::IsUnderDomainLock());
10860 m_ADUnloadSink->AddRef();
10861 return m_ADUnloadSink;
10864 ADUnloadSink* AppDomain::GetADUnloadSinkForUnload()
10866 // unload thread only. Doesn't need to have AD lock
10867 LIMITED_METHOD_CONTRACT;
10869 m_ADUnloadSink->AddRef();
10870 return m_ADUnloadSink;
10872 #endif // CROSSGEN_COMPILE
10874 void AppDomain::EnumStaticGCRefs(promote_func* fn, ScanContext* sc)
10883 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
10884 GCHeapUtilities::IsServerHeap() &&
10885 IsGCSpecialThread());
10887 AppDomain::AssemblyIterator asmIterator = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution));
10888 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
10889 while (asmIterator.Next(pDomainAssembly.This()))
10891 // @TODO: Review when DomainAssemblies get added.
10892 _ASSERTE(pDomainAssembly != NULL);
10893 pDomainAssembly->EnumStaticGCRefs(fn, sc);
10899 #endif // !DACCESS_COMPILE
10901 //------------------------------------------------------------------------
10902 UINT32 BaseDomain::GetTypeID(PTR_MethodTable pMT) {
10906 PRECONDITION(pMT->GetDomain() == this);
10909 return m_typeIDMap.GetTypeID(pMT);
10912 //------------------------------------------------------------------------
10913 // Returns the ID of the type if found. If not found, returns INVALID_TYPE_ID
10914 UINT32 BaseDomain::LookupTypeID(PTR_MethodTable pMT)
10919 WRAPPER(GC_TRIGGERS);
10920 PRECONDITION(pMT->GetDomain() == this);
10923 return m_typeIDMap.LookupTypeID(pMT);
10926 //------------------------------------------------------------------------
10927 PTR_MethodTable BaseDomain::LookupType(UINT32 id) {
10931 WRAPPER(GC_TRIGGERS);
10932 CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS);
10935 PTR_MethodTable pMT = m_typeIDMap.LookupType(id);
10936 if (pMT == NULL && !IsSharedDomain()) {
10937 pMT = SharedDomain::GetDomain()->LookupType(id);
10940 CONSISTENCY_CHECK(CheckPointer(pMT));
10941 CONSISTENCY_CHECK(pMT->IsInterface());
10945 #ifndef DACCESS_COMPILE
10948 //------------------------------------------------------------------------
10949 BOOL GetCompatibilityFlag(CompatibilityFlag flag)
10959 #endif // !DACCESS_COMPILE
10961 //---------------------------------------------------------------------------------------
10964 AppDomain::AssemblyIterator::Next(
10965 CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
10969 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
10973 CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
10974 return Next_Unlocked(pDomainAssemblyHolder);
10977 //---------------------------------------------------------------------------------------
10979 // Note: Does not lock the assembly list, but locks collectible assemblies for adding references.
10982 AppDomain::AssemblyIterator::Next_Unlocked(
10983 CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
10991 #ifndef DACCESS_COMPILE
10992 _ASSERTE(m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
10995 while (m_Iterator.Next())
10997 // Get element from the list/iterator (without adding reference to the assembly)
10998 DomainAssembly * pDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
10999 if (pDomainAssembly == NULL)
11004 if (pDomainAssembly->IsError())
11006 if (m_assemblyIterationFlags & kIncludeFailedToLoad)
11008 *pDomainAssemblyHolder = pDomainAssembly;
11011 continue; // reject
11014 // First, reject DomainAssemblies whose load status is not to be included in
11017 if (pDomainAssembly->IsAvailableToProfilers() &&
11018 (m_assemblyIterationFlags & kIncludeAvailableToProfilers))
11020 // The assembly has reached the state at which we would notify profilers,
11021 // and we're supposed to include such assemblies in the enumeration. So
11022 // don't reject it (i.e., noop here, and don't bother with the rest of
11023 // the load status checks). Check for this first, since
11024 // kIncludeAvailableToProfilers contains some loaded AND loading
11027 else if (pDomainAssembly->IsLoaded())
11029 // A loaded assembly
11030 if (!(m_assemblyIterationFlags & kIncludeLoaded))
11032 continue; // reject
11037 // A loading assembly
11038 if (!(m_assemblyIterationFlags & kIncludeLoading))
11040 continue; // reject
11044 // Next, reject DomainAssemblies whose execution / introspection status is
11045 // not to be included in the enumeration
11047 if (pDomainAssembly->IsIntrospectionOnly())
11049 // introspection assembly
11050 if (!(m_assemblyIterationFlags & kIncludeIntrospection))
11052 continue; // reject
11057 // execution assembly
11058 if (!(m_assemblyIterationFlags & kIncludeExecution))
11060 continue; // reject
11064 // Next, reject collectible assemblies
11065 if (pDomainAssembly->IsCollectible())
11067 if (m_assemblyIterationFlags & kExcludeCollectible)
11069 _ASSERTE(!(m_assemblyIterationFlags & kIncludeCollected));
11070 continue; // reject
11073 // Un-tenured collectible assemblies should not be returned. (This can only happen in a brief
11074 // window during collectible assembly creation. No thread should need to have a pointer
11075 // to the just allocated DomainAssembly at this stage.)
11076 if (!pDomainAssembly->GetAssembly()->GetManifestModule()->IsTenured())
11078 continue; // reject
11081 if (pDomainAssembly->GetLoaderAllocator()->AddReferenceIfAlive())
11082 { // The assembly is alive
11084 // Set the holder value (incl. increasing ref-count)
11085 *pDomainAssemblyHolder = pDomainAssembly;
11087 // Now release the reference we took in the if-condition
11088 pDomainAssembly->GetLoaderAllocator()->Release();
11091 // The assembly is not alive anymore (and we didn't increase its ref-count in the
11094 if (!(m_assemblyIterationFlags & kIncludeCollected))
11096 continue; // reject
11098 // Set the holder value to assembly with 0 ref-count without increasing the ref-count (won't
11099 // call Release either)
11100 pDomainAssemblyHolder->Assign(pDomainAssembly, FALSE);
11104 *pDomainAssemblyHolder = pDomainAssembly;
11108 *pDomainAssemblyHolder = NULL;
11110 } // AppDomain::AssemblyIterator::Next_Unlocked
11112 #ifndef DACCESS_COMPILE
11114 //---------------------------------------------------------------------------------------
11116 // Can be called only from AppDomain shutdown code:AppDomain::ShutdownAssemblies.
11117 // Does not add-ref collectible assemblies (as the LoaderAllocator might not be reachable from the
11118 // DomainAssembly anymore).
11121 AppDomain::AssemblyIterator::Next_UnsafeNoAddRef(
11122 DomainAssembly ** ppDomainAssembly)
11130 // Make sure we are iterating all assemblies (see the only caller code:AppDomain::ShutdownAssemblies)
11131 _ASSERTE(m_assemblyIterationFlags ==
11132 (kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
11133 // It also means that we do not exclude anything
11134 _ASSERTE((m_assemblyIterationFlags & kExcludeCollectible) == 0);
11136 // We are on shutdown path, so lock shouldn't be neccessary, but all _Unlocked methods on AssemblyList
11137 // have asserts that the lock is held, so why not to take it ...
11138 CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
11140 while (m_Iterator.Next())
11142 // Get element from the list/iterator (without adding reference to the assembly)
11143 *ppDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
11144 if (*ppDomainAssembly == NULL)
11152 *ppDomainAssembly = NULL;
11154 } // AppDomain::AssemblyIterator::Next_UnsafeNoAddRef
11157 //---------------------------------------------------------------------------------------
11159 BOOL AppDomain::IsImageFromTrustedPath(PEImage* pPEImage)
11166 PRECONDITION(CheckPointer(pPEImage));
11170 const SString &sImagePath = pPEImage->GetPath();
11172 return !sImagePath.IsEmpty();
11175 #endif //!DACCESS_COMPILE
11177 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
11179 // Returns a BOOL indicating if the binding model has been locked for the AppDomain
11180 BOOL AppDomain::IsBindingModelLocked()
11190 return m_fIsBindingModelLocked.Load();
11193 // Marks the binding model locked for AppDomain
11194 BOOL AppDomain::LockBindingModel()
11196 LIMITED_METHOD_CONTRACT;
11198 BOOL fDidWeLockBindingModel = FALSE;
11200 if (InterlockedCompareExchangeT<BOOL>(&m_fIsBindingModelLocked, TRUE, FALSE) == FALSE)
11202 fDidWeLockBindingModel = TRUE;
11205 return fDidWeLockBindingModel;
11208 BOOL AppDomain::IsHostAssemblyResolverInUse()
11210 LIMITED_METHOD_CONTRACT;
11212 return (GetFusionContext() != GetTPABinderContext());
11215 // Helper used by the assembly binder to check if the specified AppDomain can use apppath assembly resolver
11216 BOOL RuntimeCanUseAppPathAssemblyResolver(DWORD adid)
11220 NOTHROW; // Cannot throw since it is invoked by the Binder that expects to get a hresult
11228 // We need to be in COOP mode to get the AppDomain*
11231 AppDomain *pTargetDomain = SystemDomain::GetAppDomainFromId(id, ADV_CURRENTAD);
11232 _ASSERTE(pTargetDomain != NULL);
11234 pTargetDomain->LockBindingModel();
11236 return !pTargetDomain->IsHostAssemblyResolverInUse();
11239 // Returns S_OK if the assembly was successfully loaded
11240 HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, IAssemblyName *pIAssemblyName, CLRPrivBinderCoreCLR *pTPABinder, BINDER_SPACE::AssemblyName *pAssemblyName, ICLRPrivAssembly **ppLoadedAssembly)
11247 PRECONDITION(ppLoadedAssembly != NULL);
11251 HRESULT hr = E_FAIL;
11253 // DevDiv #933506: Exceptions thrown during AssemblyLoadContext.Load should propagate
11256 // Switch to COOP mode since we are going to work with managed references
11261 ASSEMBLYNAMEREF oRefAssemblyName;
11262 ASSEMBLYREF oRefLoadedAssembly;
11265 ZeroMemory(&_gcRefs, sizeof(_gcRefs));
11267 GCPROTECT_BEGIN(_gcRefs);
11269 ICLRPrivAssembly *pAssemblyBindingContext = NULL;
11271 bool fInvokedForTPABinder = (pTPABinder == NULL)?true:false;
11273 // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.Resolve method.
11275 // First, initialize an assembly spec for the requested assembly
11278 hr = spec.Init(pIAssemblyName);
11281 bool fResolvedAssembly = false;
11282 bool fResolvedAssemblyViaTPALoadContext = false;
11284 // Allocate an AssemblyName managed object
11285 _gcRefs.oRefAssemblyName = (ASSEMBLYNAMEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME));
11287 // Initialize the AssemblyName object from the AssemblySpec
11288 spec.AssemblyNameInit(&_gcRefs.oRefAssemblyName, NULL);
11290 if (!fInvokedForTPABinder)
11292 // Step 2 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName) - Invoke Load method
11293 // This is not invoked for TPA Binder since it always returns NULL.
11295 // Finally, setup arguments for invocation
11296 BinderMethodID idHAR_Resolve = METHOD__ASSEMBLYLOADCONTEXT__RESOLVE;
11297 MethodDescCallSite methLoadAssembly(idHAR_Resolve);
11299 // Setup the arguments for the call
11302 PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
11303 ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
11307 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
11308 if (_gcRefs.oRefLoadedAssembly != NULL)
11310 fResolvedAssembly = true;
11313 // Step 3 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
11314 if (!fResolvedAssembly)
11316 // If we could not resolve the assembly using Load method, then attempt fallback with TPA Binder.
11317 // Since TPA binder cannot fallback to itself, this fallback does not happen for binds within TPA binder.
11319 // Switch to pre-emp mode before calling into the binder
11321 ICLRPrivAssembly *pCoreCLRFoundAssembly = NULL;
11322 hr = pTPABinder->BindAssemblyByName(pIAssemblyName, &pCoreCLRFoundAssembly);
11325 pAssemblyBindingContext = pCoreCLRFoundAssembly;
11326 fResolvedAssembly = true;
11327 fResolvedAssemblyViaTPALoadContext = true;
11332 if (!fResolvedAssembly)
11334 // Step 4 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
11336 // If we couldnt resolve the assembly using TPA LoadContext as well, then
11337 // attempt to resolve it using the Resolving event.
11338 // Finally, setup arguments for invocation
11339 BinderMethodID idHAR_ResolveUsingEvent = METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUSINGEVENT;
11340 MethodDescCallSite methLoadAssembly(idHAR_ResolveUsingEvent);
11342 // Setup the arguments for the call
11345 PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
11346 ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
11350 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
11351 if (_gcRefs.oRefLoadedAssembly != NULL)
11353 // Set the flag indicating we found the assembly
11354 fResolvedAssembly = true;
11358 if (fResolvedAssembly && !fResolvedAssemblyViaTPALoadContext)
11360 // If we are here, assembly was successfully resolved via Load or Resolving events.
11361 _ASSERTE(_gcRefs.oRefLoadedAssembly != NULL);
11363 // We were able to get the assembly loaded. Now, get its name since the host could have
11364 // performed the resolution using an assembly with different name.
11365 DomainAssembly *pDomainAssembly = _gcRefs.oRefLoadedAssembly->GetDomainAssembly();
11366 PEAssembly *pLoadedPEAssembly = NULL;
11367 bool fFailLoad = false;
11368 if (!pDomainAssembly)
11370 // Reflection emitted assemblies will not have a domain assembly.
11375 pLoadedPEAssembly = pDomainAssembly->GetFile();
11376 if (pLoadedPEAssembly->HasHostAssembly() != true)
11378 // Reflection emitted assemblies will not have a domain assembly.
11383 // The loaded assembly's ICLRPrivAssembly* is saved as HostAssembly in PEAssembly
11387 spec.GetFileOrDisplayName(0, name);
11388 COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_DYNAMICALLY_EMITTED_ASSEMBLIES_UNSUPPORTED, name);
11391 // Is the assembly already bound using a binding context that will be incompatible?
11392 // An example is attempting to consume an assembly bound to WinRT binder.
11393 pAssemblyBindingContext = pLoadedPEAssembly->GetHostAssembly();
11396 #ifdef FEATURE_COMINTEROP
11397 if (AreSameBinderInstance(pAssemblyBindingContext, GetAppDomain()->GetWinRtBinder()))
11399 // It is invalid to return an assembly bound to an incompatible binder
11400 *ppLoadedAssembly = NULL;
11402 spec.GetFileOrDisplayName(0, name);
11403 COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_BINDING_CONTEXT, name);
11405 #endif // FEATURE_COMINTEROP
11407 // Get the ICLRPrivAssembly reference to return back to.
11408 *ppLoadedAssembly = clr::SafeAddRef(pAssemblyBindingContext);
11414 // EX_CATCH_HRESULT(hr);
11419 #endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
11421 //approximate size of loader data
11422 //maintained for each assembly
11423 #define APPROX_LOADER_DATA_PER_ASSEMBLY 8196
11425 size_t AppDomain::EstimateSize()
11435 size_t retval = sizeof(AppDomain);
11436 retval += GetLoaderAllocator()->EstimateSize();
11437 //very rough estimate
11438 retval += GetAssemblyCount() * APPROX_LOADER_DATA_PER_ASSEMBLY;
11442 #ifdef DACCESS_COMPILE
11445 DomainLocalModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
11449 // Enumerate the DomainLocalModule itself. DLMs are allocated to be larger than
11450 // sizeof(DomainLocalModule) to make room for ClassInit flags and non-GC statics.
11451 // "DAC_ENUM_DTHIS()" probably does not account for this, so we might not enumerate
11452 // all of the ClassInit flags and non-GC statics.
11453 // sizeof(DomainLocalModule) == 0x28
11456 if (m_pDomainFile.IsValid())
11458 m_pDomainFile->EnumMemoryRegions(flags);
11461 if (m_pDynamicClassTable.Load().IsValid())
11463 DacEnumMemoryRegion(dac_cast<TADDR>(m_pDynamicClassTable.Load()),
11464 m_aDynamicEntries * sizeof(DynamicClassInfo));
11466 for (SIZE_T i = 0; i < m_aDynamicEntries; i++)
11468 PTR_DynamicEntry entry = dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[i].m_pDynamicEntry.Load());
11469 if (entry.IsValid())
11471 // sizeof(DomainLocalModule::DynamicEntry) == 8
11479 DomainLocalBlock::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
11482 // Block is contained in AppDomain, don't enum this.
11484 if (m_pModuleSlots.IsValid())
11486 DacEnumMemoryRegion(dac_cast<TADDR>(m_pModuleSlots),
11487 m_aModuleIndices * sizeof(TADDR));
11489 for (SIZE_T i = 0; i < m_aModuleIndices; i++)
11491 PTR_DomainLocalModule domMod = m_pModuleSlots[i];
11492 if (domMod.IsValid())
11494 domMod->EnumMemoryRegions(flags);
11501 BaseDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11507 // This is wrong. Don't do it.
11508 // BaseDomain cannot be instantiated.
11509 // The only thing this code can hope to accomplish is to potentially break
11510 // memory enumeration walking through the derived class if we
11511 // explicitly call the base class enum first.
11512 // DAC_ENUM_VTHIS();
11515 EMEM_OUT(("MEM: %p BaseDomain\n", dac_cast<TADDR>(this)));
11519 AppDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11526 //sizeof(AppDomain) == 0xeb0
11529 BaseDomain::EnumMemoryRegions(flags, false);
11531 // We don't need AppDomain name in triage dumps.
11532 if (flags != CLRDATA_ENUM_MEM_TRIAGE)
11534 m_friendlyName.EnumMemoryRegions(flags);
11537 m_Assemblies.EnumMemoryRegions(flags);
11538 AssemblyIterator assem = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution | kIncludeIntrospection));
11539 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
11541 while (assem.Next(pDomainAssembly.This()))
11543 pDomainAssembly->EnumMemoryRegions(flags);
11546 m_sDomainLocalBlock.EnumMemoryRegions(flags);
11548 m_LoaderAllocator.EnumMemoryRegions(flags);
11552 SystemDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11560 BaseDomain::EnumMemoryRegions(flags, false);
11562 if (m_pSystemFile.IsValid())
11564 m_pSystemFile->EnumMemoryRegions(flags);
11566 if (m_pSystemAssembly.IsValid())
11568 m_pSystemAssembly->EnumMemoryRegions(flags);
11570 if (m_pDefaultDomain.IsValid())
11572 m_pDefaultDomain->EnumMemoryRegions(flags, true);
11575 m_appDomainIndexList.EnumMem();
11576 (&m_appDomainIndexList)->EnumMemoryRegions(flags);
11580 SharedDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11588 BaseDomain::EnumMemoryRegions(flags, false);
11589 #ifdef FEATURE_LOADER_OPTIMIZATION
11590 m_assemblyMap.EnumMemoryRegions(flags);
11591 SharedAssemblyIterator assem;
11592 while (assem.Next())
11594 assem.GetAssembly()->EnumMemoryRegions(flags);
11599 #endif //DACCESS_COMPILE
11602 PTR_LoaderAllocator SystemDomain::GetGlobalLoaderAllocator()
11604 return PTR_LoaderAllocator(PTR_HOST_MEMBER_TADDR(SystemDomain,System(),m_GlobalAllocator));
11607 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
11609 #ifndef CROSSGEN_COMPILE
11610 // Return the total processor time (user and kernel) used by threads executing in this AppDomain so far. The
11611 // result is in 100ns units.
11612 ULONGLONG AppDomain::QueryProcessorUsage()
11622 #ifndef DACCESS_COMPILE
11623 Thread *pThread = NULL;
11625 // Need to update our accumulated processor time count with current values from each thread that is
11626 // currently executing in this domain.
11628 // Take the thread store lock while we enumerate threads.
11629 ThreadStoreLockHolder tsl;
11630 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
11632 // Skip unstarted and dead threads and those that are currently executing in a different AppDomain.
11633 if (pThread->IsUnstarted() || pThread->IsDead() || pThread->GetDomain(INDEBUG(TRUE)) != this)
11636 // Add the amount of time spent by the thread in the AppDomain since the last time we asked (calling
11637 // Thread::QueryThreadProcessorUsage() will reset the thread's counter).
11638 UpdateProcessorUsage(pThread->QueryThreadProcessorUsage());
11640 #endif // !DACCESS_COMPILE
11642 // Return the updated total.
11643 return m_ullTotalProcessorUsage;
11646 // Add to the current count of processor time used by threads within this AppDomain. This API is called by
11647 // threads transitioning between AppDomains.
11648 void AppDomain::UpdateProcessorUsage(ULONGLONG ullAdditionalUsage)
11650 LIMITED_METHOD_CONTRACT;
11652 // Need to be careful to synchronize here, multiple threads could be racing to update this count.
11653 ULONGLONG ullOldValue;
11654 ULONGLONG ullNewValue;
11657 ullOldValue = m_ullTotalProcessorUsage;
11658 ullNewValue = ullOldValue + ullAdditionalUsage;
11659 } while (InterlockedCompareExchange64((LONGLONG*)&m_ullTotalProcessorUsage,
11660 (LONGLONG)ullNewValue,
11661 (LONGLONG)ullOldValue) != (LONGLONG)ullOldValue);
11663 #endif // CROSSGEN_COMPILE
11665 #endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
11667 #if defined(FEATURE_TYPEEQUIVALENCE)
11669 #ifndef DACCESS_COMPILE
11670 TypeEquivalenceHashTable * AppDomain::GetTypeEquivalenceCache()
11676 INJECT_FAULT(COMPlusThrowOM());
11681 // Take the critical section all of the time in debug builds to ensure that it is safe to take
11682 // the critical section in the unusual times when it may actually be needed in retail builds
11684 CrstHolder ch(&m_TypeEquivalenceCrst);
11687 if (m_pTypeEquivalenceTable.Load() == NULL)
11690 CrstHolder ch(&m_TypeEquivalenceCrst);
11692 if (m_pTypeEquivalenceTable.Load() == NULL)
11694 m_pTypeEquivalenceTable = TypeEquivalenceHashTable::Create(this, 12, &m_TypeEquivalenceCrst);
11697 return m_pTypeEquivalenceTable;
11699 #endif //!DACCESS_COMPILE
11701 #endif //FEATURE_TYPEEQUIVALENCE
11703 #if !defined(DACCESS_COMPILE)
11705 //---------------------------------------------------------------------------------------------------------------------
11706 void AppDomain::PublishHostedAssembly(
11707 DomainAssembly * pDomainAssembly)
11717 if (pDomainAssembly->GetFile()->HasHostAssembly())
11719 // We have to serialize all Add operations
11720 CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
11721 _ASSERTE(m_hostAssemblyMap.Lookup(pDomainAssembly->GetFile()->GetHostAssembly()) == nullptr);
11723 // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
11724 HostAssemblyMap::AddPhases addCall;
11726 // 1. Preallocate one element
11727 addCall.PreallocateForAdd(&m_hostAssemblyMap);
11729 // 2. Take the reader lock which can be taken during stack walking
11730 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
11731 ForbidSuspendThreadHolder suspend;
11733 CrstHolder lock(&m_crstHostAssemblyMap);
11734 // 3. Add the element to the hash table (no call out into host)
11735 addCall.Add(pDomainAssembly);
11738 // 4. Cleanup the old memory (if any)
11739 addCall.DeleteOldTable();
11746 //---------------------------------------------------------------------------------------------------------------------
11747 void AppDomain::UpdatePublishHostedAssembly(
11748 DomainAssembly * pAssembly,
11760 if (pAssembly->GetFile()->HasHostAssembly())
11762 // We have to serialize all Add operations
11763 CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
11765 // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
11766 OriginalFileHostAssemblyMap::AddPhases addCall;
11767 bool fAddOrigFile = false;
11769 // For cases where the pefile is being updated
11770 // 1. Preallocate one element
11771 if (pFile != pAssembly->GetFile())
11773 addCall.PreallocateForAdd(&m_hostAssemblyMapForOrigFile);
11774 fAddOrigFile = true;
11778 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
11779 ForbidSuspendThreadHolder suspend;
11781 CrstHolder lock(&m_crstHostAssemblyMap);
11783 // Remove from hash table.
11784 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
11785 m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
11787 // Update PEFile on DomainAssembly. (This may cause the key for the hash to change, which is why we need this function)
11788 pAssembly->UpdatePEFileWorker(pFile);
11790 _ASSERTE(fAddOrigFile == (pAssembly->GetOriginalFile() != pAssembly->GetFile()));
11793 // 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)
11794 addCall.Add(pAssembly);
11797 // Add back to the hashtable (the call to Remove above guarantees that we will not call into host for table reallocation)
11798 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) == nullptr);
11799 m_hostAssemblyMap.Add(pAssembly);
11803 // 4. Cleanup the old memory (if any)
11805 addCall.DeleteOldTable();
11811 pAssembly->UpdatePEFileWorker(pFile);
11815 //---------------------------------------------------------------------------------------------------------------------
11816 void AppDomain::UnPublishHostedAssembly(
11817 DomainAssembly * pAssembly)
11828 if (pAssembly->GetFile()->HasHostAssembly())
11830 ForbidSuspendThreadHolder suspend;
11832 CrstHolder lock(&m_crstHostAssemblyMap);
11833 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
11834 m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
11836 // We also have an entry in m_hostAssemblyMapForOrigFile. Handle that case.
11837 if (pAssembly->GetOriginalFile() != pAssembly->GetFile())
11839 m_hostAssemblyMapForOrigFile.Remove(pAssembly->GetOriginalFile()->GetHostAssembly());
11845 // In AppX processes, all PEAssemblies that are reach this stage should have host binders.
11846 _ASSERTE(!AppX::IsAppXProcess());
11850 #if defined(FEATURE_COMINTEROP)
11851 HRESULT AppDomain::SetWinrtApplicationContext(SString &appLocalWinMD)
11853 STANDARD_VM_CONTRACT;
11855 _ASSERTE(WinRTSupported());
11856 _ASSERTE(m_pWinRtBinder != nullptr);
11858 _ASSERTE(GetTPABinderContext() != NULL);
11859 BINDER_SPACE::ApplicationContext *pApplicationContext = GetTPABinderContext()->GetAppContext();
11860 _ASSERTE(pApplicationContext != NULL);
11862 return m_pWinRtBinder->SetApplicationContext(pApplicationContext, appLocalWinMD);
11865 #endif // FEATURE_COMINTEROP
11867 #endif //!DACCESS_COMPILE
11869 //---------------------------------------------------------------------------------------------------------------------
11870 PTR_DomainAssembly AppDomain::FindAssembly(PTR_ICLRPrivAssembly pHostAssembly)
11881 if (pHostAssembly == nullptr)
11885 ForbidSuspendThreadHolder suspend;
11887 CrstHolder lock(&m_crstHostAssemblyMap);
11888 PTR_DomainAssembly returnValue = m_hostAssemblyMap.Lookup(pHostAssembly);
11889 if (returnValue == NULL)
11891 // If not found in the m_hostAssemblyMap, look in the m_hostAssemblyMapForOrigFile
11892 // This is necessary as it may happen during in a second AppDomain that the PEFile
11893 // first discovered in the AppDomain may not be used by the DomainFile, but the CLRPrivBinderFusion
11894 // will in some cases find the pHostAssembly associated with this no longer used PEFile
11895 // instead of the PEFile that was finally decided upon.
11896 returnValue = m_hostAssemblyMapForOrigFile.Lookup(pHostAssembly);
11899 return returnValue;
11904 #if !defined(DACCESS_COMPILE) && defined(FEATURE_NATIVE_IMAGE_GENERATION)
11906 void ZapperSetBindingPaths(ICorCompilationDomain *pDomain, SString &trustedPlatformAssemblies, SString &platformResourceRoots, SString &appPaths, SString &appNiPaths)
11908 CLRPrivBinderCoreCLR *pBinder = static_cast<CLRPrivBinderCoreCLR*>(((CompilationDomain *)pDomain)->GetFusionContext());
11909 _ASSERTE(pBinder != NULL);
11910 pBinder->SetupBindingPaths(trustedPlatformAssemblies, platformResourceRoots, appPaths, appNiPaths);
11911 #ifdef FEATURE_COMINTEROP
11912 SString emptString;
11913 ((CompilationDomain*)pDomain)->SetWinrtApplicationContext(emptString);
11919 #if !defined(CROSSGEN_COMPILE)
11920 bool IsSingleAppDomain()
11922 STARTUP_FLAGS flags = CorHost2::GetStartupFlags();
11923 if(flags & STARTUP_SINGLE_APPDOMAIN)
11929 bool IsSingleAppDomain()