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 "runtimecallablewrapper.h"
50 #include "mngstdinterfaces.h"
51 #include "olevariant.h"
52 #include "rcwrefcache.h"
53 #include "olecontexthelpers.h"
54 #endif // FEATURE_COMINTEROP
55 #ifdef FEATURE_TYPEEQUIVALENCE
56 #include "typeequivalencehash.hpp"
59 #include "appdomain.inl"
60 #include "typeparse.h"
61 #include "mdaassistants.h"
62 #include "threadpoolrequest.h"
64 #include "nativeoverlapped.h"
68 #endif // !FEATURE_PAL
70 #include "stringarraylist.h"
72 #include "../binder/inc/clrprivbindercoreclr.h"
75 #include "clrprivtypecachewinrt.h"
79 #pragma warning(disable:4324)
83 // this file handles string conversion errors for itself
84 #undef MAKE_TRANSLATIONFAILED
86 // Define these macro's to do strict validation for jit lock and class
87 // init entry leaks. This defines determine if the asserts that
88 // verify for these leaks are defined or not. These asserts can
89 // sometimes go off even if no entries have been leaked so this
90 // defines should be used with caution.
92 // If we are inside a .cctor when the application shut's down then the
93 // class init lock's head will be set and this will cause the assert
96 // If we are jitting a method when the application shut's down then
97 // the jit lock's head will be set causing the assert to go off.
99 //#define STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
101 static const WCHAR DEFAULT_DOMAIN_FRIENDLY_NAME[] = W("DefaultDomain");
102 static const WCHAR OTHER_DOMAIN_FRIENDLY_NAME_PREFIX[] = W("Domain");
104 #define STATIC_OBJECT_TABLE_BUCKET_SIZE 1020
106 #define MAX_URL_LENGTH 2084 // same as INTERNET_MAX_URL_LENGTH
108 //#define _DEBUG_ADUNLOAD 1
110 HRESULT RunDllMain(MethodDesc *pMD, HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved); // clsload.cpp
118 SPTR_IMPL(SystemDomain, SystemDomain, m_pSystemDomain);
119 SVAL_IMPL(ArrayListStatic, SystemDomain, m_appDomainIndexList);
120 SPTR_IMPL(SharedDomain, SharedDomain, m_pSharedDomain);
121 SVAL_IMPL(BOOL, SystemDomain, s_fForceDebug);
122 SVAL_IMPL(BOOL, SystemDomain, s_fForceProfiling);
123 SVAL_IMPL(BOOL, SystemDomain, s_fForceInstrument);
125 #ifndef DACCESS_COMPILE
127 // Base Domain Statics
128 CrstStatic BaseDomain::m_SpecialStaticsCrst;
130 int BaseDomain::m_iNumberOfProcessors = 0;
132 // Shared Domain Statics
134 static BYTE g_pSharedDomainMemory[sizeof(SharedDomain)];
136 // System Domain Statics
137 GlobalStringLiteralMap* SystemDomain::m_pGlobalStringLiteralMap = NULL;
140 static BYTE g_pSystemDomainMemory[sizeof(SystemDomain)];
142 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
143 size_t SystemDomain::m_totalSurvivedBytes = 0;
144 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
146 CrstStatic SystemDomain::m_SystemDomainCrst;
147 CrstStatic SystemDomain::m_DelayedUnloadCrst;
149 ULONG SystemDomain::s_dNumAppDomains = 0;
151 AppDomain * SystemDomain::m_pAppDomainBeingUnloaded = NULL;
152 ADIndex SystemDomain::m_dwIndexOfAppDomainBeingUnloaded;
153 Thread *SystemDomain::m_pAppDomainUnloadRequestingThread = 0;
154 Thread *SystemDomain::m_pAppDomainUnloadingThread = 0;
156 ArrayListStatic SystemDomain::m_appDomainIdList;
158 DWORD SystemDomain::m_dwLowestFreeIndex = 0;
162 // comparison function to be used for matching clsids in our clsid hash table
163 BOOL CompareCLSID(UPTR u1, UPTR u2)
171 INJECT_FAULT(COMPlusThrowOM(););
175 GUID *pguid = (GUID *)(u1 << 1);
176 _ASSERTE(pguid != NULL);
178 MethodTable *pMT= (MethodTable *)u2;
179 _ASSERTE(pMT!= NULL);
182 pMT->GetGuid(&guid, TRUE);
183 if (!IsEqualIID(guid, *pguid))
189 #ifndef CROSSGEN_COMPILE
190 // Constructor for the LargeHeapHandleBucket class.
191 LargeHeapHandleBucket::LargeHeapHandleBucket(LargeHeapHandleBucket *pNext, DWORD Size, BaseDomain *pDomain, BOOL bCrossAD)
195 , m_CurrentEmbeddedFreePos(0) // hint for where to start a search for an embedded free item
202 PRECONDITION(CheckPointer(pDomain));
203 INJECT_FAULT(COMPlusThrowOM(););
207 PTRARRAYREF HandleArrayObj;
209 // Allocate the array in the large object heap.
212 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
213 HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, TRUE);
217 // During AD creation we don't want to assign the handle array to the currently running AD but
218 // to the AD being created. Ensure that AllocateArrayEx doesn't set the AD and then set it here.
219 AppDomain *pAD = pDomain->AsAppDomain();
221 _ASSERTE(pAD->IsBeingCreated());
225 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
226 array = AllocateArrayEx(
227 ClassLoader::LoadArrayTypeThrowing(g_pObjectClass),
234 array->SetAppDomain(pAD);
236 HandleArrayObj = (PTRARRAYREF)array;
239 // Retrieve the pointer to the data inside the array. This is legal since the array
240 // is located in the large object heap and is guaranteed not to move.
241 m_pArrayDataPtr = (OBJECTREF *)HandleArrayObj->GetDataPtr();
243 // Store the array in a strong handle to keep it alive.
244 m_hndHandleArray = pDomain->CreatePinningHandle((OBJECTREF)HandleArrayObj);
248 // Destructor for the LargeHeapHandleBucket class.
249 LargeHeapHandleBucket::~LargeHeapHandleBucket()
258 if (m_hndHandleArray)
260 DestroyPinningHandle(m_hndHandleArray);
261 m_hndHandleArray = NULL;
266 // Allocate handles from the bucket.
267 OBJECTREF *LargeHeapHandleBucket::AllocateHandles(DWORD nRequested)
277 _ASSERTE(nRequested > 0 && nRequested <= GetNumRemainingHandles());
278 _ASSERTE(m_pArrayDataPtr == (OBJECTREF*)((PTRARRAYREF)ObjectFromHandle(m_hndHandleArray))->GetDataPtr());
280 // Store the handles in the buffer that was passed in
281 OBJECTREF* ret = &m_pArrayDataPtr[m_CurrentPos];
282 m_CurrentPos += nRequested;
287 // look for a free item embedded in the table
288 OBJECTREF *LargeHeapHandleBucket::TryAllocateEmbeddedFreeHandle()
298 OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
299 _ASSERTE(pPreallocatedSentinalObject != NULL);
301 for (int i = m_CurrentEmbeddedFreePos; i < m_CurrentPos; i++)
303 if (m_pArrayDataPtr[i] == pPreallocatedSentinalObject)
305 m_CurrentEmbeddedFreePos = i;
306 m_pArrayDataPtr[i] = NULL;
307 return &m_pArrayDataPtr[i];
311 // 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)
313 m_CurrentEmbeddedFreePos = 0;
318 // Maximum bucket size will be 64K on 32-bit and 128K on 64-bit.
319 // We subtract out a small amount to leave room for the object
320 // header and length of the array.
322 #define MAX_BUCKETSIZE (16384 - 4)
324 // Constructor for the LargeHeapHandleTable class.
325 LargeHeapHandleTable::LargeHeapHandleTable(BaseDomain *pDomain, DWORD InitialBucketSize)
328 , m_NextBucketSize(InitialBucketSize)
329 , m_pFreeSearchHint(NULL)
337 PRECONDITION(CheckPointer(pDomain));
338 INJECT_FAULT(COMPlusThrowOM(););
348 // Destructor for the LargeHeapHandleTable class.
349 LargeHeapHandleTable::~LargeHeapHandleTable()
358 // Delete the buckets.
361 LargeHeapHandleBucket *pOld = m_pHead;
362 m_pHead = pOld->GetNext();
367 //*****************************************************************************
369 // LOCKING RULES FOR AllocateHandles() and ReleaseHandles() 12/08/2004
372 // These functions are not protected by any locking in this location but rather the callers are
373 // assumed to be doing suitable locking for the handle table. The handle table itself is
374 // behaving rather like a thread-agnostic collection class -- it doesn't want to know
375 // much about the outside world and so it is just doing its job with no awareness of
378 // The instance in question is
379 // There are two locations you can find a LargeHeapHandleTable
380 // 1) there is one in every BaseDomain, it is used to keep track of the static members
382 // 2) there is one in the System Domain that is used for the GlobalStringLiteralMap
384 // the one in (2) is not the same as the one that is in the BaseDomain object that corresponds
385 // to the SystemDomain -- that one is basically stilborn because the string literals don't go
386 // there and of course the System Domain has no code loaded into it -- only regular
387 // AppDomains (like Domain 0) actually execute code. As a result handle tables are in
388 // practice used either for string literals or for static members but never for both.
389 // At least not at this writing.
391 // Now it's useful to consider what the locking discipline is for these classes.
395 // First case: (easiest) is the statics members
397 // Each BaseDomain has its own critical section
399 // BaseDomain::AllocateObjRefPtrsInLargeTable takes a lock with
400 // CrstHolder ch(&m_LargeHeapHandleTableCrst);
402 // it does this before it calls AllocateHandles which suffices. It does not call ReleaseHandles
403 // at any time (although ReleaseHandles may be called via AllocateHandles if the request
404 // doesn't fit in the current block, the remaining handles at the end of the block are released
405 // automatically as part of allocation/recycling)
407 // note: Recycled handles are only used during String Literal allocation because we only try
408 // to recycle handles if the allocation request is for exactly one handle.
410 // The handles in the BaseDomain handle table are released when the Domain is unloaded
411 // as the GC objects become rootless at that time.
413 // This dispenses with all of the Handle tables except the one that is used for string literals
417 // Second case: Allocation for use in a string literal
419 // AppDomainStringLiteralMap::GetStringLiteral
421 // LargeHeapHandleBlockHolder constructor
423 // m_Data = pOwner->AllocateHandles(nCount);
425 // before doing this AppDomainStringLiteralMap::GetStringLiteral takes this lock
427 // CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
429 // which is the lock for the hash table that it owns
431 // STRINGREF *AppDomainStringLiteralMap::GetInternedString
433 // has a similar call path and uses the same approach and the same lock
434 // this covers all the paths which allocate
438 // Third case: Releases for use in a string literal entry
440 // CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
441 // taken in the AppDomainStringLiteralMap functions below protects the 4 ways that this can happen
445 // in an appdomain unload case
447 // AppDomainStringLiteralMap::~AppDomainStringLiteralMap() takes the lock then
449 // StringLiteralEntry::Release
451 // SystemDomain::GetGlobalStringLiteralMapNoCreate()->RemoveStringLiteralEntry(this)
453 // m_LargeHeapHandleTable.ReleaseHandles((OBJECTREF*)pObjRef, 1);
457 // AppDomainStringLiteralMap::GetStringLiteral() can call StringLiteralEntry::Release in some
458 // error cases, leading to the same stack as above
462 // AppDomainStringLiteralMap::GetInternedString() can call StringLiteralEntry::Release in some
463 // error cases, leading to the same stack as above
467 // The same code paths in 3b and 3c and also end up releasing if an exception is thrown
468 // during their processing. Both these paths use a StringLiteralEntryHolder to assist in cleanup,
469 // the StaticRelease method of the StringLiteralEntry gets called, which in turn calls the
473 // Allocate handles from the large heap handle table.
474 OBJECTREF* LargeHeapHandleTable::AllocateHandles(DWORD nRequested, BOOL bCrossAD)
481 PRECONDITION(nRequested > 0);
482 INJECT_FAULT(COMPlusThrowOM(););
486 // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
488 // the lock must be registered and already held by the caller per contract
490 _ASSERTE(m_pCrstDebug != NULL);
491 _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
494 if (nRequested == 1 && m_cEmbeddedFree != 0)
496 // special casing singleton requests to look for slots that can be re-used
498 // we need to do this because string literals are allocated one at a time and then sometimes
499 // released. we do not wish for the number of handles consumed by string literals to
500 // increase forever as assemblies are loaded and unloaded
502 if (m_pFreeSearchHint == NULL)
503 m_pFreeSearchHint = m_pHead;
505 while (m_pFreeSearchHint)
507 OBJECTREF* pObjRef = m_pFreeSearchHint->TryAllocateEmbeddedFreeHandle();
510 // the slot is to have been prepared with a null ready to go
511 _ASSERTE(*pObjRef == NULL);
515 m_pFreeSearchHint = m_pFreeSearchHint->GetNext();
518 // the search doesn't wrap around so it's possible that we might have embedded free items
519 // and not find them but that's ok, we'll get them on the next alloc... all we're trying to do
520 // is to not have big leaks over time.
524 // Retrieve the remaining number of handles in the bucket.
525 DWORD NumRemainingHandlesInBucket = (m_pHead != NULL) ? m_pHead->GetNumRemainingHandles() : 0;
527 // create a new block if this request doesn't fit in the current block
528 if (nRequested > NumRemainingHandlesInBucket)
532 // mark the handles in that remaining region as available for re-use
533 ReleaseHandles(m_pHead->CurrentPos(), NumRemainingHandlesInBucket);
535 // mark what's left as having been used
536 m_pHead->ConsumeRemaining();
539 // create a new bucket for this allocation
541 // We need a block big enough to hold the requested handles
542 DWORD NewBucketSize = max(m_NextBucketSize, nRequested);
544 m_pHead = new LargeHeapHandleBucket(m_pHead, NewBucketSize, m_pDomain, bCrossAD);
546 m_NextBucketSize = min(m_NextBucketSize * 2, MAX_BUCKETSIZE);
549 return m_pHead->AllocateHandles(nRequested);
552 //*****************************************************************************
553 // Release object handles allocated using AllocateHandles().
554 void LargeHeapHandleTable::ReleaseHandles(OBJECTREF *pObjRef, DWORD nReleased)
561 PRECONDITION(CheckPointer(pObjRef));
565 // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
567 // the lock must be registered and already held by the caller per contract
569 _ASSERTE(m_pCrstDebug != NULL);
570 _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
573 OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
574 _ASSERTE(pPreallocatedSentinalObject != NULL);
577 // Add the released handles to the list of available handles.
578 for (DWORD i = 0; i < nReleased; i++)
580 SetObjectReference(&pObjRef[i], pPreallocatedSentinalObject, NULL);
583 m_cEmbeddedFree += nReleased;
589 // Constructor for the ThreadStaticHandleBucket class.
590 ThreadStaticHandleBucket::ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain)
599 PRECONDITION(CheckPointer(pDomain));
600 INJECT_FAULT(COMPlusThrowOM(););
604 PTRARRAYREF HandleArrayObj;
606 // Allocate the array on the GC heap.
607 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
608 HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, FALSE);
610 // Store the array in a strong handle to keep it alive.
611 m_hndHandleArray = pDomain->CreateStrongHandle((OBJECTREF)HandleArrayObj);
614 // Destructor for the ThreadStaticHandleBucket class.
615 ThreadStaticHandleBucket::~ThreadStaticHandleBucket()
625 if (m_hndHandleArray)
627 DestroyStrongHandle(m_hndHandleArray);
628 m_hndHandleArray = NULL;
632 // Allocate handles from the bucket.
633 OBJECTHANDLE ThreadStaticHandleBucket::GetHandles()
643 return m_hndHandleArray;
646 // Constructor for the ThreadStaticHandleTable class.
647 ThreadStaticHandleTable::ThreadStaticHandleTable(BaseDomain *pDomain)
656 PRECONDITION(CheckPointer(pDomain));
661 // Destructor for the ThreadStaticHandleTable class.
662 ThreadStaticHandleTable::~ThreadStaticHandleTable()
671 // Delete the buckets.
674 ThreadStaticHandleBucket *pOld = m_pHead;
675 m_pHead = pOld->GetNext();
680 // Allocate handles from the large heap handle table.
681 OBJECTHANDLE ThreadStaticHandleTable::AllocateHandles(DWORD nRequested)
688 PRECONDITION(nRequested > 0);
689 INJECT_FAULT(COMPlusThrowOM(););
693 // create a new bucket for this allocation
694 m_pHead = new ThreadStaticHandleBucket(m_pHead, nRequested, m_pDomain);
696 return m_pHead->GetHandles();
699 #endif // CROSSGEN_COMPILE
702 //*****************************************************************************
704 //*****************************************************************************
705 void BaseDomain::Attach()
707 m_SpecialStaticsCrst.Init(CrstSpecialStatics);
710 BaseDomain::BaseDomain()
712 // initialize fields so the domain can be safely destructed
713 // shouldn't call anything that can fail here - use ::Init instead
723 m_fDisableInterfaceCache = FALSE;
725 m_pFusionContext = NULL;
726 m_pTPABinderContext = NULL;
728 // Make sure the container is set to NULL so that it gets loaded when it is used.
729 m_pLargeHeapHandleTable = NULL;
731 #ifndef CROSSGEN_COMPILE
732 // Note that m_handleStore is overridden by app domains
733 m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
735 m_handleStore = NULL;
738 m_pMarshalingData = NULL;
740 m_dwContextStatics = 0;
741 #ifdef FEATURE_COMINTEROP
742 m_pMngStdInterfacesInfo = NULL;
743 m_pWinRtBinder = NULL;
745 m_FileLoadLock.PreInit();
747 m_ClassInitLock.PreInit();
748 m_ILStubGenLock.PreInit();
750 #ifdef FEATURE_CODE_VERSIONING
751 m_codeVersionManager.PreInit(this == (BaseDomain *)g_pSharedDomainMemory);
754 } //BaseDomain::BaseDomain
756 //*****************************************************************************
757 void BaseDomain::Init()
764 INJECT_FAULT(COMPlusThrowOM(););
769 // Initialize the domain locks
772 if (this == reinterpret_cast<BaseDomain*>(&g_pSharedDomainMemory[0]))
773 m_DomainCrst.Init(CrstSharedBaseDomain);
774 else if (this == reinterpret_cast<BaseDomain*>(&g_pSystemDomainMemory[0]))
775 m_DomainCrst.Init(CrstSystemBaseDomain);
777 m_DomainCrst.Init(CrstBaseDomain);
779 m_DomainCacheCrst.Init(CrstAppDomainCache);
780 m_DomainLocalBlockCrst.Init(CrstDomainLocalBlock);
782 m_InteropDataCrst.Init(CrstInteropData, CRST_REENTRANCY);
784 m_WinRTFactoryCacheCrst.Init(CrstWinRTFactoryCache, CRST_UNSAFE_COOPGC);
786 // NOTE: CRST_UNSAFE_COOPGC prevents a GC mode switch to preemptive when entering this crst.
787 // If you remove this flag, we will switch to preemptive mode when entering
788 // m_FileLoadLock, which means all functions that enter it will become
789 // GC_TRIGGERS. (This includes all uses of PEFileListLockHolder, LoadLockHolder, etc.) So be sure
790 // to update the contracts if you remove this flag.
791 m_FileLoadLock.Init(CrstAssemblyLoader,
792 CrstFlags(CRST_HOST_BREAKABLE), TRUE);
795 // The JIT lock and the CCtor locks are at the same level (and marked as
796 // UNSAFE_SAME_LEVEL) because they are all part of the same deadlock detection mechanism. We
797 // see through cycles of JITting and .cctor execution and then explicitly allow the cycle to
798 // be broken by giving access to uninitialized classes. If there is no cycle or if the cycle
799 // involves other locks that arent part of this special deadlock-breaking semantics, then
800 // we continue to block.
802 m_JITLock.Init(CrstJit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
803 m_ClassInitLock.Init(CrstClassInit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
805 m_ILStubGenLock.Init(CrstILStubGen, CrstFlags(CRST_REENTRANCY), TRUE);
807 // Large heap handle table CRST.
808 m_LargeHeapHandleTableCrst.Init(CrstAppDomainHandleTable);
810 m_crstLoaderAllocatorReferences.Init(CrstLoaderAllocatorReferences);
811 // Has to switch thread to GC_NOTRIGGER while being held (see code:BaseDomain#AssemblyListLock)
812 m_crstAssemblyList.Init(CrstAssemblyList, CrstFlags(
813 CRST_GC_NOTRIGGER_WHEN_TAKEN | CRST_DEBUGGER_THREAD | CRST_TAKEN_DURING_SHUTDOWN));
815 // Initialize the EE marshaling data to NULL.
816 m_pMarshalingData = NULL;
818 #ifdef FEATURE_COMINTEROP
819 // Allocate the managed standard interfaces information.
820 m_pMngStdInterfacesInfo = new MngStdInterfacesInfo();
823 CLRPrivBinderWinRT::NamespaceResolutionKind fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_WindowsAPI;
824 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DesignerNamespaceResolutionEnabled) != FALSE)
826 fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_DesignerResolveEvent;
828 CLRPrivTypeCacheWinRT * pWinRtTypeCache = CLRPrivTypeCacheWinRT::GetOrCreateTypeCache();
829 m_pWinRtBinder = CLRPrivBinderWinRT::GetOrCreateBinder(pWinRtTypeCache, fNamespaceResolutionKind);
831 #endif // FEATURE_COMINTEROP
833 // Init the COM Interop data hash
835 LockOwner lock = {&m_InteropDataCrst, IsOwnerOfCrst};
836 m_interopDataHash.Init(0, NULL, false, &lock);
839 m_dwSizedRefHandles = 0;
840 if (!m_iNumberOfProcessors)
842 m_iNumberOfProcessors = GetCurrentProcessCpuCount();
846 #undef LOADERHEAP_PROFILE_COUNTER
848 #ifndef CROSSGEN_COMPILE
849 //*****************************************************************************
850 void BaseDomain::Terminate()
860 m_crstLoaderAllocatorReferences.Destroy();
861 m_DomainCrst.Destroy();
862 m_DomainCacheCrst.Destroy();
863 m_DomainLocalBlockCrst.Destroy();
864 m_InteropDataCrst.Destroy();
866 JitListLockEntry* pJitElement;
867 ListLockEntry* pElement;
869 // All the threads that are in this domain had better be stopped by this
872 // We might be jitting or running a .cctor so we need to empty that queue.
873 pJitElement = m_JITLock.Pop(TRUE);
876 #ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
877 _ASSERTE ((m_JITLock.m_pHead->m_dwRefCount == 1
878 && m_JITLock.m_pHead->m_hrResultCode == E_FAIL) ||
879 dbg_fDrasticShutdown || g_fInControlC);
880 #endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
882 pJitElement = m_JITLock.Pop(TRUE);
887 pElement = m_ClassInitLock.Pop(TRUE);
890 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
891 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
894 pElement = m_ClassInitLock.Pop(TRUE);
896 m_ClassInitLock.Destroy();
898 FileLoadLock* pFileElement;
899 pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
902 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
903 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
905 pFileElement->Release();
906 pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
908 m_FileLoadLock.Destroy();
910 pElement = m_ILStubGenLock.Pop(TRUE);
913 #ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
914 _ASSERTE ((m_ILStubGenLock.m_pHead->m_dwRefCount == 1
915 && m_ILStubGenLock.m_pHead->m_hrResultCode == E_FAIL) ||
916 dbg_fDrasticShutdown || g_fInControlC);
917 #endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
919 pElement = m_ILStubGenLock.Pop(TRUE);
921 m_ILStubGenLock.Destroy();
923 m_LargeHeapHandleTableCrst.Destroy();
925 if (m_pLargeHeapHandleTable != NULL)
927 delete m_pLargeHeapHandleTable;
928 m_pLargeHeapHandleTable = NULL;
933 // Kind of a workaround - during unloading, we need to have an EE halt
934 // around deleting this stuff. So it gets deleted in AppDomain::Terminate()
935 // for those things (because there is a convenient place there.)
936 GetLoaderAllocator()->CleanupStringLiteralMap();
939 #ifdef FEATURE_COMINTEROP
940 if (m_pMngStdInterfacesInfo)
942 delete m_pMngStdInterfacesInfo;
943 m_pMngStdInterfacesInfo = NULL;
946 if (m_pWinRtBinder != NULL)
948 m_pWinRtBinder->Release();
950 #endif // FEATURE_COMINTEROP
952 ClearFusionContext();
954 m_dwSizedRefHandles = 0;
956 #endif // CROSSGEN_COMPILE
958 void BaseDomain::InitVSD()
960 STANDARD_VM_CONTRACT;
962 // This is a workaround for gcc, since it fails to successfully resolve
963 // "TypeIDMap::STARTING_SHARED_DOMAIN_ID" when used within the ?: operator.
965 if (IsSharedDomain())
967 startingId = TypeIDMap::STARTING_SHARED_DOMAIN_ID;
971 startingId = TypeIDMap::STARTING_UNSHARED_DOMAIN_ID;
974 // By passing false as the last parameter, interfaces loaded in the
975 // shared domain will not be given fat type ids if RequiresFatDispatchTokens
976 // is set. This is correct, as the fat dispatch tokens are only needed to solve
977 // uniqueness problems involving domain specific types.
978 m_typeIDMap.Init(startingId, 2, !IsSharedDomain());
980 #ifndef CROSSGEN_COMPILE
981 GetLoaderAllocator()->InitVirtualCallStubManager(this);
985 #ifndef CROSSGEN_COMPILE
987 DWORD BaseDomain::AllocateContextStaticsOffset(DWORD* pOffsetSlot)
996 CrstHolder ch(&m_SpecialStaticsCrst);
998 DWORD dwOffset = *pOffsetSlot;
1000 if (dwOffset == (DWORD)-1)
1002 // Allocate the slot
1003 dwOffset = m_dwContextStatics++;
1004 *pOffsetSlot = dwOffset;
1010 void BaseDomain::ClearFusionContext()
1020 if(m_pFusionContext) {
1021 m_pFusionContext->Release();
1022 m_pFusionContext = NULL;
1024 if (m_pTPABinderContext) {
1025 m_pTPABinderContext->Release();
1026 m_pTPABinderContext = NULL;
1030 #ifdef FEATURE_PREJIT
1031 void AppDomain::DeleteNativeCodeRanges()
1042 // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized
1043 // and yet we are destroying it. (This is the case if we OOM during AppDomain creation.)
1044 if (m_Assemblies.IsEmpty())
1047 // Shutdown assemblies
1048 AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad) );
1049 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1051 while (i.Next(pDomainAssembly.This()))
1053 Assembly * assembly = pDomainAssembly->m_pAssembly;
1054 if ((assembly != NULL) && !assembly->IsDomainNeutral())
1055 assembly->DeleteNativeCodeRanges();
1060 void AppDomain::ShutdownAssemblies()
1070 // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized
1071 // and yet we are destroying it. (This is the case if we OOM during AppDomain creation.)
1072 if (m_Assemblies.IsEmpty())
1075 // Shutdown assemblies
1076 // has two stages because Terminate needs info from the Assembly's dependencies
1078 // Stage 1: call code:Assembly::Terminate
1079 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1080 kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
1081 DomainAssembly * pDomainAssembly = NULL;
1083 while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1085 // Note: cannot use DomainAssembly::GetAssembly() here as it asserts that the assembly has been
1086 // loaded to at least the FILE_LOAD_ALLOCATE level. Since domain shutdown can take place
1087 // asynchronously this property cannot be guaranteed. Access the m_pAssembly field directly instead.
1088 Assembly * assembly = pDomainAssembly->m_pAssembly;
1089 if (assembly && !assembly->IsDomainNeutral())
1090 assembly->Terminate();
1093 // Stage 2: Clear the list of assemblies
1094 i = IterateAssembliesEx((AssemblyIterationFlags)(
1095 kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
1096 while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1098 // We are in shutdown path, no one else can get to the list anymore
1099 delete pDomainAssembly;
1101 m_Assemblies.Clear(this);
1103 // Stage 2: Clear the loader allocators registered for deletion from code:Assembly:Terminate calls in
1105 // Note: It is not clear to me why we cannot delete the loader allocator from within
1106 // code:DomainAssembly::~DomainAssembly
1107 ShutdownFreeLoaderAllocators(FALSE);
1108 } // AppDomain::ShutdownAssemblies
1110 void AppDomain::ShutdownFreeLoaderAllocators(BOOL bFromManagedCode)
1112 // If we're called from managed code (i.e. the finalizer thread) we take a lock in
1113 // LoaderAllocator::CleanupFailedTypeInit, which may throw. Otherwise we're called
1114 // from the app-domain shutdown path in which we can avoid taking the lock.
1118 if (bFromManagedCode) THROWS; else NOTHROW;
1124 CrstHolder ch(GetLoaderAllocatorReferencesLock());
1126 // Shutdown the LoaderAllocators associated with collectible assemblies
1127 while (m_pDelayedLoaderAllocatorUnloadList != NULL)
1129 LoaderAllocator * pCurrentLoaderAllocator = m_pDelayedLoaderAllocatorUnloadList;
1130 // Remove next loader allocator from the list
1131 m_pDelayedLoaderAllocatorUnloadList = m_pDelayedLoaderAllocatorUnloadList->m_pLoaderAllocatorDestroyNext;
1133 if (bFromManagedCode)
1135 // For loader allocator finalization, we need to be careful about cleaning up per-appdomain allocations
1136 // and synchronizing with GC using delay unload list. We need to wait for next Gen2 GC to finish to ensure
1137 // that GC heap does not have any references to the MethodTables being unloaded.
1139 pCurrentLoaderAllocator->CleanupFailedTypeInit();
1141 pCurrentLoaderAllocator->CleanupHandles();
1144 SystemDomain::System()->AddToDelayedUnloadList(pCurrentLoaderAllocator);
1148 // For appdomain unload, delete the loader allocator right away
1149 delete pCurrentLoaderAllocator;
1152 } // AppDomain::ShutdownFreeLoaderAllocators
1154 //---------------------------------------------------------------------------------------
1156 // Register the loader allocator for deletion in code:AppDomain::ShutdownFreeLoaderAllocators.
1158 void AppDomain::RegisterLoaderAllocatorForDeletion(LoaderAllocator * pLoaderAllocator)
1169 CrstHolder ch(GetLoaderAllocatorReferencesLock());
1171 pLoaderAllocator->m_pLoaderAllocatorDestroyNext = m_pDelayedLoaderAllocatorUnloadList;
1172 m_pDelayedLoaderAllocatorUnloadList = pLoaderAllocator;
1175 void AppDomain::ShutdownNativeDllSearchDirectories()
1177 LIMITED_METHOD_CONTRACT;
1178 // Shutdown assemblies
1179 PathIterator i = IterateNativeDllSearchDirectories();
1186 m_NativeDllSearchDirectories.Clear();
1189 void AppDomain::ReleaseDomainBoundInfo()
1198 // Shutdown assemblies
1199 m_AssemblyCache.OnAppDomainUnload();
1201 AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeFailedToLoad) );
1202 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1204 while (i.Next(pDomainAssembly.This()))
1206 pDomainAssembly->ReleaseManagedData();
1210 void AppDomain::ReleaseFiles()
1212 STANDARD_VM_CONTRACT;
1214 // Shutdown assemblies
1215 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1216 kIncludeLoaded | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeLoading));
1217 CollectibleAssemblyHolder<DomainAssembly *> pAsm;
1219 while (i.Next(pAsm.This()))
1221 if (pAsm->GetCurrentAssembly() == NULL)
1223 // Might be domain neutral or not, but should have no live objects as it has not been
1224 // really loaded yet. Just reset it.
1225 _ASSERTE(FitsIn<DWORD>(i.GetIndex()));
1226 m_Assemblies.Set(this, static_cast<DWORD>(i.GetIndex()), NULL);
1227 delete pAsm.Extract();
1231 if (!pAsm->GetCurrentAssembly()->IsDomainNeutral())
1232 pAsm->ReleaseFiles();
1235 } // AppDomain::ReleaseFiles
1238 OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate, BOOL bCrossAD)
1245 PRECONDITION((nRequested > 0));
1246 INJECT_FAULT(COMPlusThrowOM(););
1250 if (ppLazyAllocate && *ppLazyAllocate)
1252 // Allocation already happened
1253 return *ppLazyAllocate;
1256 // Enter preemptive state, take the lock and go back to cooperative mode.
1258 CrstHolder ch(&m_LargeHeapHandleTableCrst);
1261 if (ppLazyAllocate && *ppLazyAllocate)
1263 // Allocation already happened
1264 return *ppLazyAllocate;
1267 // Make sure the large heap handle table is initialized.
1268 if (!m_pLargeHeapHandleTable)
1269 InitLargeHeapHandleTable();
1271 // Allocate the handles.
1272 OBJECTREF* result = m_pLargeHeapHandleTable->AllocateHandles(nRequested, bCrossAD);
1276 *ppLazyAllocate = result;
1282 #endif // CROSSGEN_COMPILE
1284 #endif // !DACCESS_COMPILE
1287 PTR_BaseDomain BaseDomain::ComputeBaseDomain(
1288 BaseDomain * pGenericDefinitionDomain, // the domain that owns the generic type or method
1289 Instantiation classInst, // the type arguments to the type (if any)
1290 Instantiation methodInst) // the type arguments to the method (if any)
1292 CONTRACT(PTR_BaseDomain)
1298 POSTCONDITION(CheckPointer(RETVAL));
1304 if (pGenericDefinitionDomain && pGenericDefinitionDomain->IsAppDomain())
1305 RETURN PTR_BaseDomain(pGenericDefinitionDomain);
1307 for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
1309 PTR_BaseDomain pArgDomain = classInst[i].GetDomain();
1310 if (pArgDomain->IsAppDomain())
1314 for (DWORD i = 0; i < methodInst.GetNumArgs(); i++)
1316 PTR_BaseDomain pArgDomain = methodInst[i].GetDomain();
1317 if (pArgDomain->IsAppDomain())
1320 RETURN (pGenericDefinitionDomain ?
1321 PTR_BaseDomain(pGenericDefinitionDomain) :
1322 PTR_BaseDomain(SystemDomain::System()));
1325 PTR_BaseDomain BaseDomain::ComputeBaseDomain(TypeKey * pKey)
1337 if (pKey->GetKind() == ELEMENT_TYPE_CLASS)
1338 return BaseDomain::ComputeBaseDomain(pKey->GetModule()->GetDomain(),
1339 pKey->GetInstantiation());
1340 else if (pKey->GetKind() != ELEMENT_TYPE_FNPTR)
1341 return pKey->GetElementType().GetDomain();
1343 return BaseDomain::ComputeBaseDomain(NULL,Instantiation(pKey->GetRetAndArgTypes(), pKey->GetNumArgs()+1));
1350 #ifndef DACCESS_COMPILE
1352 // Insert class in the hash table
1353 void AppDomain::InsertClassForCLSID(MethodTable* pMT, BOOL fForceInsert /*=FALSE*/)
1360 INJECT_FAULT(COMPlusThrowOM(););
1366 // Ensure that registered classes are activated for allocation
1367 pMT->EnsureInstanceActive();
1369 // Note that it is possible for multiple classes to claim the same CLSID, and in such a
1370 // case it is arbitrary which one we will return for a future query for a given app domain.
1372 pMT->GetGuid(&cvid, fForceInsert);
1374 if (!IsEqualIID(cvid, GUID_NULL))
1376 //<TODO>@todo get a better key</TODO>
1377 LPVOID val = (LPVOID)pMT;
1379 LockHolder lh(this);
1381 if (LookupClass(cvid) != pMT)
1383 m_clsidHash.InsertValue(GetKeyFromGUID(&cvid), val);
1389 void AppDomain::InsertClassForCLSID(MethodTable* pMT, GUID *pGuid)
1394 PRECONDITION(CheckPointer(pMT));
1395 PRECONDITION(CheckPointer(pGuid));
1399 LPVOID val = (LPVOID)pMT;
1401 LockHolder lh(this);
1404 if (LookupClass(*cvid) != pMT)
1406 m_clsidHash.InsertValue(GetKeyFromGUID(pGuid), val);
1412 #endif // DACCESS_COMPILE
1414 #ifdef FEATURE_COMINTEROP
1416 #ifndef DACCESS_COMPILE
1417 void AppDomain::CacheTypeByName(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1419 WRAPPER_NO_CONTRACT;
1420 LockHolder lh(this);
1421 CacheTypeByNameWorker(ssClassName, vCacheVersion, typeHandle, bFlags, bReplaceExisting);
1424 void AppDomain::CacheTypeByNameWorker(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1430 PRECONDITION(!typeHandle.IsNull());
1434 NewArrayHolder<WCHAR> wzClassName(DuplicateStringThrowing(ssClassName.GetUnicode()));
1436 if (m_vNameToTypeMapVersion != vCacheVersion)
1439 if (m_pNameToTypeMap == nullptr)
1441 m_pNameToTypeMap = new NameToTypeMapTable();
1444 NameToTypeMapEntry e;
1445 e.m_key.m_wzName = wzClassName;
1446 e.m_key.m_cchName = ssClassName.GetCount();
1447 e.m_typeHandle = typeHandle;
1448 e.m_nEpoch = this->m_nEpoch;
1449 e.m_bFlags = bFlags;
1450 if (!bReplaceExisting)
1451 m_pNameToTypeMap->Add(e);
1453 m_pNameToTypeMap->AddOrReplace(e);
1455 wzClassName.SuppressRelease();
1457 #endif // DACCESS_COMPILE
1459 TypeHandle AppDomain::LookupTypeByName(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1461 WRAPPER_NO_CONTRACT;
1462 LockHolder lh(this);
1463 return LookupTypeByNameWorker(ssClassName, pvCacheVersion, pbFlags);
1466 TypeHandle AppDomain::LookupTypeByNameWorker(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1473 PRECONDITION(CheckPointer(pbFlags, NULL_OK));
1477 *pvCacheVersion = m_vNameToTypeMapVersion;
1479 if (m_pNameToTypeMap == nullptr)
1480 return TypeHandle(); // a null TypeHandle
1482 NameToTypeMapEntry::Key key;
1483 key.m_cchName = ssClassName.GetCount();
1484 key.m_wzName = ssClassName.GetUnicode();
1486 const NameToTypeMapEntry * pEntry = m_pNameToTypeMap->LookupPtr(key);
1488 return TypeHandle(); // a null TypeHandle
1490 if (pbFlags != NULL)
1491 *pbFlags = pEntry->m_bFlags;
1493 return pEntry->m_typeHandle;
1496 PTR_MethodTable AppDomain::LookupTypeByGuid(const GUID & guid)
1510 GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1511 sGuid.Append(wszGuid);
1514 TypeHandle th = LookupTypeByName(sGuid, &ver, NULL);
1518 _ASSERTE(!th.IsTypeDesc());
1519 return th.AsMethodTable();
1522 #ifdef FEATURE_PREJIT
1525 // Next look in each ngen'ed image in turn
1526 AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1527 kIncludeLoaded | kIncludeExecution));
1528 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1529 while (assemblyIterator.Next(pDomainAssembly.This()))
1531 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1533 DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1536 Module * pModule = i.GetLoadedModule();
1537 if (!pModule->HasNativeImage())
1539 _ASSERTE(!pModule->IsCollectible());
1540 PTR_MethodTable pMT = pModule->LookupTypeByGuid(guid);
1548 #endif // FEATURE_PREJIT
1552 #ifndef DACCESS_COMPILE
1553 void AppDomain::CacheWinRTTypeByGuid(TypeHandle typeHandle)
1560 PRECONDITION(!typeHandle.IsTypeDesc());
1561 PRECONDITION(CanCacheWinRTTypeByGuid(typeHandle));
1565 PTR_MethodTable pMT = typeHandle.AsMethodTable();
1568 if (pMT->GetGuidForWinRT(&guid))
1574 GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1575 sGuid.Append(wszGuid);
1582 LockHolder lh(this);
1583 th = LookupTypeByNameWorker(sGuid, &vCacheVersion, &bFlags);
1587 // no other entry with the same GUID exists in the cache
1588 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags);
1590 else if (typeHandle.AsMethodTable() != th.AsMethodTable() && th.IsProjectedFromWinRT())
1592 // If we found a native WinRT type cached with the same GUID, replace it.
1593 // Otherwise simply add the new mapping to the cache.
1594 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags, TRUE);
1599 #endif // DACCESS_COMPILE
1601 void AppDomain::GetCachedWinRTTypes(
1602 SArray<PTR_MethodTable> * pTypes,
1603 SArray<GUID> * pGuids,
1616 LockHolder lh(this);
1618 for (auto it = m_pNameToTypeMap->Begin(), end = m_pNameToTypeMap->End();
1622 NameToTypeMapEntry entry = (NameToTypeMapEntry)(*it);
1623 TypeHandle th = entry.m_typeHandle;
1624 if (th.AsMethodTable() != NULL &&
1625 entry.m_key.m_wzName[0] == W('{') &&
1626 entry.m_nEpoch >= minEpoch)
1628 _ASSERTE(!th.IsTypeDesc());
1629 PTR_MethodTable pMT = th.AsMethodTable();
1630 // we're parsing the GUID value from the cache, because projected types do not cache the
1631 // COM GUID in their GetGuid() but rather the legacy GUID
1633 if (LPWSTRToGuid(&iid, entry.m_key.m_wzName, 38) && iid != GUID_NULL)
1635 pTypes->Append(pMT);
1636 pGuids->Append(iid);
1641 #ifdef FEATURE_PREJIT
1642 // Next look in each ngen'ed image in turn
1643 AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1644 kIncludeLoaded | kIncludeExecution));
1645 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1646 while (assemblyIterator.Next(pDomainAssembly.This()))
1648 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1650 DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1653 Module * pModule = i.GetLoadedModule();
1654 if (!pModule->HasNativeImage())
1656 _ASSERTE(!pModule->IsCollectible());
1658 pModule->GetCachedWinRTTypes(pTypes, pGuids);
1661 #endif // FEATURE_PREJIT
1663 if (pCurEpoch != NULL)
1664 *pCurEpoch = m_nEpoch;
1668 #ifndef CROSSGEN_COMPILE
1669 #ifndef DACCESS_COMPILE
1671 void WinRTFactoryCacheTraits::OnDestructPerEntryCleanupAction(const WinRTFactoryCacheEntry& e)
1673 WRAPPER_NO_CONTRACT;
1674 if (e.m_pCtxEntry != NULL)
1676 e.m_pCtxEntry->Release();
1678 // the AD is going away, no need to destroy the OBJECTHANDLE
1681 void AppDomain::CacheWinRTFactoryObject(MethodTable *pClassMT, OBJECTREF *refFactory, LPVOID lpCtxCookie)
1688 PRECONDITION(CheckPointer(pClassMT));
1692 CtxEntryHolder pNewCtxEntry;
1693 if (lpCtxCookie != NULL)
1695 // We don't want to insert the context cookie in the cache because it's just an address
1696 // of an internal COM data structure which will be freed when the apartment is torn down.
1697 // What's worse, if another apartment is later created, its context cookie may have exactly
1698 // the same value leading to incorrect cache hits. We'll use our CtxEntry instead which
1699 // is ref-counted and keeps the COM data structure alive even after the apartment ceases
1701 pNewCtxEntry = CtxEntryCache::GetCtxEntryCache()->FindCtxEntry(lpCtxCookie, GetThread());
1704 WinRTFactoryCacheLockHolder lh(this);
1706 if (m_pWinRTFactoryCache == nullptr)
1708 m_pWinRTFactoryCache = new WinRTFactoryCache();
1711 WinRTFactoryCacheEntry *pEntry = const_cast<WinRTFactoryCacheEntry*>(m_pWinRTFactoryCache->LookupPtr(pClassMT));
1715 // No existing entry for this cache
1718 WinRTFactoryCacheEntry e;
1720 OBJECTHANDLEHolder ohNewHandle(CreateHandle(*refFactory));
1723 e.m_pCtxEntry = pNewCtxEntry;
1724 e.m_ohFactoryObject = ohNewHandle;
1726 m_pWinRTFactoryCache->Add(e);
1728 // suppress release of the CtxEntry and handle after we successfully inserted the new entry
1729 pNewCtxEntry.SuppressRelease();
1730 ohNewHandle.SuppressRelease();
1737 // release the old CtxEntry and update the entry
1738 CtxEntry *pTemp = pNewCtxEntry.Extract();
1739 pNewCtxEntry = pEntry->m_pCtxEntry;
1740 pEntry->m_pCtxEntry = pTemp;
1742 IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
1743 mgr->StoreObjectInHandle(pEntry->m_ohFactoryObject, OBJECTREFToObject(*refFactory));
1747 OBJECTREF AppDomain::LookupWinRTFactoryObject(MethodTable *pClassMT, LPVOID lpCtxCookie)
1754 PRECONDITION(CheckPointer(pClassMT));
1755 PRECONDITION(CheckPointer(m_pWinRTFactoryCache, NULL_OK));
1760 if (m_pWinRTFactoryCache == nullptr)
1764 // Retrieve cached factory
1766 WinRTFactoryCacheLockHolder lh(this);
1768 const WinRTFactoryCacheEntry *pEntry = m_pWinRTFactoryCache->LookupPtr(pClassMT);
1773 // Ignore factories from a different context, unless lpCtxCookie == NULL,
1774 // which means the factory is free-threaded
1775 // Note that we cannot touch the RCW to retrieve cookie at this point
1776 // because the RCW might belong to a STA thread and that STA thread might die
1777 // and take the RCW with it. Therefore we have to save cookie in this cache
1779 if (pEntry->m_pCtxEntry == NULL || pEntry->m_pCtxEntry->GetCtxCookie() == lpCtxCookie)
1780 return ObjectFromHandle(pEntry->m_ohFactoryObject);
1785 void AppDomain::RemoveWinRTFactoryObjects(LPVOID pCtxCookie)
1795 if (m_pWinRTFactoryCache == nullptr)
1798 // helper class for delayed CtxEntry cleanup
1799 class CtxEntryListReleaseHolder
1802 CQuickArrayList<CtxEntry *> m_list;
1804 ~CtxEntryListReleaseHolder()
1814 for (SIZE_T i = 0; i < m_list.Size(); i++)
1816 m_list[i]->Release();
1819 } ctxEntryListReleaseHolder;
1823 WinRTFactoryCacheLockHolder lh(this);
1825 // Go through the hash table and remove items in the given context
1826 for (WinRTFactoryCache::Iterator it = m_pWinRTFactoryCache->Begin(); it != m_pWinRTFactoryCache->End(); it++)
1828 if (it->m_pCtxEntry != NULL && it->m_pCtxEntry->GetCtxCookie() == pCtxCookie)
1830 // Releasing the CtxEntry may trigger GC which we can't do under the lock so we push
1831 // it on our local list and release them all after we're done iterating the hashtable.
1832 ctxEntryListReleaseHolder.m_list.Push(it->m_pCtxEntry);
1834 DestroyHandle(it->m_ohFactoryObject);
1835 m_pWinRTFactoryCache->Remove(it);
1841 OBJECTREF AppDomain::GetMissingObject()
1854 FieldDesc *pValueFD = MscorlibBinder::GetField(FIELD__MISSING__VALUE);
1856 pValueFD->CheckRunClassInitThrowing();
1858 // Retrieve the value static field and store it.
1859 OBJECTHANDLE hndMissing = CreateHandle(pValueFD->GetStaticOBJECTREF());
1861 if (FastInterlockCompareExchangePointer(&m_hndMissing, hndMissing, NULL) != NULL)
1863 // Exchanged failed. The m_hndMissing did not equal NULL and was returned.
1864 DestroyHandle(hndMissing);
1868 return ObjectFromHandle(m_hndMissing);
1871 #endif // DACCESS_COMPILE
1872 #endif //CROSSGEN_COMPILE
1873 #endif // FEATURE_COMINTEROP
1875 #ifndef DACCESS_COMPILE
1877 EEMarshalingData *BaseDomain::GetMarshalingData()
1879 CONTRACT (EEMarshalingData*)
1884 INJECT_FAULT(COMPlusThrowOM());
1885 POSTCONDITION(CheckPointer(m_pMarshalingData));
1889 if (!m_pMarshalingData)
1892 CrstHolder holder(&m_InteropDataCrst);
1894 if (!m_pMarshalingData)
1896 LoaderHeap* pHeap = GetLoaderAllocator()->GetLowFrequencyHeap();
1897 m_pMarshalingData = new (pHeap) EEMarshalingData(this, pHeap, &m_DomainCrst);
1901 RETURN m_pMarshalingData;
1904 void BaseDomain::DeleteMarshalingData()
1914 // We are in shutdown - no need to take any lock
1915 if (m_pMarshalingData)
1917 delete m_pMarshalingData;
1918 m_pMarshalingData = NULL;
1922 #ifndef CROSSGEN_COMPILE
1924 STRINGREF *BaseDomain::IsStringInterned(STRINGREF *pString)
1931 PRECONDITION(CheckPointer(pString));
1932 INJECT_FAULT(COMPlusThrowOM(););
1936 return GetLoaderAllocator()->IsStringInterned(pString);
1939 STRINGREF *BaseDomain::GetOrInternString(STRINGREF *pString)
1946 PRECONDITION(CheckPointer(pString));
1947 INJECT_FAULT(COMPlusThrowOM(););
1951 return GetLoaderAllocator()->GetOrInternString(pString);
1954 void BaseDomain::InitLargeHeapHandleTable()
1961 PRECONDITION(m_pLargeHeapHandleTable==NULL);
1962 INJECT_FAULT(COMPlusThrowOM(););
1966 m_pLargeHeapHandleTable = new LargeHeapHandleTable(this, STATIC_OBJECT_TABLE_BUCKET_SIZE);
1969 m_pLargeHeapHandleTable->RegisterCrstDebug(&m_LargeHeapHandleTableCrst);
1973 #ifdef FEATURE_COMINTEROP
1974 MethodTable* AppDomain::GetLicenseInteropHelperMethodTable()
1983 if(m_pLicenseInteropHelperMT == NULL)
1985 // Do this work outside of the lock so we don't have an unbreakable lock condition
1987 TypeHandle licenseMgrTypeHnd;
1988 MethodDescCallSite loadLM(METHOD__MARSHAL__LOAD_LICENSE_MANAGER);
1990 licenseMgrTypeHnd = (MethodTable*) loadLM.Call_RetLPVOID((ARG_SLOT*)NULL);
1993 // Look up this method by name, because the type is actually declared in System.dll. <TODO>@todo: why?</TODO>
1996 MethodDesc *pGetLIHMD = MemberLoader::FindMethod(licenseMgrTypeHnd.AsMethodTable(),
1997 "GetLicenseInteropHelperType", &gsig_SM_Void_RetIntPtr);
1998 _ASSERTE(pGetLIHMD);
2000 TypeHandle lihTypeHnd;
2002 MethodDescCallSite getLIH(pGetLIHMD);
2003 lihTypeHnd = (MethodTable*) getLIH.Call_RetLPVOID((ARG_SLOT*)NULL);
2005 BaseDomain::LockHolder lh(this);
2007 if(m_pLicenseInteropHelperMT == NULL)
2008 m_pLicenseInteropHelperMT = lihTypeHnd.AsMethodTable();
2010 return m_pLicenseInteropHelperMT;
2013 COMorRemotingFlag AppDomain::GetComOrRemotingFlag()
2023 // 0. check if the value is already been set
2024 if (m_COMorRemotingFlag != COMorRemoting_NotInitialized)
2025 return m_COMorRemotingFlag;
2027 // 1. check whether the process is AppX
2028 if (AppX::IsAppXProcess())
2030 // do not use Remoting in AppX
2031 m_COMorRemotingFlag = COMorRemoting_COM;
2032 return m_COMorRemotingFlag;
2035 // 2. check the xml file
2036 m_COMorRemotingFlag = GetPreferComInsteadOfManagedRemotingFromConfigFile();
2037 if (m_COMorRemotingFlag != COMorRemoting_NotInitialized)
2039 return m_COMorRemotingFlag;
2042 // 3. check the global setting
2043 if (NULL != g_pConfig && g_pConfig->ComInsteadOfManagedRemoting())
2045 m_COMorRemotingFlag = COMorRemoting_COM;
2049 m_COMorRemotingFlag = COMorRemoting_Remoting;
2052 return m_COMorRemotingFlag;
2055 BOOL AppDomain::GetPreferComInsteadOfManagedRemoting()
2057 WRAPPER_NO_CONTRACT;
2059 return (GetComOrRemotingFlag() == COMorRemoting_COM);
2062 COMorRemotingFlag AppDomain::GetPreferComInsteadOfManagedRemotingFromConfigFile()
2072 return COMorRemoting_COM;
2074 #endif // FEATURE_COMINTEROP
2076 #endif // CROSSGEN_COMPILE
2078 //*****************************************************************************
2079 //*****************************************************************************
2080 //*****************************************************************************
2082 void *SystemDomain::operator new(size_t size, void *pInPlace)
2084 LIMITED_METHOD_CONTRACT;
2089 void SystemDomain::operator delete(void *pMem)
2091 LIMITED_METHOD_CONTRACT;
2092 // Do nothing - new() was in-place
2096 void SystemDomain::SetCompilationOverrides(BOOL fForceDebug,
2097 BOOL fForceProfiling,
2098 BOOL fForceInstrument)
2100 LIMITED_METHOD_CONTRACT;
2101 s_fForceDebug = fForceDebug;
2102 s_fForceProfiling = fForceProfiling;
2103 s_fForceInstrument = fForceInstrument;
2106 #endif //!DACCESS_COMPILE
2108 void SystemDomain::GetCompilationOverrides(BOOL * fForceDebug,
2109 BOOL * fForceProfiling,
2110 BOOL * fForceInstrument)
2112 LIMITED_METHOD_DAC_CONTRACT;
2113 *fForceDebug = s_fForceDebug;
2114 *fForceProfiling = s_fForceProfiling;
2115 *fForceInstrument = s_fForceInstrument;
2118 #ifndef DACCESS_COMPILE
2120 void SystemDomain::Attach()
2127 PRECONDITION(m_pSystemDomain == NULL);
2128 INJECT_FAULT(COMPlusThrowOM(););
2132 #ifndef CROSSGEN_COMPILE
2133 // Initialize stub managers
2134 PrecodeStubManager::Init();
2135 DelegateInvokeStubManager::Init();
2136 JumpStubStubManager::Init();
2137 RangeSectionStubManager::Init();
2138 ILStubManager::Init();
2139 InteropDispatchStubManager::Init();
2140 StubLinkStubManager::Init();
2142 ThunkHeapStubManager::Init();
2144 TailCallStubManager::Init();
2146 PerAppDomainTPCountList::InitAppDomainIndexList();
2147 #endif // CROSSGEN_COMPILE
2149 m_appDomainIndexList.Init();
2150 m_appDomainIdList.Init();
2152 m_SystemDomainCrst.Init(CrstSystemDomain, (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN));
2153 m_DelayedUnloadCrst.Init(CrstSystemDomainDelayedUnloadList, CRST_UNSAFE_COOPGC);
2155 // Initialize the ID dispenser that is used for domain neutral module IDs
2156 g_pModuleIndexDispenser = new IdDispenser();
2158 // Create the global SystemDomain and initialize it.
2159 m_pSystemDomain = new (&g_pSystemDomainMemory[0]) SystemDomain();
2160 // No way it can fail since g_pSystemDomainMemory is a static array.
2161 CONSISTENCY_CHECK(CheckPointer(m_pSystemDomain));
2163 LOG((LF_CLASSLOADER,
2165 "Created system domain at %p\n",
2168 // We need to initialize the memory pools etc. for the system domain.
2169 m_pSystemDomain->BaseDomain::Init(); // Setup the memory heaps
2171 // Create the default domain
2172 m_pSystemDomain->CreateDefaultDomain();
2173 SharedDomain::Attach();
2175 // Each domain gets its own ReJitManager, and ReJitManager has its own static
2176 // initialization to run
2177 ReJitManager::InitStatic();
2180 #ifndef CROSSGEN_COMPILE
2182 void SystemDomain::DetachBegin()
2184 WRAPPER_NO_CONTRACT;
2185 // Shut down the domain and its children (but don't deallocate anything just
2188 // TODO: we should really not running managed DLLMain during process detach.
2189 if (GetThread() == NULL)
2195 m_pSystemDomain->Stop();
2198 void SystemDomain::DetachEnd()
2207 // Shut down the domain and its children (but don't deallocate anything just
2212 m_pSystemDomain->ClearFusionContext();
2213 if (m_pSystemDomain->m_pDefaultDomain)
2214 m_pSystemDomain->m_pDefaultDomain->ClearFusionContext();
2218 void SystemDomain::Stop()
2220 WRAPPER_NO_CONTRACT;
2221 AppDomainIterator i(TRUE);
2224 if (i.GetDomain()->m_Stage < AppDomain::STAGE_CLEARED)
2225 i.GetDomain()->Stop();
2229 void SystemDomain::Terminate() // bNotifyProfiler is ignored
2239 // This ignores the refences and terminates the appdomains
2240 AppDomainIterator i(FALSE);
2244 delete i.GetDomain();
2245 // Keep the iterator from Releasing the current domain
2246 i.m_pCurrent = NULL;
2249 if (m_pSystemFile != NULL) {
2250 m_pSystemFile->Release();
2251 m_pSystemFile = NULL;
2254 m_pSystemAssembly = NULL;
2257 delete[] m_pwDevpath;
2263 if (m_pGlobalStringLiteralMap) {
2264 delete m_pGlobalStringLiteralMap;
2265 m_pGlobalStringLiteralMap = NULL;
2269 SharedDomain::Detach();
2271 BaseDomain::Terminate();
2273 #ifdef FEATURE_COMINTEROP
2274 if (g_pRCWCleanupList != NULL)
2275 delete g_pRCWCleanupList;
2276 #endif // FEATURE_COMINTEROP
2277 m_GlobalAllocator.Terminate();
2281 void SystemDomain::PreallocateSpecialObjects()
2288 INJECT_FAULT(COMPlusThrowOM(););
2292 _ASSERTE(g_pPreallocatedSentinelObject == NULL);
2294 OBJECTREF pPreallocatedSentinalObject = AllocateObject(g_pObjectClass);
2295 g_pPreallocatedSentinelObject = CreatePinningHandle( pPreallocatedSentinalObject );
2297 #ifdef FEATURE_PREJIT
2298 if (SystemModule()->HasNativeImage())
2300 CORCOMPILE_EE_INFO_TABLE *pEEInfo = SystemModule()->GetNativeImage()->GetNativeEEInfoTable();
2301 pEEInfo->emptyString = (CORINFO_Object **)StringObject::GetEmptyStringRefPtr();
2306 void SystemDomain::CreatePreallocatedExceptions()
2313 INJECT_FAULT(COMPlusThrowOM(););
2317 EXCEPTIONREF pBaseException = (EXCEPTIONREF)AllocateObject(g_pExceptionClass);
2318 pBaseException->SetHResult(COR_E_EXCEPTION);
2319 pBaseException->SetXCode(EXCEPTION_COMPLUS);
2320 _ASSERTE(g_pPreallocatedBaseException == NULL);
2321 g_pPreallocatedBaseException = CreateHandle(pBaseException);
2324 EXCEPTIONREF pOutOfMemory = (EXCEPTIONREF)AllocateObject(g_pOutOfMemoryExceptionClass);
2325 pOutOfMemory->SetHResult(COR_E_OUTOFMEMORY);
2326 pOutOfMemory->SetXCode(EXCEPTION_COMPLUS);
2327 _ASSERTE(g_pPreallocatedOutOfMemoryException == NULL);
2328 g_pPreallocatedOutOfMemoryException = CreateHandle(pOutOfMemory);
2331 EXCEPTIONREF pStackOverflow = (EXCEPTIONREF)AllocateObject(g_pStackOverflowExceptionClass);
2332 pStackOverflow->SetHResult(COR_E_STACKOVERFLOW);
2333 pStackOverflow->SetXCode(EXCEPTION_COMPLUS);
2334 _ASSERTE(g_pPreallocatedStackOverflowException == NULL);
2335 g_pPreallocatedStackOverflowException = CreateHandle(pStackOverflow);
2338 EXCEPTIONREF pExecutionEngine = (EXCEPTIONREF)AllocateObject(g_pExecutionEngineExceptionClass);
2339 pExecutionEngine->SetHResult(COR_E_EXECUTIONENGINE);
2340 pExecutionEngine->SetXCode(EXCEPTION_COMPLUS);
2341 _ASSERTE(g_pPreallocatedExecutionEngineException == NULL);
2342 g_pPreallocatedExecutionEngineException = CreateHandle(pExecutionEngine);
2345 EXCEPTIONREF pRudeAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2346 pRudeAbortException->SetHResult(COR_E_THREADABORTED);
2347 pRudeAbortException->SetXCode(EXCEPTION_COMPLUS);
2348 _ASSERTE(g_pPreallocatedRudeThreadAbortException == NULL);
2349 g_pPreallocatedRudeThreadAbortException = CreateHandle(pRudeAbortException);
2352 EXCEPTIONREF pAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2353 pAbortException->SetHResult(COR_E_THREADABORTED);
2354 pAbortException->SetXCode(EXCEPTION_COMPLUS);
2355 _ASSERTE(g_pPreallocatedThreadAbortException == NULL);
2356 g_pPreallocatedThreadAbortException = CreateHandle( pAbortException );
2358 #endif // CROSSGEN_COMPILE
2360 void SystemDomain::Init()
2362 STANDARD_VM_CONTRACT;
2370 "sizeof(EEClass) = %d\n"
2371 "sizeof(MethodTable) = %d\n"
2372 "sizeof(MethodDesc)= %d\n"
2373 "sizeof(FieldDesc) = %d\n"
2374 "sizeof(Module) = %d\n",
2376 sizeof(MethodTable),
2383 // The base domain is initialized in SystemDomain::Attach()
2384 // to allow stub caches to use the memory pool. Do not
2385 // initialze it here!
2387 #ifndef CROSSGEN_COMPILE
2389 Context *curCtx = GetCurrentContext();
2392 _ASSERTE(curCtx->GetDomain() != NULL);
2395 #ifdef FEATURE_PREJIT
2396 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapDisable) != 0)
2397 g_fAllowNativeImages = false;
2400 m_pSystemFile = NULL;
2401 m_pSystemAssembly = NULL;
2406 // Get the install directory so we can find mscorlib
2407 hr = GetInternalSystemDirectory(NULL, &size);
2408 if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
2411 // GetInternalSystemDirectory returns a size, including the null!
2412 WCHAR *buffer = m_SystemDirectory.OpenUnicodeBuffer(size-1);
2413 IfFailThrow(GetInternalSystemDirectory(buffer, &size));
2414 m_SystemDirectory.CloseBuffer();
2415 m_SystemDirectory.Normalize();
2417 // At this point m_SystemDirectory should already be canonicalized
2420 m_BaseLibrary.Append(m_SystemDirectory);
2421 if (!m_BaseLibrary.EndsWith(DIRECTORY_SEPARATOR_CHAR_W))
2423 m_BaseLibrary.Append(DIRECTORY_SEPARATOR_CHAR_W);
2425 m_BaseLibrary.Append(g_pwBaseLibrary);
2426 m_BaseLibrary.Normalize();
2428 LoadBaseSystemClasses();
2431 // We are about to start allocating objects, so we must be in cooperative mode.
2432 // However, many of the entrypoints to the system (DllGetClassObject and all
2433 // N/Direct exports) get called multiple times. Sometimes they initialize the EE,
2434 // but generally they remain in preemptive mode. So we really want to push/pop
2438 #ifndef CROSSGEN_COMPILE
2439 if (!NingenEnabled())
2441 CreatePreallocatedExceptions();
2443 PreallocateSpecialObjects();
2447 // Finish loading mscorlib now.
2448 m_pSystemAssembly->GetDomainAssembly()->EnsureActive();
2452 BOOL fPause = EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_PauseOnLoad, FALSE);
2456 ClrSleepEx(20, TRUE);
2461 #ifndef CROSSGEN_COMPILE
2462 void SystemDomain::LazyInitGlobalStringLiteralMap()
2469 INJECT_FAULT(COMPlusThrowOM(););
2473 // Allocate the global string literal map.
2474 NewHolder<GlobalStringLiteralMap> pGlobalStringLiteralMap(new GlobalStringLiteralMap());
2476 // Initialize the global string literal map.
2477 pGlobalStringLiteralMap->Init();
2479 if (InterlockedCompareExchangeT<GlobalStringLiteralMap *>(&m_pGlobalStringLiteralMap, pGlobalStringLiteralMap, NULL) == NULL)
2481 pGlobalStringLiteralMap.SuppressRelease();
2485 void AppDomain::CreateADUnloadStartEvent()
2496 g_pUnloadStartEvent = new CLREvent();
2497 g_pUnloadStartEvent->CreateAutoEvent(FALSE);
2500 /*static*/ void SystemDomain::EnumAllStaticGCRefs(promote_func* fn, ScanContext* sc)
2510 // We don't do a normal AppDomainIterator because we can't take the SystemDomain lock from
2512 // We're only supposed to call this from a Server GC. We're walking here m_appDomainIdList
2513 // m_appDomainIdList will have an AppDomain* or will be NULL. So the only danger is if we
2514 // Fetch an AppDomain and then in some other thread the AppDomain is deleted.
2516 // If the thread deleting the AppDomain (AppDomain::~AppDomain)was in Preemptive mode
2517 // while doing SystemDomain::EnumAllStaticGCRefs we will issue a GCX_COOP(), which will wait
2518 // for the GC to finish, so we are safe
2520 // If the thread is in cooperative mode, it must have been suspended for the GC so a delete
2523 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
2524 GCHeapUtilities::IsServerHeap() &&
2525 IsGCSpecialThread());
2527 SystemDomain* sysDomain = SystemDomain::System();
2531 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2532 for (i = 0 ; i < count ; i++)
2534 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2535 if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
2537 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2540 sc->pCurrentDomain = pAppDomain;
2542 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2543 pAppDomain->EnumStaticGCRefs(fn, sc);
2551 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2552 void SystemDomain::ResetADSurvivedBytes()
2562 _ASSERTE(GCHeapUtilities::IsGCInProgress());
2564 SystemDomain* sysDomain = SystemDomain::System();
2568 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2569 for (i = 0 ; i < count ; i++)
2571 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2572 if (pAppDomain && pAppDomain->IsUserActive())
2574 pAppDomain->ResetSurvivedBytes();
2582 ULONGLONG SystemDomain::GetADSurvivedBytes()
2592 SystemDomain* sysDomain = SystemDomain::System();
2593 ULONGLONG ullTotalADSurvived = 0;
2597 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2598 for (i = 0 ; i < count ; i++)
2600 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2601 if (pAppDomain && pAppDomain->IsUserActive())
2603 ULONGLONG ullSurvived = pAppDomain->GetSurvivedBytes();
2604 ullTotalADSurvived += ullSurvived;
2609 return ullTotalADSurvived;
2612 void SystemDomain::RecordTotalSurvivedBytes(size_t totalSurvivedBytes)
2622 m_totalSurvivedBytes = totalSurvivedBytes;
2624 SystemDomain* sysDomain = SystemDomain::System();
2628 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2629 for (i = 0 ; i < count ; i++)
2631 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2632 if (pAppDomain && pAppDomain->IsUserActive())
2634 FireEtwAppDomainMemSurvived((ULONGLONG)pAppDomain, pAppDomain->GetSurvivedBytes(), totalSurvivedBytes, GetClrInstanceId());
2641 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2643 // Only called when EE is suspended.
2644 DWORD SystemDomain::GetTotalNumSizedRefHandles()
2654 SystemDomain* sysDomain = SystemDomain::System();
2655 DWORD dwTotalNumSizedRefHandles = 0;
2659 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2660 for (i = 0 ; i < count ; i++)
2662 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2663 if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
2665 dwTotalNumSizedRefHandles += pAppDomain->GetNumSizedRefHandles();
2670 return dwTotalNumSizedRefHandles;
2672 #endif // CROSSGEN_COMPILE
2674 void SystemDomain::LoadBaseSystemClasses()
2676 STANDARD_VM_CONTRACT;
2678 ETWOnStartup(LdSysBases_V1, LdSysBasesEnd_V1);
2681 m_pSystemFile = PEAssembly::OpenSystem(NULL);
2683 // Only partially load the system assembly. Other parts of the code will want to access
2684 // the globals in this function before finishing the load.
2685 m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemFile, FILE_LOAD_POST_LOADLIBRARY)->GetCurrentAssembly();
2687 // Set up binder for mscorlib
2688 MscorlibBinder::AttachModule(m_pSystemAssembly->GetManifestModule());
2691 g_pObjectClass = MscorlibBinder::GetClass(CLASS__OBJECT);
2693 // Now that ObjectClass is loaded, we can set up
2694 // the system for finalizers. There is no point in deferring this, since we need
2695 // to know this before we allocate our first object.
2696 g_pObjectFinalizerMD = MscorlibBinder::GetMethod(METHOD__OBJECT__FINALIZE);
2699 g_pCanonMethodTableClass = MscorlibBinder::GetClass(CLASS____CANON);
2701 // NOTE: !!!IMPORTANT!!! ValueType and Enum MUST be loaded one immediately after
2702 // the other, because we have coded MethodTable::IsChildValueType
2703 // in such a way that it depends on this behaviour.
2704 // Load the ValueType class
2705 g_pValueTypeClass = MscorlibBinder::GetClass(CLASS__VALUE_TYPE);
2707 // Load the enum class
2708 g_pEnumClass = MscorlibBinder::GetClass(CLASS__ENUM);
2709 _ASSERTE(!g_pEnumClass->IsValueType());
2711 // Load System.RuntimeType
2712 g_pRuntimeTypeClass = MscorlibBinder::GetClass(CLASS__CLASS);
2713 _ASSERTE(g_pRuntimeTypeClass->IsFullyLoaded());
2716 g_pArrayClass = MscorlibBinder::GetClass(CLASS__ARRAY);
2718 // Calling a method on IList<T> for an array requires redirection to a method on
2719 // the SZArrayHelper class. Retrieving such methods means calling
2720 // GetActualImplementationForArrayGenericIListMethod, which calls FetchMethod for
2721 // the corresponding method on SZArrayHelper. This basically results in a class
2722 // load due to a method call, which the debugger cannot handle, so we pre-load
2723 // the SZArrayHelper class here.
2724 g_pSZArrayHelperClass = MscorlibBinder::GetClass(CLASS__SZARRAYHELPER);
2726 // Load ByReference class
2728 // NOTE: ByReference<T> must be the first by-ref-like system type to be loaded,
2729 // because MethodTable::ClassifyEightBytesWithManagedLayout depends on it.
2730 g_pByReferenceClass = MscorlibBinder::GetClass(CLASS__BYREFERENCE);
2732 // Load Nullable class
2733 g_pNullableClass = MscorlibBinder::GetClass(CLASS__NULLABLE);
2735 // Load the Object array class.
2736 g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pObjectClass)).AsArray();
2738 // We have delayed allocation of mscorlib's static handles until we load the object class
2739 MscorlibBinder::GetModule()->AllocateRegularStaticHandles(DefaultDomain());
2741 g_TypedReferenceMT = MscorlibBinder::GetClass(CLASS__TYPED_REFERENCE);
2743 // Make sure all primitive types are loaded
2744 for (int et = ELEMENT_TYPE_VOID; et <= ELEMENT_TYPE_R8; et++)
2745 MscorlibBinder::LoadPrimitiveType((CorElementType)et);
2747 MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_I);
2748 MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_U);
2750 // unfortunately, the following cannot be delay loaded since the jit
2751 // uses it to compute method attributes within a function that cannot
2752 // handle Complus exception and the following call goes through a path
2753 // where a complus exception can be thrown. It is unfortunate, because
2754 // we know that the delegate class and multidelegate class are always
2755 // guaranteed to be found.
2756 g_pDelegateClass = MscorlibBinder::GetClass(CLASS__DELEGATE);
2757 g_pMulticastDelegateClass = MscorlibBinder::GetClass(CLASS__MULTICAST_DELEGATE);
2759 // used by IsImplicitInterfaceOfSZArray
2760 MscorlibBinder::GetClass(CLASS__IENUMERABLEGENERIC);
2761 MscorlibBinder::GetClass(CLASS__ICOLLECTIONGENERIC);
2762 MscorlibBinder::GetClass(CLASS__ILISTGENERIC);
2763 MscorlibBinder::GetClass(CLASS__IREADONLYCOLLECTIONGENERIC);
2764 MscorlibBinder::GetClass(CLASS__IREADONLYLISTGENERIC);
2767 g_pStringClass = MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_STRING);
2768 _ASSERTE(g_pStringClass->GetBaseSize() == ObjSizeOf(StringObject)+sizeof(WCHAR));
2769 _ASSERTE(g_pStringClass->GetComponentSize() == 2);
2771 // Used by Buffer::BlockCopy
2772 g_pByteArrayMT = ClassLoader::LoadArrayTypeThrowing(
2773 TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1))).AsArray()->GetMethodTable();
2775 #ifndef CROSSGEN_COMPILE
2776 ECall::PopulateManagedStringConstructors();
2777 #endif // CROSSGEN_COMPILE
2779 g_pExceptionClass = MscorlibBinder::GetClass(CLASS__EXCEPTION);
2780 g_pOutOfMemoryExceptionClass = MscorlibBinder::GetException(kOutOfMemoryException);
2781 g_pStackOverflowExceptionClass = MscorlibBinder::GetException(kStackOverflowException);
2782 g_pExecutionEngineExceptionClass = MscorlibBinder::GetException(kExecutionEngineException);
2783 g_pThreadAbortExceptionClass = MscorlibBinder::GetException(kThreadAbortException);
2786 // used by gc to handle predefined agility checking
2787 g_pThreadClass = MscorlibBinder::GetClass(CLASS__THREAD);
2789 #ifdef FEATURE_COMINTEROP
2790 g_pBaseCOMObject = MscorlibBinder::GetClass(CLASS__COM_OBJECT);
2791 g_pBaseRuntimeClass = MscorlibBinder::GetClass(CLASS__RUNTIME_CLASS);
2793 MscorlibBinder::GetClass(CLASS__IDICTIONARYGENERIC);
2794 MscorlibBinder::GetClass(CLASS__IREADONLYDICTIONARYGENERIC);
2795 MscorlibBinder::GetClass(CLASS__ATTRIBUTE);
2796 MscorlibBinder::GetClass(CLASS__EVENT_HANDLERGENERIC);
2798 MscorlibBinder::GetClass(CLASS__IENUMERABLE);
2799 MscorlibBinder::GetClass(CLASS__ICOLLECTION);
2800 MscorlibBinder::GetClass(CLASS__ILIST);
2801 MscorlibBinder::GetClass(CLASS__IDISPOSABLE);
2804 WinRTInterfaceRedirector::VerifyRedirectedInterfaceStubs();
2808 #ifdef FEATURE_ICASTABLE
2809 g_pICastableInterface = MscorlibBinder::GetClass(CLASS__ICASTABLE);
2810 #endif // FEATURE_ICASTABLE
2812 // Load a special marker method used to detect Constrained Execution Regions
2814 g_pExecuteBackoutCodeHelperMethod = MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__EXECUTE_BACKOUT_CODE_HELPER);
2816 // Make sure that FCall mapping for Monitor.Enter is initialized. We need it in case Monitor.Enter is used only as JIT helper.
2817 // For more details, see comment in code:JITutil_MonEnterWorker around "__me = GetEEFuncEntryPointMacro(JIT_MonEnter)".
2818 ECall::GetFCallImpl(MscorlibBinder::GetMethod(METHOD__MONITOR__ENTER));
2820 #ifdef PROFILING_SUPPORTED
2821 // Note that g_profControlBlock.fBaseSystemClassesLoaded must be set to TRUE only after
2822 // all base system classes are loaded. Profilers are not allowed to call any type-loading
2823 // APIs until g_profControlBlock.fBaseSystemClassesLoaded is TRUE. It is important that
2824 // all base system classes need to be loaded before profilers can trigger the type loading.
2825 g_profControlBlock.fBaseSystemClassesLoaded = TRUE;
2826 #endif // PROFILING_SUPPORTED
2828 #if defined(_DEBUG) && !defined(CROSSGEN_COMPILE)
2829 if (!NingenEnabled())
2835 #if defined(HAVE_GCCOVER) && defined(FEATURE_PREJIT)
2836 if (GCStress<cfg_instr_ngen>::IsEnabled())
2838 // Setting up gc coverage requires the base system classes
2839 // to be initialized. So we have deferred it until now for mscorlib.
2840 Module *pModule = MscorlibBinder::GetModule();
2841 _ASSERTE(pModule->IsSystem());
2842 if(pModule->HasNativeImage())
2844 SetupGcCoverageForNativeImage(pModule);
2847 #endif // defined(HAVE_GCCOVER) && !defined(FEATURE_PREJIT)
2851 void SystemDomain::LoadDomain(AppDomain *pDomain)
2858 PRECONDITION(CheckPointer(System()));
2859 INJECT_FAULT(COMPlusThrowOM(););
2863 pDomain->SetCanUnload(); // by default can unload any domain
2864 SystemDomain::System()->AddDomain(pDomain);
2867 ADIndex SystemDomain::GetNewAppDomainIndex(AppDomain *pAppDomain)
2869 STANDARD_VM_CONTRACT;
2871 DWORD count = m_appDomainIndexList.GetCount();
2877 // So that we can keep AD index inside object header.
2878 // We do not want to create syncblock unless needed.
2885 // Look for an unused index. Note that in a checked build,
2886 // we never reuse indexes - this makes it easier to tell
2887 // when we are looking at a stale app domain.
2890 i = m_appDomainIndexList.FindElement(m_dwLowestFreeIndex, NULL);
2891 if (i == (DWORD) ArrayList::NOT_FOUND)
2893 m_dwLowestFreeIndex = i+1;
2895 if (m_dwLowestFreeIndex >= 2000)
2897 m_dwLowestFreeIndex = 0;
2903 IfFailThrow(m_appDomainIndexList.Append(pAppDomain));
2905 m_appDomainIndexList.Set(i, pAppDomain);
2907 _ASSERTE(i < m_appDomainIndexList.GetCount());
2909 // Note that index 0 means domain agile.
2910 return ADIndex(i+1);
2913 void SystemDomain::ReleaseAppDomainIndex(ADIndex index)
2915 WRAPPER_NO_CONTRACT;
2916 SystemDomain::LockHolder lh;
2917 // Note that index 0 means domain agile.
2920 _ASSERTE(m_appDomainIndexList.Get(index.m_dwIndex) != NULL);
2922 m_appDomainIndexList.Set(index.m_dwIndex, NULL);
2925 if (index.m_dwIndex < m_dwLowestFreeIndex)
2926 m_dwLowestFreeIndex = index.m_dwIndex;
2930 #endif // !DACCESS_COMPILE
2932 PTR_AppDomain SystemDomain::GetAppDomainAtIndex(ADIndex index)
2934 LIMITED_METHOD_CONTRACT;
2936 _ASSERTE(index.m_dwIndex != 0);
2938 PTR_AppDomain pAppDomain = TestGetAppDomainAtIndex(index);
2940 _ASSERTE(pAppDomain || !"Attempt to access unloaded app domain");
2945 PTR_AppDomain SystemDomain::TestGetAppDomainAtIndex(ADIndex index)
2947 LIMITED_METHOD_CONTRACT;
2949 _ASSERTE(index.m_dwIndex != 0);
2952 #ifndef DACCESS_COMPILE
2953 _ASSERTE(index.m_dwIndex < (DWORD)m_appDomainIndexList.GetCount());
2954 AppDomain *pAppDomain = (AppDomain*) m_appDomainIndexList.Get(index.m_dwIndex);
2955 #else // DACCESS_COMPILE
2956 PTR_ArrayListStatic pList = &m_appDomainIndexList;
2957 AppDomain *pAppDomain = dac_cast<PTR_AppDomain>(pList->Get(index.m_dwIndex));
2958 #endif // DACCESS_COMPILE
2959 return PTR_AppDomain(pAppDomain);
2962 #ifndef DACCESS_COMPILE
2964 // See also code:SystemDomain::ReleaseAppDomainId
2965 ADID SystemDomain::GetNewAppDomainId(AppDomain *pAppDomain)
2972 INJECT_FAULT(COMPlusThrowOM(););
2976 DWORD i = m_appDomainIdList.GetCount();
2978 IfFailThrow(m_appDomainIdList.Append(pAppDomain));
2980 _ASSERTE(i < m_appDomainIdList.GetCount());
2985 AppDomain *SystemDomain::GetAppDomainAtId(ADID index)
2990 if (!SystemDomain::IsUnderDomainLock() && !IsGCThread()) { MODE_COOPERATIVE;} else { DISABLED(MODE_ANY);}
2998 if(index.m_dwId == 0)
3000 DWORD requestedID = index.m_dwId - 1;
3002 if(requestedID >= (DWORD)m_appDomainIdList.GetCount())
3005 AppDomain * result = (AppDomain *)m_appDomainIdList.Get(requestedID);
3007 #ifndef CROSSGEN_COMPILE
3008 if(result==NULL && GetThread() == FinalizerThread::GetFinalizerThread() &&
3009 SystemDomain::System()->AppDomainBeingUnloaded()!=NULL &&
3010 SystemDomain::System()->AppDomainBeingUnloaded()->GetId()==index)
3011 result=SystemDomain::System()->AppDomainBeingUnloaded();
3012 // If the current thread can't enter the AppDomain, then don't return it.
3013 if (!result || !result->CanThreadEnter(GetThread()))
3015 #endif // CROSSGEN_COMPILE
3020 // Releases an appdomain index. Note that today we have code that depends on these
3021 // indexes not being recycled, so we don't actually shrink m_appDomainIdList, but
3022 // simply zero out an entry. THus we 'leak' the memory associated the slot in
3023 // m_appDomainIdList.
3025 // TODO make this a sparse structure so that we avoid that leak.
3027 void SystemDomain::ReleaseAppDomainId(ADID index)
3029 LIMITED_METHOD_CONTRACT;
3032 _ASSERTE(index.m_dwId < (DWORD)m_appDomainIdList.GetCount());
3034 m_appDomainIdList.Set(index.m_dwId, NULL);
3037 #if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3040 int g_fMainThreadApartmentStateSet = 0;
3043 Thread::ApartmentState SystemDomain::GetEntryPointThreadAptState(IMDInternalImport* pScope, mdMethodDef mdMethod)
3045 STANDARD_VM_CONTRACT;
3048 IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
3049 DEFAULTDOMAIN_MTA_TYPE,
3052 BOOL fIsMTA = FALSE;
3056 IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
3057 DEFAULTDOMAIN_STA_TYPE,
3060 BOOL fIsSTA = FALSE;
3064 if (fIsSTA && fIsMTA)
3065 COMPlusThrowHR(COR_E_CUSTOMATTRIBUTEFORMAT);
3068 return Thread::AS_InSTA;
3070 return Thread::AS_InMTA;
3072 return Thread::AS_Unknown;
3075 void SystemDomain::SetThreadAptState (Thread::ApartmentState state)
3077 STANDARD_VM_CONTRACT;
3079 Thread* pThread = GetThread();
3082 if(state == Thread::AS_InSTA)
3084 Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InSTA, TRUE);
3085 _ASSERTE(pState == Thread::AS_InSTA);
3087 else if (state == Thread::AS_InMTA)
3089 Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InMTA, TRUE);
3090 _ASSERTE(pState == Thread::AS_InMTA);
3094 g_fMainThreadApartmentStateSet++;
3097 #endif // defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3099 // Looks in all the modules for the DefaultDomain attribute
3100 // The order is assembly and then the modules. It is first
3101 // come, first serve.
3102 BOOL SystemDomain::SetGlobalSharePolicyUsingAttribute(IMDInternalImport* pScope, mdMethodDef mdMethod)
3104 STANDARD_VM_CONTRACT;
3110 void SystemDomain::SetupDefaultDomain()
3117 INJECT_FAULT(COMPlusThrowOM(););
3122 Thread *pThread = GetThread();
3126 pDomain = pThread->GetDomain();
3131 ENTER_DOMAIN_PTR(SystemDomain::System()->DefaultDomain(),ADV_DEFAULTAD)
3133 // Push this frame around loading the main assembly to ensure the
3134 // debugger can properly recgonize any managed code that gets run
3135 // as "class initializaion" code.
3136 FrameWithCookie<DebuggerClassInitMarkFrame> __dcimf;
3140 InitializeDefaultDomain(TRUE);
3145 END_DOMAIN_TRANSITION;
3150 HRESULT SystemDomain::SetupDefaultDomainNoThrow()
3163 SystemDomain::SetupDefaultDomain();
3165 EX_CATCH_HRESULT(hr);
3171 int g_fInitializingInitialAD = 0;
3174 // This routine completes the initialization of the default domaine.
3175 // After this call mananged code can be executed.
3176 void SystemDomain::InitializeDefaultDomain(
3177 BOOL allowRedirects,
3178 ICLRPrivBinder * pBinder)
3180 STANDARD_VM_CONTRACT;
3182 WCHAR* pwsConfig = NULL;
3183 WCHAR* pwsPath = NULL;
3185 ETWOnStartup (InitDefaultDomain_V1, InitDefaultDomainEnd_V1);
3188 // Setup the default AppDomain.
3191 g_fInitializingInitialAD++;
3194 AppDomain* pDefaultDomain = SystemDomain::System()->DefaultDomain();
3196 if (pBinder != nullptr)
3198 pDefaultDomain->SetLoadContextHostBinder(pBinder);
3204 pDefaultDomain->InitializeDomainContext(allowRedirects, pwsPath, pwsConfig);
3206 #ifndef CROSSGEN_COMPILE
3207 if (!NingenEnabled())
3210 if (!IsSingleAppDomain())
3212 pDefaultDomain->InitializeDefaultDomainManager();
3215 #endif // CROSSGEN_COMPILE
3218 // DefaultDomain Load event
3219 ETW::LoaderLog::DomainLoad(pDefaultDomain);
3222 g_fInitializingInitialAD--;
3225 TESTHOOKCALL(RuntimeStarted(RTS_DEFAULTADREADY));
3230 #ifndef CROSSGEN_COMPILE
3233 Volatile<LONG> g_fInExecuteMainMethod = 0;
3239 #endif // CROSSGEN_COMPILE
3243 // Helper function to load an assembly. This is called from LoadCOMClass.
3246 Assembly *AppDomain::LoadAssemblyHelper(LPCWSTR wszAssembly,
3247 LPCWSTR wszCodeBase)
3249 CONTRACT(Assembly *)
3252 POSTCONDITION(CheckPointer(RETVAL));
3253 PRECONDITION(wszAssembly || wszCodeBase);
3254 INJECT_FAULT(COMPlusThrowOM(););
3260 #define MAKE_TRANSLATIONFAILED { ThrowOutOfMemory(); }
3261 MAKE_UTF8PTR_FROMWIDE(szAssembly,wszAssembly);
3262 #undef MAKE_TRANSLATIONFAILED
3264 IfFailThrow(spec.Init(szAssembly));
3268 spec.SetCodeBase(wszCodeBase);
3270 RETURN spec.LoadAssembly(FILE_LOADED);
3273 #if defined(FEATURE_CLASSIC_COMINTEROP) && !defined(CROSSGEN_COMPILE)
3275 MethodTable *AppDomain::LoadCOMClass(GUID clsid,
3276 BOOL bLoadRecord/*=FALSE*/,
3277 BOOL* pfAssemblyInReg/*=NULL*/)
3279 // @CORESYSTODO: what to do here?
3283 #endif // FEATURE_CLASSIC_COMINTEROP && !CROSSGEN_COMPILE
3287 bool SystemDomain::IsReflectionInvocationMethod(MethodDesc* pMeth)
3297 MethodTable* pCaller = pMeth->GetMethodTable();
3299 // All Reflection Invocation methods are defined in mscorlib.dll
3300 if (!pCaller->GetModule()->IsSystem())
3303 /* List of types that should be skipped to identify true caller */
3304 static const BinderClassID reflectionInvocationTypes[] = {
3309 CLASS__CONSTRUCTOR_INFO,
3312 CLASS__METHOD_HANDLE,
3313 CLASS__FIELD_HANDLE,
3316 CLASS__RT_FIELD_INFO,
3321 CLASS__PROPERTY_INFO,
3324 CLASS__ASSEMBLYBASE,
3326 CLASS__TYPE_DELEGATOR,
3327 CLASS__RUNTIME_HELPERS,
3328 CLASS__LAZY_INITIALIZER,
3329 CLASS__DYNAMICMETHOD,
3331 CLASS__MULTICAST_DELEGATE,
3335 static const BinderClassID genericReflectionInvocationTypes[] = {
3339 static mdTypeDef genericReflectionInvocationTypeDefs[NumItems(genericReflectionInvocationTypes)];
3341 static bool fInited = false;
3343 if (!VolatileLoad(&fInited))
3345 // Make sure all types are loaded so that we can use faster GetExistingClass()
3346 for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3348 MscorlibBinder::GetClass(reflectionInvocationTypes[i]);
3351 // Make sure all types are loaded so that we can use faster GetExistingClass()
3352 for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypes); i++)
3354 genericReflectionInvocationTypeDefs[i] = MscorlibBinder::GetClass(genericReflectionInvocationTypes[i])->GetCl();
3357 MscorlibBinder::GetClass(CLASS__APP_DOMAIN);
3359 VolatileStore(&fInited, true);
3362 if (pCaller->HasInstantiation())
3364 // For generic types, pCaller will be an instantiated type and never equal to the type definition.
3365 // So we compare their TypeDef tokens instead.
3366 for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypeDefs); i++)
3368 if (pCaller->GetCl() == genericReflectionInvocationTypeDefs[i])
3374 for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3376 if (MscorlibBinder::GetExistingClass(reflectionInvocationTypes[i]) == pCaller)
3384 #ifndef CROSSGEN_COMPILE
3385 struct CallersDataWithStackMark
3387 StackCrawlMark* stackMark;
3389 MethodDesc* pFoundMethod;
3390 MethodDesc* pPrevMethod;
3391 AppDomain* pAppDomain;
3395 MethodDesc* SystemDomain::GetCallersMethod(StackCrawlMark* stackMark,
3396 AppDomain **ppAppDomain/*=NULL*/)
3404 INJECT_FAULT(COMPlusThrowOM(););
3410 CallersDataWithStackMark cdata;
3411 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3412 cdata.stackMark = stackMark;
3414 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3416 if(cdata.pFoundMethod) {
3418 *ppAppDomain = cdata.pAppDomain;
3419 return cdata.pFoundMethod;
3425 MethodTable* SystemDomain::GetCallersType(StackCrawlMark* stackMark,
3426 AppDomain **ppAppDomain/*=NULL*/)
3434 INJECT_FAULT(COMPlusThrowOM(););
3438 CallersDataWithStackMark cdata;
3439 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3440 cdata.stackMark = stackMark;
3442 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3444 if(cdata.pFoundMethod) {
3446 *ppAppDomain = cdata.pAppDomain;
3447 return cdata.pFoundMethod->GetMethodTable();
3453 Module* SystemDomain::GetCallersModule(StackCrawlMark* stackMark,
3454 AppDomain **ppAppDomain/*=NULL*/)
3462 INJECT_FAULT(COMPlusThrowOM(););
3468 CallersDataWithStackMark cdata;
3469 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3470 cdata.stackMark = stackMark;
3472 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3474 if(cdata.pFoundMethod) {
3476 *ppAppDomain = cdata.pAppDomain;
3477 return cdata.pFoundMethod->GetModule();
3485 MethodDesc* pMethod;
3489 Assembly* SystemDomain::GetCallersAssembly(StackCrawlMark *stackMark,
3490 AppDomain **ppAppDomain/*=NULL*/)
3492 WRAPPER_NO_CONTRACT;
3493 Module* mod = GetCallersModule(stackMark, ppAppDomain);
3495 return mod->GetAssembly();
3500 Module* SystemDomain::GetCallersModule(int skip)
3507 INJECT_FAULT(COMPlusThrowOM(););
3514 ZeroMemory(&cdata, sizeof(CallersData));
3517 StackWalkFunctions(GetThread(), CallersMethodCallback, &cdata);
3520 return cdata.pMethod->GetModule();
3526 StackWalkAction SystemDomain::CallersMethodCallbackWithStackMark(CrawlFrame* pCf, VOID* data)
3534 INJECT_FAULT(COMPlusThrowOM(););
3539 MethodDesc *pFunc = pCf->GetFunction();
3541 /* We asked to be called back only for functions */
3544 CallersDataWithStackMark* pCaller = (CallersDataWithStackMark*) data;
3545 if (pCaller->stackMark)
3547 if (!pCf->IsInCalleesFrames(pCaller->stackMark))
3549 // save the current in case it is the one we want
3550 pCaller->pPrevMethod = pFunc;
3551 pCaller->pAppDomain = pCf->GetAppDomain();
3552 return SWA_CONTINUE;
3555 // LookForMe stack crawl marks needn't worry about reflection or
3556 // remoting frames on the stack. Each frame above (newer than) the
3557 // target will be captured by the logic above. Once we transition to
3558 // finding the stack mark below the AofRA, we know that we hit the
3559 // target last time round and immediately exit with the cached result.
3561 if (*(pCaller->stackMark) == LookForMe)
3563 pCaller->pFoundMethod = pCaller->pPrevMethod;
3568 // Skip reflection and remoting frames that could lie between a stack marked
3569 // method and its true caller (or that caller and its own caller). These
3570 // frames are infrastructure and logically transparent to the stack crawling
3573 // Skipping remoting frames. We always skip entire client to server spans
3574 // (though we see them in the order server then client during a stack crawl
3577 // We spot the server dispatcher end because all calls are dispatched
3578 // through a single method: StackBuilderSink._PrivateProcessMessage.
3580 Frame* frame = pCf->GetFrame();
3581 _ASSERTE(pCf->IsFrameless() || frame);
3585 // Skipping reflection frames. We don't need to be quite as exhaustive here
3586 // as the security or reflection stack walking code since we know this logic
3587 // is only invoked for selected methods in mscorlib itself. So we're
3588 // reasonably sure we won't have any sensitive methods late bound invoked on
3589 // constructors, properties or events. This leaves being invoked via
3590 // MethodInfo, Type or Delegate (and depending on which invoke overload is
3591 // being used, several different reflection classes may be involved).
3593 g_IBCLogger.LogMethodDescAccess(pFunc);
3595 if (SystemDomain::IsReflectionInvocationMethod(pFunc))
3596 return SWA_CONTINUE;
3598 if (frame && frame->GetFrameType() == Frame::TYPE_MULTICAST)
3600 // This must be either a secure delegate frame or a true multicast delegate invocation.
3602 _ASSERTE(pFunc->GetMethodTable()->IsDelegate());
3604 DELEGATEREF del = (DELEGATEREF)((SecureDelegateFrame*)frame)->GetThis(); // This can throw.
3606 if (COMDelegate::IsSecureDelegate(del))
3608 if (del->IsWrapperDelegate())
3610 // On ARM, we use secure delegate infrastructure to preserve R4 register.
3611 return SWA_CONTINUE;
3613 // For a secure delegate frame, we should return the delegate creator instead
3614 // of the delegate method itself.
3615 pFunc = (MethodDesc*) del->GetMethodPtrAux();
3619 _ASSERTE(COMDelegate::IsTrueMulticastDelegate(del));
3620 return SWA_CONTINUE;
3624 // Return the first non-reflection/remoting frame if no stack mark was
3626 if (!pCaller->stackMark)
3628 pCaller->pFoundMethod = pFunc;
3629 pCaller->pAppDomain = pCf->GetAppDomain();
3633 // If we got here, we must already be in the frame containing the stack mark and we are not looking for "me".
3634 _ASSERTE(pCaller->stackMark &&
3635 pCf->IsInCalleesFrames(pCaller->stackMark) &&
3636 *(pCaller->stackMark) != LookForMe);
3638 // When looking for caller's caller, we delay returning results for another
3639 // round (the way this is structured, we will still be able to skip
3640 // reflection and remoting frames between the caller and the caller's
3643 if ((*(pCaller->stackMark) == LookForMyCallersCaller) &&
3644 (pCaller->pFoundMethod == NULL))
3646 pCaller->pFoundMethod = pFunc;
3647 return SWA_CONTINUE;
3650 // If remoting is not available, we only set the caller if the crawlframe is from the same domain.
3651 // Why? Because if the callerdomain is different from current domain,
3652 // there have to be interop/native frames in between.
3653 // For example, in the CORECLR, if we find the caller to be in a different domain, then the
3654 // call into reflection is due to an unmanaged call into mscorlib. For that
3655 // case, the caller really is an INTEROP method.
3656 // In general, if the caller is INTEROP, we set the caller/callerdomain to be NULL
3657 // (To be precise: they are already NULL and we don't change them).
3658 if (pCf->GetAppDomain() == GetAppDomain())
3659 // We must either be looking for the caller, or the caller's caller when
3660 // we've already found the caller (we used a non-null value in pFoundMethod
3661 // simply as a flag, the correct method to return in both case is the
3664 pCaller->pFoundMethod = pFunc;
3665 pCaller->pAppDomain = pCf->GetAppDomain();
3672 StackWalkAction SystemDomain::CallersMethodCallback(CrawlFrame* pCf, VOID* data)
3674 LIMITED_METHOD_CONTRACT;
3675 STATIC_CONTRACT_SO_TOLERANT;
3676 MethodDesc *pFunc = pCf->GetFunction();
3678 /* We asked to be called back only for functions */
3681 CallersData* pCaller = (CallersData*) data;
3682 if(pCaller->skip == 0) {
3683 pCaller->pMethod = pFunc;
3688 return SWA_CONTINUE;
3692 #endif // CROSSGEN_COMPILE
3694 #ifdef CROSSGEN_COMPILE
3695 // defined in compile.cpp
3696 extern CompilationDomain * theDomain;
3699 void SystemDomain::CreateDefaultDomain()
3701 STANDARD_VM_CONTRACT;
3703 #ifdef CROSSGEN_COMPILE
3704 AppDomainRefHolder pDomain(theDomain);
3706 AppDomainRefHolder pDomain(new AppDomain());
3709 SystemDomain::LockHolder lh;
3712 // need to make this assignment here since we'll be releasing
3713 // the lock before calling AddDomain. So any other thread
3714 // grabbing this lock after we release it will find that
3715 // the COM Domain has already been created
3716 m_pDefaultDomain = pDomain;
3717 _ASSERTE (pDomain->GetId().m_dwId == DefaultADID);
3719 // allocate a Virtual Call Stub Manager for the default domain
3720 m_pDefaultDomain->InitVSD();
3722 pDomain->SetStage(AppDomain::STAGE_OPEN);
3723 pDomain.SuppressRelease();
3725 LOG((LF_CLASSLOADER | LF_CORDB,
3727 "Created default domain at %p\n", m_pDefaultDomain));
3730 #ifdef DEBUGGING_SUPPORTED
3732 void SystemDomain::PublishAppDomainAndInformDebugger (AppDomain *pDomain)
3736 if(!g_fEEInit) {THROWS;} else {DISABLED(NOTHROW);};
3737 if(!g_fEEInit) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);};
3742 LOG((LF_CORDB, LL_INFO100, "SD::PADAID: Adding 0x%x\n", pDomain));
3744 // Call the publisher API to add this appdomain entry to the list
3745 // The publisher will handle failures, so we don't care if this succeeds or fails.
3746 if (g_pDebugInterface != NULL)
3748 g_pDebugInterface->AddAppDomainToIPC(pDomain);
3752 #endif // DEBUGGING_SUPPORTED
3754 void SystemDomain::AddDomain(AppDomain* pDomain)
3761 PRECONDITION(CheckPointer((pDomain)));
3768 _ASSERTE (pDomain->m_Stage != AppDomain::STAGE_CREATING);
3769 if (pDomain->m_Stage == AppDomain::STAGE_READYFORMANAGEDCODE ||
3770 pDomain->m_Stage == AppDomain::STAGE_ACTIVE)
3772 pDomain->SetStage(AppDomain::STAGE_OPEN);
3773 IncrementNumAppDomains(); // Maintain a count of app domains added to the list.
3777 // Note that if you add another path that can reach here without calling
3778 // PublishAppDomainAndInformDebugger, then you should go back & make sure
3779 // that PADAID gets called. Right after this call, if not sooner.
3780 LOG((LF_CORDB, LL_INFO1000, "SD::AD:Would have added domain here! 0x%x\n",
3784 BOOL SystemDomain::RemoveDomain(AppDomain* pDomain)
3791 PRECONDITION(CheckPointer(pDomain));
3792 PRECONDITION(!pDomain->IsDefaultDomain());
3796 // You can not remove the default domain.
3799 if (!pDomain->IsActive())
3808 #ifdef PROFILING_SUPPORTED
3809 void SystemDomain::NotifyProfilerStartup()
3820 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3822 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System());
3827 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3829 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System(), S_OK);
3834 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3835 _ASSERTE(System()->DefaultDomain());
3836 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System()->DefaultDomain());
3841 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3842 _ASSERTE(System()->DefaultDomain());
3843 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3848 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3849 _ASSERTE(SharedDomain::GetDomain());
3850 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) SharedDomain::GetDomain());
3855 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3856 _ASSERTE(SharedDomain::GetDomain());
3857 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) SharedDomain::GetDomain(), S_OK);
3862 HRESULT SystemDomain::NotifyProfilerShutdown()
3873 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3875 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System());
3880 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3882 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System(), S_OK);
3887 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3888 _ASSERTE(System()->DefaultDomain());
3889 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System()->DefaultDomain());
3894 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3895 _ASSERTE(System()->DefaultDomain());
3896 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3901 #endif // PROFILING_SUPPORTED
3905 struct AppDomain::ThreadTrackInfo {
3907 CDynArray<Frame *> frameStack;
3911 AppDomain::AppDomain()
3913 // initialize fields so the appdomain can be safely destructed
3914 // shouldn't call anything that can fail here - use ::Init instead
3925 m_pNextInDelayedUnloadList = NULL;
3926 m_fRudeUnload = FALSE;
3927 m_pUnloadRequestThread = NULL;
3928 m_ADUnloadSink=NULL;
3931 // Initialize Shared state. Assemblies are loaded
3932 // into each domain by default.
3933 #ifdef FEATURE_LOADER_OPTIMIZATION
3934 m_SharePolicy = SHARE_POLICY_UNSPECIFIED;
3937 m_pRootAssembly = NULL;
3939 m_pwDynamicDir = NULL;
3942 m_pDefaultContext = NULL;
3943 #ifdef FEATURE_COMINTEROP
3944 m_pComCallWrapperCache = NULL;
3946 m_pRCWRefCache = NULL;
3947 m_pLicenseInteropHelperMT = NULL;
3948 m_COMorRemotingFlag = COMorRemoting_NotInitialized;
3949 memset(m_rpCLRTypes, 0, sizeof(m_rpCLRTypes));
3950 #endif // FEATURE_COMINTEROP
3952 m_pUMEntryThunkCache = NULL;
3954 m_pAsyncPool = NULL;
3955 m_handleStore = NULL;
3957 m_ExposedObject = NULL;
3958 m_pComIPForExposedObject = NULL;
3961 m_pThreadTrackInfoList = NULL;
3962 m_TrackSpinLock = 0;
3963 m_Assemblies.Debug_SetAppDomain(this);
3966 m_dwThreadEnterCount = 0;
3967 m_dwThreadsStillInAppDomain = (ULONG)-1;
3969 #ifdef FEATURE_COMINTEROP
3970 m_pRefDispIDCache = NULL;
3971 m_hndMissing = NULL;
3974 m_pRefClassFactHash = NULL;
3975 m_anonymouslyHostedDynamicMethodsAssembly = NULL;
3977 m_ReversePInvokeCanEnter=TRUE;
3978 m_ForceTrivialWaitOperations = false;
3979 m_Stage=STAGE_CREATING;
3981 m_bForceGCOnUnload=FALSE;
3982 m_bUnloadingFromUnloadEvent=FALSE;
3986 m_dwCreationHolders=0;
3989 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3990 m_ullTotalProcessorUsage = 0;
3991 m_pullAllocBytes = NULL;
3992 m_pullSurvivedBytes = NULL;
3993 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3995 #ifdef FEATURE_TYPEEQUIVALENCE
3996 m_pTypeEquivalenceTable = NULL;
3997 #endif // FEATURE_TYPEEQUIVALENCE
3999 #ifdef FEATURE_COMINTEROP
4000 m_pNameToTypeMap = NULL;
4001 m_vNameToTypeMapVersion = 0;
4003 m_pWinRTFactoryCache = NULL;
4004 #endif // FEATURE_COMINTEROP
4006 #ifdef FEATURE_PREJIT
4007 m_pDomainFileWithNativeImageList = NULL;
4010 m_fIsBindingModelLocked.Store(FALSE);
4012 } // AppDomain::AppDomain
4014 AppDomain::~AppDomain()
4024 #ifndef CROSSGEN_COMPILE
4026 _ASSERTE(m_dwCreationHolders == 0);
4028 // release the TPIndex. note that since TPIndex values are recycled the TPIndex
4029 // can only be released once all threads in the AppDomain have exited.
4030 if (GetTPIndex().m_dwIndex != 0)
4031 PerAppDomainTPCountList::ResetAppDomainIndex(GetTPIndex());
4033 if (m_dwId.m_dwId!=0)
4034 SystemDomain::ReleaseAppDomainId(m_dwId);
4036 m_AssemblyCache.Clear();
4039 m_ADUnloadSink->Release();
4047 #ifdef FEATURE_COMINTEROP
4048 if (m_pNameToTypeMap != nullptr)
4050 delete m_pNameToTypeMap;
4051 m_pNameToTypeMap = nullptr;
4053 if (m_pWinRTFactoryCache != nullptr)
4055 delete m_pWinRTFactoryCache;
4056 m_pWinRTFactoryCache = nullptr;
4058 #endif //FEATURE_COMINTEROP
4061 // If we were tracking thread AD transitions, cleanup the list on shutdown
4062 if (m_pThreadTrackInfoList)
4064 while (m_pThreadTrackInfoList->Count() > 0)
4066 // Get the very last element
4067 ThreadTrackInfo *pElem = *(m_pThreadTrackInfoList->Get(m_pThreadTrackInfoList->Count() - 1));
4073 // Remove pointer entry from the list
4074 m_pThreadTrackInfoList->Delete(m_pThreadTrackInfoList->Count() - 1);
4077 // Now delete the list itself
4078 delete m_pThreadTrackInfoList;
4079 m_pThreadTrackInfoList = NULL;
4083 #endif // CROSSGEN_COMPILE
4086 //*****************************************************************************
4087 //*****************************************************************************
4088 //*****************************************************************************
4089 void AppDomain::Init()
4094 PRECONDITION(SystemDomain::IsUnderDomainLock());
4098 m_pDelayedLoaderAllocatorUnloadList = NULL;
4100 SetStage( STAGE_CREATING);
4103 // The lock is taken also during stack walking (GC or profiler)
4104 // - To prevent deadlock with GC thread, we cannot trigger GC while holding the lock
4105 // - To prevent deadlock with profiler thread, we cannot allow thread suspension
4106 m_crstHostAssemblyMap.Init(
4107 CrstHostAssemblyMap,
4108 (CrstFlags)(CRST_GC_NOTRIGGER_WHEN_TAKEN
4109 | CRST_DEBUGGER_THREAD
4110 INDEBUG(| CRST_DEBUG_ONLY_CHECK_FORBID_SUSPEND_THREAD)));
4111 m_crstHostAssemblyMapAdd.Init(CrstHostAssemblyMapAdd);
4113 m_dwId = SystemDomain::GetNewAppDomainId(this);
4115 m_LoaderAllocator.Init(this);
4117 #ifndef CROSSGEN_COMPILE
4118 //Allocate the threadpool entry before the appdomin id list. Otherwise,
4119 //the thread pool list will be out of sync if insertion of id in
4120 //the appdomain fails.
4121 m_tpIndex = PerAppDomainTPCountList::AddNewTPIndex();
4122 #endif // CROSSGEN_COMPILE
4124 m_dwIndex = SystemDomain::GetNewAppDomainIndex(this);
4126 #ifndef CROSSGEN_COMPILE
4127 PerAppDomainTPCountList::SetAppDomainId(m_tpIndex, m_dwId);
4129 m_ADUnloadSink=new ADUnloadSink();
4134 // Set up the IL stub cache
4135 m_ILStubCache.Init(GetLoaderAllocator()->GetHighFrequencyHeap());
4137 // Set up the binding caches
4138 m_AssemblyCache.Init(&m_DomainCacheCrst, GetHighFrequencyHeap());
4139 m_UnmanagedCache.InitializeTable(this, &m_DomainCacheCrst);
4141 m_MemoryPressure = 0;
4143 m_sDomainLocalBlock.Init(this);
4145 #ifndef CROSSGEN_COMPILE
4147 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4148 // NOTE: it's important that we initialize ARM data structures before calling
4149 // Ref_CreateHandleTableBucket, this is because AD::Init() can race with GC
4150 // and once we add ourselves to the handle table map the GC can start walking
4151 // our handles and calling AD::RecordSurvivedBytes() which touches ARM data.
4152 if (GCHeapUtilities::IsServerHeap())
4153 m_dwNumHeaps = CPUGroupInfo::CanEnableGCCPUGroups() ?
4154 CPUGroupInfo::GetNumActiveProcessors() :
4155 GetCurrentProcessCpuCount();
4158 m_pullAllocBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
4159 m_pullSurvivedBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
4160 for (DWORD i = 0; i < m_dwNumHeaps; i++)
4162 m_pullAllocBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
4163 m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
4165 m_ullLastEtwAllocBytes = 0;
4166 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4168 // Default domain reuses the handletablemap that was created during EEStartup since
4169 // default domain cannot be unloaded.
4170 if (GetId().m_dwId == DefaultADID)
4172 m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
4176 m_handleStore = GCHandleUtilities::GetGCHandleManager()->CreateHandleStore((void*)(uintptr_t)m_dwIndex.m_dwIndex);
4184 #endif // CROSSGEN_COMPILE
4186 #ifdef FEATURE_TYPEEQUIVALENCE
4187 m_TypeEquivalenceCrst.Init(CrstTypeEquivalenceMap);
4190 m_ReflectionCrst.Init(CrstReflection, CRST_UNSAFE_ANYMODE);
4191 m_RefClassFactCrst.Init(CrstClassFactInfoHash);
4194 LockOwner lock = {&m_DomainCrst, IsOwnerOfCrst};
4195 m_clsidHash.Init(0,&CompareCLSID,true, &lock); // init hash table
4198 SetStage(STAGE_READYFORMANAGEDCODE);
4200 #ifndef CROSSGEN_COMPILE
4201 m_pDefaultContext = new Context(this);
4203 m_ExposedObject = CreateHandle(NULL);
4205 // Create the Application Security Descriptor
4207 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains++);
4209 #ifdef FEATURE_COMINTEROP
4210 if (!AppX::IsAppXProcess())
4213 #endif //FEATURE_COMINTEROP
4215 #ifdef FEATURE_TIERED_COMPILATION
4216 m_tieredCompilationManager.Init(GetId());
4218 #endif // CROSSGEN_COMPILE
4219 } // AppDomain::Init
4222 /*********************************************************************/
4224 BOOL AppDomain::IsCompilationDomain()
4226 LIMITED_METHOD_CONTRACT;
4228 BOOL isCompilationDomain = (m_dwFlags & COMPILATION_DOMAIN) != 0;
4229 #ifdef FEATURE_PREJIT
4230 _ASSERTE(!isCompilationDomain ||
4231 (IsCompilationProcess() && IsPassiveDomain()));
4232 #endif // FEATURE_PREJIT
4233 return isCompilationDomain;
4236 #ifndef CROSSGEN_COMPILE
4238 extern int g_fADUnloadWorkerOK;
4241 // This helper will send the AppDomain creation notifications for profiler / debugger.
4242 // If it throws, its backout code will also send a notification.
4243 // If it succeeds, then we still need to send a AppDomainCreateFinished notification.
4244 void AppDomain::CreateUnmanagedObject(AppDomainCreationHolder<AppDomain>& pDomain)
4251 INJECT_FAULT(COMPlusThrowOM(););
4257 pDomain.Assign(new AppDomain());
4258 if (g_fADUnloadWorkerOK<0)
4260 AppDomain::CreateADUnloadWorker();
4264 // We addref Appdomain object here and notify a profiler that appdomain
4265 // creation has started, then return to managed code which will call
4266 // the function that releases the appdomain and notifies a profiler that we finished
4267 // creating the appdomain. If an exception is raised while we're in that managed code
4268 // we will leak memory and the profiler will not be notified about the failure
4270 #ifdef PROFILING_SUPPORTED
4271 // Signal profile if present.
4273 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
4274 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) (AppDomain*) pDomain);
4278 #endif // PROFILING_SUPPORTED
4281 SystemDomain::LockHolder lh;
4283 // allocate a Virtual Call Stub Manager for this domain
4287 pDomain->SetCanUnload(); // by default can unload any domain
4289 #ifdef DEBUGGING_SUPPORTED
4290 // Notify the debugger here, before the thread transitions into the
4291 // AD to finish the setup, and before any assemblies are loaded into it.
4292 SystemDomain::PublishAppDomainAndInformDebugger(pDomain);
4293 #endif // DEBUGGING_SUPPORTED
4295 STRESS_LOG2 (LF_APPDOMAIN, LL_INFO100, "Create domain [%d] %p\n", pDomain->GetId().m_dwId, (AppDomain*)pDomain);
4296 pDomain->LoadSystemAssemblies();
4297 pDomain->SetupSharedStatics();
4299 pDomain->SetStage(AppDomain::STAGE_ACTIVE);
4301 #ifdef PROFILING_SUPPORTED
4304 // Need the first assembly loaded in to get any data on an app domain.
4306 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
4307 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID)(AppDomain*) pDomain, GET_EXCEPTION()->GetHR());
4313 // On success, caller must still send the AppDomainCreationFinished notification.
4314 #endif // PROFILING_SUPPORTED
4317 void AppDomain::Stop()
4327 #ifdef FEATURE_MULTICOREJIT
4328 GetMulticoreJitManager().StopProfile(true);
4331 // Set the unloaded flag before notifying the debugger
4332 GetLoaderAllocator()->SetIsUnloaded();
4334 #ifdef DEBUGGING_SUPPORTED
4335 if (IsDebuggerAttached())
4336 NotifyDebuggerUnload();
4337 #endif // DEBUGGING_SUPPORTED
4339 m_pRootAssembly = NULL; // This assembly is in the assembly list;
4341 #ifdef DEBUGGING_SUPPORTED
4342 if (NULL != g_pDebugInterface)
4344 // Call the publisher API to delete this appdomain entry from the list
4345 CONTRACT_VIOLATION(ThrowsViolation);
4346 g_pDebugInterface->RemoveAppDomainFromIPC (this);
4348 #endif // DEBUGGING_SUPPORTED
4351 void AppDomain::Terminate()
4364 _ASSERTE(m_dwThreadEnterCount == 0 || IsDefaultDomain());
4366 if (m_pComIPForExposedObject)
4368 m_pComIPForExposedObject->Release();
4369 m_pComIPForExposedObject = NULL;
4372 delete m_pDefaultContext;
4373 m_pDefaultContext = NULL;
4375 if (m_pUMEntryThunkCache)
4377 delete m_pUMEntryThunkCache;
4378 m_pUMEntryThunkCache = NULL;
4381 #ifdef FEATURE_COMINTEROP
4390 delete m_pRCWRefCache;
4391 m_pRCWRefCache = NULL;
4394 if (m_pComCallWrapperCache)
4396 m_pComCallWrapperCache->Neuter();
4397 m_pComCallWrapperCache->Release();
4400 // if the above released the wrapper cache, then it will call back and reset our
4401 // m_pComCallWrapperCache to null. If not null, then need to set it's domain pointer to
4403 if (! m_pComCallWrapperCache)
4405 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::Terminate ComCallWrapperCache released\n"));
4410 m_pComCallWrapperCache = NULL;
4411 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::Terminate ComCallWrapperCache not released\n"));
4415 #endif // FEATURE_COMINTEROP
4418 if (!IsAtProcessExit())
4420 // if we're not shutting down everything then clean up the string literals associated
4421 // with this appdomain -- note that is no longer needs to happen while suspended
4422 // because the appropriate locks are taken in the GlobalStringLiteralMap
4423 // this is important as this locks have a higher lock number than does the
4424 // thread-store lock which is taken when we suspend.
4425 GetLoaderAllocator()->CleanupStringLiteralMap();
4427 // Suspend the EE to do some clean up that can only occur
4428 // while no threads are running.
4429 GCX_COOP (); // SuspendEE may require current thread to be in Coop mode
4430 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
4433 // Note that this must be performed before restarting the EE. It will clean
4434 // the cache and prevent others from using stale cache entries.
4435 //@TODO: Would be nice to get this back to BaseDomain, but need larger fix for that.
4436 // NOTE: Must have the runtime suspended to unlink managers
4437 // NOTE: May be NULL due to OOM during initialization. Can skip in that case.
4438 GetLoaderAllocator()->UninitVirtualCallStubManager();
4439 MethodTable::ClearMethodDataCache();
4440 ClearJitGenericHandleCache(this);
4442 // @TODO s_TPMethodTableCrst prevents us from from keeping the whole
4443 // assembly shutdown logic here. See if we can do better in the next milestone
4444 #ifdef FEATURE_PREJIT
4445 DeleteNativeCodeRanges();
4448 if (!IsAtProcessExit())
4451 ThreadSuspend::RestartEE(FALSE, TRUE);
4454 ShutdownAssemblies();
4455 ShutdownNativeDllSearchDirectories();
4457 if (m_pRefClassFactHash)
4459 m_pRefClassFactHash->Destroy();
4460 // storage for m_pRefClassFactHash itself is allocated on the loader heap
4463 #ifdef FEATURE_TYPEEQUIVALENCE
4464 m_TypeEquivalenceCrst.Destroy();
4467 m_ReflectionCrst.Destroy();
4468 m_RefClassFactCrst.Destroy();
4470 m_LoaderAllocator.Terminate();
4472 BaseDomain::Terminate();
4476 GCHandleUtilities::GetGCHandleManager()->DestroyHandleStore(m_handleStore);
4477 m_handleStore = NULL;
4480 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4481 if (m_pullAllocBytes)
4483 delete [] m_pullAllocBytes;
4485 if (m_pullSurvivedBytes)
4487 delete [] m_pullSurvivedBytes;
4489 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4491 if(m_dwIndex.m_dwIndex != 0)
4492 SystemDomain::ReleaseAppDomainIndex(m_dwIndex);
4493 } // AppDomain::Terminate
4495 void AppDomain::CloseDomain()
4506 BOOL bADRemoved=FALSE;;
4508 AddRef(); // Hold a reference
4509 AppDomainRefHolder AdHolder(this);
4511 SystemDomain::LockHolder lh;
4513 SystemDomain::System()->DecrementNumAppDomains(); // Maintain a count of app domains added to the list.
4514 bADRemoved = SystemDomain::System()->RemoveDomain(this);
4521 /*********************************************************************/
4523 struct GetExposedObject_Args
4529 static void GetExposedObject_Wrapper(LPVOID ptr)
4538 GetExposedObject_Args *args = (GetExposedObject_Args *) ptr;
4539 *(args->ref) = args->pDomain->GetExposedObject();
4543 OBJECTREF AppDomain::GetExposedObject()
4550 INJECT_FAULT(COMPlusThrowOM(););
4554 OBJECTREF ref = GetRawExposedObject();
4557 APPDOMAINREF obj = NULL;
4559 Thread *pThread = GetThread();
4560 if (pThread->GetDomain() != this)
4562 GCPROTECT_BEGIN(ref);
4563 GetExposedObject_Args args = {this, &ref};
4564 // call through DoCallBack with a domain transition
4565 pThread->DoADCallBack(this,GetExposedObject_Wrapper, &args,ADV_CREATING|ADV_RUNNINGIN);
4569 MethodTable *pMT = MscorlibBinder::GetClass(CLASS__APP_DOMAIN);
4571 // Create the module object
4572 obj = (APPDOMAINREF) AllocateObject(pMT);
4573 obj->SetDomain(this);
4575 if (!StoreFirstObjectInHandle(m_ExposedObject, (OBJECTREF) obj))
4577 obj = (APPDOMAINREF) GetRawExposedObject();
4581 return (OBJECTREF) obj;
4589 OBJECTREF AppDomain::DoSetup(OBJECTREF* setupInfo)
4596 INJECT_FAULT(COMPlusThrowOM(););
4600 ADID adid=GetAppDomain()->GetId();
4602 OBJECTREF retval=NULL;
4603 GCPROTECT_BEGIN(retval);
4605 ENTER_DOMAIN_PTR(this,ADV_CREATING);
4607 MethodDescCallSite setup(METHOD__APP_DOMAIN__SETUP);
4611 args[0]=ObjToArgSlot(*setupInfo);
4613 OBJECTREF activator;
4614 activator=setup.Call_RetOBJECTREF(args);
4615 _ASSERTE(activator==NULL);
4617 #if defined(FEATURE_MULTICOREJIT)
4618 // Disable AutoStartProfile in default domain from this code path.
4619 // It's called from SystemDomain::ExecuteMainMethod for normal program, not needed for SL and Asp.Net
4620 if (! IsDefaultDomain())
4624 GetMulticoreJitManager().AutoStartProfile(this);
4628 END_DOMAIN_TRANSITION;
4633 #endif // !CROSSGEN_COMPILE
4635 #ifdef FEATURE_COMINTEROP
4636 #ifndef CROSSGEN_COMPILE
4637 HRESULT AppDomain::GetComIPForExposedObject(IUnknown **pComIP)
4639 // Assumption: This function is called for AppDomain's that the current
4640 // thread is in or has entered, or the AppDomain is kept alive.
4642 // Assumption: This function can now throw. The caller is responsible for any
4643 // BEGIN_EXTERNAL_ENTRYPOINT, EX_TRY, or other
4644 // techniques to convert to a COM HRESULT protocol.
4654 Thread *pThread = GetThread();
4655 if (m_pComIPForExposedObject)
4657 GCX_PREEMP_THREAD_EXISTS(pThread);
4658 m_pComIPForExposedObject->AddRef();
4659 *pComIP = m_pComIPForExposedObject;
4663 IUnknown* punk = NULL;
4665 OBJECTREF ref = NULL;
4666 GCPROTECT_BEGIN(ref);
4670 ENTER_DOMAIN_PTR(this,ADV_DEFAULTAD)
4672 ref = GetExposedObject();
4673 punk = GetComIPFromObjectRef(&ref);
4674 if (FastInterlockCompareExchangePointer(&m_pComIPForExposedObject, punk, NULL) == NULL)
4676 GCX_PREEMP_THREAD_EXISTS(pThread);
4677 m_pComIPForExposedObject->AddRef();
4680 END_DOMAIN_TRANSITION;
4686 *pComIP = m_pComIPForExposedObject;
4691 #endif //#ifndef CROSSGEN_COMPILE
4693 MethodTable *AppDomain::GetRedirectedType(WinMDAdapter::RedirectedTypeIndex index)
4703 // If we have the type loaded already, use that
4704 if (m_rpCLRTypes[index] != nullptr)
4706 return m_rpCLRTypes[index];
4709 WinMDAdapter::FrameworkAssemblyIndex frameworkAssemblyIndex;
4710 WinMDAdapter::GetRedirectedTypeInfo(index, nullptr, nullptr, nullptr, &frameworkAssemblyIndex, nullptr, nullptr);
4711 MethodTable * pMT = LoadRedirectedType(index, frameworkAssemblyIndex);
4712 m_rpCLRTypes[index] = pMT;
4716 MethodTable* AppDomain::LoadRedirectedType(WinMDAdapter::RedirectedTypeIndex index, WinMDAdapter::FrameworkAssemblyIndex assembly)
4723 PRECONDITION(index < WinMDAdapter::RedirectedTypeIndex_Count);
4727 LPCSTR szClrNamespace;
4729 LPCSTR szFullWinRTName;
4730 WinMDAdapter::FrameworkAssemblyIndex nFrameworkAssemblyIndex;
4732 WinMDAdapter::GetRedirectedTypeInfo(index, &szClrNamespace, &szClrName, &szFullWinRTName, &nFrameworkAssemblyIndex, nullptr, nullptr);
4734 _ASSERTE(nFrameworkAssemblyIndex >= WinMDAdapter::FrameworkAssembly_Mscorlib &&
4735 nFrameworkAssemblyIndex < WinMDAdapter::FrameworkAssembly_Count);
4737 if (assembly != nFrameworkAssemblyIndex)
4739 // The framework type does not live in the assembly we were requested to load redirected types from
4742 else if (nFrameworkAssemblyIndex == WinMDAdapter::FrameworkAssembly_Mscorlib)
4744 return ClassLoader::LoadTypeByNameThrowing(MscorlibBinder::GetModule()->GetAssembly(),
4747 ClassLoader::ThrowIfNotFound,
4748 ClassLoader::LoadTypes,
4749 CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4754 AssemblyMetaDataInternal context;
4755 const BYTE * pbKeyToken;
4756 DWORD cbKeyTokenLength;
4759 WinMDAdapter::GetExtraAssemblyRefProps(nFrameworkAssemblyIndex,
4766 Assembly* pAssembly = AssemblySpec::LoadAssembly(pSimpleName,
4772 return ClassLoader::LoadTypeByNameThrowing(
4776 ClassLoader::ThrowIfNotFound,
4777 ClassLoader::LoadTypes,
4778 CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4781 #endif //FEATURE_COMINTEROP
4783 #endif //!DACCESS_COMPILE
4785 #ifndef DACCESS_COMPILE
4787 bool IsPlatformAssembly(LPCSTR szName, DomainAssembly *pDomainAssembly)
4794 PRECONDITION(CheckPointer(szName));
4795 PRECONDITION(CheckPointer(pDomainAssembly));
4799 PEAssembly *pPEAssembly = pDomainAssembly->GetFile();
4801 if (strcmp(szName, pPEAssembly->GetSimpleName()) != 0)
4807 const BYTE *pbPublicKey = static_cast<const BYTE *>(pPEAssembly->GetPublicKey(&cbPublicKey));
4808 if (pbPublicKey == nullptr)
4813 return StrongNameIsSilverlightPlatformKey(pbPublicKey, cbPublicKey);
4816 void AppDomain::AddAssembly(DomainAssembly * assem)
4823 INJECT_FAULT(COMPlusThrowOM(););
4828 CrstHolder ch(GetAssemblyListLock());
4830 // Attempt to find empty space in assemblies list
4831 DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4832 for (DWORD i = 0; i < asmCount; ++i)
4834 if (m_Assemblies.Get_UnlockedNoReference(i) == NULL)
4836 m_Assemblies.Set_Unlocked(i, assem);
4841 // If empty space not found, simply add to end of list
4842 IfFailThrow(m_Assemblies.Append_Unlocked(assem));
4846 void AppDomain::RemoveAssembly_Unlocked(DomainAssembly * pAsm)
4855 _ASSERTE(GetAssemblyListLock()->OwnedByCurrentThread());
4857 DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4858 for (DWORD i = 0; i < asmCount; ++i)
4860 if (m_Assemblies.Get_UnlockedNoReference(i) == pAsm)
4862 m_Assemblies.Set_Unlocked(i, NULL);
4867 _ASSERTE(!"Unreachable");
4870 BOOL AppDomain::ContainsAssembly(Assembly * assem)
4872 WRAPPER_NO_CONTRACT;
4873 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
4875 (assem->IsIntrospectionOnly() ? kIncludeIntrospection : kIncludeExecution)));
4876 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
4878 while (i.Next(pDomainAssembly.This()))
4880 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
4881 if (pAssembly == assem)
4888 EEClassFactoryInfoHashTable* AppDomain::SetupClassFactHash()
4895 INJECT_FAULT(COMPlusThrowOM(););
4899 CrstHolder ch(&m_ReflectionCrst);
4901 if (m_pRefClassFactHash == NULL)
4903 AllocMemHolder<void> pCache(GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (EEClassFactoryInfoHashTable))));
4904 EEClassFactoryInfoHashTable *tmp = new (pCache) EEClassFactoryInfoHashTable;
4905 LockOwner lock = {&m_RefClassFactCrst,IsOwnerOfCrst};
4906 if (!tmp->Init(20, &lock))
4908 pCache.SuppressRelease();
4909 m_pRefClassFactHash = tmp;
4912 return m_pRefClassFactHash;
4915 #ifdef FEATURE_COMINTEROP
4916 DispIDCache* AppDomain::SetupRefDispIDCache()
4923 INJECT_FAULT(COMPlusThrowOM(););
4927 CrstHolder ch(&m_ReflectionCrst);
4929 if (m_pRefDispIDCache == NULL)
4931 AllocMemHolder<void> pCache = GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (DispIDCache)));
4933 DispIDCache *tmp = new (pCache) DispIDCache;
4936 pCache.SuppressRelease();
4937 m_pRefDispIDCache = tmp;
4940 return m_pRefDispIDCache;
4943 #endif // FEATURE_COMINTEROP
4945 FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
4952 PRECONDITION(pLock->HasLock());
4953 PRECONDITION(pLock->FindFileLock(pFile) == NULL);
4954 INJECT_FAULT(COMPlusThrowOM(););
4958 NewHolder<FileLoadLock> result(new FileLoadLock(pLock, pFile, pDomainFile));
4960 pLock->AddElement(result);
4961 result->AddRef(); // Add one ref on behalf of the ListLock's reference. The corresponding Release() happens in FileLoadLock::CompleteLoadLevel.
4962 return result.Extract();
4965 FileLoadLock::~FileLoadLock()
4975 ((PEFile *) m_data)->Release();
4978 DomainFile *FileLoadLock::GetDomainFile()
4980 LIMITED_METHOD_CONTRACT;
4981 return m_pDomainFile;
4984 FileLoadLevel FileLoadLock::GetLoadLevel()
4986 LIMITED_METHOD_CONTRACT;
4990 ADID FileLoadLock::GetAppDomainId()
4992 LIMITED_METHOD_CONTRACT;
4993 return m_AppDomainId;
4996 // Acquire will return FALSE and not take the lock if the file
4997 // has already been loaded to the target level. Otherwise,
4998 // it will return TRUE and take the lock.
5000 // Note that the taker must release the lock via IncrementLoadLevel.
5002 BOOL FileLoadLock::Acquire(FileLoadLevel targetLevel)
5004 WRAPPER_NO_CONTRACT;
5006 // If we are already loaded to the desired level, the lock is "free".
5007 if (m_level >= targetLevel)
5010 if (!DeadlockAwareEnter())
5012 // We failed to get the lock due to a deadlock.
5016 if (m_level >= targetLevel)
5025 BOOL FileLoadLock::CanAcquire(FileLoadLevel targetLevel)
5027 // If we are already loaded to the desired level, the lock is "free".
5028 if (m_level >= targetLevel)
5031 return CanDeadlockAwareEnter();
5034 #if !defined(DACCESS_COMPILE) && (defined(LOGGING) || defined(STRESS_LOG))
5035 static const char *fileLoadLevelName[] =
5037 "CREATE", // FILE_LOAD_CREATE
5038 "BEGIN", // FILE_LOAD_BEGIN
5039 "FIND_NATIVE_IMAGE", // FILE_LOAD_FIND_NATIVE_IMAGE
5040 "VERIFY_NATIVE_IMAGE_DEPENDENCIES", // FILE_LOAD_VERIFY_NATIVE_IMAGE_DEPENDENCIES
5041 "ALLOCATE", // FILE_LOAD_ALLOCATE
5042 "ADD_DEPENDENCIES", // FILE_LOAD_ADD_DEPENDENCIES
5043 "PRE_LOADLIBRARY", // FILE_LOAD_PRE_LOADLIBRARY
5044 "LOADLIBRARY", // FILE_LOAD_LOADLIBRARY
5045 "POST_LOADLIBRARY", // FILE_LOAD_POST_LOADLIBRARY
5046 "EAGER_FIXUPS", // FILE_LOAD_EAGER_FIXUPS
5047 "VTABLE FIXUPS", // FILE_LOAD_VTABLE_FIXUPS
5048 "DELIVER_EVENTS", // FILE_LOAD_DELIVER_EVENTS
5049 "LOADED", // FILE_LOADED
5050 "VERIFY_EXECUTION", // FILE_LOAD_VERIFY_EXECUTION
5051 "ACTIVE", // FILE_ACTIVE
5053 #endif // !DACCESS_COMPILE && (LOGGING || STRESS_LOG)
5055 BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success)
5062 PRECONDITION(HasLock());
5066 // Increment may happen more than once if reentrancy occurs (e.g. LoadLibrary)
5067 if (level > m_level)
5069 // Must complete each level in turn, unless we have an error
5070 CONSISTENCY_CHECK(m_pDomainFile->IsError() || (level == (m_level+1)));
5071 // Remove the lock from the list if the load is completed
5072 if (level >= FILE_ACTIVE)
5076 PEFileListLockHolder lock((PEFileListLock*)m_pList);
5079 BOOL fDbgOnly_SuccessfulUnlink =
5081 m_pList->Unlink(this);
5082 _ASSERTE(fDbgOnly_SuccessfulUnlink);
5084 m_pDomainFile->ClearLoading();
5086 CONSISTENCY_CHECK(m_dwRefCount >= 2); // Caller (LoadDomainFile) should have 1 refcount and m_pList should have another which was acquired in FileLoadLock::Create.
5088 m_level = (FileLoadLevel)level;
5091 // In AppDomain::IsLoading, if the lock is taken on m_pList and then FindFileLock returns NULL,
5092 // we depend on the DomainFile's load level being up to date. Hence we must update the load
5093 // level while the m_pList lock is held.
5095 m_pDomainFile->SetLoadLevel(level);
5099 Release(); // Release m_pList's refcount on this lock, which was acquired in FileLoadLock::Create
5104 m_level = (FileLoadLevel)level;
5107 m_pDomainFile->SetLoadLevel(level);
5110 #ifndef DACCESS_COMPILE
5113 case FILE_LOAD_ALLOCATE:
5114 case FILE_LOAD_ADD_DEPENDENCIES:
5115 case FILE_LOAD_DELIVER_EVENTS:
5117 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.
5118 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);
5131 void FileLoadLock::SetError(Exception *ex)
5138 PRECONDITION(CheckPointer(ex));
5139 PRECONDITION(HasLock());
5140 INJECT_FAULT(COMPlusThrowOM(););
5144 m_cachedHR = ex->GetHR();
5146 LOG((LF_LOADER, LL_WARNING, "LOADER: %x:***%s*\t!!!Non-transient error 0x%x\n",
5147 m_pDomainFile->GetAppDomain(), m_pDomainFile->GetSimpleName(), m_cachedHR));
5149 m_pDomainFile->SetError(ex);
5151 CompleteLoadLevel(FILE_ACTIVE, FALSE);
5154 void FileLoadLock::AddRef()
5156 LIMITED_METHOD_CONTRACT;
5157 FastInterlockIncrement((LONG *) &m_dwRefCount);
5160 UINT32 FileLoadLock::Release()
5170 LONG count = FastInterlockDecrement((LONG *) &m_dwRefCount);
5177 FileLoadLock::FileLoadLock(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
5178 : ListLockEntry(pLock, pFile, "File load lock"),
5179 m_level((FileLoadLevel) (FILE_LOAD_CREATE)),
5180 m_pDomainFile(pDomainFile),
5182 m_AppDomainId(pDomainFile->GetAppDomain()->GetId())
5184 WRAPPER_NO_CONTRACT;
5188 void FileLoadLock::HolderLeave(FileLoadLock *pThis)
5190 LIMITED_METHOD_CONTRACT;
5200 // Assembly loading:
5202 // Assembly loading is carefully layered to avoid deadlocks in the
5203 // presence of circular loading dependencies.
5204 // A LoadLevel is associated with each assembly as it is being loaded. During the
5205 // act of loading (abstractly, increasing its load level), its lock is
5206 // held, and the current load level is stored on the thread. Any
5207 // recursive loads during that period are automatically restricted to
5208 // only partially load the dependent assembly to the same level as the
5209 // caller (or to one short of that level in the presence of a deadlock
5212 // Each loading stage must be carfully constructed so that
5213 // this constraint is expected and can be dealt with.
5215 // Note that there is one case where this still doesn't handle recursion, and that is the
5216 // security subsytem. The security system runs managed code, and thus must typically fully
5217 // initialize assemblies of permission sets it is trying to use. (And of course, these may be used
5218 // while those assemblies are initializing.) This is dealt with in the historical manner - namely
5219 // the security system passes in a special flag which says that it will deal with null return values
5220 // in the case where a load cannot be safely completed due to such issues.
5223 void AppDomain::LoadSystemAssemblies()
5225 STANDARD_VM_CONTRACT;
5227 // The only reason to make an assembly a "system assembly" is if the EE is caching
5228 // pointers to stuff in the assembly. Because this is going on, we need to preserve
5229 // the invariant that the assembly is loaded into every app domain.
5231 // Right now we have only one system assembly. We shouldn't need to add any more.
5233 LoadAssembly(NULL, SystemDomain::System()->SystemFile(), FILE_ACTIVE);
5236 FileLoadLevel AppDomain::GetDomainFileLoadLevel(DomainFile *pFile)
5246 LoadLockHolder lock(this);
5248 FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5250 if (pLockEntry == NULL)
5251 return pFile->GetLoadLevel();
5253 return pLockEntry->GetLoadLevel();
5256 // This checks if the thread has initiated (or completed) loading at the given level. A false guarantees that
5257 // (a) The current thread (or a thread blocking on the current thread) has not started loading the file
5258 // at the given level, and
5259 // (b) No other thread had started loading the file at this level at the start of this function call.
5261 // Note that another thread may start loading the file at that level in a race with the completion of
5262 // this function. However, the caller still has the guarantee that such a load started after this
5263 // function was called (and e.g. any state in place before the function call will be seen by the other thread.)
5265 // Conversely, a true guarantees that either the current thread has started the load step, or another
5266 // thread has completed the load step.
5269 BOOL AppDomain::IsLoading(DomainFile *pFile, FileLoadLevel level)
5272 if (pFile->GetLoadLevel() < level)
5274 FileLoadLock *pLock = NULL;
5276 LoadLockHolder lock(this);
5278 pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5282 // No thread involved with loading
5283 return pFile->GetLoadLevel() >= level;
5289 FileLoadLockRefHolder lockRef(pLock);
5291 if (pLock->Acquire(level))
5293 // We got the lock - therefore no other thread has started this loading step yet.
5298 // We didn't get the lock - either this thread is already doing the load,
5299 // or else the load has already finished.
5304 // CheckLoading is a weaker form of IsLoading, which will not block on
5305 // other threads waiting for their status. This is appropriate for asserts.
5306 CHECK AppDomain::CheckLoading(DomainFile *pFile, FileLoadLevel level)
5309 if (pFile->GetLoadLevel() < level)
5311 FileLoadLock *pLock = NULL;
5313 LoadLockHolder lock(this);
5315 pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5318 && pLock->CanAcquire(level))
5320 // We can get the lock - therefore no other thread has started this loading step yet.
5321 CHECK_FAILF(("Loading step %d has not been initiated yet", level));
5324 // We didn't get the lock - either this thread is already doing the load,
5325 // or else the load has already finished.
5331 CHECK AppDomain::CheckCanLoadTypes(Assembly *pAssembly)
5340 CHECK_MSG(CheckValidModule(pAssembly->GetManifestModule()),
5341 "Type loading can occur only when executing in the assembly's app domain");
5345 CHECK AppDomain::CheckCanExecuteManagedCode(MethodDesc* pMD)
5355 Module* pModule=pMD->GetModule();
5357 CHECK_MSG(CheckValidModule(pModule),
5358 "Managed code can only run when executing in the module's app domain");
5360 if (!pMD->IsInterface() || pMD->IsStatic()) //interfaces require no activation for instance methods
5362 //cctor could have been interupted by ADU
5363 CHECK_MSG(HasUnloadStarted() || pModule->CheckActivated(),
5364 "Managed code can only run when its module has been activated in the current app domain");
5367 CHECK_MSG(!IsPassiveDomain() || pModule->CanExecuteCode(),
5368 "Executing managed code from an unsafe assembly in a Passive AppDomain");
5373 #endif // !DACCESS_COMPILE
5375 void AppDomain::LoadDomainFile(DomainFile *pFile,
5376 FileLoadLevel targetLevel)
5380 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
5381 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
5382 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM();); }
5383 INJECT_FAULT(COMPlusThrowOM(););
5387 // Quick exit if finished
5388 if (pFile->GetLoadLevel() >= targetLevel)
5391 // Handle the error case
5392 pFile->ThrowIfError(targetLevel);
5395 #ifndef DACCESS_COMPILE
5397 if (pFile->IsLoading())
5401 // Load some more if appropriate
5402 LoadLockHolder lock(this);
5404 FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5405 if (pLockEntry == NULL)
5407 _ASSERTE (!pFile->IsLoading());
5411 pLockEntry->AddRef();
5415 LoadDomainFile(pLockEntry, targetLevel);
5418 #else // DACCESS_COMPILE
5420 #endif // DACCESS_COMPILE
5423 #ifndef DACCESS_COMPILE
5425 FileLoadLevel AppDomain::GetThreadFileLoadLevel()
5427 WRAPPER_NO_CONTRACT;
5428 if (GetThread()->GetLoadLevelLimiter() == NULL)
5431 return (FileLoadLevel)(GetThread()->GetLoadLevelLimiter()->GetLoadLevel()-1);
5435 Assembly *AppDomain::LoadAssembly(AssemblySpec* pIdentity,
5437 FileLoadLevel targetLevel)
5439 CONTRACT(Assembly *)
5444 PRECONDITION(CheckPointer(pFile));
5445 POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // May be NULL in recursive load case
5446 INJECT_FAULT(COMPlusThrowOM(););
5450 DomainAssembly *pAssembly = LoadDomainAssembly(pIdentity, pFile, targetLevel);
5451 PREFIX_ASSUME(pAssembly != NULL);
5453 RETURN pAssembly->GetAssembly();
5456 #ifndef CROSSGEN_COMPILE
5458 class LoadDomainAssemblyStress : APIThreadStress
5462 AssemblySpec* pSpec;
5464 FileLoadLevel targetLevel;
5466 LoadDomainAssemblyStress(AppDomain *pThis, AssemblySpec* pSpec, PEAssembly *pFile, FileLoadLevel targetLevel)
5467 : pThis(pThis), pSpec(pSpec), pFile(pFile), targetLevel(targetLevel) {LIMITED_METHOD_CONTRACT;}
5471 WRAPPER_NO_CONTRACT;
5472 STATIC_CONTRACT_SO_INTOLERANT;
5474 pThis->LoadDomainAssembly(pSpec, pFile, targetLevel);
5477 #endif // CROSSGEN_COMPILE
5479 extern BOOL AreSameBinderInstance(ICLRPrivBinder *pBinderA, ICLRPrivBinder *pBinderB);
5481 DomainAssembly* AppDomain::LoadDomainAssembly( AssemblySpec* pSpec,
5483 FileLoadLevel targetLevel)
5485 STATIC_CONTRACT_THROWS;
5487 if (pSpec == nullptr)
5489 // skip caching, since we don't have anything to base it on
5490 return LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
5493 DomainAssembly* pRetVal = NULL;
5496 pRetVal = LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
5500 Exception* pEx=GET_EXCEPTION();
5501 if (!pEx->IsTransient())
5503 // Setup the binder reference in AssemblySpec from the PEAssembly if one is not already set.
5504 ICLRPrivBinder* pCurrentBindingContext = pSpec->GetBindingContext();
5505 ICLRPrivBinder* pBindingContextFromPEAssembly = pFile->GetBindingContext();
5507 if (pCurrentBindingContext == NULL)
5509 // Set the binding context we got from the PEAssembly if AssemblySpec does not
5510 // have that information
5511 _ASSERTE(pBindingContextFromPEAssembly != NULL);
5512 pSpec->SetBindingContext(pBindingContextFromPEAssembly);
5517 // Binding context in the spec should be the same as the binding context in the PEAssembly
5518 _ASSERTE(AreSameBinderInstance(pCurrentBindingContext, pBindingContextFromPEAssembly));
5522 if (!EEFileLoadException::CheckType(pEx))
5525 pSpec->GetFileOrDisplayName(0, name);
5526 pEx=new EEFileLoadException(name, pEx->GetHR(), NULL, pEx);
5527 AddExceptionToCache(pSpec, pEx);
5528 PAL_CPP_THROW(Exception *, pEx);
5531 AddExceptionToCache(pSpec, pEx);
5540 DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
5542 FileLoadLevel targetLevel)
5544 CONTRACT(DomainAssembly *)
5549 PRECONDITION(CheckPointer(pFile));
5550 PRECONDITION(pFile->IsSystem() || ::GetAppDomain()==this);
5551 POSTCONDITION(CheckPointer(RETVAL));
5552 POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
5553 || RETVAL->GetLoadLevel() >= targetLevel);
5554 POSTCONDITION(RETVAL->CheckNoError(targetLevel));
5555 INJECT_FAULT(COMPlusThrowOM(););
5560 DomainAssembly * result;
5562 #ifndef CROSSGEN_COMPILE
5563 LoadDomainAssemblyStress ts (this, pIdentity, pFile, targetLevel);
5566 // Go into preemptive mode since this may take a while.
5569 // Check for existing fully loaded assembly, or for an assembly which has failed during the loading process.
5570 result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
5574 // Allocate the DomainAssembly a bit early to avoid GC mode problems. We could potentially avoid
5575 // a rare redundant allocation by moving this closer to FileLoadLock::Create, but it's not worth it.
5577 NewHolder<DomainAssembly> pDomainAssembly;
5578 pDomainAssembly = new DomainAssembly(this, pFile, this->GetLoaderAllocator());
5580 LoadLockHolder lock(this);
5582 // Find the list lock entry
5583 FileLoadLock * fileLock = (FileLoadLock *)lock->FindFileLock(pFile);
5584 if (fileLock == NULL)
5586 // Check again in case we were racing
5587 result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
5590 // We are the first one in - create the DomainAssembly
5591 fileLock = FileLoadLock::Create(lock, pFile, pDomainAssembly);
5592 pDomainAssembly.SuppressRelease();
5604 // We pass our ref on fileLock to LoadDomainFile to release.
5606 // Note that if we throw here, we will poison fileLock with an error condition,
5607 // so it will not be removed until app domain unload. So there is no need
5608 // to release our ref count.
5609 result = (DomainAssembly *)LoadDomainFile(fileLock, targetLevel);
5613 result->EnsureLoadLevel(targetLevel);
5617 result->EnsureLoadLevel(targetLevel);
5619 // Malformed metadata may contain a Module reference to what is actually
5620 // an Assembly. In this case we need to throw an exception, since returning
5621 // a DomainModule as a DomainAssembly is a type safety violation.
5622 if (!result->IsAssembly())
5624 ThrowHR(COR_E_ASSEMBLYEXPECTED);
5627 // Cache result in all cases, since found pFile could be from a different AssemblyRef than pIdentity
5628 // Do not cache WindowsRuntime assemblies, they are cached in code:CLRPrivTypeCacheWinRT
5629 if ((pIdentity != NULL) && (pIdentity->CanUseWithBindingCache()) && (result->CanUseWithBindingCache()))
5630 GetAppDomain()->AddAssemblyToCache(pIdentity, result);
5633 } // AppDomain::LoadDomainAssembly
5638 FileLoadLock *pLock;
5639 FileLoadLevel targetLevel;
5643 #ifndef CROSSGEN_COMPILE
5644 static void LoadDomainFile_Wrapper(void *ptr)
5646 WRAPPER_NO_CONTRACT;
5647 STATIC_CONTRACT_SO_INTOLERANT;
5649 LoadFileArgs *args = (LoadFileArgs *) ptr;
5650 args->result = GetAppDomain()->LoadDomainFile(args->pLock, args->targetLevel);
5652 #endif // !CROSSGEN_COMPILE
5654 DomainFile *AppDomain::LoadDomainFile(FileLoadLock *pLock, FileLoadLevel targetLevel)
5656 CONTRACT(DomainFile *)
5659 PRECONDITION(CheckPointer(pLock));
5660 PRECONDITION(pLock->GetDomainFile()->GetAppDomain() == this);
5661 POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
5662 || RETVAL->GetLoadLevel() >= targetLevel);
5663 POSTCONDITION(RETVAL->CheckNoError(targetLevel));
5669 COMPlusThrow(kAppDomainUnloadedException);
5672 APIThreadStress::SyncThreadStress();
5674 DomainFile *pFile = pLock->GetDomainFile();
5676 // Make sure we release the lock on exit
5677 FileLoadLockRefHolder lockRef(pLock);
5679 // We need to perform the early steps of loading mscorlib without a domain transition. This is
5680 // important for bootstrapping purposes - we need to get mscorlib at least partially loaded
5681 // into a domain before we can run serialization code to do the transition.
5683 // Note that we cannot do this in general for all assemblies, because some of the security computations
5684 // require the managed exposed object, which must be created in the correct app domain.
5686 if (this != GetAppDomain()
5687 && pFile->GetFile()->IsSystem()
5688 && targetLevel > FILE_LOAD_ALLOCATE)
5690 // Re-call the routine with a limited load level. This will cause the first part of the load to
5691 // get performed in the current app domain.
5694 LoadDomainFile(pLock, targetLevel > FILE_LOAD_ALLOCATE ? FILE_LOAD_ALLOCATE : targetLevel);
5696 // Now continue on to complete the rest of the load, if any.
5699 // Do a quick out check for the already loaded case.
5700 if (pLock->GetLoadLevel() >= targetLevel)
5702 pFile->ThrowIfError(targetLevel);
5707 #ifndef CROSSGEN_COMPILE
5708 // Make sure we are in the right domain. Many of the load operations require the target domain
5709 // to be the current app domain, most notably anything involving managed code or managed object
5711 if (this != GetAppDomain()
5712 && (!pFile->GetFile()->IsSystem() || targetLevel > FILE_LOAD_ALLOCATE))
5714 // Transition to the correct app domain and perform the load there.
5717 // we will release the lock in the other app domain
5718 lockRef.SuppressRelease();
5720 if(!CanLoadCode() || GetDefaultContext() ==NULL)
5721 COMPlusThrow(kAppDomainUnloadedException);
5722 LoadFileArgs args = {pLock, targetLevel, NULL};
5723 GetThread()->DoADCallBack(this, LoadDomainFile_Wrapper, (void *) &args, ADV_CREATING);
5727 #endif // CROSSGEN_COMPILE
5729 // Initialize a loading queue. This will hold any loads which are triggered recursively but
5730 // which cannot be immediately satisfied due to anti-deadlock constraints.
5732 // PendingLoadQueues are allocated on the stack during a load, and
5733 // shared with all nested loads on the same thread. (Note that we won't use
5734 // "candidate" if we are in a recursive load; that's OK since they are cheap to
5736 FileLoadLevel immediateTargetLevel = targetLevel;
5738 LoadLevelLimiter limit;
5741 // We cannot set a target level higher than that allowed by the limiter currently.
5742 // This is because of anti-deadlock constraints.
5743 if (immediateTargetLevel > limit.GetLoadLevel())
5744 immediateTargetLevel = limit.GetLoadLevel();
5746 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t>>>Load initiated, %s/%s\n",
5747 pFile->GetAppDomain(), pFile->GetSimpleName(),
5748 fileLoadLevelName[immediateTargetLevel], fileLoadLevelName[targetLevel]));
5750 // Now loop and do the load incrementally to the target level.
5751 if (pLock->GetLoadLevel() < immediateTargetLevel)
5754 APIThreadStress::SyncThreadStress();
5756 while (pLock->Acquire(immediateTargetLevel))
5758 FileLoadLevel workLevel;
5760 FileLoadLockHolder fileLock(pLock);
5762 // Work level is next step to do
5763 workLevel = (FileLoadLevel)(fileLock->GetLoadLevel()+1);
5765 // Set up the anti-deadlock constraint: we cannot safely recursively load any assemblies
5766 // on this thread to a higher level than this assembly is being loaded now.
5767 // Note that we do allow work at a parallel level; any deadlocks caused here will
5768 // be resolved by the deadlock detection in the FileLoadLocks.
5769 limit.SetLoadLevel(workLevel);
5772 (workLevel == FILE_LOAD_BEGIN
5773 || workLevel == FILE_LOADED
5774 || workLevel == FILE_ACTIVE)
5775 ? LL_INFO10 : LL_INFO1000,
5776 "LOADER: %p:***%s*\t loading at level %s\n",
5777 this, pFile->GetSimpleName(), fileLoadLevelName[workLevel]));
5779 TryIncrementalLoad(pFile, workLevel, fileLock);
5781 TESTHOOKCALL(CompletedFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5784 if (pLock->GetLoadLevel() == immediateTargetLevel-1)
5786 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load limited due to detected deadlock, %s\n",
5787 pFile->GetAppDomain(), pFile->GetSimpleName(),
5788 fileLoadLevelName[immediateTargetLevel-1]));
5792 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load completed, %s\n",
5793 pFile->GetAppDomain(), pFile->GetSimpleName(),
5794 fileLoadLevelName[pLock->GetLoadLevel()]));
5798 // There may have been an error stored on the domain file by another thread, or from a previous load
5799 pFile->ThrowIfError(targetLevel);
5801 // There are two normal results from the above loop.
5803 // 1. We succeeded in loading the file to the current thread's load level.
5804 // 2. We succeeded in loading the file to the current thread's load level - 1, due
5805 // to deadlock condition with another thread loading the same assembly.
5807 // Either of these are considered satisfactory results, as code inside a load must expect
5808 // a parial load result.
5810 // However, if load level elevation has occurred, then it is possible for a deadlock to
5811 // prevent us from loading an assembly which was loading before the elevation at a radically
5812 // lower level. In such a case, we throw an exception which transiently fails the current
5813 // load, since it is likely we have not satisfied the caller.
5814 // (An alternate, and possibly preferable, strategy here would be for all callers to explicitly
5815 // identify the minimum load level acceptable via CheckLoadDomainFile and throw from there.)
5817 pFile->RequireLoadLevel((FileLoadLevel)(immediateTargetLevel-1));
5823 void AppDomain::TryIncrementalLoad(DomainFile *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder)
5825 STANDARD_VM_CONTRACT;
5827 // This is factored out so we don't call EX_TRY in a loop (EX_TRY can _alloca)
5829 BOOL released = FALSE;
5830 FileLoadLock* pLoadLock = lockHolder.GetValue();
5835 // Special case: for LoadLibrary, we cannot hold the lock during the
5836 // actual LoadLibrary call, because we might get a callback from _CorDllMain on any
5837 // other thread. (Note that this requires DomainFile's LoadLibrary to be independently threadsafe.)
5839 if (workLevel == FILE_LOAD_LOADLIBRARY)
5841 lockHolder.Release();
5846 TESTHOOKCALL(NextFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5847 BOOL success = pFile->DoIncrementalLoad(workLevel);
5848 TESTHOOKCALL(CompletingFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5851 // Reobtain lock to increment level. (Note that another thread may
5852 // have already done it which is OK.
5853 if (pLoadLock->Acquire(workLevel))
5855 // note lockHolder.Acquire isn't wired up to actually take the lock
5856 lockHolder = pLoadLock;
5863 // Complete the level.
5864 if (pLoadLock->CompleteLoadLevel(workLevel, success) &&
5865 pLoadLock->GetLoadLevel()==FILE_LOAD_DELIVER_EVENTS)
5867 lockHolder.Release();
5869 pFile->DeliverAsyncEvents();
5875 Exception *pEx = GET_EXCEPTION();
5878 //We will cache this error and wire this load to forever fail,
5879 // unless the exception is transient or the file is loaded OK but just cannot execute
5880 if (!pEx->IsTransient() && !pFile->IsLoaded())
5885 // Reobtain lock to increment level. (Note that another thread may
5886 // have already done it which is OK.
5887 if (pLoadLock->Acquire(workLevel)) // note pLockHolder->Acquire isn't wired up to actually take the lock
5889 // note lockHolder.Acquire isn't wired up to actually take the lock
5890 lockHolder = pLoadLock;
5897 // Report the error in the lock
5898 pLoadLock->SetError(pEx);
5901 if (!EEFileLoadException::CheckType(pEx))
5902 EEFileLoadException::Throw(pFile->GetFile(), pEx->GetHR(), pEx);
5905 // Otherwise, we simply abort this load, and can retry later on.
5906 // @todo cleanup: make sure that each level is restartable after an exception, and
5907 // leaves no bad side effects
5912 // Checks whether the module is valid to be in the given app domain (need not be yet loaded)
5913 CHECK AppDomain::CheckValidModule(Module * pModule)
5923 if (pModule->FindDomainFile(this) != NULL)
5928 Assembly * pAssembly = pModule->GetAssembly();
5930 CCHECK(pAssembly->IsDomainNeutral());
5931 #ifdef FEATURE_LOADER_OPTIMIZATION
5932 Assembly * pSharedAssembly = NULL;
5933 _ASSERTE(this == ::GetAppDomain());
5935 SharedAssemblyLocator locator(pAssembly->GetManifestFile());
5936 pSharedAssembly = SharedDomain::GetDomain()->FindShareableAssembly(&locator);
5939 CCHECK(pAssembly == pSharedAssembly);
5947 #ifdef FEATURE_LOADER_OPTIMIZATION
5948 // Loads an existing Module into an AppDomain
5949 // WARNING: this can only be done in a very limited scenario - the Module must be an unloaded domain neutral
5950 // dependency in the app domain in question. Normal code should not call this!
5951 DomainFile *AppDomain::LoadDomainNeutralModuleDependency(Module *pModule, FileLoadLevel targetLevel)
5953 CONTRACT(DomainFile *)
5958 PRECONDITION(::GetAppDomain()==this);
5959 PRECONDITION(CheckPointer(pModule));
5960 POSTCONDITION(CheckValidModule(pModule));
5961 POSTCONDITION(CheckPointer(RETVAL));
5962 POSTCONDITION(RETVAL->GetModule() == pModule);
5966 DomainFile *pDomainFile = pModule->FindDomainFile(this);
5968 STRESS_LOG3(LF_CLASSLOADER, LL_INFO100,"LDNMD: DomainFile %p for module %p in AppDomain %i\n",pDomainFile,pModule,GetId().m_dwId);
5970 if (pDomainFile == NULL)
5974 Assembly *pAssembly = pModule->GetAssembly();
5976 DomainAssembly *pDomainAssembly = pAssembly->FindDomainAssembly(this);
5977 if (pDomainAssembly == NULL)
5979 AssemblySpec spec(this);
5980 spec.InitializeSpec(pAssembly->GetManifestFile());
5982 pDomainAssembly = spec.LoadDomainAssembly(targetLevel);
5986 //if the domain assembly already exists, we need to load it to the target level
5987 pDomainAssembly->EnsureLoadLevel (targetLevel);
5990 if(pAssembly != pDomainAssembly->GetAssembly())
5992 ThrowHR(SECURITY_E_INCOMPATIBLE_SHARE);
5995 _ASSERTE (pModule == pAssembly->GetManifestModule());
5996 pDomainFile = pDomainAssembly;
6000 // If the DomainFile already exists, we need to load it to the target level.
6001 pDomainFile->EnsureLoadLevel (targetLevel);
6007 AppDomain::SharePolicy AppDomain::GetSharePolicy()
6009 LIMITED_METHOD_CONTRACT;
6011 return SHARE_POLICY_NEVER;
6013 #endif // FEATURE_LOADER_OPTIMIZATION
6016 void AppDomain::CheckForMismatchedNativeImages(AssemblySpec * pSpec, const GUID * pGuid)
6018 STANDARD_VM_CONTRACT;
6021 // The native images are ever used only for trusted images in CoreCLR.
6022 // We don't wish to open the IL file at runtime so we just forgo any
6023 // eager consistency checking. But we still want to prevent mistmatched
6024 // NGen images from being used. We record all mappings between assembly
6025 // names and MVID, and fail once we detect mismatch.
6028 if (pSpec->IsStrongNamed() && pSpec->HasPublicKey())
6030 pSpec->ConvertPublicKeyToToken();
6034 // CoreCLR binder unifies assembly versions. Ignore assembly version here to
6035 // detect more types of potential mismatches.
6037 AssemblyMetaDataInternal * pContext = pSpec->GetContext();
6038 pContext->usMajorVersion = (USHORT)-1;
6039 pContext->usMinorVersion = (USHORT)-1;
6040 pContext->usBuildNumber = (USHORT)-1;
6041 pContext->usRevisionNumber = (USHORT)-1;
6043 // Ignore the WinRT type while considering if two assemblies have the same identity.
6044 pSpec->SetWindowsRuntimeType(NULL, NULL);
6046 CrstHolder ch(&m_DomainCrst);
6048 const NativeImageDependenciesEntry * pEntry = m_NativeImageDependencies.Lookup(pSpec);
6052 if (*pGuid != pEntry->m_guidMVID)
6055 msg.Printf("ERROR: Native images generated against multiple versions of assembly %s. ", pSpec->GetName());
6056 WszOutputDebugString(msg.GetUnicode());
6057 COMPlusThrowNonLocalized(kFileLoadException, msg.GetUnicode());
6063 // No entry yet - create one
6065 AllocMemTracker amTracker;
6066 AllocMemTracker *pamTracker = &amTracker;
6068 NativeImageDependenciesEntry * pNewEntry =
6069 new (pamTracker->Track(GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(NativeImageDependenciesEntry)))))
6070 NativeImageDependenciesEntry();
6072 pNewEntry->m_AssemblySpec.CopyFrom(pSpec);
6073 pNewEntry->m_AssemblySpec.CloneFieldsToLoaderHeap(AssemblySpec::ALL_OWNED, GetLowFrequencyHeap(), pamTracker);
6075 pNewEntry->m_guidMVID = *pGuid;
6077 m_NativeImageDependencies.Add(pNewEntry);
6078 amTracker.SuppressRelease();
6083 void AppDomain::SetupSharedStatics()
6090 INJECT_FAULT(COMPlusThrowOM(););
6094 #ifndef CROSSGEN_COMPILE
6095 if (NingenEnabled())
6098 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: SetupSharedStatics()"));
6100 // don't do any work in init stage. If not init only do work in non-shared case if are default domain
6101 _ASSERTE(!g_fEEInit);
6103 // Because we are allocating/referencing objects, need to be in cooperative mode
6106 static OBJECTHANDLE hSharedStaticsHandle = NULL;
6108 if (hSharedStaticsHandle == NULL) {
6109 // Note that there is no race here since the default domain is always set up first
6110 _ASSERTE(IsDefaultDomain());
6112 MethodTable *pMT = MscorlibBinder::GetClass(CLASS__SHARED_STATICS);
6113 _ASSERTE(pMT->IsClassPreInited());
6115 hSharedStaticsHandle = CreateGlobalHandle(AllocateObject(pMT));
6118 DomainLocalModule *pLocalModule;
6120 if (IsSingleAppDomain())
6122 pLocalModule = MscorlibBinder::GetModule()->GetDomainLocalModule();
6126 pLocalModule = GetDomainLocalBlock()->GetModuleSlot(
6127 MscorlibBinder::GetModule()->GetModuleIndex());
6130 FieldDesc *pFD = MscorlibBinder::GetField(FIELD__SHARED_STATICS__SHARED_STATICS);
6132 OBJECTREF* pHandle = (OBJECTREF*)
6133 ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pFD->GetOffset());
6134 SetObjectReference( pHandle, ObjectFromHandle(hSharedStaticsHandle), this );
6136 // This is a convenient place to initialize String.Empty.
6137 // It is treated as intrinsic by the JIT as so the static constructor would never run.
6138 // Leaving it uninitialized would confuse debuggers.
6140 // String should not have any static constructors.
6141 _ASSERTE(g_pStringClass->IsClassPreInited());
6143 FieldDesc * pEmptyStringFD = MscorlibBinder::GetField(FIELD__STRING__EMPTY);
6144 OBJECTREF* pEmptyStringHandle = (OBJECTREF*)
6145 ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pEmptyStringFD->GetOffset());
6146 SetObjectReference( pEmptyStringHandle, StringObject::GetEmptyString(), this );
6147 #endif // CROSSGEN_COMPILE
6150 DomainAssembly * AppDomain::FindAssembly(PEAssembly * pFile, FindAssemblyOptions options/* = FindAssemblyOptions_None*/)
6157 INJECT_FAULT(COMPlusThrowOM(););
6161 const bool includeFailedToLoad = (options & FindAssemblyOptions_IncludeFailedToLoad) != 0;
6163 if (pFile->HasHostAssembly())
6165 DomainAssembly * pDA = FindAssembly(pFile->GetHostAssembly());
6166 if (pDA != nullptr && (pDA->IsLoaded() || (includeFailedToLoad && pDA->IsError())))
6173 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
6175 (includeFailedToLoad ? kIncludeFailedToLoad : 0) |
6176 (pFile->IsIntrospectionOnly() ? kIncludeIntrospection : kIncludeExecution)));
6177 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
6179 while (i.Next(pDomainAssembly.This()))
6181 PEFile * pManifestFile = pDomainAssembly->GetFile();
6182 if (pManifestFile &&
6183 !pManifestFile->IsResource() &&
6184 pManifestFile->Equals(pFile))
6186 // Caller already has PEAssembly, so we can give DomainAssembly away freely without AddRef
6187 return pDomainAssembly.Extract();
6193 static const AssemblyIterationFlags STANDARD_IJW_ITERATOR_FLAGS =
6194 (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kExcludeCollectible);
6197 void AppDomain::SetFriendlyName(LPCWSTR pwzFriendlyName, BOOL fDebuggerCares/*=TRUE*/)
6202 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6204 INJECT_FAULT(COMPlusThrowOM(););
6208 // Do all computations into a temporary until we're ensured of success
6209 SString tmpFriendlyName;
6212 if (pwzFriendlyName)
6213 tmpFriendlyName.Set(pwzFriendlyName);
6216 // If there is an assembly, try to get the name from it.
6217 // If no assembly, but if it's the DefaultDomain, then give it a name
6219 if (m_pRootAssembly)
6221 tmpFriendlyName.SetUTF8(m_pRootAssembly->GetSimpleName());
6223 SString::Iterator i = tmpFriendlyName.End();
6224 if (tmpFriendlyName.FindBack(i, '.'))
6225 tmpFriendlyName.Truncate(i);
6229 if (IsDefaultDomain())
6230 tmpFriendlyName.Set(DEFAULT_DOMAIN_FRIENDLY_NAME);
6232 // This is for the profiler - if they call GetFriendlyName on an AppdomainCreateStarted
6233 // event, then we want to give them a temporary name they can use.
6234 else if (GetId().m_dwId != 0)
6236 tmpFriendlyName.Clear();
6237 tmpFriendlyName.Printf(W("%s %d"), OTHER_DOMAIN_FRIENDLY_NAME_PREFIX, GetId().m_dwId);
6243 tmpFriendlyName.Normalize();
6246 m_friendlyName = tmpFriendlyName;
6247 m_friendlyName.Normalize();
6249 if(g_pDebugInterface)
6251 // update the name in the IPC publishing block
6252 if (SUCCEEDED(g_pDebugInterface->UpdateAppDomainEntryInIPC(this)))
6254 // inform the attached debugger that the name of this appdomain has changed.
6255 if (IsDebuggerAttached() && fDebuggerCares)
6256 g_pDebugInterface->NameChangeEvent(this, NULL);
6261 void AppDomain::ResetFriendlyName(BOOL fDebuggerCares/*=TRUE*/)
6263 WRAPPER_NO_CONTRACT;
6264 SetFriendlyName(NULL, fDebuggerCares);
6267 LPCWSTR AppDomain::GetFriendlyName(BOOL fDebuggerCares/*=TRUE*/)
6272 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6274 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6275 INJECT_FAULT(COMPlusThrowOM(););
6280 // Handle NULL this pointer - this happens sometimes when printing log messages
6281 // but in general shouldn't occur in real code
6286 if (m_friendlyName.IsEmpty())
6287 SetFriendlyName(NULL, fDebuggerCares);
6289 RETURN m_friendlyName;
6292 LPCWSTR AppDomain::GetFriendlyNameForLogging()
6299 POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
6303 // Handle NULL this pointer - this happens sometimes when printing log messages
6304 // but in general shouldn't occur in real code
6308 RETURN (m_friendlyName.IsEmpty() ?W(""):(LPCWSTR)m_friendlyName);
6311 LPCWSTR AppDomain::GetFriendlyNameForDebugger()
6316 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6318 POSTCONDITION(CheckPointer(RETVAL));
6323 if (m_friendlyName.IsEmpty())
6325 BOOL fSuccess = FALSE;
6329 SetFriendlyName(NULL);
6335 // Gobble all exceptions.
6337 EX_END_CATCH(SwallowAllExceptions);
6345 RETURN m_friendlyName;
6349 #endif // !DACCESS_COMPILE
6351 #ifdef DACCESS_COMPILE
6353 PVOID AppDomain::GetFriendlyNameNoSet(bool* isUtf8)
6357 if (!m_friendlyName.IsEmpty())
6360 return m_friendlyName.DacGetRawContent();
6362 else if (m_pRootAssembly)
6365 return (PVOID)m_pRootAssembly->GetSimpleName();
6367 else if (dac_cast<TADDR>(this) ==
6368 dac_cast<TADDR>(SystemDomain::System()->DefaultDomain()))
6371 return (PVOID)DEFAULT_DOMAIN_FRIENDLY_NAME;
6379 #endif // DACCESS_COMPILE
6381 #ifndef DACCESS_COMPILE
6383 BOOL AppDomain::AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAllowFailure)
6390 PRECONDITION(CheckPointer(pSpec));
6391 // Hosted fusion binder makes an exception here, so we cannot assert.
6392 //PRECONDITION(pSpec->CanUseWithBindingCache());
6393 //PRECONDITION(pFile->CanUseWithBindingCache());
6394 INJECT_FAULT(COMPlusThrowOM(););
6398 CrstHolder holder(&m_DomainCacheCrst);
6399 // !!! suppress exceptions
6400 if(!m_AssemblyCache.StoreFile(pSpec, pFile) && !fAllowFailure)
6402 // TODO: Disabling the below assertion as currently we experience
6403 // inconsistency on resolving the Microsoft.Office.Interop.MSProject.dll
6404 // This causes below assertion to fire and crashes the VS. This issue
6405 // is being tracked with Dev10 Bug 658555. Brought back it when this bug
6409 EEFileLoadException::Throw(pSpec, FUSION_E_CACHEFILE_FAILED, NULL);
6415 BOOL AppDomain::AddAssemblyToCache(AssemblySpec* pSpec, DomainAssembly *pAssembly)
6422 PRECONDITION(CheckPointer(pSpec));
6423 PRECONDITION(CheckPointer(pAssembly));
6424 PRECONDITION(pSpec->CanUseWithBindingCache());
6425 PRECONDITION(pAssembly->CanUseWithBindingCache());
6426 INJECT_FAULT(COMPlusThrowOM(););
6430 CrstHolder holder(&m_DomainCacheCrst);
6431 // !!! suppress exceptions
6432 BOOL bRetVal = m_AssemblyCache.StoreAssembly(pSpec, pAssembly);
6436 BOOL AppDomain::AddExceptionToCache(AssemblySpec* pSpec, Exception *ex)
6443 PRECONDITION(CheckPointer(pSpec));
6444 PRECONDITION(pSpec->CanUseWithBindingCache());
6445 INJECT_FAULT(COMPlusThrowOM(););
6449 if (ex->IsTransient())
6452 CrstHolder holder(&m_DomainCacheCrst);
6453 // !!! suppress exceptions
6454 return m_AssemblyCache.StoreException(pSpec, ex);
6457 void AppDomain::AddUnmanagedImageToCache(LPCWSTR libraryName, HMODULE hMod)
6464 PRECONDITION(CheckPointer(libraryName));
6465 INJECT_FAULT(COMPlusThrowOM(););
6471 spec.SetCodeBase(libraryName);
6472 m_UnmanagedCache.InsertEntry(&spec, hMod);
6478 HMODULE AppDomain::FindUnmanagedImageInCache(LPCWSTR libraryName)
6485 PRECONDITION(CheckPointer(libraryName,NULL_OK));
6486 POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
6487 INJECT_FAULT(COMPlusThrowOM(););
6490 if(libraryName == NULL) RETURN NULL;
6493 spec.SetCodeBase(libraryName);
6494 RETURN (HMODULE) m_UnmanagedCache.LookupEntry(&spec, 0);
6498 BOOL AppDomain::IsCached(AssemblySpec *pSpec)
6500 WRAPPER_NO_CONTRACT;
6502 // Check to see if this fits our rather loose idea of a reference to mscorlib.
6503 // If so, don't use fusion to bind it - do it ourselves.
6504 if (pSpec->IsMscorlib())
6507 return m_AssemblyCache.Contains(pSpec);
6510 void AppDomain::GetCacheAssemblyList(SetSHash<PTR_DomainAssembly>& assemblyList)
6512 CrstHolder holder(&m_DomainCacheCrst);
6513 m_AssemblyCache.GetAllAssemblies(assemblyList);
6516 PEAssembly* AppDomain::FindCachedFile(AssemblySpec* pSpec, BOOL fThrow /*=TRUE*/)
6532 // Check to see if this fits our rather loose idea of a reference to mscorlib.
6533 // If so, don't use fusion to bind it - do it ourselves.
6534 if (fThrow && pSpec->IsMscorlib())
6536 CONSISTENCY_CHECK(SystemDomain::System()->SystemAssembly() != NULL);
6537 PEAssembly *pFile = SystemDomain::System()->SystemFile();
6542 return m_AssemblyCache.LookupFile(pSpec, fThrow);
6546 BOOL AppDomain::PostBindResolveAssembly(AssemblySpec *pPrePolicySpec,
6547 AssemblySpec *pPostPolicySpec,
6548 HRESULT hrBindResult,
6549 AssemblySpec **ppFailedSpec)
6551 STATIC_CONTRACT_THROWS;
6552 STATIC_CONTRACT_GC_TRIGGERS;
6553 PRECONDITION(CheckPointer(pPrePolicySpec));
6554 PRECONDITION(CheckPointer(pPostPolicySpec));
6555 PRECONDITION(CheckPointer(ppFailedSpec));
6557 BOOL fFailure = TRUE;
6558 *ppFailedSpec = pPrePolicySpec;
6561 PEAssemblyHolder result;
6563 if ((EEFileLoadException::GetFileLoadKind(hrBindResult) == kFileNotFoundException) ||
6564 (hrBindResult == FUSION_E_REF_DEF_MISMATCH) ||
6565 (hrBindResult == FUSION_E_INVALID_NAME))
6567 result = TryResolveAssembly(*ppFailedSpec, FALSE /* fPreBind */);
6569 if (result != NULL && pPrePolicySpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
6573 // Given the post-policy resolve event construction of the CLR binder,
6574 // chained managed resolve events can race with each other, therefore we do allow
6575 // the adding of the result to fail. Checking for already chached specs
6576 // is not an option as it would introduce another race window.
6577 // The binder does a re-fetch of the
6578 // orignal binding spec and therefore will not cause inconsistency here.
6579 // For the purposes of the resolve event, failure to add to the cache still is a success.
6580 AddFileToCache(pPrePolicySpec, result, TRUE /* fAllowFailure */);
6581 if (*ppFailedSpec != pPrePolicySpec && pPostPolicySpec->CanUseWithBindingCache())
6583 AddFileToCache(pPostPolicySpec, result, TRUE /* fAllowFailure */ );
6591 //----------------------------------------------------------------------------------------
6592 // Helper class for hosted binder
6594 class PEAssemblyAsPrivAssemblyInfo : public IUnknownCommon<ICLRPrivAssemblyInfo>
6597 //------------------------------------------------------------------------------------
6600 PEAssemblyAsPrivAssemblyInfo(PEAssembly *pPEAssembly)
6602 LIMITED_METHOD_CONTRACT;
6603 STATIC_CONTRACT_THROWS;
6605 if (pPEAssembly == nullptr)
6606 ThrowHR(E_UNEXPECTED);
6608 pPEAssembly->AddRef();
6609 m_pPEAssembly = pPEAssembly;
6612 //------------------------------------------------------------------------------------
6613 // ICLRPrivAssemblyInfo methods
6615 //------------------------------------------------------------------------------------
6616 STDMETHOD(GetAssemblyName)(
6617 __in DWORD cchBuffer,
6618 __out_opt LPDWORD pcchBuffer,
6619 __out_ecount_part_opt(cchBuffer, *pcchBuffer) LPWSTR wzBuffer)
6631 if ((cchBuffer == 0) != (wzBuffer == nullptr))
6633 return E_INVALIDARG;
6636 LPCUTF8 szName = m_pPEAssembly->GetSimpleName();
6640 IfFailRet(FString::Utf8_Unicode_Length(szName, &bIsAscii, &cchName));
6642 if (cchBuffer < cchName + 1)
6644 if (pcchBuffer != nullptr)
6646 *pcchBuffer = cchName + 1;
6648 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6652 IfFailRet(FString::Utf8_Unicode(szName, bIsAscii, wzBuffer, cchName));
6653 if (pcchBuffer != nullptr)
6655 *pcchBuffer = cchName;
6661 //------------------------------------------------------------------------------------
6662 STDMETHOD(GetAssemblyVersion)(
6668 WRAPPER_NO_CONTRACT;
6669 return m_pPEAssembly->GetVersion(pMajor, pMinor, pBuild, pRevision);
6672 //------------------------------------------------------------------------------------
6673 STDMETHOD(GetAssemblyPublicKey)(
6678 STATIC_CONTRACT_LIMITED_METHOD;
6679 STATIC_CONTRACT_CAN_TAKE_LOCK;
6681 VALIDATE_PTR_RET(pcbBuffer);
6682 VALIDATE_CONDITION((pbBuffer == nullptr) == (cbBuffer == 0), return E_INVALIDARG);
6688 // Note: PEAssembly::GetPublicKey will return bogus data pointer when *pcbBuffer == 0
6689 LPCVOID pbKey = m_pPEAssembly->GetPublicKey(pcbBuffer);
6691 if (*pcbBuffer != 0)
6693 if (pbBuffer != nullptr && cbBuffer >= *pcbBuffer)
6695 memcpy(pbBuffer, pbKey, *pcbBuffer);
6700 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6705 hr = S_FALSE; // ==> No public key
6708 EX_CATCH_HRESULT(hr);
6714 ReleaseHolder<PEAssembly> m_pPEAssembly;
6717 //-----------------------------------------------------------------------------------------------------------------
6718 static HRESULT VerifyBindHelper(
6719 ICLRPrivAssembly *pPrivAssembly,
6720 IAssemblyName *pAssemblyName,
6721 PEAssembly *pPEAssembly)
6723 STATIC_CONTRACT_THROWS;
6724 STATIC_CONTRACT_GC_TRIGGERS;
6727 // Create an ICLRPrivAssemblyInfo to call to ICLRPrivAssembly::VerifyBind
6728 NewHolder<PEAssemblyAsPrivAssemblyInfo> pPrivAssemblyInfoImpl = new PEAssemblyAsPrivAssemblyInfo(pPEAssembly);
6729 ReleaseHolder<ICLRPrivAssemblyInfo> pPrivAssemblyInfo;
6730 IfFailRet(pPrivAssemblyInfoImpl->QueryInterface(__uuidof(ICLRPrivAssemblyInfo), (LPVOID *)&pPrivAssemblyInfo));
6731 pPrivAssemblyInfoImpl.SuppressRelease();
6733 // Call VerifyBind to give the host a chance to reject the bind based on assembly image contents.
6734 IfFailRet(pPrivAssembly->VerifyBind(pAssemblyName, pPrivAssembly, pPrivAssemblyInfo));
6739 //-----------------------------------------------------------------------------------------------------------------
6740 HRESULT AppDomain::BindAssemblySpecForHostedBinder(
6741 AssemblySpec * pSpec,
6742 IAssemblyName * pAssemblyName,
6743 ICLRPrivBinder * pBinder,
6744 PEAssembly ** ppAssembly)
6746 STANDARD_VM_CONTRACT;
6748 PRECONDITION(CheckPointer(pSpec));
6749 PRECONDITION(pSpec->GetAppDomain() == this);
6750 PRECONDITION(CheckPointer(ppAssembly));
6751 PRECONDITION(pSpec->GetCodeBase() == nullptr);
6756 // The Fusion binder can throw (to preserve compat, since it will actually perform an assembly
6757 // load as part of it's bind), so we need to be careful here to catch any FileNotFoundException
6758 // objects if fThrowIfNotFound is false.
6759 ReleaseHolder<ICLRPrivAssembly> pPrivAssembly;
6761 // We return HRESULTs here on failure instead of throwing as failures here are not necessarily indicative
6762 // of an actual application problem. Returning an error code is substantially faster than throwing, and
6763 // should be used when possible.
6764 IfFailRet(pBinder->BindAssemblyByName(pAssemblyName, &pPrivAssembly));
6766 IfFailRet(BindHostedPrivAssembly(nullptr, pPrivAssembly, pAssemblyName, ppAssembly));
6772 //-----------------------------------------------------------------------------------------------------------------
6774 AppDomain::BindHostedPrivAssembly(
6775 PEAssembly * pParentAssembly,
6776 ICLRPrivAssembly * pPrivAssembly,
6777 IAssemblyName * pAssemblyName,
6778 PEAssembly ** ppAssembly,
6779 BOOL fIsIntrospectionOnly) // = FALSE
6781 STANDARD_VM_CONTRACT;
6783 PRECONDITION(CheckPointer(pPrivAssembly));
6784 PRECONDITION(CheckPointer(ppAssembly));
6788 *ppAssembly = nullptr;
6790 // See if result has been previously loaded.
6792 DomainAssembly* pDomainAssembly = FindAssembly(pPrivAssembly);
6793 if (pDomainAssembly != nullptr)
6795 *ppAssembly = clr::SafeAddRef(pDomainAssembly->GetFile());
6799 if (*ppAssembly != nullptr)
6800 { // Already exists: ask the binder to verify and return the assembly.
6801 return VerifyBindHelper(pPrivAssembly, pAssemblyName, *ppAssembly);
6804 // Get the IL PEFile.
6805 PEImageHolder pPEImageIL;
6807 // Does not already exist, so get the resource for the assembly and load it.
6809 ReleaseHolder<ICLRPrivResource> pIResourceIL;
6811 IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_IL, &dwImageType, &pIResourceIL));
6812 _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_IL);
6814 pPEImageIL = PEImage::OpenImage(pIResourceIL, MDInternalImport_Default);
6817 // See if an NI is available.
6818 DWORD dwAvailableImages;
6819 IfFailRet(pPrivAssembly->GetAvailableImageTypes(&dwAvailableImages));
6820 _ASSERTE(dwAvailableImages & ASSEMBLY_IMAGE_TYPE_IL); // Just double checking that IL bit is always set.
6822 // Get the NI PEFile if available.
6823 PEImageHolder pPEImageNI;
6824 if (dwAvailableImages & ASSEMBLY_IMAGE_TYPE_NATIVE)
6827 ReleaseHolder<ICLRPrivResource> pIResourceNI;
6829 IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_NATIVE, &dwImageType, &pIResourceNI));
6830 _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_NATIVE || FAILED(hr));
6832 pPEImageNI = PEImage::OpenImage(pIResourceNI, MDInternalImport_TrustedNativeImage);
6834 _ASSERTE(pPEImageIL != nullptr);
6836 // Create a PEAssembly using the IL and NI images.
6837 PEAssemblyHolder pPEAssembly = PEAssembly::Open(pParentAssembly, pPEImageIL, pPEImageNI, pPrivAssembly, fIsIntrospectionOnly);
6840 // Ask the binder to verify.
6841 IfFailRet(VerifyBindHelper(pPrivAssembly, pAssemblyName, pPEAssembly));
6844 *ppAssembly = pPEAssembly.Extract();
6847 } // AppDomain::BindHostedPrivAssembly
6849 //---------------------------------------------------------------------------------------------------------------------
6850 PEAssembly * AppDomain::BindAssemblySpec(
6851 AssemblySpec * pSpec,
6852 BOOL fThrowOnFileNotFound,
6853 BOOL fRaisePrebindEvents,
6854 StackCrawlMark * pCallerStackMark,
6855 BOOL fUseHostBinderIfAvailable)
6857 STATIC_CONTRACT_THROWS;
6858 STATIC_CONTRACT_GC_TRIGGERS;
6859 PRECONDITION(CheckPointer(pSpec));
6860 PRECONDITION(pSpec->GetAppDomain() == this);
6861 PRECONDITION(this==::GetAppDomain());
6865 BOOL fForceReThrow = FALSE;
6867 #if defined(FEATURE_COMINTEROP)
6868 // Handle WinRT assemblies in the classic/hybrid scenario. If this is an AppX process,
6869 // then this case will be handled by the previous block as part of the full set of
6870 // available binding hosts.
6871 if (pSpec->IsContentType_WindowsRuntime())
6875 // Get the assembly display name.
6876 ReleaseHolder<IAssemblyName> pAssemblyName;
6878 IfFailThrow(pSpec->CreateFusionName(&pAssemblyName, TRUE, TRUE));
6881 PEAssemblyHolder pAssembly;
6885 hr = BindAssemblySpecForHostedBinder(pSpec, pAssemblyName, m_pWinRtBinder, &pAssembly);
6887 goto EndTry2; // Goto end of try block.
6890 // The combination of this conditional catch/ the following if statement which will throw reduces the count of exceptions
6891 // thrown in scenarios where the exception does not escape the method. We cannot get rid of the try/catch block, as
6892 // there are cases within some of the clrpriv binder's which throw.
6893 // Note: In theory, FileNotFound should always come here as HRESULT, never as exception.
6894 EX_CATCH_HRESULT_IF(hr,
6895 !fThrowOnFileNotFound && Assembly::FileNotFound(hr))
6897 if (FAILED(hr) && (fThrowOnFileNotFound || !Assembly::FileNotFound(hr)))
6899 if (Assembly::FileNotFound(hr))
6901 _ASSERTE(fThrowOnFileNotFound);
6902 // Uses defaultScope
6903 EEFileLoadException::Throw(pSpec, hr);
6906 // WinRT type bind failures
6907 _ASSERTE(pSpec->IsContentType_WindowsRuntime());
6908 if (hr == HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE)) // Returned by RoResolveNamespace when using 3rd party WinRT types in classic process
6910 if (fThrowOnFileNotFound)
6911 { // Throw NotSupportedException (with custom message) wrapped by TypeLoadException to give user type name for diagnostics
6912 // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6913 EEMessageException ex(kNotSupportedException, IDS_EE_WINRT_THIRDPARTY_NOTSUPPORTED);
6914 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
6917 else if ((hr == CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT) || // Returned e.g. for WinRT type name without namespace
6918 (hr == COR_E_PLATFORMNOTSUPPORTED)) // Using WinRT on pre-Win8 OS
6920 if (fThrowOnFileNotFound)
6921 { // Throw ArgumentException/PlatformNotSupportedException wrapped by TypeLoadException to give user type name for diagnostics
6922 // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6923 EEMessageException ex(hr);
6924 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
6932 _ASSERTE((FAILED(hr) && !fThrowOnFileNotFound) || pAssembly != nullptr);
6934 return pAssembly.Extract();
6937 #endif // FEATURE_COMINTEROP
6938 if (pSpec->HasUniqueIdentity())
6940 HRESULT hrBindResult = S_OK;
6941 PEAssemblyHolder result;
6946 if (!IsCached(pSpec))
6950 bool fAddFileToCache = false;
6952 BOOL fIsWellKnown = FALSE;
6954 // Use CoreClr's fusion alternative
6955 CoreBindResult bindResult;
6957 pSpec->Bind(this, fThrowOnFileNotFound, &bindResult, FALSE /* fNgenExplicitBind */, FALSE /* fExplicitBindToNativeImage */, pCallerStackMark);
6958 hrBindResult = bindResult.GetHRBindResult();
6960 if (bindResult.Found())
6962 if (SystemDomain::SystemFile() && bindResult.IsMscorlib())
6964 // Avoid rebinding to another copy of mscorlib
6965 result = SystemDomain::SystemFile();
6966 result.SuppressRelease(); // Didn't get a refcount
6970 // IsSystem on the PEFile should be false, even for mscorlib satellites
6971 result = PEAssembly::Open(&bindResult,
6972 FALSE, pSpec->IsIntrospectionOnly());
6974 fAddFileToCache = true;
6976 // Setup the reference to the binder, which performed the bind, into the AssemblySpec
6977 ICLRPrivBinder* pBinder = result->GetBindingContext();
6978 _ASSERTE(pBinder != NULL);
6979 pSpec->SetBindingContext(pBinder);
6983 if (fAddFileToCache)
6987 if (pSpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
6989 // Failure to add simply means someone else beat us to it. In that case
6990 // the FindCachedFile call below (after catch block) will update result
6991 // to the cached value.
6992 AddFileToCache(pSpec, result, TRUE /*fAllowFailure*/);
6995 else if (!fIsWellKnown)
6997 _ASSERTE(fThrowOnFileNotFound == FALSE);
6999 // Don't trigger the resolve event for the CoreLib satellite assembly. A misbehaving resolve event may
7000 // return an assembly that does not match, and this can cause recursive resource lookups during error
7001 // reporting. The CoreLib satellite assembly is loaded from relative locations based on the culture, see
7002 // AssemblySpec::Bind().
7003 if (!pSpec->IsMscorlibSatellite())
7005 // Trigger the resolve event also for non-throw situation.
7006 // However, this code path will behave as if the resolve handler has thrown,
7007 // that is, not trigger an MDA.
7009 AssemblySpec NewSpec(this);
7010 AssemblySpec *pFailedSpec = NULL;
7012 fForceReThrow = TRUE; // Managed resolve event handler can throw
7014 // Purposly ignore return value
7015 PostBindResolveAssembly(pSpec, &NewSpec, hrBindResult, &pFailedSpec);
7023 Exception *ex = GET_EXCEPTION();
7025 AssemblySpec NewSpec(this);
7026 AssemblySpec *pFailedSpec = NULL;
7028 // Let transient exceptions or managed resolve event handler exceptions propagate
7029 if (ex->IsTransient() || fForceReThrow)
7035 // This is not executed for SO exceptions so we need to disable the backout
7036 // stack validation to prevent false violations from being reported.
7037 DISABLE_BACKOUT_STACK_VALIDATION;
7039 BOOL fFailure = PostBindResolveAssembly(pSpec, &NewSpec, ex->GetHR(), &pFailedSpec);
7042 BOOL bFileNotFoundException =
7043 (EEFileLoadException::GetFileLoadKind(ex->GetHR()) == kFileNotFoundException);
7045 if (!bFileNotFoundException)
7047 fFailure = AddExceptionToCache(pFailedSpec, ex);
7048 } // else, fFailure stays TRUE
7049 // Effectively, fFailure == bFileNotFoundException || AddExceptionToCache(pFailedSpec, ex)
7051 // Only throw this exception if we are the first in the cache
7055 // If the BindingFailure MDA is enabled, trigger one for this failure
7056 // Note: TryResolveAssembly() can also throw if an AssemblyResolve event subscriber throws
7057 // and the MDA isn't sent in this case (or for transient failure cases)
7059 #ifdef MDA_SUPPORTED
7060 MdaBindingFailure* pProbe = MDA_GET_ASSISTANT(BindingFailure);
7063 // Transition to cooperative GC mode before using any OBJECTREFs.
7066 OBJECTREF exceptionObj = GET_THROWABLE();
7067 GCPROTECT_BEGIN(exceptionObj)
7069 pProbe->BindFailed(pFailedSpec, &exceptionObj);
7075 // In the same cases as for the MDA, store the failure information for DAC to read
7076 if (IsDebuggerAttached()) {
7077 FailedAssembly *pFailed = new FailedAssembly();
7078 pFailed->Initialize(pFailedSpec, ex);
7079 IfFailThrow(m_failedAssemblies.Append(pFailed));
7082 if (!bFileNotFoundException || fThrowOnFileNotFound)
7085 // V1.1 App-compatibility workaround. See VSW530166 if you want to whine about it.
7087 // In Everett, if we failed to download an assembly because of a broken network cable,
7088 // we returned a FileNotFoundException with a COR_E_FILENOTFOUND hr embedded inside
7089 // (which would be exposed when marshaled to native.)
7091 // In Whidbey, we now set the more appropriate INET_E_RESOURCE_NOT_FOUND hr. But
7092 // the online/offline switch code in VSTO for Everett hardcoded a check for
7093 // COR_E_FILENOTFOUND.
7095 // So now, to keep that code from breaking, we have to remap INET_E_RESOURCE_NOT_FOUND
7096 // back to COR_E_FILENOTFOUND. We're doing it here rather down in Fusion so as to affect
7097 // the least number of callers.
7099 if (ex->GetHR() == INET_E_RESOURCE_NOT_FOUND)
7101 EEFileLoadException::Throw(pFailedSpec, COR_E_FILENOTFOUND, ex);
7104 if (EEFileLoadException::CheckType(ex))
7106 if (pFailedSpec == pSpec)
7108 EX_RETHROW; //preserve the information
7112 StackSString exceptionDisplayName, failedSpecDisplayName;
7114 ((EEFileLoadException*)ex)->GetName(exceptionDisplayName);
7115 pFailedSpec->GetFileOrDisplayName(0, failedSpecDisplayName);
7117 if (exceptionDisplayName.CompareCaseInsensitive(failedSpecDisplayName) == 0)
7119 EX_RETHROW; // Throw the original exception. Otherwise, we'd throw an exception that contains the same message twice.
7124 EEFileLoadException::Throw(pFailedSpec, ex->GetHR(), ex);
7131 EX_END_CATCH(RethrowTerminalExceptions);
7133 // 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
7134 // thread to store our result. Note that we may throw from here, if there is a cached exception.
7135 // This will release the refcount of the current result holder (if any), and will replace
7136 // it with a non-addref'ed result
7137 if (pSpec->CanUseWithBindingCache() && (result== NULL || result->CanUseWithBindingCache()))
7139 result = FindCachedFile(pSpec);
7145 return result.Extract();
7149 // Unsupported content type
7150 if (fThrowOnFileNotFound)
7152 ThrowHR(COR_E_BADIMAGEFORMAT);
7156 } // AppDomain::BindAssemblySpec
7160 PEAssembly *AppDomain::TryResolveAssembly(AssemblySpec *pSpec, BOOL fPreBind)
7162 STATIC_CONTRACT_THROWS;
7163 STATIC_CONTRACT_GC_TRIGGERS;
7164 STATIC_CONTRACT_MODE_ANY;
7166 PEAssembly *result = NULL;
7170 result = pSpec->ResolveAssemblyFile(this, fPreBind);
7174 Exception *pEx = GET_EXCEPTION();
7176 if (!pEx->IsTransient())
7178 AddExceptionToCache(pSpec, pEx);
7179 if (!EEFileLoadException::CheckType(pEx))
7180 EEFileLoadException::Throw(pSpec, pEx->GetHR(), pEx);
7189 ULONG AppDomain::AddRef()
7191 LIMITED_METHOD_CONTRACT;
7192 return InterlockedIncrement(&m_cRef);
7195 ULONG AppDomain::Release()
7202 PRECONDITION(m_cRef > 0);
7206 ULONG cRef = InterlockedDecrement(&m_cRef);
7209 _ASSERTE (m_Stage == STAGE_CREATING || m_Stage == STAGE_CLOSED);
7212 TESTHOOKCALL(AppDomainDestroyed(adid.m_dwId));
7218 AppDomain* AppDomain::s_pAppDomainToRaiseUnloadEvent;
7219 BOOL AppDomain::s_fProcessUnloadDomainEvent = FALSE;
7221 #ifndef CROSSGEN_COMPILE
7223 void AppDomain::RaiseUnloadDomainEvent_Wrapper(LPVOID ptr)
7230 INJECT_FAULT(COMPlusThrowOM(););
7235 AppDomain* pDomain = (AppDomain *) ptr;
7236 pDomain->RaiseUnloadDomainEvent();
7239 void AppDomain::ProcessUnloadDomainEventOnFinalizeThread()
7248 Thread *pThread = GetThread();
7249 _ASSERTE (pThread && IsFinalizerThread());
7251 // if we are not unloading domain now, do not process the event
7252 if (SystemDomain::AppDomainBeingUnloaded() == NULL)
7254 s_pAppDomainToRaiseUnloadEvent->SetStage(STAGE_UNLOAD_REQUESTED);
7255 s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
7256 s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7257 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
7260 FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, TRUE);
7261 AppDomain::EnableADUnloadWorkerForFinalizer();
7262 pThread->SetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
7263 s_pAppDomainToRaiseUnloadEvent->RaiseUnloadDomainEvent();
7264 pThread->ResetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
7265 s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
7266 s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7267 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
7268 FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, FALSE);
7270 if (pThread->IsAbortRequested())
7272 pThread->UnmarkThreadForAbort(Thread::TAR_Thread);
7276 void AppDomain::RaiseUnloadDomainEvent()
7287 Thread *pThread = GetThread();
7288 if (this != pThread->GetDomain())
7290 pThread->DoADCallBack(this, AppDomain::RaiseUnloadDomainEvent_Wrapper, this,ADV_FINALIZER|ADV_COMPILATION);
7296 APPDOMAINREF Domain;
7299 ZeroMemory(&gc, sizeof(gc));
7301 GCPROTECT_BEGIN(gc);
7302 gc.Domain = (APPDOMAINREF) GetRawExposedObject();
7303 if (gc.Domain != NULL)
7305 gc.Delegate = gc.Domain->m_pDomainUnloadEventHandler;
7306 if (gc.Delegate != NULL)
7307 DistributeEvent(&gc.Delegate, (OBJECTREF *) &gc.Domain);
7313 void AppDomain::RaiseLoadingAssemblyEvent(DomainAssembly *pAssembly)
7319 PRECONDITION(this == GetAppDomain());
7326 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
7331 APPDOMAINREF AppDomainRef;
7334 ZeroMemory(&gc, sizeof(gc));
7336 if ((gc.AppDomainRef = (APPDOMAINREF) GetRawExposedObject()) != NULL) {
7337 if (gc.AppDomainRef->m_pAssemblyEventHandler != NULL)
7340 GCPROTECT_BEGIN(gc);
7342 gc.orThis = pAssembly->GetExposedAssemblyObject();
7344 MethodDescCallSite onAssemblyLoad(METHOD__APP_DOMAIN__ON_ASSEMBLY_LOAD, &gc.orThis);
7346 // GetExposedAssemblyObject may cause a gc, so call this before filling args[0]
7347 args[1] = ObjToArgSlot(gc.orThis);
7348 args[0] = ObjToArgSlot(gc.AppDomainRef);
7350 onAssemblyLoad.Call(args);
7359 EX_END_CATCH(SwallowAllExceptions);
7363 BOOL AppDomain::OnUnhandledException(OBJECTREF *pThrowable, BOOL isTerminating/*=TRUE*/)
7365 STATIC_CONTRACT_NOTHROW;
7366 STATIC_CONTRACT_GC_TRIGGERS;
7367 STATIC_CONTRACT_MODE_ANY;
7373 // The Everett behavior was to send the unhandled exception event only to the Default
7374 // AppDomain (since that's the only place that exceptions actually went unhandled).
7376 // During Whidbey development, we broadcast the event to all AppDomains in the process.
7378 // But the official shipping Whidbey behavior is that the unhandled exception event is
7379 // sent to the Default AppDomain and to whatever AppDomain the exception went unhandled
7380 // in. To achieve this, we declare the exception to be unhandled *BEFORE* we marshal
7381 // it back to the Default AppDomain at the base of the Finalizer, threadpool and managed
7384 // The rationale for sending the event to the Default AppDomain as well as the one the
7385 // exception went unhandled in is:
7387 // 1) This is compatible with the pre-Whidbey behavior, where only the Default AppDomain
7388 // received the notification.
7390 // 2) This is convenient for hosts, which don't want to bother injecting listeners into
7391 // every single AppDomain.
7393 AppDomain *pAppDomain = GetAppDomain();
7394 OBJECTREF orSender = 0;
7396 GCPROTECT_BEGIN(orSender);
7398 orSender = pAppDomain->GetRawExposedObject();
7400 retVal = pAppDomain->RaiseUnhandledExceptionEventNoThrow(&orSender, pThrowable, isTerminating);
7408 // Move outside of the AppDomain iteration, to avoid issues with the GC Frames being outside
7409 // the domain transition. This is a chronic issue that causes us to report roots for an AppDomain
7410 // after we have left it. This causes problems with AppDomain unloading that we only find
7411 // with stress coverage..
7412 void AppDomain::RaiseOneExitProcessEvent()
7424 APPDOMAINREF Domain;
7427 ZeroMemory(&gc, sizeof(gc));
7429 GCPROTECT_BEGIN(gc);
7430 gc.Domain = (APPDOMAINREF) SystemDomain::GetCurrentDomain()->GetRawExposedObject();
7431 if (gc.Domain != NULL)
7433 gc.Delegate = gc.Domain->m_pProcessExitEventHandler;
7434 if (gc.Delegate != NULL)
7435 DistributeEvent(&gc.Delegate, (OBJECTREF *) &gc.Domain);
7440 // Local wrapper used in AppDomain::RaiseExitProcessEvent,
7441 // introduced solely to avoid stack overflow because of _alloca in the loop.
7442 // It's just factored out body of the loop, but it has to be a member method of AppDomain,
7443 // because it calls private RaiseOneExitProcessEvent
7444 /*static*/ void AppDomain::RaiseOneExitProcessEvent_Wrapper(AppDomainIterator* pi)
7446 STATIC_CONTRACT_MODE_COOPERATIVE;
7447 STATIC_CONTRACT_THROWS;
7448 STATIC_CONTRACT_GC_TRIGGERS;
7450 ENTER_DOMAIN_PTR(pi->GetDomain(), ADV_ITERATOR)
7451 AppDomain::RaiseOneExitProcessEvent();
7452 END_DOMAIN_TRANSITION;
7455 static LONG s_ProcessedExitProcessEventCount = 0;
7457 LONG GetProcessedExitProcessEventCount()
7459 LIMITED_METHOD_CONTRACT;
7460 return s_ProcessedExitProcessEventCount;
7463 void AppDomain::RaiseExitProcessEvent()
7468 STATIC_CONTRACT_MODE_COOPERATIVE;
7469 STATIC_CONTRACT_THROWS;
7470 STATIC_CONTRACT_GC_TRIGGERS;
7472 // Only finalizer thread during shutdown can call this function.
7473 _ASSERTE ((g_fEEShutDown&ShutDown_Finalize1) && GetThread() == FinalizerThread::GetFinalizerThread());
7475 _ASSERTE (GetThread()->PreemptiveGCDisabled());
7477 _ASSERTE (GetThread()->GetDomain()->IsDefaultDomain());
7479 AppDomainIterator i(TRUE);
7482 RaiseOneExitProcessEvent_Wrapper(&i);
7483 FastInterlockIncrement(&s_ProcessedExitProcessEventCount);
7489 AppDomain::RaiseUnhandledExceptionEventNoThrow(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating)
7502 bRetVal = RaiseUnhandledExceptionEvent(pSender, pThrowable, isTerminating);
7507 EX_END_CATCH(SwallowAllExceptions) // Swallow any errors.
7513 AppDomain::HasUnhandledExceptionEventHandler()
7518 GC_NOTRIGGER; //essential
7522 if (!CanThreadEnter(GetThread()))
7524 if (GetRawExposedObject()==NULL)
7526 return (((APPDOMAINREF)GetRawExposedObject())->m_pUnhandledExceptionEventHandler!=NULL);
7530 AppDomain::RaiseUnhandledExceptionEvent(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating)
7537 INJECT_FAULT(COMPlusThrowOM(););
7541 if (!HasUnhandledExceptionEventHandler())
7544 BOOL result = FALSE;
7546 _ASSERTE(pThrowable != NULL && IsProtectedByGCFrame(pThrowable));
7547 _ASSERTE(pSender != NULL && IsProtectedByGCFrame(pSender));
7549 _ASSERTE(this == GetThread()->GetDomain());
7552 OBJECTREF orDelegate = NULL;
7554 GCPROTECT_BEGIN(orDelegate);
7556 APPDOMAINREF orAD = (APPDOMAINREF) GetAppDomain()->GetRawExposedObject();
7560 orDelegate = orAD->m_pUnhandledExceptionEventHandler;
7561 if (orDelegate != NULL)
7564 DistributeUnhandledExceptionReliably(&orDelegate, pSender, pThrowable, isTerminating);
7573 #endif // CROSSGEN_COMPILE
7575 // You must be in the correct context before calling this
7576 // routine. Therefore, it is only good for initializing the
7578 void AppDomain::InitializeDomainContext(BOOL allowRedirects,
7587 INJECT_FAULT(COMPlusThrowOM(););
7591 if (NingenEnabled())
7594 CreateFusionContext();
7599 #ifndef CROSSGEN_COMPILE
7601 STRINGREF pFilePath;
7604 PTRARRAYREF propertyNames;
7605 PTRARRAYREF propertyValues;
7607 ZeroMemory(&gc, sizeof(gc));
7609 GCPROTECT_BEGIN(gc);
7612 gc.pFilePath = StringObject::NewString(pwszPath);
7617 gc.pConfig = StringObject::NewString(pwszConfig);
7621 if ((gc.ref = GetExposedObject()) != NULL)
7623 MethodDescCallSite setupDomain(METHOD__APP_DOMAIN__SETUP_DOMAIN);
7627 ObjToArgSlot(gc.ref),
7628 BoolToArgSlot(allowRedirects),
7629 ObjToArgSlot(gc.pFilePath),
7630 ObjToArgSlot(gc.pConfig),
7631 ObjToArgSlot(gc.propertyNames),
7632 ObjToArgSlot(gc.propertyValues)
7634 setupDomain.Call(args);
7637 #endif // CROSSGEN_COMPILE
7641 IUnknown *AppDomain::CreateFusionContext()
7643 CONTRACT(IUnknown *)
7648 POSTCONDITION(CheckPointer(RETVAL));
7649 INJECT_FAULT(COMPlusThrowOM(););
7653 if (!m_pFusionContext)
7655 ETWOnStartup (FusionAppCtx_V1, FusionAppCtxEnd_V1);
7656 CLRPrivBinderCoreCLR *pTPABinder = NULL;
7660 // Initialize the assembly binder for the default context loads for CoreCLR.
7661 IfFailThrow(CCoreCLRBinderHelper::DefaultBinderSetupContext(GetId().m_dwId, &pTPABinder));
7662 m_pFusionContext = reinterpret_cast<IUnknown *>(pTPABinder);
7664 // By default, initial binding context setup for CoreCLR is also the TPABinding context
7665 (m_pTPABinderContext = pTPABinder)->AddRef();
7669 RETURN m_pFusionContext;
7674 //---------------------------------------------------------------------------------------
7676 // AppDomain::IsDebuggerAttached - is a debugger attached to this process
7682 // TRUE if a debugger is attached to this process, FALSE otherwise.
7685 // This is identical to CORDebuggerAttached. This exists idependantly for legacy reasons - we used to
7686 // support attaching to individual AppDomains. This should probably go away eventually.
7689 BOOL AppDomain::IsDebuggerAttached()
7691 LIMITED_METHOD_CONTRACT;
7693 if (CORDebuggerAttached())
7703 #ifdef DEBUGGING_SUPPORTED
7705 // This is called from the debugger to request notification events from
7706 // Assemblies, Modules, Types in this appdomain.
7707 BOOL AppDomain::NotifyDebuggerLoad(int flags, BOOL attaching)
7709 WRAPPER_NO_CONTRACT;
7710 BOOL result = FALSE;
7712 if (!attaching && !IsDebuggerAttached())
7717 // Attach to our assemblies
7718 LOG((LF_CORDB, LL_INFO100, "AD::NDA: Iterating assemblies\n"));
7719 i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution));
7720 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7721 while (i.Next(pDomainAssembly.This()))
7723 result = (pDomainAssembly->NotifyDebuggerLoad(flags, attaching) ||
7730 void AppDomain::NotifyDebuggerUnload()
7732 WRAPPER_NO_CONTRACT;
7733 if (!IsDebuggerAttached())
7736 LOG((LF_CORDB, LL_INFO10, "AD::NDD domain [%d] %#08x %ls\n",
7737 GetId().m_dwId, this, GetFriendlyNameForLogging()));
7739 LOG((LF_CORDB, LL_INFO100, "AD::NDD: Interating domain bound assemblies\n"));
7740 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution));
7741 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7743 // Detach from our assemblies
7744 while (i.Next(pDomainAssembly.This()))
7746 LOG((LF_CORDB, LL_INFO100, "AD::NDD: Iterating assemblies\n"));
7747 pDomainAssembly->NotifyDebuggerUnload();
7750 #endif // DEBUGGING_SUPPORTED
7752 void AppDomain::SetSystemAssemblyLoadEventSent(BOOL fFlag)
7754 LIMITED_METHOD_CONTRACT;
7756 m_dwFlags |= LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
7758 m_dwFlags &= ~LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
7761 BOOL AppDomain::WasSystemAssemblyLoadEventSent(void)
7763 LIMITED_METHOD_CONTRACT;
7764 return ((m_dwFlags & LOAD_SYSTEM_ASSEMBLY_EVENT_SENT) == 0) ? FALSE : TRUE;
7767 #ifndef CROSSGEN_COMPILE
7768 // U->M thunks created in this domain and not associated with a delegate.
7769 UMEntryThunkCache *AppDomain::GetUMEntryThunkCache()
7776 INJECT_FAULT(COMPlusThrowOM(););
7780 if (!m_pUMEntryThunkCache)
7782 UMEntryThunkCache *pUMEntryThunkCache = new UMEntryThunkCache(this);
7784 if (FastInterlockCompareExchangePointer(&m_pUMEntryThunkCache, pUMEntryThunkCache, NULL) != NULL)
7786 // some thread swooped in and set the field
7787 delete pUMEntryThunkCache;
7790 _ASSERTE(m_pUMEntryThunkCache);
7791 return m_pUMEntryThunkCache;
7794 #ifdef FEATURE_COMINTEROP
7796 ComCallWrapperCache *AppDomain::GetComCallWrapperCache()
7803 INJECT_FAULT(COMPlusThrowOM(););
7807 if (! m_pComCallWrapperCache)
7809 BaseDomain::LockHolder lh(this);
7811 if (! m_pComCallWrapperCache)
7812 m_pComCallWrapperCache = ComCallWrapperCache::Create(this);
7814 _ASSERTE(m_pComCallWrapperCache);
7815 return m_pComCallWrapperCache;
7818 RCWRefCache *AppDomain::GetRCWRefCache()
7820 CONTRACT(RCWRefCache*)
7825 POSTCONDITION(CheckPointer(RETVAL));
7829 if (!m_pRCWRefCache) {
7830 NewHolder<RCWRefCache> pRCWRefCache = new RCWRefCache(this);
7831 if (FastInterlockCompareExchangePointer(&m_pRCWRefCache, (RCWRefCache *)pRCWRefCache, NULL) == NULL)
7833 pRCWRefCache.SuppressRelease();
7836 RETURN m_pRCWRefCache;
7839 RCWCache *AppDomain::CreateRCWCache()
7846 INJECT_FAULT(COMPlusThrowOM(););
7847 POSTCONDITION(CheckPointer(RETVAL));
7851 // Initialize the global RCW cleanup list here as well. This is so that it
7852 // it guaranteed to exist if any RCW's are created, but it is not created
7854 if (!g_pRCWCleanupList)
7856 SystemDomain::LockHolder lh;
7858 if (!g_pRCWCleanupList)
7859 g_pRCWCleanupList = new RCWCleanupList();
7861 _ASSERTE(g_pRCWCleanupList);
7864 BaseDomain::LockHolder lh(this);
7867 m_pRCWCache = new RCWCache(this);
7873 void AppDomain::ReleaseRCWs(LPVOID pCtxCookie)
7875 WRAPPER_NO_CONTRACT;
7877 m_pRCWCache->ReleaseWrappersWorker(pCtxCookie);
7879 RemoveWinRTFactoryObjects(pCtxCookie);
7882 void AppDomain::DetachRCWs()
7884 WRAPPER_NO_CONTRACT;
7886 m_pRCWCache->DetachWrappersWorker();
7889 #endif // FEATURE_COMINTEROP
7891 BOOL AppDomain::CanThreadEnter(Thread *pThread)
7893 WRAPPER_NO_CONTRACT;
7895 if (m_Stage < STAGE_EXITED)
7898 if (pThread == SystemDomain::System()->GetUnloadingThread())
7899 return m_Stage < STAGE_FINALIZING;
7900 if (pThread == FinalizerThread::GetFinalizerThread())
7901 return m_Stage < STAGE_FINALIZED;
7906 void AppDomain::AllowThreadEntrance(AppDomain * pApp)
7914 PRECONDITION(CheckPointer(pApp));
7918 if (pApp->GetUnloadRequestThread() == NULL)
7920 // This is asynchonous unload, either by a host, or by AppDomain.Unload from AD unload event.
7921 if (!pApp->IsUnloadingFromUnloadEvent())
7923 pApp->SetStage(STAGE_UNLOAD_REQUESTED);
7924 pApp->EnableADUnloadWorker(
7925 pApp->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7930 SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
7932 #ifdef FEATURE_COMINTEROP
7933 if (pApp->m_pComCallWrapperCache)
7934 pApp->m_pComCallWrapperCache->ResetDomainIsUnloading();
7935 #endif // FEATURE_COMINTEROP
7937 pApp->SetStage(STAGE_OPEN);
7940 void AppDomain::RestrictThreadEntrance(AppDomain * pApp)
7945 DISABLED(GC_TRIGGERS);
7947 DISABLED(FORBID_FAULT);
7948 PRECONDITION(CheckPointer(pApp));
7952 #ifdef FEATURE_COMINTEROP
7953 // Set the flag on our CCW cache so stubs won't enter
7954 if (pApp->m_pComCallWrapperCache)
7955 pApp->m_pComCallWrapperCache->SetDomainIsUnloading();
7956 #endif // FEATURE_COMINTEROP
7958 SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
7959 // Release our ID so remoting and thread pool won't enter
7960 pApp->SetStage(STAGE_EXITED);
7963 void AppDomain::Exit(BOOL fRunFinalizers, BOOL fAsyncExit)
7973 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Exiting domain [%d] %#08x %ls\n",
7974 GetId().m_dwId, this, GetFriendlyNameForLogging()));
7976 RestrictEnterHolder RestrictEnter(this);
7979 SystemDomain::LockHolder lh; // we don't want to close appdomain if other thread can be preparing to unload it
7980 SetStage(STAGE_EXITING); // Note that we're trying to exit
7983 // Raise the event indicating the domain is being unloaded.
7984 if (GetDefaultContext())
7986 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, this);
7988 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
7989 //if (timeout == INFINITE)
7991 // timeout = 20000; // 20 seconds
7993 DWORD timeoutForFinalizer = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
7994 ULONGLONG curTime = CLRGetTickCount64();
7995 ULONGLONG endTime = 0;
7996 if (timeout != INFINITE)
7998 endTime = curTime + timeout;
7999 // We will try to kill AD unload event if it takes too long, and then we move on to the next registered caller.
8003 while (s_pAppDomainToRaiseUnloadEvent != NULL)
8005 FinalizerThread::FinalizerThreadWait(s_fProcessUnloadDomainEvent?timeout:timeoutForFinalizer);
8006 if (endTime != 0 && s_pAppDomainToRaiseUnloadEvent != NULL)
8008 if (CLRGetTickCount64() >= endTime)
8011 sThreadId.Printf(W("%x"), FinalizerThread::GetFinalizerThread()->GetThreadId());
8012 COMPlusThrow(kCannotUnloadAppDomainException,
8013 IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD,
8020 // Tell the tiered compilation manager to stop initiating any new work for background
8021 // jit optimization. Its possible the standard thread unwind mechanisms would pre-emptively
8022 // evacuate the jit threadpool worker threads from the domain on their own, but I see no reason
8023 // to take the risk of relying on them when we can easily augment with a cooperative
8024 // shutdown check. This notification only initiates the process of evacuating the threads
8025 // and then the UnwindThreads() call below is where blocking will occur to ensure the threads
8026 // have exited the domain.
8028 #ifdef FEATURE_TIERED_COMPILATION
8029 m_tieredCompilationManager.Shutdown();
8033 // Set up blocks so no threads can enter except for the finalizer and the thread
8034 // doing the unload.
8037 RestrictThreadEntrance(this);
8039 // Cause existing threads to abort out of this domain. This should ensure all
8040 // normal threads are outside the domain, and we've already ensured that no new threads
8043 PerAppDomainTPCountList::AppDomainUnloadingHolder tpAdUnloadHolder(GetTPIndex());
8046 if (!NingenEnabled())
8051 TESTHOOKCALL(UnwoundThreads(GetId().m_dwId)) ;
8052 ProcessEventForHost(Event_DomainUnload, (PVOID)(UINT_PTR)GetId().m_dwId);
8054 RestrictEnter.SuppressRelease(); //after this point we don't guarantee appdomain consistency
8055 #ifdef PROFILING_SUPPORTED
8056 // Signal profile if present.
8058 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
8060 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) this);
8063 #endif // PROFILING_SUPPORTED
8064 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains--);
8065 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomainsUnloaded++);
8067 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is exited.\n",
8068 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8070 // Send ETW events for this domain's unload and potentially iterate through this
8071 // domain's modules & assemblies to send events for their unloads as well. This
8072 // needs to occur before STAGE_FINALIZED (to ensure everything is there), so we do
8073 // this before any finalization occurs at all.
8074 ETW::LoaderLog::DomainUnload(this);
8076 CodeVersionManager::OnAppDomainExit(this);
8079 // Spin running finalizers until we flush them all. We need to make multiple passes
8080 // in case the finalizers create more finalizable objects. This is important to clear
8081 // the finalizable objects as roots, as well as to actually execute the finalizers. This
8082 // will only finalize instances instances of types that aren't potentially agile becuase we can't
8083 // risk finalizing agile objects. So we will be left with instances of potentially agile types
8084 // in handles or statics.
8086 // <TODO>@todo: Need to ensure this will terminate in a reasonable amount of time. Eventually
8087 // we should probably start passing FALSE for fRunFinalizers. Also I'm not sure we
8088 // guarantee that FinalizerThreadWait will ever terminate in general.</TODO>
8091 SetStage(STAGE_FINALIZING);
8093 // Flush finalizers now.
8094 FinalizerThread::UnloadAppDomain(this, fRunFinalizers);
8096 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8097 ULONGLONG startTime = CLRGetTickCount64();
8098 ULONGLONG elapsedTime = 0;
8099 DWORD finalizerWait = 0;
8101 while (FinalizerThread::GetUnloadingAppDomain() != NULL)
8104 if (timeout != INFINITE)
8106 elapsedTime = CLRGetTickCount64() - startTime;
8108 if (timeout > elapsedTime)
8110 finalizerWait = timeout - static_cast<DWORD>(elapsedTime);
8112 FinalizerThread::FinalizerThreadWait(finalizerWait); //will set stage to finalized
8113 if (timeout != INFINITE && FinalizerThread::GetUnloadingAppDomain() != NULL)
8115 elapsedTime = CLRGetTickCount64() - startTime;
8116 if (timeout <= elapsedTime)
8119 // TODO: Consider escalation from RudeAppDomain
8125 tpAdUnloadHolder.SuppressRelease();
8126 PerAppDomainTPCountList::ResetAppDomainTPCounts(GetTPIndex());
8128 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is finalized.\n",
8129 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8132 AppDomainRefHolder This(this);
8133 AddRef(); // Hold a reference so CloseDomain won't delete us yet
8134 CloseDomain(); // Remove ourself from the list of app domains
8136 // This needs to be done prior to destroying the handle tables below.
8137 ReleaseDomainBoundInfo();
8140 // It should be impossible to run non-mscorlib code in this domain now.
8141 // Cleanup all of our roots except the handles. We do this to allow as many
8142 // finalizers as possible to run correctly. If we delete the handles, they
8145 if (!NingenEnabled())
8152 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is cleared.\n",
8153 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8155 if (fAsyncExit && fRunFinalizers)
8158 m_AssemblyCache.Clear();
8159 ClearFusionContext();
8161 if (!NingenEnabled())
8163 AddMemoryPressure();
8166 SystemDomain::System()->AddToDelayedUnloadList(this, fAsyncExit);
8167 SystemDomain::SetUnloadDomainCleared();
8168 if (m_dwId.m_dwId!=0)
8169 SystemDomain::ReleaseAppDomainId(m_dwId);
8170 #ifdef PROFILING_SUPPORTED
8171 // Always signal profile if present, even when failed.
8173 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
8175 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) this, S_OK);
8178 #endif // PROFILING_SUPPORTED
8182 void AppDomain::Close()
8191 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is collected.\n",
8192 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8196 RemoveMemoryPressure();
8198 _ASSERTE(m_cRef>0); //should be alive at this point otherwise iterator can revive us and crash
8200 SystemDomain::LockHolder lh; // Avoid races with AppDomainIterator
8201 SetStage(STAGE_CLOSED);
8204 // CONSIDER: move releasing remoting cache from managed code to here.
8208 void AppDomain::ResetUnloadRequestThread(ADID Id)
8214 PRECONDITION(!IsADUnloadHelperThread());
8219 AppDomainFromIDHolder ad(Id, TRUE);
8220 if(!ad.IsUnloaded() && ad->m_Stage < STAGE_UNLOAD_REQUESTED)
8222 Thread *pThread = ad->GetUnloadRequestThread();
8223 if(pThread==GetThread())
8225 ad->m_dwThreadsStillInAppDomain=(ULONG)-1;
8229 if (pThread->GetUnloadBoundaryFrame() && pThread->IsBeingAbortedForADUnload())
8231 pThread->UnmarkThreadForAbort(Thread::TAR_ADUnload);
8233 ad->GetUnloadRequestThread()->ResetUnloadBoundaryFrame();
8234 pThread->ResetBeginAbortedForADUnload();
8237 ad->SetUnloadRequestThread(NULL);
8243 int g_fADUnloadWorkerOK = -1;
8245 HRESULT AppDomain::UnloadById(ADID dwId, BOOL fSync,BOOL fExceptionsPassThrough)
8249 if(fExceptionsPassThrough) {THROWS;} else {NOTHROW;}
8251 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
8256 if (dwId==(ADID)DefaultADID)
8257 return COR_E_CANNOTUNLOADAPPDOMAIN;
8259 Thread *pThread = GetThread();
8261 // Finalizer thread can not wait until AD unload is done,
8262 // because AD unload is going to wait for Finalizer Thread.
8263 if (fSync && pThread == FinalizerThread::GetFinalizerThread() &&
8264 !pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent))
8265 return COR_E_CANNOTUNLOADAPPDOMAIN;
8268 // AD unload helper thread should have been created.
8269 _ASSERTE (g_fADUnloadWorkerOK == 1);
8271 _ASSERTE (!IsADUnloadHelperThread());
8273 BOOL fIsRaisingUnloadEvent = (pThread != NULL && pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent));
8275 if (fIsRaisingUnloadEvent)
8277 AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_GC);
8279 if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
8280 return COR_E_APPDOMAINUNLOADED;
8282 pApp->EnableADUnloadWorker();
8288 ADUnloadSinkHolder pSink;
8291 SystemDomain::LockHolder ulh;
8293 AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_ADLock);
8295 if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
8296 return COR_E_APPDOMAINUNLOADED;
8298 if (g_fADUnloadWorkerOK != 1)
8301 return E_UNEXPECTED;
8306 pApp->EnableADUnloadWorker();
8310 pSink = pApp->PrepareForWaitUnloadCompletion();
8312 pApp->EnableADUnloadWorker();
8314 // release the holders - we don't care anymore if the appdomain is gone
8317 #ifdef FEATURE_TESTHOOKS
8318 if (fExceptionsPassThrough)
8320 CONTRACT_VIOLATION(FaultViolation);
8321 return UnloadWaitNoCatch(dwId,pSink);
8325 return UnloadWait(dwId,pSink);
8328 HRESULT AppDomain::UnloadWait(ADID Id, ADUnloadSink * pSink)
8334 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
8341 // IF you ever try to change this to something not using events, please address the fact that
8342 // AppDomain::StopEEAndUnwindThreads relies on that events are used.
8344 pSink->WaitUnloadCompletion();
8346 EX_CATCH_HRESULT(hr);
8349 hr=pSink->GetUnloadResult();
8353 ResetUnloadRequestThread(Id);
8358 #ifdef FEATURE_TESTHOOKS
8359 HRESULT AppDomain::UnloadWaitNoCatch(ADID Id, ADUnloadSink * pSink)
8361 STATIC_CONTRACT_THROWS;
8362 STATIC_CONTRACT_MODE_ANY;
8364 Holder<ADID, DoNothing<ADID>, AppDomain::ResetUnloadRequestThread> resetUnloadHolder(Id);
8366 // IF you ever try to change this to something not using events, please address the fact that
8367 // AppDomain::StopEEAndUnwindThreads relies on that events are used.
8368 pSink->WaitUnloadCompletion();
8370 HRESULT hr = pSink->GetUnloadResult();
8373 resetUnloadHolder.SuppressRelease();
8379 void AppDomain::Unload(BOOL fForceUnload)
8386 INJECT_FAULT(COMPlusThrowOM(););
8390 #ifdef FEATURE_MULTICOREJIT
8392 // Avoid profiling file is partially written in ASP.net scenarios, call it earlier
8393 GetMulticoreJitManager().StopProfile(true);
8397 Thread *pThread = GetThread();
8400 if (! fForceUnload && !g_pConfig->AppDomainUnload())
8403 EPolicyAction action;
8404 EClrOperation operation;
8405 if (!IsRudeUnload())
8407 operation = OPR_AppDomainUnload;
8411 operation = OPR_AppDomainRudeUnload;
8413 action = GetEEPolicy()->GetDefaultAction(operation,NULL);
8414 GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
8418 case eUnloadAppDomain:
8420 case eRudeUnloadAppDomain:
8424 case eFastExitProcess:
8425 case eRudeExitProcess:
8426 case eDisableRuntime:
8427 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_ADUNLOAD);
8428 _ASSERTE (!"Should not get here");
8434 #if (defined(_DEBUG) || defined(BREAK_ON_UNLOAD) || defined(AD_LOG_MEMORY) || defined(AD_SNAPSHOT))
8435 static int unloadCount = 0;
8438 #ifdef AD_LOG_MEMORY
8441 static int logMemory = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADLogMemory);
8442 typedef void (__cdecl *LogItFcn) ( int );
8443 static LogItFcn pLogIt = NULL;
8445 if (logMemory && ! pLogIt)
8447 HMODULE hMod = CLRLoadLibrary(W("mpdh.dll"));
8450 pLogIt = (LogItFcn)GetProcAddress(hMod, "logIt");
8459 #endif // AD_LOG_MEMORY
8461 if (IsDefaultDomain() && !IsSingleAppDomain())
8462 COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_DEFAULT);
8464 _ASSERTE(CanUnload());
8466 if (pThread == FinalizerThread::GetFinalizerThread() || GetUnloadRequestThread() == FinalizerThread::GetFinalizerThread())
8467 COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_IN_FINALIZER);
8469 _ASSERTE(! SystemDomain::AppDomainBeingUnloaded());
8471 // should not be running in this AD because unload spawned thread in default domain
8472 if (!NingenEnabled())
8474 _ASSERTE(!pThread->IsRunningIn(this, NULL));
8478 #ifdef APPDOMAIN_STATE
8479 _ASSERTE_ALL_BUILDS("clr/src/VM/AppDomain.cpp", pThread->GetDomain()->IsDefaultDomain());
8482 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Unloading domain [%d] %#08x %ls\n", GetId().m_dwId, this, GetFriendlyName()));
8484 STRESS_LOG3 (LF_APPDOMAIN, LL_INFO100, "Unload domain [%d, %d] %p\n", GetId().m_dwId, GetIndex().m_dwIndex, this);
8486 UnloadHolder hold(this);
8488 SystemDomain::System()->SetUnloadRequestingThread(GetUnloadRequestThread());
8489 SystemDomain::System()->SetUnloadingThread(pThread);
8493 static int dumpSB = -1;
8496 dumpSB = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADDumpSB);
8500 LogSpewAlways("Starting unload %3.3d\n", unloadCount);
8501 DumpSyncBlockCache();
8505 BOOL bForceGC=m_bForceGCOnUnload;
8507 #ifdef AD_LOG_MEMORY
8510 #endif // AD_LOG_MEMORY
8513 static int takeSnapShot = -1;
8515 if (takeSnapShot == -1)
8516 takeSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeSnapShot);
8520 #endif // AD_SNAPSHOT
8526 static int cfgForceGC = -1;
8528 if (cfgForceGC == -1)
8529 cfgForceGC =!CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ADULazyMemoryRelease);
8531 bForceGC=bForceGC||cfgForceGC;
8532 AppDomainRefHolder This(this);
8535 // Do the actual unloading
8537 // We do not want other threads to abort the current one.
8538 ThreadPreventAsyncHolder preventAsync;
8539 Exit(TRUE, !bForceGC);
8543 GCHeapUtilities::GetGCHeap()->GarbageCollect();
8544 FinalizerThread::FinalizerThreadWait();
8545 SetStage(STAGE_COLLECTED);
8549 #ifdef AD_LOG_MEMORY
8553 pLogIt(unloadCount);
8555 #endif // AD_LOG_MEMORY
8561 sprintf_s(buffer, _countof(buffer), "vadump -p %d -o > vadump.%d", GetCurrentProcessId(), unloadCount);
8563 sprintf_s(buffer, _countof(buffer), "umdh -p:%d -d -i:1 -f:umdh.%d", GetCurrentProcessId(), unloadCount);
8565 int takeDHSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeDHSnapShot);
8568 sprintf_s(buffer, _countof(buffer), "dh -p %d -s -g -h -b -f dh.%d", GetCurrentProcessId(), unloadCount);
8572 #endif // AD_SNAPSHOT
8577 // do extra finalizer wait to remove any leftover sb entries
8578 FinalizerThread::FinalizerThreadWait();
8579 GCHeapUtilities::GetGCHeap()->GarbageCollect();
8580 FinalizerThread::FinalizerThreadWait();
8581 LogSpewAlways("Done unload %3.3d\n", unloadCount);
8582 DumpSyncBlockCache();
8585 swprintf_s(buffer, NumItems(buffer), W("DumpSB.%d"), unloadCount);
8586 _ASSERTE(WszMoveFileEx(W("COMPLUS.LOG"), buffer, MOVEFILE_REPLACE_EXISTING));
8587 // this will open a new file
8593 void AppDomain::ExceptionUnwind(Frame *pFrame)
8597 DISABLED(GC_TRIGGERS); // EEResourceException
8598 DISABLED(THROWS); // EEResourceException
8603 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind for %8.8x\n", pFrame));
8605 printf("%x AppDomain::ExceptionUnwind for %8.8p\n", GetThread()->GetThreadId(), pFrame);
8607 Thread *pThread = GetThread();
8610 if (! pThread->ShouldChangeAbortToUnload(pFrame))
8612 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: not first transition or abort\n"));
8616 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: changing to unload\n"));
8619 OBJECTREF throwable = NULL;
8620 EEResourceException e(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded_ThreadUnwound"));
8621 throwable = e.GetThrowable();
8623 // reset the exception to an AppDomainUnloadedException
8624 if (throwable != NULL)
8626 GetThread()->SafeSetThrowables(throwable);
8630 BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread)
8641 Thread *pThread = NULL;
8642 DWORD nThreadsNeedMoreWork=0;
8643 if (retryCount != (unsigned int)-1 && retryCount < g_pConfig->AppDomainUnloadRetryCount())
8645 Thread *pCurThread = GetThread();
8646 if (pCurThread->CatchAtSafePoint())
8647 pCurThread->PulseGCMode();
8650 // We know which thread is not in the domain now. We just need to
8651 // work on those threads. We do not need to suspend the runtime.
8652 ThreadStoreLockHolder tsl;
8654 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8656 if (pThread == pCurThread)
8661 if (pThread == FinalizerThread::GetFinalizerThread())
8666 if (pThread->GetUnloadBoundaryFrame() == NULL)
8671 // A thread may have UnloadBoundaryFrame set if
8672 // 1. Being unloaded by AD unload helper thread
8673 // 2. Escalation from OOM or SO triggers AD unload
8674 // Here we only need to work on threads that are in the domain. If we work on other threads,
8675 // those threads may be stucked in a finally, and we will not be able to escalate for them,
8676 // therefore AD unload is blocked.
8677 if (pThread->IsBeingAbortedForADUnload() ||
8678 pThread == SystemDomain::System()->GetUnloadRequestingThread())
8680 nThreadsNeedMoreWork++;
8683 if (!(IsRudeUnload() ||
8684 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())))
8689 if ((pThread == SystemDomain::System()->GetUnloadRequestingThread()) && *pFMarkUnloadRequestThread)
8691 // Mark thread for abortion only once; later on interrupt only
8692 *pFMarkUnloadRequestThread = FALSE;
8693 pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
8697 if (pThread->m_State & Thread::TS_Interruptible)
8699 pThread->UserInterrupt(Thread::TI_Abort);
8703 if (pThread->PreemptiveGCDisabledOther())
8705 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
8706 Thread::SuspendThreadResult str = pThread->SuspendThread();
8707 if (str == Thread::STR_Success)
8709 if (pThread->PreemptiveGCDisabledOther() &&
8710 (!pThread->IsAbortInitiated() || pThread->IsRudeAbort()))
8712 pThread->HandleJITCaseForAbort();
8714 pThread->ResumeThread();
8719 } // ThreadStoreLockHolder
8721 m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
8722 return !nThreadsNeedMoreWork;
8725 // For now piggyback on the GC's suspend EE mechanism
8726 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
8728 // <TODO>@todo: what to do with any threads that didn't stop?</TODO>
8729 _ASSERTE(ThreadStore::s_pThreadStore->DbgBackgroundThreadCount() > 0);
8732 int totalADCount = 0;
8733 int finalizerADCount = 0;
8736 RuntimeExceptionKind reKind = kLastException;
8738 SmallStackSString ssThreadId;
8740 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8742 // we already checked that we're not running in the unload domain
8743 if (pThread == GetThread())
8749 void PrintStackTraceWithADToLog(Thread *pThread);
8750 if (LoggingOn(LF_APPDOMAIN, LL_INFO100)) {
8751 LOG((LF_APPDOMAIN, LL_INFO100, "\nStackTrace for %x\n", pThread->GetThreadId()));
8752 PrintStackTraceWithADToLog(pThread);
8756 Frame *pFrame = pThread->GetFirstTransitionInto(this, &count);
8758 _ASSERTE(count == 0);
8759 if (pThread->IsBeingAbortedForADUnload())
8761 pThread->ResetBeginAbortedForADUnload();
8766 if (pThread != FinalizerThread::GetFinalizerThread())
8768 totalADCount += count;
8769 nThreadsNeedMoreWork++;
8770 pThread->SetUnloadBoundaryFrame(pFrame);
8774 finalizerADCount = count;
8777 // don't setup the exception info for the unloading thread unless it's the last one in
8778 if (retryCount != ((unsigned int) -1) && retryCount > g_pConfig->AppDomainUnloadRetryCount() && reKind == kLastException &&
8779 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft()))
8781 #ifdef AD_BREAK_ON_CANNOT_UNLOAD
8782 static int breakOnCannotUnload = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADBreakOnCannotUnload);
8783 if (breakOnCannotUnload)
8784 _ASSERTE(!"Cannot unload AD");
8785 #endif // AD_BREAK_ON_CANNOT_UNLOAD
8786 reKind = kCannotUnloadAppDomainException;
8787 resId = IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD;
8788 ssThreadId.Printf(W("%x"), pThread->GetThreadId());
8789 STRESS_LOG2(LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads cannot stop thread %x with %d transitions\n", pThread->GetThreadId(), count);
8790 // don't break out of this early or the assert totalADCount == (int)m_dwThreadEnterCount below will fire
8791 // it's better to chew a little extra time here and make sure our counts are consistent
8793 // only abort the thread requesting the unload if it's the last one in, that way it will get
8794 // notification that the unload failed for some other thread not being aborted. And don't abort
8795 // the finalizer thread - let it finish it's work as it's allowed to be in there. If it won't finish,
8796 // then we will eventually get a CannotUnloadException on it.
8798 if (pThread != FinalizerThread::GetFinalizerThread() &&
8799 // If the domain is rudely unloaded, we will unwind the requesting thread out
8800 // Rude unload is going to succeed, or escalated to disable runtime or higher.
8802 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())
8807 STRESS_LOG2(LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count);
8808 LOG((LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count));
8810 printf("AppDomain::UnwindThreads %x stopping %x with first frame %8.8p\n", GetThread()->GetThreadId(), pThread->GetThreadId(), pFrame);
8812 if (pThread == SystemDomain::System()->GetUnloadRequestingThread())
8814 // Mark thread for abortion only once; later on interrupt only
8815 *pFMarkUnloadRequestThread = FALSE;
8817 pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
8819 TESTHOOKCALL(UnwindingThreads(GetId().m_dwId)) ;
8821 _ASSERTE(totalADCount + finalizerADCount == (int)m_dwThreadEnterCount);
8823 //@TODO: This is intended to catch a stress bug. Remove when no longer needed.
8824 if (totalADCount + finalizerADCount != (int)m_dwThreadEnterCount)
8825 FreeBuildDebugBreak();
8827 // if our count did get messed up, set it to whatever count we actually found in the domain to avoid looping
8828 // or other problems related to incorrect count. This is very much a bug if this happens - a thread should always
8829 // exit the domain gracefully.
8830 // m_dwThreadEnterCount = totalADCount;
8832 if (reKind != kLastException)
8835 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8837 if (pThread->IsBeingAbortedForADUnload())
8839 pThread->ResetBeginAbortedForADUnload();
8844 // CommonTripThread will handle the abort for any threads that we've marked
8845 ThreadSuspend::RestartEE(FALSE, TRUE);
8846 if (reKind != kLastException)
8847 COMPlusThrow(reKind, resId, ssThreadId.GetUnicode());
8849 _ASSERTE((totalADCount==0 && nThreadsNeedMoreWork==0) ||(totalADCount!=0 && nThreadsNeedMoreWork!=0));
8851 m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
8852 return (totalADCount == 0);
8855 void AppDomain::UnwindThreads()
8857 // This function should guarantee appdomain
8858 // consistency even if it fails. Everything that is going
8859 // to make the appdomain impossible to reenter
8860 // should be factored out
8862 // <TODO>@todo: need real synchronization here!!!</TODO>
8871 int retryCount = -1;
8872 m_dwThreadsStillInAppDomain=(ULONG)-1;
8873 ULONGLONG startTime = CLRGetTickCount64();
8875 if (GetEEPolicy()->GetDefaultAction(OPR_AppDomainUnload, NULL) == eRudeUnloadAppDomain &&
8878 GetEEPolicy()->NotifyHostOnDefaultAction(OPR_AppDomainUnload, eRudeUnloadAppDomain);
8882 // Force threads to go through slow path during AD unload.
8883 TSSuspendHolder shTrap;
8885 BOOL fCurrentUnloadMode = IsRudeUnload();
8886 BOOL fMarkUnloadRequestThread = TRUE;
8888 // now wait for all the threads running in our AD to get out
8891 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8892 EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, NULL);
8893 if (timeout != INFINITE && action > eUnloadAppDomain) {
8894 // Escalation policy specified.
8895 ULONGLONG curTime = CLRGetTickCount64();
8896 ULONGLONG elapseTime = curTime - startTime;
8897 if (elapseTime > timeout)
8902 case eRudeUnloadAppDomain:
8903 GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
8905 STRESS_LOG1(LF_APPDOMAIN, LL_INFO100,"Escalating to RADU, adid=%d",GetId().m_dwId);
8908 case eFastExitProcess:
8909 case eRudeExitProcess:
8910 case eDisableRuntime:
8911 GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
8912 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
8913 _ASSERTE (!"Should not reach here");
8921 if (LoggingOn(LF_APPDOMAIN, LL_INFO100))
8922 DumpADThreadTrack();
8924 BOOL fNextUnloadMode = IsRudeUnload();
8925 if (fCurrentUnloadMode != fNextUnloadMode)
8927 // We have changed from normal unload to rude unload. We need to mark the thread
8928 // with RudeAbort, but we can only do this safely if the runtime is suspended.
8929 fCurrentUnloadMode = fNextUnloadMode;
8932 if (StopEEAndUnwindThreads(retryCount, &fMarkUnloadRequestThread))
8934 if (timeout != INFINITE)
8936 // Turn off the timeout used by AD.
8941 // GCStress takes a long time to unwind, due to expensive creation of
8942 // a threadabort exception.
8943 if (!GCStress<cfg_any>::IsEnabled())
8945 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount));
8947 printf("AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount);
8951 if (m_dwThreadEnterCount != 0)
8954 GetThread()->UserSleep(20);
8956 GetThread()->UserSleep(10);
8963 void AppDomain::ClearGCHandles()
8973 SetStage(STAGE_HANDLETABLE_NOACCESS);
8975 GCHeapUtilities::GetGCHeap()->WaitUntilConcurrentGCComplete();
8977 // Keep async pin handles alive by moving them to default domain
8978 HandleAsyncPinHandles();
8980 // Remove our handle store as a source of GC roots
8981 m_handleStore->Uproot();
8984 // When an AD is unloaded, we will release all objects in this AD.
8985 // If a future asynchronous operation, like io completion port function,
8986 // we need to keep the memory space fixed so that the gc heap is not corrupted.
8987 void AppDomain::HandleAsyncPinHandles()
8997 IGCHandleStore *pBucket = m_handleStore;
8999 // IO completion port picks IO job using FIFO. Here is how we know which AsyncPinHandle can be freed.
9000 // 1. We mark all non-pending AsyncPinHandle with READYTOCLEAN.
9001 // 2. We queue a dump Overlapped to the IO completion as a marker.
9002 // 3. When the Overlapped is picked up by completion port, we wait until all previous IO jobs are processed.
9003 // 4. Then we can delete all AsyncPinHandle marked with READYTOCLEAN.
9004 IGCHandleStore *pBucketInDefault = SystemDomain::System()->DefaultDomain()->m_handleStore;
9006 auto clearIfComplete = [](Object* object)
9008 LIMITED_METHOD_CONTRACT;
9010 assert(object != nullptr);
9011 if (object->GetGCSafeMethodTable() != g_pOverlappedDataClass)
9016 OVERLAPPEDDATAREF overlapped = (OVERLAPPEDDATAREF)(ObjectToOBJECTREF((Object*)object));
9017 if (overlapped->HasCompleted())
9019 // IO has finished. We don't need to pin the user buffer any longer.
9020 overlapped->m_userObject = NULL;
9023 BashMTForPinnedObject(ObjectToOBJECTREF(object));
9026 auto setHandle = [](Object* object, OBJECTHANDLE handle)
9028 LIMITED_METHOD_CONTRACT;
9030 assert(object != nullptr);
9033 if (object->GetGCSafeMethodTable() != g_pOverlappedDataClass)
9038 OverlappedDataObject* overlapped = (OverlappedDataObject*)object;
9039 overlapped->m_pinSelf = handle;
9042 pBucket->RelocateAsyncPinnedHandles(pBucketInDefault, clearIfComplete, setHandle);
9044 OverlappedDataObject::RequestCleanup();
9047 void AppDomain::ClearGCRoots()
9057 Thread *pThread = NULL;
9058 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
9060 // Tell the JIT managers to delete any entries in their structures. All the cooperative mode threads are stopped at
9061 // this point, so only need to synchronize the preemptive mode threads.
9062 ExecutionManager::Unload(GetLoaderAllocator());
9064 while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL)
9066 // Delete the thread local static store
9067 pThread->DeleteThreadStaticData(this);
9069 // <TODO>@TODO: A pre-allocated AppDomainUnloaded exception might be better.</TODO>
9070 if (m_handleStore->ContainsHandle(pThread->m_LastThrownObjectHandle))
9072 // Never delete a handle to a preallocated exception object.
9073 if (!CLRException::IsPreallocatedExceptionHandle(pThread->m_LastThrownObjectHandle))
9075 DestroyHandle(pThread->m_LastThrownObjectHandle);
9078 pThread->m_LastThrownObjectHandle = NULL;
9081 // Clear out the exceptions objects held by a thread.
9082 pThread->GetExceptionState()->ClearThrowablesForUnload(m_handleStore);
9085 //delete them while we still have the runtime suspended
9086 // This must be deleted before the loader heaps are deleted.
9087 if (m_pMarshalingData != NULL)
9089 delete m_pMarshalingData;
9090 m_pMarshalingData = NULL;
9093 if (m_pLargeHeapHandleTable != NULL)
9095 delete m_pLargeHeapHandleTable;
9096 m_pLargeHeapHandleTable = NULL;
9099 ThreadSuspend::RestartEE(FALSE, TRUE);
9104 void AppDomain::TrackADThreadEnter(Thread *pThread, Frame *pFrame)
9111 PRECONDITION(CheckPointer(pThread));
9112 PRECONDITION(pFrame != (Frame*)(size_t) INVALID_POINTER_CD);
9116 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9118 if (m_pThreadTrackInfoList == NULL)
9119 m_pThreadTrackInfoList = new (nothrow) ThreadTrackInfoList;
9120 // If we don't assert here, we will AV in the for loop below
9121 _ASSERTE(m_pThreadTrackInfoList);
9123 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9125 ThreadTrackInfo *pTrack = NULL;
9127 for (i=0; i < pTrackList->Count(); i++) {
9128 if ((*(pTrackList->Get(i)))->pThread == pThread) {
9129 pTrack = *(pTrackList->Get(i));
9134 pTrack = new (nothrow) ThreadTrackInfo;
9135 // If we don't assert here, we will AV in the for loop below.
9137 pTrack->pThread = pThread;
9138 ThreadTrackInfo **pSlot = pTrackList->Append();
9142 InterlockedIncrement((LONG*)&m_dwThreadEnterCount);
9146 pSlot = pTrack->frameStack.Insert(0);
9150 for (i=0; i < pTrackList->Count(); i++)
9151 totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
9152 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9154 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9158 void AppDomain::TrackADThreadExit(Thread *pThread, Frame *pFrame)
9162 if (GetThread()) {MODE_COOPERATIVE;}
9168 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9170 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9171 _ASSERTE(pTrackList);
9172 ThreadTrackInfo *pTrack = NULL;
9174 for (i=0; i < pTrackList->Count(); i++)
9176 if ((*(pTrackList->Get(i)))->pThread == pThread)
9178 pTrack = *(pTrackList->Get(i));
9183 _ASSERTE(*(pTrack->frameStack.Get(0)) == pFrame);
9184 pTrack->frameStack.Delete(0);
9185 InterlockedDecrement((LONG*)&m_dwThreadEnterCount);
9188 for (i=0; i < pTrackList->Count(); i++)
9189 totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
9190 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9192 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9195 void AppDomain::DumpADThreadTrack()
9205 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9207 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9212 LOG((LF_APPDOMAIN, LL_INFO10000, "\nThread dump of %d threads for [%d] %#08x %S\n",
9213 m_dwThreadEnterCount, GetId().m_dwId, this, GetFriendlyNameForLogging()));
9215 for (int i=0; i < pTrackList->Count(); i++)
9217 ThreadTrackInfo *pTrack = *(pTrackList->Get(i));
9218 if (pTrack->frameStack.Count()==0)
9220 LOG((LF_APPDOMAIN, LL_INFO100, " ADEnterCount for %x is %d\n", pTrack->pThread->GetThreadId(), pTrack->frameStack.Count()));
9221 totThreads += pTrack->frameStack.Count();
9222 for (int j=0; j < pTrack->frameStack.Count(); j++)
9223 LOG((LF_APPDOMAIN, LL_INFO100, " frame %8.8x\n", *(pTrack->frameStack.Get(j))));
9225 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9228 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9233 #endif // CROSSGEN_COMPILE
9235 void *SharedDomain::operator new(size_t size, void *pInPlace)
9237 LIMITED_METHOD_CONTRACT;
9241 void SharedDomain::operator delete(void *pMem)
9243 LIMITED_METHOD_CONTRACT;
9244 // Do nothing - new() was in-place
9248 void SharedDomain::Attach()
9255 INJECT_FAULT(COMPlusThrowOM(););
9259 // Create the global SharedDomain and initialize it.
9260 m_pSharedDomain = new (&g_pSharedDomainMemory[0]) SharedDomain();
9261 SystemDomain::GetGlobalLoaderAllocator()->m_pDomain = m_pSharedDomain;
9262 // This cannot fail since g_pSharedDomainMemory is a static array.
9263 CONSISTENCY_CHECK(CheckPointer(m_pSharedDomain));
9265 LOG((LF_CLASSLOADER,
9267 "Created shared domain at %p\n",
9270 // We need to initialize the memory pools etc. for the system domain.
9271 m_pSharedDomain->Init(); // Setup the memory heaps
9273 // allocate a Virtual Call Stub Manager for the shared domain
9274 m_pSharedDomain->InitVSD();
9277 #ifndef CROSSGEN_COMPILE
9278 void SharedDomain::Detach()
9280 if (m_pSharedDomain)
9282 m_pSharedDomain->Terminate();
9283 delete m_pSharedDomain;
9284 m_pSharedDomain = NULL;
9287 #endif // CROSSGEN_COMPILE
9289 #endif // !DACCESS_COMPILE
9291 SharedDomain *SharedDomain::GetDomain()
9293 LIMITED_METHOD_DAC_CONTRACT;
9295 return m_pSharedDomain;
9298 #ifndef DACCESS_COMPILE
9300 #define INITIAL_ASSEMBLY_MAP_SIZE 17
9301 void SharedDomain::Init()
9308 INJECT_FAULT(COMPlusThrowOM(););
9314 #ifdef FEATURE_LOADER_OPTIMIZATION
9315 m_FileCreateLock.Init(CrstSharedAssemblyCreate, CRST_DEFAULT,TRUE);
9317 LockOwner lock = { &m_DomainCrst, IsOwnerOfCrst };
9318 m_assemblyMap.Init(INITIAL_ASSEMBLY_MAP_SIZE, CompareSharedAssembly, TRUE, &lock);
9319 #endif // FEATURE_LOADER_OPTIMIZATION
9321 ETW::LoaderLog::DomainLoad(this);
9324 #ifndef CROSSGEN_COMPILE
9325 void SharedDomain::Terminate()
9327 // make sure we delete the StringLiteralMap before unloading
9328 // the asemblies since the string literal map entries can
9329 // point to metadata string literals.
9330 GetLoaderAllocator()->CleanupStringLiteralMap();
9332 #ifdef FEATURE_LOADER_OPTIMIZATION
9333 PtrHashMap::PtrIterator i = m_assemblyMap.begin();
9337 Assembly *pAssembly = (Assembly*) i.GetValue();
9342 ListLockEntry* pElement;
9343 pElement = m_FileCreateLock.Pop(TRUE);
9346 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
9347 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
9350 pElement = (FileLoadLock*) m_FileCreateLock.Pop(TRUE);
9352 m_FileCreateLock.Destroy();
9353 #endif // FEATURE_LOADER_OPTIMIZATION
9354 BaseDomain::Terminate();
9356 #endif // CROSSGEN_COMPILE
9360 #ifdef FEATURE_LOADER_OPTIMIZATION
9362 BOOL SharedDomain::CompareSharedAssembly(UPTR u1, UPTR u2)
9372 // This is the input to the lookup
9373 SharedAssemblyLocator *pLocator = (SharedAssemblyLocator *) (u1<<1);
9375 // This is the value stored in the table
9376 Assembly *pAssembly = (Assembly *) u2;
9377 if (pLocator->GetType()==SharedAssemblyLocator::DOMAINASSEMBLY)
9379 if (!pAssembly->GetManifestFile()->Equals(pLocator->GetDomainAssembly()->GetFile()))
9382 return pAssembly->CanBeShared(pLocator->GetDomainAssembly());
9385 if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLY)
9386 return pAssembly->GetManifestFile()->Equals(pLocator->GetPEAssembly());
9388 if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLYEXACT)
9389 return pAssembly->GetManifestFile() == pLocator->GetPEAssembly();
9390 _ASSERTE(!"Unexpected type of assembly locator");
9394 DWORD SharedAssemblyLocator::Hash()
9401 INJECT_FAULT(COMPlusThrowOM(););
9404 if (m_type==DOMAINASSEMBLY)
9405 return GetDomainAssembly()->HashIdentity();
9406 if (m_type==PEASSEMBLY||m_type==PEASSEMBLYEXACT)
9407 return GetPEAssembly()->HashIdentity();
9408 _ASSERTE(!"Unexpected type of assembly locator");
9412 Assembly * SharedDomain::FindShareableAssembly(SharedAssemblyLocator * pLocator)
9419 INJECT_FAULT(COMPlusThrowOM(););
9423 Assembly * match= (Assembly *) m_assemblyMap.LookupValue(pLocator->Hash(), pLocator);
9424 if (match != (Assembly *) INVALIDENTRY)
9430 SIZE_T SharedDomain::GetShareableAssemblyCount()
9432 LIMITED_METHOD_CONTRACT;
9434 return m_assemblyMap.GetCount();
9437 void SharedDomain::AddShareableAssembly(Assembly * pAssembly)
9444 INJECT_FAULT(COMPlusThrowOM(););
9448 // We have a lock on the file. There should be no races to add the same assembly.
9451 LockHolder holder(this);
9455 pAssembly->SetIsTenured();
9456 m_assemblyMap.InsertValue(pAssembly->HashIdentity(), pAssembly);
9460 // There was an error adding the assembly to the assembly hash (probably an OOM),
9461 // so we need to unset the tenured bit so that correct cleanup can happen.
9462 pAssembly->UnsetIsTenured();
9467 LOG((LF_CODESHARING,
9469 "Successfully added shareable assembly \"%s\".\n",
9470 pAssembly->GetManifestFile()->GetSimpleName()));
9473 #endif // FEATURE_LOADER_OPTIMIZATION
9474 #endif // !DACCESS_COMPILE
9476 DWORD DomainLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex /*=(DWORD)-1*/)
9484 { // SO tolerance exception for debug-only assertion.
9485 CONTRACT_VIOLATION(SOToleranceViolation);
9486 CONSISTENCY_CHECK(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9489 if (pMT->IsDynamicStatics())
9491 _ASSERTE(!pMT->ContainsGenericVariables());
9492 DWORD dynamicClassID = pMT->GetModuleDynamicEntryID();
9493 if(m_aDynamicEntries <= dynamicClassID)
9495 return (m_pDynamicClassTable[dynamicClassID].m_dwFlags);
9499 if (iClassIndex == (DWORD)-1)
9500 iClassIndex = pMT->GetClassIndex();
9501 return GetPrecomputedStaticsClassData()[iClassIndex];
9505 #ifndef DACCESS_COMPILE
9507 void DomainLocalModule::SetClassInitialized(MethodTable* pMT)
9517 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9519 _ASSERTE(!IsClassInitialized(pMT));
9520 _ASSERTE(!IsClassInitError(pMT));
9522 SetClassFlags(pMT, ClassInitFlags::INITIALIZED_FLAG);
9525 void DomainLocalModule::SetClassInitError(MethodTable* pMT)
9527 WRAPPER_NO_CONTRACT;
9529 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9531 SetClassFlags(pMT, ClassInitFlags::ERROR_FLAG);
9534 void DomainLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags)
9539 PRECONDITION(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9540 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9541 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9544 if (pMT->IsDynamicStatics())
9546 _ASSERTE(!pMT->ContainsGenericVariables());
9547 DWORD dwID = pMT->GetModuleDynamicEntryID();
9548 EnsureDynamicClassIndex(dwID);
9549 m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags;
9553 GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags;
9557 void DomainLocalModule::EnsureDynamicClassIndex(DWORD dwID)
9564 INJECT_FAULT(COMPlusThrowOM(););
9565 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9566 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9570 if (dwID < m_aDynamicEntries)
9572 _ASSERTE(m_pDynamicClassTable.Load() != NULL);
9576 SIZE_T aDynamicEntries = max(16, m_aDynamicEntries.Load());
9577 while (aDynamicEntries <= dwID)
9579 aDynamicEntries *= 2;
9582 DynamicClassInfo* pNewDynamicClassTable;
9583 pNewDynamicClassTable = (DynamicClassInfo*)
9584 (void*)GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
9585 S_SIZE_T(sizeof(DynamicClassInfo)) * S_SIZE_T(aDynamicEntries));
9587 memcpy(pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * m_aDynamicEntries);
9589 // Note: Memory allocated on loader heap is zero filled
9590 // memset(pNewDynamicClassTable + m_aDynamicEntries, 0, (aDynamicEntries - m_aDynamicEntries) * sizeof(DynamicClassInfo));
9592 _ASSERTE(m_aDynamicEntries%2 == 0);
9594 // Commit new dynamic table. The lock-free helpers depend on the order.
9596 m_pDynamicClassTable = pNewDynamicClassTable;
9598 m_aDynamicEntries = aDynamicEntries;
9601 #ifndef CROSSGEN_COMPILE
9602 void DomainLocalModule::AllocateDynamicClass(MethodTable *pMT)
9608 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9609 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9613 _ASSERTE(!pMT->ContainsGenericVariables());
9614 _ASSERTE(!pMT->IsSharedByGenericInstantiations());
9615 _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9616 _ASSERTE(pMT->IsDynamicStatics());
9618 DWORD dynamicEntryIDIndex = pMT->GetModuleDynamicEntryID();
9620 EnsureDynamicClassIndex(dynamicEntryIDIndex);
9622 _ASSERTE(m_aDynamicEntries > dynamicEntryIDIndex);
9624 EEClass *pClass = pMT->GetClass();
9626 DWORD dwStaticBytes = pClass->GetNonGCRegularStaticFieldBytes();
9627 DWORD dwNumHandleStatics = pClass->GetNumHandleRegularStatics();
9629 _ASSERTE(!IsClassAllocated(pMT));
9630 _ASSERTE(!IsClassInitialized(pMT));
9631 _ASSERTE(!IsClassInitError(pMT));
9633 DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry;
9635 // We need this check because maybe a class had a cctor but no statics
9636 if (dwStaticBytes > 0 || dwNumHandleStatics > 0)
9638 if (pDynamicStatics == NULL)
9640 LoaderHeap * pLoaderAllocator = GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap();
9642 if (pMT->Collectible())
9644 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(sizeof(CollectibleDynamicEntry)));
9648 SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes;
9650 #ifdef FEATURE_64BIT_ALIGNMENT
9651 // Allocate memory with extra alignment only if it is really necessary
9652 if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
9654 static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0);
9655 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE);
9659 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(dynamicEntrySize));
9662 // Note: Memory allocated on loader heap is zero filled
9664 m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry = pDynamicStatics;
9667 if (pMT->Collectible() && (dwStaticBytes != 0))
9670 OBJECTREF nongcStaticsArray = NULL;
9671 GCPROTECT_BEGIN(nongcStaticsArray);
9672 #ifdef FEATURE_64BIT_ALIGNMENT
9673 // Allocate memory with extra alignment only if it is really necessary
9674 if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
9675 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8)-1)) / (sizeof(CLR_I8)));
9678 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes);
9679 ((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray);
9682 if (dwNumHandleStatics > 0)
9684 if (!pMT->Collectible())
9686 GetAppDomain()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
9687 &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics);
9692 OBJECTREF gcStaticsArray = NULL;
9693 GCPROTECT_BEGIN(gcStaticsArray);
9694 gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass);
9695 ((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(gcStaticsArray);
9703 void DomainLocalModule::PopulateClass(MethodTable *pMT)
9712 _ASSERTE(!pMT->ContainsGenericVariables());
9714 // <todo> the only work actually done here for non-dynamics is the freezing related work.
9715 // See if we can eliminate this and make this a dynamic-only path </todo>
9716 DWORD iClassIndex = pMT->GetClassIndex();
9718 if (!IsClassAllocated(pMT, iClassIndex))
9720 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9722 if (!IsClassAllocated(pMT, iClassIndex))
9724 // Allocate dynamic space if necessary
9725 if (pMT->IsDynamicStatics())
9726 AllocateDynamicClass(pMT);
9728 // determine flags to set on the statics block
9729 DWORD dwFlags = ClassInitFlags::ALLOCATECLASS_FLAG;
9731 if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics())
9733 _ASSERTE(!IsClassInitialized(pMT));
9734 _ASSERTE(!IsClassInitError(pMT));
9735 dwFlags |= ClassInitFlags::INITIALIZED_FLAG;
9738 if (pMT->Collectible())
9740 dwFlags |= ClassInitFlags::COLLECTIBLE_FLAG;
9743 // Set all flags at the same time to avoid races
9744 SetClassFlags(pMT, dwFlags);
9750 #endif // CROSSGEN_COMPILE
9752 void DomainLocalBlock::EnsureModuleIndex(ModuleIndex index)
9759 INJECT_FAULT(COMPlusThrowOM(););
9760 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9761 PRECONDITION(m_pDomain->OwnDomainLocalBlockLock());
9765 if (m_aModuleIndices > index.m_dwIndex)
9767 _ASSERTE(m_pModuleSlots != NULL);
9771 SIZE_T aModuleIndices = max(16, m_aModuleIndices);
9772 while (aModuleIndices <= index.m_dwIndex)
9774 aModuleIndices *= 2;
9777 PTR_DomainLocalModule* pNewModuleSlots = (PTR_DomainLocalModule*) (void*)m_pDomain->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(PTR_DomainLocalModule)) * S_SIZE_T(aModuleIndices));
9779 memcpy(pNewModuleSlots, m_pModuleSlots, sizeof(SIZE_T)*m_aModuleIndices);
9781 // Note: Memory allocated on loader heap is zero filled
9782 // memset(pNewModuleSlots + m_aModuleIndices, 0 , (aModuleIndices - m_aModuleIndices)*sizeof(PTR_DomainLocalModule) );
9784 // Commit new table. The lock-free helpers depend on the order.
9786 m_pModuleSlots = pNewModuleSlots;
9788 m_aModuleIndices = aModuleIndices;
9792 void DomainLocalBlock::SetModuleSlot(ModuleIndex index, PTR_DomainLocalModule pLocalModule)
9794 // Need to synchronize with table growth in this domain
9795 BaseDomain::DomainLocalBlockLockHolder lh(m_pDomain);
9797 EnsureModuleIndex(index);
9799 _ASSERTE(index.m_dwIndex < m_aModuleIndices);
9801 // We would like this assert here, unfortunately, loading a module in this appdomain can fail
9802 // after here and we will keep the module around and reuse the slot when we retry (if
9803 // the failure happened due to a transient error, such as OOM). In that case the slot wont
9805 //_ASSERTE(m_pModuleSlots[index.m_dwIndex] == 0);
9807 m_pModuleSlots[index.m_dwIndex] = pLocalModule;
9810 #ifndef CROSSGEN_COMPILE
9812 DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef)
9819 INJECT_FAULT(COMPlusThrowOM(););
9823 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
9826 DomainAssembly* pResolvedAssembly = NULL;
9827 _ASSERTE(strcmp(szName, g_AppDomainClassName));
9832 OBJECTREF AppDomainRef;
9833 OBJECTREF AssemblyRef;
9836 ZeroMemory(&gc, sizeof(gc));
9838 GCPROTECT_BEGIN(gc);
9839 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9841 if (pAssembly != NULL)
9842 gc.AssemblyRef = pAssembly->GetExposedAssemblyObject();
9844 MethodDescCallSite onTypeResolve(METHOD__APP_DOMAIN__ON_TYPE_RESOLVE, &gc.AppDomainRef);
9846 gc.str = StringObject::NewString(szName);
9849 ObjToArgSlot(gc.AppDomainRef),
9850 ObjToArgSlot(gc.AssemblyRef),
9851 ObjToArgSlot(gc.str)
9853 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onTypeResolve.Call_RetOBJECTREF(args);
9855 if (ResultingAssemblyRef != NULL)
9857 pResolvedAssembly = ResultingAssemblyRef->GetDomainAssembly();
9859 if (pResultingAssemblyRef)
9860 *pResultingAssemblyRef = ResultingAssemblyRef;
9863 if (pResolvedAssembly->IsCollectible())
9865 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
9872 return pResolvedAssembly;
9876 Assembly* AppDomain::RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName)
9883 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9884 INJECT_FAULT(COMPlusThrowOM(););
9888 Assembly* pResolvedAssembly = NULL;
9893 OBJECTREF AppDomainRef;
9894 OBJECTREF AssemblyRef;
9897 ZeroMemory(&gc, sizeof(gc));
9899 GCPROTECT_BEGIN(gc);
9900 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9902 if (pAssembly != NULL)
9903 gc.AssemblyRef=pAssembly->GetExposedAssemblyObject();
9905 MethodDescCallSite onResourceResolve(METHOD__APP_DOMAIN__ON_RESOURCE_RESOLVE, &gc.AppDomainRef);
9906 gc.str = StringObject::NewString(szName);
9909 ObjToArgSlot(gc.AppDomainRef),
9910 ObjToArgSlot(gc.AssemblyRef),
9911 ObjToArgSlot(gc.str)
9913 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onResourceResolve.Call_RetOBJECTREF(args);
9914 if (ResultingAssemblyRef != NULL)
9916 pResolvedAssembly = ResultingAssemblyRef->GetAssembly();
9917 if (pResolvedAssembly->IsCollectible())
9919 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
9925 RETURN pResolvedAssembly;
9930 AppDomain::RaiseAssemblyResolveEvent(
9931 AssemblySpec * pSpec,
9932 BOOL fIntrospection,
9940 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9941 INJECT_FAULT(COMPlusThrowOM(););
9945 BinderMethodID methodId;
9946 StackSString ssName;
9947 pSpec->GetFileOrDisplayName(0, ssName);
9951 methodId = METHOD__APP_DOMAIN__ON_ASSEMBLY_RESOLVE; // post-bind execution event (the classic V1.0 event)
9959 // Elevate threads allowed loading level. This allows the host to load an assembly even in a restricted
9960 // condition. Note, however, that this exposes us to possible recursion failures, if the host tries to
9961 // load the assemblies currently being loaded. (Such cases would then throw an exception.)
9963 OVERRIDE_LOAD_LEVEL_LIMIT(FILE_ACTIVE);
9964 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
9968 Assembly* pAssembly = NULL;
9971 OBJECTREF AppDomainRef;
9972 OBJECTREF AssemblyRef;
9975 ZeroMemory(&gc, sizeof(gc));
9977 GCPROTECT_BEGIN(gc);
9978 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9980 if (pSpec->GetParentAssembly() != NULL)
9983 gc.AssemblyRef=pSpec->GetParentAssembly()->GetExposedAssemblyObject();
9986 MethodDescCallSite onAssemblyResolve(methodId, &gc.AppDomainRef);
9988 gc.str = StringObject::NewString(ssName);
9989 ARG_SLOT args[3] = {
9990 ObjToArgSlot(gc.AppDomainRef),
9991 ObjToArgSlot(gc.AssemblyRef),
9992 ObjToArgSlot(gc.str)
9995 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onAssemblyResolve.Call_RetOBJECTREF(args);
9997 if (ResultingAssemblyRef != NULL)
9999 pAssembly = ResultingAssemblyRef->GetAssembly();
10000 if (pAssembly->IsCollectible())
10002 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
10008 if (pAssembly != NULL)
10010 if ((!(pAssembly->IsIntrospectionOnly())) != (!fIntrospection))
10012 // Cannot return an introspection assembly from an execution callback or vice-versa
10013 COMPlusThrow(kFileLoadException, pAssembly->IsIntrospectionOnly() ? IDS_CLASSLOAD_ASSEMBLY_RESOLVE_RETURNED_INTROSPECTION : IDS_CLASSLOAD_ASSEMBLY_RESOLVE_RETURNED_EXECUTION);
10016 // Check that the public key token matches the one specified in the spec
10017 // MatchPublicKeys throws as appropriate
10018 pSpec->MatchPublicKeys(pAssembly);
10022 } // AppDomain::RaiseAssemblyResolveEvent
10025 //---------------------------------------------------------------------------------------
10027 // Determine the type of AppDomainManager to use for the default AppDomain
10030 // v2.0 of the CLR used environment variables APPDOMAIN_MANAGER_ASM and APPDOMAIN_MANAGER_TYPE to set the
10031 // domain manager. For compatibility these are still supported, along with appDomainManagerAsm and
10032 // appDomainManagerType config file switches. If the config switches are supplied, the entry point must be
10036 void AppDomain::InitializeDefaultDomainManager()
10043 INJECT_FAULT(COMPlusThrowOM(););
10044 PRECONDITION(GetId().m_dwId == DefaultADID);
10048 OBJECTREF orThis = GetExposedObject();
10049 GCPROTECT_BEGIN(orThis);
10051 MethodDescCallSite initCompatFlags(METHOD__APP_DOMAIN__INITIALIZE_COMPATIBILITY_FLAGS);
10054 ObjToArgSlot(orThis)
10057 initCompatFlags.Call(args);
10062 CLREvent * AppDomain::g_pUnloadStartEvent;
10064 void AppDomain::CreateADUnloadWorker()
10066 STANDARD_VM_CONTRACT;
10068 // Do not create adUnload thread if there is only default domain
10069 if(IsSingleAppDomain())
10073 BOOL fCreator = FALSE;
10074 if (FastInterlockCompareExchange((LONG *)&g_fADUnloadWorkerOK,-2,-1)==-1) //we're first
10076 #ifdef _TARGET_X86_ // use the smallest possible stack on X86
10077 DWORD stackSize = 128 * 1024;
10079 DWORD stackSize = 512 * 1024; // leave X64 unchanged since we have plenty of VM
10081 Thread *pThread = SetupUnstartedThread();
10082 if (pThread->CreateNewThread(stackSize, ADUnloadThreadStart, pThread))
10086 dwRet = pThread->StartThread();
10088 // When running under a user mode native debugger there is a race
10089 // between the moment we've created the thread (in CreateNewThread) and
10090 // the moment we resume it (in StartThread); the debugger may receive
10091 // the "ct" (create thread) notification, and it will attempt to
10092 // suspend/resume all threads in the process. Now imagine the debugger
10093 // resumes this thread first, and only later does it try to resume the
10094 // newly created thread (the ADU worker thread). In these conditions our
10095 // call to ResumeThread may come before the debugger's call to ResumeThread
10096 // actually causing dwRet to equal 2.
10097 // We cannot use IsDebuggerPresent() in the condition below because the
10098 // debugger may have been detached between the time it got the notification
10099 // and the moment we execute the test below.
10100 _ASSERTE(dwRet == 1 || dwRet == 2);
10104 pThread->DecExternalCount(FALSE);
10105 FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK, -1);
10106 ThrowOutOfMemory();
10110 YIELD_WHILE (g_fADUnloadWorkerOK == -2);
10112 if (g_fADUnloadWorkerOK == -1) {
10115 ThrowOutOfMemory();
10124 /*static*/ void AppDomain::ADUnloadWorkerHelper(AppDomain *pDomain)
10126 STATIC_CONTRACT_NOTHROW;
10127 STATIC_CONTRACT_GC_TRIGGERS;
10128 STATIC_CONTRACT_MODE_COOPERATIVE;
10129 ADUnloadSink* pADUnloadSink=pDomain->GetADUnloadSinkForUnload();
10134 pDomain->Unload(FALSE);
10136 EX_CATCH_HRESULT(hr);
10140 SystemDomain::LockHolder lh;
10141 pADUnloadSink->ReportUnloadResult(hr,NULL);
10142 pADUnloadSink->Release();
10146 void AppDomain::DoADUnloadWork()
10153 INJECT_FAULT(COMPlusThrowOM(););
10160 AppDomain *pDomainToUnload = NULL;
10163 // Take the lock so that no domain can be added or removed from the system domain
10164 SystemDomain::LockHolder lh;
10166 DWORD numDomain = SystemDomain::GetCurrentAppDomainMaxIndex();
10167 for (; i <= numDomain; i ++) {
10168 AppDomain * pDomain = SystemDomain::TestGetAppDomainAtIndex(ADIndex(i));
10170 // @todo: We used to also select a domain if pDomain->IsUnload() returned true. But that causes
10171 // problems when we've failed to completely unload the AD in the past. If we've reached the CLEARED
10172 // stage, for instance, then there will be no default context and AppDomain::Exit() will simply crash.
10174 if (pDomain && pDomain->IsUnloadRequested())
10176 pDomainToUnload = pDomain;
10183 if (!pDomainToUnload) {
10187 // We are the only thread that can unload domains so no one else can delete the appdomain
10188 ADUnloadWorkerHelper(pDomainToUnload);
10192 static void DoADUnloadWorkHelper()
10194 STATIC_CONTRACT_NOTHROW;
10195 STATIC_CONTRACT_GC_TRIGGERS;
10196 STATIC_CONTRACT_MODE_COOPERATIVE;
10199 AppDomain::DoADUnloadWork();
10204 EX_END_CATCH(SwallowAllExceptions);
10207 ULONGLONG g_ObjFinalizeStartTime = 0;
10208 Volatile<BOOL> g_FinalizerIsRunning = FALSE;
10209 Volatile<ULONG> g_FinalizerLoopCount = 0;
10211 ULONGLONG GetObjFinalizeStartTime()
10213 LIMITED_METHOD_CONTRACT;
10214 return g_ObjFinalizeStartTime;
10217 void FinalizerThreadAbortOnTimeout()
10219 STATIC_CONTRACT_NOTHROW;
10220 STATIC_CONTRACT_MODE_COOPERATIVE;
10221 STATIC_CONTRACT_GC_TRIGGERS;
10224 // If finalizer thread is blocked because scheduler is running another task,
10225 // or it is waiting for another thread, we first see if we get finalizer thread
10227 Thread::ThreadAbortWatchDog();
10232 Thread *pFinalizerThread = FinalizerThread::GetFinalizerThread();
10233 EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(OPR_FinalizerRun, pFinalizerThread);
10237 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10238 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10241 Thread::UAC_FinalizerTimeout);
10243 case eRudeAbortThread:
10244 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10245 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10248 Thread::UAC_FinalizerTimeout);
10250 case eUnloadAppDomain:
10252 AppDomain *pDomain = pFinalizerThread->GetDomain();
10253 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10256 Thread::UAC_FinalizerTimeout);
10257 if (!pDomain->IsDefaultDomain())
10259 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10260 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
10264 case eRudeUnloadAppDomain:
10266 AppDomain *pDomain = pFinalizerThread->GetDomain();
10267 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10270 Thread::UAC_FinalizerTimeout);
10271 if (!pDomain->IsDefaultDomain())
10273 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10274 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
10279 case eFastExitProcess:
10280 case eRudeExitProcess:
10281 case eDisableRuntime:
10282 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10283 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
10284 _ASSERTE (!"Should not get here");
10293 EX_END_CATCH(SwallowAllExceptions);
10298 WT_UnloadDomain = 0x1,
10299 WT_ThreadAbort = 0x2,
10300 WT_FinalizerThread = 0x4,
10301 WT_ClearCollectedDomains=0x8
10304 static Volatile<DWORD> s_WorkType = 0;
10307 DWORD WINAPI AppDomain::ADUnloadThreadStart(void *args)
10312 DISABLED(GC_TRIGGERS);
10314 // This function will always be at the very bottom of the stack. The only
10315 // user code it calls is the AppDomainUnload notifications which we will
10316 // not be hardenning for Whidbey.
10322 BEGIN_ENTRYPOINT_NOTHROW;
10324 ClrFlsSetThreadType (ThreadType_ADUnloadHelper);
10326 Thread *pThread = (Thread*)args;
10327 bool fOK = (pThread->HasStarted() != 0);
10330 GCX_MAYBE_PREEMP(fOK);
10332 _ASSERTE (g_fADUnloadWorkerOK == -2);
10334 FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK,fOK?1:-1);
10338 DestroyThread(pThread);
10342 pThread->SetBackground(TRUE);
10344 pThread->SetThreadStateNC(Thread::TSNC_ADUnloadHelper);
10347 DWORD TAtimeout = INFINITE;
10348 ULONGLONG endTime = Thread::GetNextSelfAbortEndTime();
10349 ULONGLONG curTime = CLRGetTickCount64();
10350 if (endTime <= curTime) {
10355 ULONGLONG diff = endTime - curTime;
10356 if (diff < MAXULONG)
10358 TAtimeout = (DWORD)diff;
10361 ULONGLONG finalizeStartTime = GetObjFinalizeStartTime();
10362 DWORD finalizeTimeout = INFINITE;
10363 DWORD finalizeTimeoutSetting = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
10364 if (finalizeTimeoutSetting != INFINITE && g_FinalizerIsRunning)
10366 if (finalizeStartTime == 0)
10368 finalizeTimeout = finalizeTimeoutSetting;
10372 endTime = finalizeStartTime + finalizeTimeoutSetting;
10373 if (endTime <= curTime) {
10374 finalizeTimeout = 0;
10378 ULONGLONG diff = endTime - curTime;
10379 if (diff < MAXULONG)
10381 finalizeTimeout = (DWORD)diff;
10387 if (AppDomain::HasWorkForFinalizerThread())
10389 if (finalizeTimeout > finalizeTimeoutSetting)
10391 finalizeTimeout = finalizeTimeoutSetting;
10395 DWORD timeout = INFINITE;
10396 if (finalizeTimeout <= TAtimeout)
10398 timeout = finalizeTimeout;
10402 timeout = TAtimeout;
10407 LOG((LF_APPDOMAIN, LL_INFO10, "Waiting to start unload\n"));
10408 g_pUnloadStartEvent->Wait(timeout,FALSE);
10411 if (finalizeTimeout != INFINITE || (s_WorkType & WT_FinalizerThread) != 0)
10413 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for Finalizer thread\n");
10414 FastInterlockAnd(&s_WorkType, ~WT_FinalizerThread);
10415 // only watch finalizer thread is finalizer method or unloadevent is being processed
10416 if (GetObjFinalizeStartTime() == finalizeStartTime && finalizeStartTime != 0 && g_FinalizerIsRunning)
10418 if (CLRGetTickCount64() >= finalizeStartTime+finalizeTimeoutSetting)
10421 FinalizerThreadAbortOnTimeout();
10424 if (s_fProcessUnloadDomainEvent && g_FinalizerIsRunning)
10427 FinalizerThreadAbortOnTimeout();
10431 if (TAtimeout != INFINITE || (s_WorkType & WT_ThreadAbort) != 0)
10433 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for thread abort\n");
10434 FastInterlockAnd(&s_WorkType, ~WT_ThreadAbort);
10436 Thread::ThreadAbortWatchDog();
10439 if ((s_WorkType & WT_UnloadDomain) != 0 && !AppDomain::HasWorkForFinalizerThread())
10441 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD unload\n");
10442 FastInterlockAnd(&s_WorkType, ~WT_UnloadDomain);
10444 DoADUnloadWorkHelper();
10447 if ((s_WorkType & WT_ClearCollectedDomains) != 0)
10449 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD cleanup\n");
10450 FastInterlockAnd(&s_WorkType, ~WT_ClearCollectedDomains);
10452 SystemDomain::System()->ClearCollectedDomains();
10459 END_ENTRYPOINT_NOTHROW;
10464 void AppDomain::EnableADUnloadWorker()
10470 SO_TOLERANT; // Called during a SO
10474 EEPolicy::AppDomainUnloadTypes type = EEPolicy::ADU_Safe;
10477 DWORD hostTestADUnload = g_pConfig->GetHostTestADUnload();
10478 if (hostTestADUnload == 2) {
10479 type = EEPolicy::ADU_Rude;
10483 EnableADUnloadWorker(type);
10486 void AppDomain::EnableADUnloadWorker(EEPolicy::AppDomainUnloadTypes type, BOOL fHasStack)
10492 SO_TOLERANT; // Called during a SO
10496 FastInterlockOr (&s_WorkType, WT_UnloadDomain);
10498 LONG stage = m_Stage;
10499 static_assert_no_msg(sizeof(m_Stage) == sizeof(int));
10501 _ASSERTE(!IsDefaultDomain());
10503 // Mark unload requested.
10504 if (type == EEPolicy::ADU_Rude) {
10507 while (stage < STAGE_UNLOAD_REQUESTED) {
10508 stage = FastInterlockCompareExchange((LONG*)&m_Stage,STAGE_UNLOAD_REQUESTED,stage);
10513 // Can not call Set due to limited stack.
10516 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker\n"));
10517 g_pUnloadStartEvent->Set();
10520 void AppDomain::EnableADUnloadWorkerForThreadAbort()
10522 LIMITED_METHOD_CONTRACT;
10523 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "Enabling unload worker for thread abort\n");
10524 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for thread abort\n"));
10525 FastInterlockOr (&s_WorkType, WT_ThreadAbort);
10526 g_pUnloadStartEvent->Set();
10530 void AppDomain::EnableADUnloadWorkerForFinalizer()
10532 LIMITED_METHOD_CONTRACT;
10533 if (GetEEPolicy()->GetTimeout(OPR_FinalizerRun) != INFINITE)
10535 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for Finalizer Thread\n"));
10536 FastInterlockOr (&s_WorkType, WT_FinalizerThread);
10537 g_pUnloadStartEvent->Set();
10541 void AppDomain::EnableADUnloadWorkerForCollectedADCleanup()
10543 LIMITED_METHOD_CONTRACT;
10544 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for collected domains\n"));
10545 FastInterlockOr (&s_WorkType, WT_ClearCollectedDomains);
10546 g_pUnloadStartEvent->Set();
10550 void SystemDomain::ClearCollectedDomains()
10560 AppDomain* pDomainsToClear=NULL;
10562 CrstHolder lh(&m_DelayedUnloadCrst);
10563 for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
10565 if ((*ppDomain)->m_Stage==AppDomain::STAGE_COLLECTED)
10567 AppDomain* pAppDomain=*ppDomain;
10568 *ppDomain=(*ppDomain)->m_pNextInDelayedUnloadList;
10569 pAppDomain->m_pNextInDelayedUnloadList=pDomainsToClear;
10570 pDomainsToClear=pAppDomain;
10573 ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
10577 for (AppDomain* pDomain=pDomainsToClear;pDomain!=NULL;)
10579 AppDomain* pNext=pDomain->m_pNextInDelayedUnloadList;
10580 pDomain->Close(); //NOTHROW!
10581 pDomain->Release();
10586 void SystemDomain::ProcessClearingDomains()
10595 CrstHolder lh(&m_DelayedUnloadCrst);
10597 for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
10599 if ((*ppDomain)->m_Stage==AppDomain::STAGE_HANDLETABLE_NOACCESS)
10601 AppDomain* pAppDomain=*ppDomain;
10602 pAppDomain->SetStage(AppDomain::STAGE_CLEARED);
10604 ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
10607 if (!m_UnloadIsAsync)
10609 // For synchronous mode, we are now done with the list.
10610 m_pDelayedUnloadList = NULL;
10614 void SystemDomain::ProcessDelayedUnloadDomains()
10624 int iGCRefPoint=GCHeapUtilities::GetGCHeap()->CollectionCount(GCHeapUtilities::GetGCHeap()->GetMaxGeneration());
10625 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCInProgress())
10628 BOOL bAppDomainToCleanup = FALSE;
10629 LoaderAllocator * pAllocatorsToDelete = NULL;
10632 CrstHolder lh(&m_DelayedUnloadCrst);
10634 for (AppDomain* pDomain=m_pDelayedUnloadList; pDomain!=NULL; pDomain=pDomain->m_pNextInDelayedUnloadList)
10636 if (pDomain->m_Stage==AppDomain::STAGE_CLEARED)
10638 // Compare with 0 to handle overflows gracefully
10639 if (0 < iGCRefPoint - pDomain->GetGCRefPoint())
10641 bAppDomainToCleanup=TRUE;
10642 pDomain->SetStage(AppDomain::STAGE_COLLECTED);
10647 LoaderAllocator ** ppAllocator=&m_pDelayedUnloadListOfLoaderAllocators;
10648 while (*ppAllocator!= NULL)
10650 LoaderAllocator * pAllocator = *ppAllocator;
10651 if (0 < iGCRefPoint - pAllocator->GetGCRefPoint())
10653 *ppAllocator = pAllocator->m_pLoaderAllocatorDestroyNext;
10655 pAllocator->m_pLoaderAllocatorDestroyNext = pAllocatorsToDelete;
10656 pAllocatorsToDelete = pAllocator;
10660 ppAllocator = &pAllocator->m_pLoaderAllocatorDestroyNext;
10665 if (bAppDomainToCleanup)
10666 AppDomain::EnableADUnloadWorkerForCollectedADCleanup();
10668 // Delete collected loader allocators on the finalizer thread. We cannot offload it to appdomain unload thread because of
10669 // there is not guaranteed to be one, and it is not that expensive operation anyway.
10670 while (pAllocatorsToDelete != NULL)
10672 LoaderAllocator * pAllocator = pAllocatorsToDelete;
10673 pAllocatorsToDelete = pAllocator->m_pLoaderAllocatorDestroyNext;
10678 #endif // CROSSGEN_COMPILE
10680 AppDomainFromIDHolder::AppDomainFromIDHolder(ADID adId, BOOL bUnsafePoint, SyncType synctype)
10682 WRAPPER_NO_CONTRACT;
10683 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
10690 Assign(adId, bUnsafePoint);
10693 AppDomainFromIDHolder::AppDomainFromIDHolder(SyncType synctype)
10695 LIMITED_METHOD_CONTRACT;
10696 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
10705 #ifndef CROSSGEN_COMPILE
10706 void ADUnloadSink::ReportUnloadResult (HRESULT hr, OBJECTREF* pException)
10712 PRECONDITION(CheckPointer(this));
10713 PRECONDITION(m_UnloadCompleteEvent.IsValid());
10717 //pException is unused;
10719 m_UnloadCompleteEvent.Set();
10722 void ADUnloadSink::WaitUnloadCompletion()
10728 PRECONDITION(CheckPointer(this));
10729 PRECONDITION(m_UnloadCompleteEvent.IsValid());
10733 CONTRACT_VIOLATION(FaultViolation);
10734 m_UnloadCompleteEvent.WaitEx(INFINITE, (WaitMode)(WaitMode_Alertable | WaitMode_ADUnload));
10737 ADUnloadSink* AppDomain::PrepareForWaitUnloadCompletion()
10743 PRECONDITION(SystemDomain::IsUnderDomainLock());
10748 ADUnloadSink* pADSink=GetADUnloadSink();
10749 PREFIX_ASSUME(pADSink!=NULL);
10750 if (m_Stage < AppDomain::STAGE_UNLOAD_REQUESTED) //we're first
10753 SetUnloadRequestThread(GetThread());
10758 ADUnloadSink::ADUnloadSink()
10766 INJECT_FAULT(COMPlusThrowOM(););
10771 m_UnloadCompleteEvent.CreateManualEvent(FALSE);
10772 m_UnloadResult=S_OK;
10775 ADUnloadSink::~ADUnloadSink()
10785 m_UnloadCompleteEvent.CloseEvent();
10790 ULONG ADUnloadSink::AddRef()
10792 LIMITED_METHOD_CONTRACT;
10793 return InterlockedIncrement(&m_cRef);
10796 ULONG ADUnloadSink::Release()
10798 LIMITED_METHOD_CONTRACT;
10799 ULONG ulRef = InterlockedDecrement(&m_cRef);
10807 void ADUnloadSink::Reset()
10809 LIMITED_METHOD_CONTRACT;
10810 m_UnloadResult=S_OK;
10811 m_UnloadCompleteEvent.Reset();
10814 ADUnloadSink* AppDomain::GetADUnloadSink()
10816 LIMITED_METHOD_CONTRACT;
10817 _ASSERTE(SystemDomain::IsUnderDomainLock());
10819 m_ADUnloadSink->AddRef();
10820 return m_ADUnloadSink;
10823 ADUnloadSink* AppDomain::GetADUnloadSinkForUnload()
10825 // unload thread only. Doesn't need to have AD lock
10826 LIMITED_METHOD_CONTRACT;
10828 m_ADUnloadSink->AddRef();
10829 return m_ADUnloadSink;
10831 #endif // CROSSGEN_COMPILE
10833 void AppDomain::EnumStaticGCRefs(promote_func* fn, ScanContext* sc)
10842 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
10843 GCHeapUtilities::IsServerHeap() &&
10844 IsGCSpecialThread());
10846 AppDomain::AssemblyIterator asmIterator = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution));
10847 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
10848 while (asmIterator.Next(pDomainAssembly.This()))
10850 // @TODO: Review when DomainAssemblies get added.
10851 _ASSERTE(pDomainAssembly != NULL);
10852 pDomainAssembly->EnumStaticGCRefs(fn, sc);
10858 #endif // !DACCESS_COMPILE
10860 //------------------------------------------------------------------------
10861 UINT32 BaseDomain::GetTypeID(PTR_MethodTable pMT) {
10865 PRECONDITION(pMT->GetDomain() == this);
10868 return m_typeIDMap.GetTypeID(pMT);
10871 //------------------------------------------------------------------------
10872 // Returns the ID of the type if found. If not found, returns INVALID_TYPE_ID
10873 UINT32 BaseDomain::LookupTypeID(PTR_MethodTable pMT)
10878 WRAPPER(GC_TRIGGERS);
10879 PRECONDITION(pMT->GetDomain() == this);
10882 return m_typeIDMap.LookupTypeID(pMT);
10885 //------------------------------------------------------------------------
10886 PTR_MethodTable BaseDomain::LookupType(UINT32 id) {
10890 WRAPPER(GC_TRIGGERS);
10891 CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS);
10894 PTR_MethodTable pMT = m_typeIDMap.LookupType(id);
10895 if (pMT == NULL && !IsSharedDomain()) {
10896 pMT = SharedDomain::GetDomain()->LookupType(id);
10899 CONSISTENCY_CHECK(CheckPointer(pMT));
10900 CONSISTENCY_CHECK(pMT->IsInterface());
10904 //---------------------------------------------------------------------------------------
10907 AppDomain::AssemblyIterator::Next(
10908 CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
10912 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
10916 CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
10917 return Next_Unlocked(pDomainAssemblyHolder);
10920 //---------------------------------------------------------------------------------------
10922 // Note: Does not lock the assembly list, but locks collectible assemblies for adding references.
10925 AppDomain::AssemblyIterator::Next_Unlocked(
10926 CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
10934 #ifndef DACCESS_COMPILE
10935 _ASSERTE(m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
10938 while (m_Iterator.Next())
10940 // Get element from the list/iterator (without adding reference to the assembly)
10941 DomainAssembly * pDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
10942 if (pDomainAssembly == NULL)
10947 if (pDomainAssembly->IsError())
10949 if (m_assemblyIterationFlags & kIncludeFailedToLoad)
10951 *pDomainAssemblyHolder = pDomainAssembly;
10954 continue; // reject
10957 // First, reject DomainAssemblies whose load status is not to be included in
10960 if (pDomainAssembly->IsAvailableToProfilers() &&
10961 (m_assemblyIterationFlags & kIncludeAvailableToProfilers))
10963 // The assembly has reached the state at which we would notify profilers,
10964 // and we're supposed to include such assemblies in the enumeration. So
10965 // don't reject it (i.e., noop here, and don't bother with the rest of
10966 // the load status checks). Check for this first, since
10967 // kIncludeAvailableToProfilers contains some loaded AND loading
10970 else if (pDomainAssembly->IsLoaded())
10972 // A loaded assembly
10973 if (!(m_assemblyIterationFlags & kIncludeLoaded))
10975 continue; // reject
10980 // A loading assembly
10981 if (!(m_assemblyIterationFlags & kIncludeLoading))
10983 continue; // reject
10987 // Next, reject DomainAssemblies whose execution / introspection status is
10988 // not to be included in the enumeration
10990 if (pDomainAssembly->IsIntrospectionOnly())
10992 // introspection assembly
10993 if (!(m_assemblyIterationFlags & kIncludeIntrospection))
10995 continue; // reject
11000 // execution assembly
11001 if (!(m_assemblyIterationFlags & kIncludeExecution))
11003 continue; // reject
11007 // Next, reject collectible assemblies
11008 if (pDomainAssembly->IsCollectible())
11010 if (m_assemblyIterationFlags & kExcludeCollectible)
11012 _ASSERTE(!(m_assemblyIterationFlags & kIncludeCollected));
11013 continue; // reject
11016 // Un-tenured collectible assemblies should not be returned. (This can only happen in a brief
11017 // window during collectible assembly creation. No thread should need to have a pointer
11018 // to the just allocated DomainAssembly at this stage.)
11019 if (!pDomainAssembly->GetAssembly()->GetManifestModule()->IsTenured())
11021 continue; // reject
11024 if (pDomainAssembly->GetLoaderAllocator()->AddReferenceIfAlive())
11025 { // The assembly is alive
11027 // Set the holder value (incl. increasing ref-count)
11028 *pDomainAssemblyHolder = pDomainAssembly;
11030 // Now release the reference we took in the if-condition
11031 pDomainAssembly->GetLoaderAllocator()->Release();
11034 // The assembly is not alive anymore (and we didn't increase its ref-count in the
11037 if (!(m_assemblyIterationFlags & kIncludeCollected))
11039 continue; // reject
11041 // Set the holder value to assembly with 0 ref-count without increasing the ref-count (won't
11042 // call Release either)
11043 pDomainAssemblyHolder->Assign(pDomainAssembly, FALSE);
11047 *pDomainAssemblyHolder = pDomainAssembly;
11051 *pDomainAssemblyHolder = NULL;
11053 } // AppDomain::AssemblyIterator::Next_Unlocked
11055 #ifndef DACCESS_COMPILE
11057 //---------------------------------------------------------------------------------------
11059 // Can be called only from AppDomain shutdown code:AppDomain::ShutdownAssemblies.
11060 // Does not add-ref collectible assemblies (as the LoaderAllocator might not be reachable from the
11061 // DomainAssembly anymore).
11064 AppDomain::AssemblyIterator::Next_UnsafeNoAddRef(
11065 DomainAssembly ** ppDomainAssembly)
11073 // Make sure we are iterating all assemblies (see the only caller code:AppDomain::ShutdownAssemblies)
11074 _ASSERTE(m_assemblyIterationFlags ==
11075 (kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
11076 // It also means that we do not exclude anything
11077 _ASSERTE((m_assemblyIterationFlags & kExcludeCollectible) == 0);
11079 // We are on shutdown path, so lock shouldn't be neccessary, but all _Unlocked methods on AssemblyList
11080 // have asserts that the lock is held, so why not to take it ...
11081 CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
11083 while (m_Iterator.Next())
11085 // Get element from the list/iterator (without adding reference to the assembly)
11086 *ppDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
11087 if (*ppDomainAssembly == NULL)
11095 *ppDomainAssembly = NULL;
11097 } // AppDomain::AssemblyIterator::Next_UnsafeNoAddRef
11100 //---------------------------------------------------------------------------------------
11102 BOOL AppDomain::IsImageFromTrustedPath(PEImage* pPEImage)
11109 PRECONDITION(CheckPointer(pPEImage));
11113 const SString &sImagePath = pPEImage->GetPath();
11115 return !sImagePath.IsEmpty();
11118 #endif //!DACCESS_COMPILE
11120 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
11122 // Returns a BOOL indicating if the binding model has been locked for the AppDomain
11123 BOOL AppDomain::IsBindingModelLocked()
11133 return m_fIsBindingModelLocked.Load();
11136 // Marks the binding model locked for AppDomain
11137 BOOL AppDomain::LockBindingModel()
11139 LIMITED_METHOD_CONTRACT;
11141 BOOL fDidWeLockBindingModel = FALSE;
11143 if (InterlockedCompareExchangeT<BOOL>(&m_fIsBindingModelLocked, TRUE, FALSE) == FALSE)
11145 fDidWeLockBindingModel = TRUE;
11148 return fDidWeLockBindingModel;
11151 BOOL AppDomain::IsHostAssemblyResolverInUse()
11153 LIMITED_METHOD_CONTRACT;
11155 return (GetFusionContext() != GetTPABinderContext());
11158 // Helper used by the assembly binder to check if the specified AppDomain can use apppath assembly resolver
11159 BOOL RuntimeCanUseAppPathAssemblyResolver(DWORD adid)
11163 NOTHROW; // Cannot throw since it is invoked by the Binder that expects to get a hresult
11171 // We need to be in COOP mode to get the AppDomain*
11174 AppDomain *pTargetDomain = SystemDomain::GetAppDomainFromId(id, ADV_CURRENTAD);
11175 _ASSERTE(pTargetDomain != NULL);
11177 pTargetDomain->LockBindingModel();
11179 return !pTargetDomain->IsHostAssemblyResolverInUse();
11182 // Returns S_OK if the assembly was successfully loaded
11183 HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, IAssemblyName *pIAssemblyName, CLRPrivBinderCoreCLR *pTPABinder, BINDER_SPACE::AssemblyName *pAssemblyName, ICLRPrivAssembly **ppLoadedAssembly)
11190 PRECONDITION(ppLoadedAssembly != NULL);
11194 HRESULT hr = E_FAIL;
11196 // DevDiv #933506: Exceptions thrown during AssemblyLoadContext.Load should propagate
11199 // Switch to COOP mode since we are going to work with managed references
11204 ASSEMBLYNAMEREF oRefAssemblyName;
11205 ASSEMBLYREF oRefLoadedAssembly;
11208 ZeroMemory(&_gcRefs, sizeof(_gcRefs));
11210 GCPROTECT_BEGIN(_gcRefs);
11212 ICLRPrivAssembly *pAssemblyBindingContext = NULL;
11214 bool fInvokedForTPABinder = (pTPABinder == NULL)?true:false;
11216 // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.Resolve method.
11218 // First, initialize an assembly spec for the requested assembly
11221 hr = spec.Init(pIAssemblyName);
11224 bool fResolvedAssembly = false;
11225 bool fResolvedAssemblyViaTPALoadContext = false;
11227 // Allocate an AssemblyName managed object
11228 _gcRefs.oRefAssemblyName = (ASSEMBLYNAMEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME));
11230 // Initialize the AssemblyName object from the AssemblySpec
11231 spec.AssemblyNameInit(&_gcRefs.oRefAssemblyName, NULL);
11233 if (!fInvokedForTPABinder)
11235 // Step 2 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName) - Invoke Load method
11236 // This is not invoked for TPA Binder since it always returns NULL.
11238 // Finally, setup arguments for invocation
11239 BinderMethodID idHAR_Resolve = METHOD__ASSEMBLYLOADCONTEXT__RESOLVE;
11240 MethodDescCallSite methLoadAssembly(idHAR_Resolve);
11242 // Setup the arguments for the call
11245 PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
11246 ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
11250 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
11251 if (_gcRefs.oRefLoadedAssembly != NULL)
11253 fResolvedAssembly = true;
11256 // Step 3 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
11257 if (!fResolvedAssembly)
11259 // If we could not resolve the assembly using Load method, then attempt fallback with TPA Binder.
11260 // Since TPA binder cannot fallback to itself, this fallback does not happen for binds within TPA binder.
11262 // Switch to pre-emp mode before calling into the binder
11264 ICLRPrivAssembly *pCoreCLRFoundAssembly = NULL;
11265 hr = pTPABinder->BindAssemblyByName(pIAssemblyName, &pCoreCLRFoundAssembly);
11268 pAssemblyBindingContext = pCoreCLRFoundAssembly;
11269 fResolvedAssembly = true;
11270 fResolvedAssemblyViaTPALoadContext = true;
11275 if (!fResolvedAssembly)
11277 // Step 4 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
11279 // If we couldnt resolve the assembly using TPA LoadContext as well, then
11280 // attempt to resolve it using the Resolving event.
11281 // Finally, setup arguments for invocation
11282 BinderMethodID idHAR_ResolveUsingEvent = METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUSINGEVENT;
11283 MethodDescCallSite methLoadAssembly(idHAR_ResolveUsingEvent);
11285 // Setup the arguments for the call
11288 PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
11289 ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
11293 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
11294 if (_gcRefs.oRefLoadedAssembly != NULL)
11296 // Set the flag indicating we found the assembly
11297 fResolvedAssembly = true;
11301 if (fResolvedAssembly && !fResolvedAssemblyViaTPALoadContext)
11303 // If we are here, assembly was successfully resolved via Load or Resolving events.
11304 _ASSERTE(_gcRefs.oRefLoadedAssembly != NULL);
11306 // We were able to get the assembly loaded. Now, get its name since the host could have
11307 // performed the resolution using an assembly with different name.
11308 DomainAssembly *pDomainAssembly = _gcRefs.oRefLoadedAssembly->GetDomainAssembly();
11309 PEAssembly *pLoadedPEAssembly = NULL;
11310 bool fFailLoad = false;
11311 if (!pDomainAssembly)
11313 // Reflection emitted assemblies will not have a domain assembly.
11318 pLoadedPEAssembly = pDomainAssembly->GetFile();
11319 if (pLoadedPEAssembly->HasHostAssembly() != true)
11321 // Reflection emitted assemblies will not have a domain assembly.
11326 // The loaded assembly's ICLRPrivAssembly* is saved as HostAssembly in PEAssembly
11330 spec.GetFileOrDisplayName(0, name);
11331 COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_DYNAMICALLY_EMITTED_ASSEMBLIES_UNSUPPORTED, name);
11334 // Is the assembly already bound using a binding context that will be incompatible?
11335 // An example is attempting to consume an assembly bound to WinRT binder.
11336 pAssemblyBindingContext = pLoadedPEAssembly->GetHostAssembly();
11339 #ifdef FEATURE_COMINTEROP
11340 if (AreSameBinderInstance(pAssemblyBindingContext, GetAppDomain()->GetWinRtBinder()))
11342 // It is invalid to return an assembly bound to an incompatible binder
11343 *ppLoadedAssembly = NULL;
11345 spec.GetFileOrDisplayName(0, name);
11346 COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_BINDING_CONTEXT, name);
11348 #endif // FEATURE_COMINTEROP
11350 // Get the ICLRPrivAssembly reference to return back to.
11351 *ppLoadedAssembly = clr::SafeAddRef(pAssemblyBindingContext);
11357 // EX_CATCH_HRESULT(hr);
11362 #endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
11364 //approximate size of loader data
11365 //maintained for each assembly
11366 #define APPROX_LOADER_DATA_PER_ASSEMBLY 8196
11368 size_t AppDomain::EstimateSize()
11378 size_t retval = sizeof(AppDomain);
11379 retval += GetLoaderAllocator()->EstimateSize();
11380 //very rough estimate
11381 retval += GetAssemblyCount() * APPROX_LOADER_DATA_PER_ASSEMBLY;
11385 #ifdef DACCESS_COMPILE
11388 DomainLocalModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
11392 // Enumerate the DomainLocalModule itself. DLMs are allocated to be larger than
11393 // sizeof(DomainLocalModule) to make room for ClassInit flags and non-GC statics.
11394 // "DAC_ENUM_DTHIS()" probably does not account for this, so we might not enumerate
11395 // all of the ClassInit flags and non-GC statics.
11396 // sizeof(DomainLocalModule) == 0x28
11399 if (m_pDomainFile.IsValid())
11401 m_pDomainFile->EnumMemoryRegions(flags);
11404 if (m_pDynamicClassTable.Load().IsValid())
11406 DacEnumMemoryRegion(dac_cast<TADDR>(m_pDynamicClassTable.Load()),
11407 m_aDynamicEntries * sizeof(DynamicClassInfo));
11409 for (SIZE_T i = 0; i < m_aDynamicEntries; i++)
11411 PTR_DynamicEntry entry = dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[i].m_pDynamicEntry.Load());
11412 if (entry.IsValid())
11414 // sizeof(DomainLocalModule::DynamicEntry) == 8
11422 DomainLocalBlock::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
11425 // Block is contained in AppDomain, don't enum this.
11427 if (m_pModuleSlots.IsValid())
11429 DacEnumMemoryRegion(dac_cast<TADDR>(m_pModuleSlots),
11430 m_aModuleIndices * sizeof(TADDR));
11432 for (SIZE_T i = 0; i < m_aModuleIndices; i++)
11434 PTR_DomainLocalModule domMod = m_pModuleSlots[i];
11435 if (domMod.IsValid())
11437 domMod->EnumMemoryRegions(flags);
11444 BaseDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11450 // This is wrong. Don't do it.
11451 // BaseDomain cannot be instantiated.
11452 // The only thing this code can hope to accomplish is to potentially break
11453 // memory enumeration walking through the derived class if we
11454 // explicitly call the base class enum first.
11455 // DAC_ENUM_VTHIS();
11458 EMEM_OUT(("MEM: %p BaseDomain\n", dac_cast<TADDR>(this)));
11462 AppDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11469 //sizeof(AppDomain) == 0xeb0
11472 BaseDomain::EnumMemoryRegions(flags, false);
11474 // We don't need AppDomain name in triage dumps.
11475 if (flags != CLRDATA_ENUM_MEM_TRIAGE)
11477 m_friendlyName.EnumMemoryRegions(flags);
11480 m_Assemblies.EnumMemoryRegions(flags);
11481 AssemblyIterator assem = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution | kIncludeIntrospection));
11482 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
11484 while (assem.Next(pDomainAssembly.This()))
11486 pDomainAssembly->EnumMemoryRegions(flags);
11489 m_sDomainLocalBlock.EnumMemoryRegions(flags);
11491 m_LoaderAllocator.EnumMemoryRegions(flags);
11495 SystemDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11503 BaseDomain::EnumMemoryRegions(flags, false);
11505 if (m_pSystemFile.IsValid())
11507 m_pSystemFile->EnumMemoryRegions(flags);
11509 if (m_pSystemAssembly.IsValid())
11511 m_pSystemAssembly->EnumMemoryRegions(flags);
11513 if (m_pDefaultDomain.IsValid())
11515 m_pDefaultDomain->EnumMemoryRegions(flags, true);
11518 m_appDomainIndexList.EnumMem();
11519 (&m_appDomainIndexList)->EnumMemoryRegions(flags);
11523 SharedDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11531 BaseDomain::EnumMemoryRegions(flags, false);
11532 #ifdef FEATURE_LOADER_OPTIMIZATION
11533 m_assemblyMap.EnumMemoryRegions(flags);
11534 SharedAssemblyIterator assem;
11535 while (assem.Next())
11537 assem.GetAssembly()->EnumMemoryRegions(flags);
11542 #endif //DACCESS_COMPILE
11545 PTR_LoaderAllocator SystemDomain::GetGlobalLoaderAllocator()
11547 return PTR_LoaderAllocator(PTR_HOST_MEMBER_TADDR(SystemDomain,System(),m_GlobalAllocator));
11550 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
11552 #ifndef CROSSGEN_COMPILE
11553 // Return the total processor time (user and kernel) used by threads executing in this AppDomain so far. The
11554 // result is in 100ns units.
11555 ULONGLONG AppDomain::QueryProcessorUsage()
11565 #ifndef DACCESS_COMPILE
11566 Thread *pThread = NULL;
11568 // Need to update our accumulated processor time count with current values from each thread that is
11569 // currently executing in this domain.
11571 // Take the thread store lock while we enumerate threads.
11572 ThreadStoreLockHolder tsl;
11573 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
11575 // Skip unstarted and dead threads and those that are currently executing in a different AppDomain.
11576 if (pThread->IsUnstarted() || pThread->IsDead() || pThread->GetDomain(INDEBUG(TRUE)) != this)
11579 // Add the amount of time spent by the thread in the AppDomain since the last time we asked (calling
11580 // Thread::QueryThreadProcessorUsage() will reset the thread's counter).
11581 UpdateProcessorUsage(pThread->QueryThreadProcessorUsage());
11583 #endif // !DACCESS_COMPILE
11585 // Return the updated total.
11586 return m_ullTotalProcessorUsage;
11589 // Add to the current count of processor time used by threads within this AppDomain. This API is called by
11590 // threads transitioning between AppDomains.
11591 void AppDomain::UpdateProcessorUsage(ULONGLONG ullAdditionalUsage)
11593 LIMITED_METHOD_CONTRACT;
11595 // Need to be careful to synchronize here, multiple threads could be racing to update this count.
11596 ULONGLONG ullOldValue;
11597 ULONGLONG ullNewValue;
11600 ullOldValue = m_ullTotalProcessorUsage;
11601 ullNewValue = ullOldValue + ullAdditionalUsage;
11602 } while (InterlockedCompareExchange64((LONGLONG*)&m_ullTotalProcessorUsage,
11603 (LONGLONG)ullNewValue,
11604 (LONGLONG)ullOldValue) != (LONGLONG)ullOldValue);
11606 #endif // CROSSGEN_COMPILE
11608 #endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
11610 #if defined(FEATURE_TYPEEQUIVALENCE)
11612 #ifndef DACCESS_COMPILE
11613 TypeEquivalenceHashTable * AppDomain::GetTypeEquivalenceCache()
11619 INJECT_FAULT(COMPlusThrowOM());
11624 // Take the critical section all of the time in debug builds to ensure that it is safe to take
11625 // the critical section in the unusual times when it may actually be needed in retail builds
11627 CrstHolder ch(&m_TypeEquivalenceCrst);
11630 if (m_pTypeEquivalenceTable.Load() == NULL)
11633 CrstHolder ch(&m_TypeEquivalenceCrst);
11635 if (m_pTypeEquivalenceTable.Load() == NULL)
11637 m_pTypeEquivalenceTable = TypeEquivalenceHashTable::Create(this, 12, &m_TypeEquivalenceCrst);
11640 return m_pTypeEquivalenceTable;
11642 #endif //!DACCESS_COMPILE
11644 #endif //FEATURE_TYPEEQUIVALENCE
11646 #if !defined(DACCESS_COMPILE)
11648 //---------------------------------------------------------------------------------------------------------------------
11649 void AppDomain::PublishHostedAssembly(
11650 DomainAssembly * pDomainAssembly)
11660 if (pDomainAssembly->GetFile()->HasHostAssembly())
11662 // We have to serialize all Add operations
11663 CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
11664 _ASSERTE(m_hostAssemblyMap.Lookup(pDomainAssembly->GetFile()->GetHostAssembly()) == nullptr);
11666 // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
11667 HostAssemblyMap::AddPhases addCall;
11669 // 1. Preallocate one element
11670 addCall.PreallocateForAdd(&m_hostAssemblyMap);
11672 // 2. Take the reader lock which can be taken during stack walking
11673 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
11674 ForbidSuspendThreadHolder suspend;
11676 CrstHolder lock(&m_crstHostAssemblyMap);
11677 // 3. Add the element to the hash table (no call out into host)
11678 addCall.Add(pDomainAssembly);
11681 // 4. Cleanup the old memory (if any)
11682 addCall.DeleteOldTable();
11689 //---------------------------------------------------------------------------------------------------------------------
11690 void AppDomain::UpdatePublishHostedAssembly(
11691 DomainAssembly * pAssembly,
11703 if (pAssembly->GetFile()->HasHostAssembly())
11705 // We have to serialize all Add operations
11706 CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
11708 // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
11709 OriginalFileHostAssemblyMap::AddPhases addCall;
11710 bool fAddOrigFile = false;
11712 // For cases where the pefile is being updated
11713 // 1. Preallocate one element
11714 if (pFile != pAssembly->GetFile())
11716 addCall.PreallocateForAdd(&m_hostAssemblyMapForOrigFile);
11717 fAddOrigFile = true;
11721 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
11722 ForbidSuspendThreadHolder suspend;
11724 CrstHolder lock(&m_crstHostAssemblyMap);
11726 // Remove from hash table.
11727 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
11728 m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
11730 // Update PEFile on DomainAssembly. (This may cause the key for the hash to change, which is why we need this function)
11731 pAssembly->UpdatePEFileWorker(pFile);
11733 _ASSERTE(fAddOrigFile == (pAssembly->GetOriginalFile() != pAssembly->GetFile()));
11736 // 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)
11737 addCall.Add(pAssembly);
11740 // Add back to the hashtable (the call to Remove above guarantees that we will not call into host for table reallocation)
11741 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) == nullptr);
11742 m_hostAssemblyMap.Add(pAssembly);
11746 // 4. Cleanup the old memory (if any)
11748 addCall.DeleteOldTable();
11754 pAssembly->UpdatePEFileWorker(pFile);
11758 //---------------------------------------------------------------------------------------------------------------------
11759 void AppDomain::UnPublishHostedAssembly(
11760 DomainAssembly * pAssembly)
11771 if (pAssembly->GetFile()->HasHostAssembly())
11773 ForbidSuspendThreadHolder suspend;
11775 CrstHolder lock(&m_crstHostAssemblyMap);
11776 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
11777 m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
11779 // We also have an entry in m_hostAssemblyMapForOrigFile. Handle that case.
11780 if (pAssembly->GetOriginalFile() != pAssembly->GetFile())
11782 m_hostAssemblyMapForOrigFile.Remove(pAssembly->GetOriginalFile()->GetHostAssembly());
11788 // In AppX processes, all PEAssemblies that are reach this stage should have host binders.
11789 _ASSERTE(!AppX::IsAppXProcess());
11793 #if defined(FEATURE_COMINTEROP)
11794 HRESULT AppDomain::SetWinrtApplicationContext(SString &appLocalWinMD)
11796 STANDARD_VM_CONTRACT;
11798 _ASSERTE(WinRTSupported());
11799 _ASSERTE(m_pWinRtBinder != nullptr);
11801 _ASSERTE(GetTPABinderContext() != NULL);
11802 BINDER_SPACE::ApplicationContext *pApplicationContext = GetTPABinderContext()->GetAppContext();
11803 _ASSERTE(pApplicationContext != NULL);
11805 return m_pWinRtBinder->SetApplicationContext(pApplicationContext, appLocalWinMD);
11808 #endif // FEATURE_COMINTEROP
11810 #endif //!DACCESS_COMPILE
11812 //---------------------------------------------------------------------------------------------------------------------
11813 PTR_DomainAssembly AppDomain::FindAssembly(PTR_ICLRPrivAssembly pHostAssembly)
11824 if (pHostAssembly == nullptr)
11828 ForbidSuspendThreadHolder suspend;
11830 CrstHolder lock(&m_crstHostAssemblyMap);
11831 PTR_DomainAssembly returnValue = m_hostAssemblyMap.Lookup(pHostAssembly);
11832 if (returnValue == NULL)
11834 // If not found in the m_hostAssemblyMap, look in the m_hostAssemblyMapForOrigFile
11835 // This is necessary as it may happen during in a second AppDomain that the PEFile
11836 // first discovered in the AppDomain may not be used by the DomainFile, but the CLRPrivBinderFusion
11837 // will in some cases find the pHostAssembly associated with this no longer used PEFile
11838 // instead of the PEFile that was finally decided upon.
11839 returnValue = m_hostAssemblyMapForOrigFile.Lookup(pHostAssembly);
11842 return returnValue;
11847 #if !defined(DACCESS_COMPILE) && defined(FEATURE_NATIVE_IMAGE_GENERATION)
11849 void ZapperSetBindingPaths(ICorCompilationDomain *pDomain, SString &trustedPlatformAssemblies, SString &platformResourceRoots, SString &appPaths, SString &appNiPaths)
11851 CLRPrivBinderCoreCLR *pBinder = static_cast<CLRPrivBinderCoreCLR*>(((CompilationDomain *)pDomain)->GetFusionContext());
11852 _ASSERTE(pBinder != NULL);
11853 pBinder->SetupBindingPaths(trustedPlatformAssemblies, platformResourceRoots, appPaths, appNiPaths);
11854 #ifdef FEATURE_COMINTEROP
11855 SString emptString;
11856 ((CompilationDomain*)pDomain)->SetWinrtApplicationContext(emptString);