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"
77 // this file handles string conversion errors for itself
78 #undef MAKE_TRANSLATIONFAILED
80 // Define these macro's to do strict validation for jit lock and class
81 // init entry leaks. This defines determine if the asserts that
82 // verify for these leaks are defined or not. These asserts can
83 // sometimes go off even if no entries have been leaked so this
84 // defines should be used with caution.
86 // If we are inside a .cctor when the application shut's down then the
87 // class init lock's head will be set and this will cause the assert
90 // If we are jitting a method when the application shut's down then
91 // the jit lock's head will be set causing the assert to go off.
93 //#define STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
95 static const WCHAR DEFAULT_DOMAIN_FRIENDLY_NAME[] = W("DefaultDomain");
96 static const WCHAR OTHER_DOMAIN_FRIENDLY_NAME_PREFIX[] = W("Domain");
98 #define STATIC_OBJECT_TABLE_BUCKET_SIZE 1020
100 #define MAX_URL_LENGTH 2084 // same as INTERNET_MAX_URL_LENGTH
102 //#define _DEBUG_ADUNLOAD 1
104 HRESULT RunDllMain(MethodDesc *pMD, HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved); // clsload.cpp
112 SPTR_IMPL(SystemDomain, SystemDomain, m_pSystemDomain);
113 SVAL_IMPL(ArrayListStatic, SystemDomain, m_appDomainIndexList);
114 SPTR_IMPL(SharedDomain, SharedDomain, m_pSharedDomain);
115 SVAL_IMPL(BOOL, SystemDomain, s_fForceDebug);
116 SVAL_IMPL(BOOL, SystemDomain, s_fForceProfiling);
117 SVAL_IMPL(BOOL, SystemDomain, s_fForceInstrument);
119 #ifndef DACCESS_COMPILE
121 // Base Domain Statics
122 CrstStatic BaseDomain::m_SpecialStaticsCrst;
124 int BaseDomain::m_iNumberOfProcessors = 0;
126 // Shared Domain Statics
128 static BYTE g_pSharedDomainMemory[sizeof(SharedDomain)];
130 // System Domain Statics
131 GlobalStringLiteralMap* SystemDomain::m_pGlobalStringLiteralMap = NULL;
134 static BYTE g_pSystemDomainMemory[sizeof(SystemDomain)];
136 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
137 size_t SystemDomain::m_totalSurvivedBytes = 0;
138 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
140 CrstStatic SystemDomain::m_SystemDomainCrst;
141 CrstStatic SystemDomain::m_DelayedUnloadCrst;
143 ULONG SystemDomain::s_dNumAppDomains = 0;
145 AppDomain * SystemDomain::m_pAppDomainBeingUnloaded = NULL;
146 ADIndex SystemDomain::m_dwIndexOfAppDomainBeingUnloaded;
147 Thread *SystemDomain::m_pAppDomainUnloadRequestingThread = 0;
148 Thread *SystemDomain::m_pAppDomainUnloadingThread = 0;
150 ArrayListStatic SystemDomain::m_appDomainIdList;
152 DWORD SystemDomain::m_dwLowestFreeIndex = 0;
156 // comparison function to be used for matching clsids in our clsid hash table
157 BOOL CompareCLSID(UPTR u1, UPTR u2)
165 INJECT_FAULT(COMPlusThrowOM(););
169 GUID *pguid = (GUID *)(u1 << 1);
170 _ASSERTE(pguid != NULL);
172 MethodTable *pMT= (MethodTable *)u2;
173 _ASSERTE(pMT!= NULL);
176 pMT->GetGuid(&guid, TRUE);
177 if (!IsEqualIID(guid, *pguid))
183 #ifndef CROSSGEN_COMPILE
184 // Constructor for the LargeHeapHandleBucket class.
185 LargeHeapHandleBucket::LargeHeapHandleBucket(LargeHeapHandleBucket *pNext, DWORD Size, BaseDomain *pDomain, BOOL bCrossAD)
189 , m_CurrentEmbeddedFreePos(0) // hint for where to start a search for an embedded free item
196 PRECONDITION(CheckPointer(pDomain));
197 INJECT_FAULT(COMPlusThrowOM(););
201 PTRARRAYREF HandleArrayObj;
203 // Allocate the array in the large object heap.
206 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
207 HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, TRUE);
211 // During AD creation we don't want to assign the handle array to the currently running AD but
212 // to the AD being created. Ensure that AllocateArrayEx doesn't set the AD and then set it here.
213 AppDomain *pAD = pDomain->AsAppDomain();
215 _ASSERTE(pAD->IsBeingCreated());
219 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
220 array = AllocateArrayEx(
221 ClassLoader::LoadArrayTypeThrowing(g_pObjectClass),
228 array->SetAppDomain(pAD);
230 HandleArrayObj = (PTRARRAYREF)array;
233 // Retrieve the pointer to the data inside the array. This is legal since the array
234 // is located in the large object heap and is guaranteed not to move.
235 m_pArrayDataPtr = (OBJECTREF *)HandleArrayObj->GetDataPtr();
237 // Store the array in a strong handle to keep it alive.
238 m_hndHandleArray = pDomain->CreatePinningHandle((OBJECTREF)HandleArrayObj);
242 // Destructor for the LargeHeapHandleBucket class.
243 LargeHeapHandleBucket::~LargeHeapHandleBucket()
252 if (m_hndHandleArray)
254 DestroyPinningHandle(m_hndHandleArray);
255 m_hndHandleArray = NULL;
260 // Allocate handles from the bucket.
261 OBJECTREF *LargeHeapHandleBucket::AllocateHandles(DWORD nRequested)
271 _ASSERTE(nRequested > 0 && nRequested <= GetNumRemainingHandles());
272 _ASSERTE(m_pArrayDataPtr == (OBJECTREF*)((PTRARRAYREF)ObjectFromHandle(m_hndHandleArray))->GetDataPtr());
274 // Store the handles in the buffer that was passed in
275 OBJECTREF* ret = &m_pArrayDataPtr[m_CurrentPos];
276 m_CurrentPos += nRequested;
281 // look for a free item embedded in the table
282 OBJECTREF *LargeHeapHandleBucket::TryAllocateEmbeddedFreeHandle()
292 OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
293 _ASSERTE(pPreallocatedSentinalObject != NULL);
295 for (int i = m_CurrentEmbeddedFreePos; i < m_CurrentPos; i++)
297 if (m_pArrayDataPtr[i] == pPreallocatedSentinalObject)
299 m_CurrentEmbeddedFreePos = i;
300 m_pArrayDataPtr[i] = NULL;
301 return &m_pArrayDataPtr[i];
305 // 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)
307 m_CurrentEmbeddedFreePos = 0;
312 // Maximum bucket size will be 64K on 32-bit and 128K on 64-bit.
313 // We subtract out a small amount to leave room for the object
314 // header and length of the array.
316 #define MAX_BUCKETSIZE (16384 - 4)
318 // Constructor for the LargeHeapHandleTable class.
319 LargeHeapHandleTable::LargeHeapHandleTable(BaseDomain *pDomain, DWORD InitialBucketSize)
322 , m_NextBucketSize(InitialBucketSize)
323 , m_pFreeSearchHint(NULL)
331 PRECONDITION(CheckPointer(pDomain));
332 INJECT_FAULT(COMPlusThrowOM(););
342 // Destructor for the LargeHeapHandleTable class.
343 LargeHeapHandleTable::~LargeHeapHandleTable()
352 // Delete the buckets.
355 LargeHeapHandleBucket *pOld = m_pHead;
356 m_pHead = pOld->GetNext();
361 //*****************************************************************************
363 // LOCKING RULES FOR AllocateHandles() and ReleaseHandles() 12/08/2004
366 // These functions are not protected by any locking in this location but rather the callers are
367 // assumed to be doing suitable locking for the handle table. The handle table itself is
368 // behaving rather like a thread-agnostic collection class -- it doesn't want to know
369 // much about the outside world and so it is just doing its job with no awareness of
372 // The instance in question is
373 // There are two locations you can find a LargeHeapHandleTable
374 // 1) there is one in every BaseDomain, it is used to keep track of the static members
376 // 2) there is one in the System Domain that is used for the GlobalStringLiteralMap
378 // the one in (2) is not the same as the one that is in the BaseDomain object that corresponds
379 // to the SystemDomain -- that one is basically stilborn because the string literals don't go
380 // there and of course the System Domain has no code loaded into it -- only regular
381 // AppDomains (like Domain 0) actually execute code. As a result handle tables are in
382 // practice used either for string literals or for static members but never for both.
383 // At least not at this writing.
385 // Now it's useful to consider what the locking discipline is for these classes.
389 // First case: (easiest) is the statics members
391 // Each BaseDomain has its own critical section
393 // BaseDomain::AllocateObjRefPtrsInLargeTable takes a lock with
394 // CrstHolder ch(&m_LargeHeapHandleTableCrst);
396 // it does this before it calls AllocateHandles which suffices. It does not call ReleaseHandles
397 // at any time (although ReleaseHandles may be called via AllocateHandles if the request
398 // doesn't fit in the current block, the remaining handles at the end of the block are released
399 // automatically as part of allocation/recycling)
401 // note: Recycled handles are only used during String Literal allocation because we only try
402 // to recycle handles if the allocation request is for exactly one handle.
404 // The handles in the BaseDomain handle table are released when the Domain is unloaded
405 // as the GC objects become rootless at that time.
407 // This dispenses with all of the Handle tables except the one that is used for string literals
411 // Second case: Allocation for use in a string literal
413 // AppDomainStringLiteralMap::GetStringLiteral
415 // LargeHeapHandleBlockHolder constructor
417 // m_Data = pOwner->AllocateHandles(nCount);
419 // before doing this AppDomainStringLiteralMap::GetStringLiteral takes this lock
421 // CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
423 // which is the lock for the hash table that it owns
425 // STRINGREF *AppDomainStringLiteralMap::GetInternedString
427 // has a similar call path and uses the same approach and the same lock
428 // this covers all the paths which allocate
432 // Third case: Releases for use in a string literal entry
434 // CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
435 // taken in the AppDomainStringLiteralMap functions below protects the 4 ways that this can happen
439 // in an appdomain unload case
441 // AppDomainStringLiteralMap::~AppDomainStringLiteralMap() takes the lock then
443 // StringLiteralEntry::Release
445 // SystemDomain::GetGlobalStringLiteralMapNoCreate()->RemoveStringLiteralEntry(this)
447 // m_LargeHeapHandleTable.ReleaseHandles((OBJECTREF*)pObjRef, 1);
451 // AppDomainStringLiteralMap::GetStringLiteral() can call StringLiteralEntry::Release in some
452 // error cases, leading to the same stack as above
456 // AppDomainStringLiteralMap::GetInternedString() can call StringLiteralEntry::Release in some
457 // error cases, leading to the same stack as above
461 // The same code paths in 3b and 3c and also end up releasing if an exception is thrown
462 // during their processing. Both these paths use a StringLiteralEntryHolder to assist in cleanup,
463 // the StaticRelease method of the StringLiteralEntry gets called, which in turn calls the
467 // Allocate handles from the large heap handle table.
468 OBJECTREF* LargeHeapHandleTable::AllocateHandles(DWORD nRequested, BOOL bCrossAD)
475 PRECONDITION(nRequested > 0);
476 INJECT_FAULT(COMPlusThrowOM(););
480 // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
482 // the lock must be registered and already held by the caller per contract
484 _ASSERTE(m_pCrstDebug != NULL);
485 _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
488 if (nRequested == 1 && m_cEmbeddedFree != 0)
490 // special casing singleton requests to look for slots that can be re-used
492 // we need to do this because string literals are allocated one at a time and then sometimes
493 // released. we do not wish for the number of handles consumed by string literals to
494 // increase forever as assemblies are loaded and unloaded
496 if (m_pFreeSearchHint == NULL)
497 m_pFreeSearchHint = m_pHead;
499 while (m_pFreeSearchHint)
501 OBJECTREF* pObjRef = m_pFreeSearchHint->TryAllocateEmbeddedFreeHandle();
504 // the slot is to have been prepared with a null ready to go
505 _ASSERTE(*pObjRef == NULL);
509 m_pFreeSearchHint = m_pFreeSearchHint->GetNext();
512 // the search doesn't wrap around so it's possible that we might have embedded free items
513 // and not find them but that's ok, we'll get them on the next alloc... all we're trying to do
514 // is to not have big leaks over time.
518 // Retrieve the remaining number of handles in the bucket.
519 DWORD NumRemainingHandlesInBucket = (m_pHead != NULL) ? m_pHead->GetNumRemainingHandles() : 0;
521 // create a new block if this request doesn't fit in the current block
522 if (nRequested > NumRemainingHandlesInBucket)
526 // mark the handles in that remaining region as available for re-use
527 ReleaseHandles(m_pHead->CurrentPos(), NumRemainingHandlesInBucket);
529 // mark what's left as having been used
530 m_pHead->ConsumeRemaining();
533 // create a new bucket for this allocation
535 // We need a block big enough to hold the requested handles
536 DWORD NewBucketSize = max(m_NextBucketSize, nRequested);
538 m_pHead = new LargeHeapHandleBucket(m_pHead, NewBucketSize, m_pDomain, bCrossAD);
540 m_NextBucketSize = min(m_NextBucketSize * 2, MAX_BUCKETSIZE);
543 return m_pHead->AllocateHandles(nRequested);
546 //*****************************************************************************
547 // Release object handles allocated using AllocateHandles().
548 void LargeHeapHandleTable::ReleaseHandles(OBJECTREF *pObjRef, DWORD nReleased)
555 PRECONDITION(CheckPointer(pObjRef));
559 // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
561 // the lock must be registered and already held by the caller per contract
563 _ASSERTE(m_pCrstDebug != NULL);
564 _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
567 OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
568 _ASSERTE(pPreallocatedSentinalObject != NULL);
571 // Add the released handles to the list of available handles.
572 for (DWORD i = 0; i < nReleased; i++)
574 SetObjectReference(&pObjRef[i], pPreallocatedSentinalObject, NULL);
577 m_cEmbeddedFree += nReleased;
583 // Constructor for the ThreadStaticHandleBucket class.
584 ThreadStaticHandleBucket::ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain)
593 PRECONDITION(CheckPointer(pDomain));
594 INJECT_FAULT(COMPlusThrowOM(););
598 PTRARRAYREF HandleArrayObj;
600 // Allocate the array on the GC heap.
601 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
602 HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, FALSE);
604 // Store the array in a strong handle to keep it alive.
605 m_hndHandleArray = pDomain->CreateStrongHandle((OBJECTREF)HandleArrayObj);
608 // Destructor for the ThreadStaticHandleBucket class.
609 ThreadStaticHandleBucket::~ThreadStaticHandleBucket()
619 if (m_hndHandleArray)
621 DestroyStrongHandle(m_hndHandleArray);
622 m_hndHandleArray = NULL;
626 // Allocate handles from the bucket.
627 OBJECTHANDLE ThreadStaticHandleBucket::GetHandles()
637 return m_hndHandleArray;
640 // Constructor for the ThreadStaticHandleTable class.
641 ThreadStaticHandleTable::ThreadStaticHandleTable(BaseDomain *pDomain)
650 PRECONDITION(CheckPointer(pDomain));
655 // Destructor for the ThreadStaticHandleTable class.
656 ThreadStaticHandleTable::~ThreadStaticHandleTable()
665 // Delete the buckets.
668 ThreadStaticHandleBucket *pOld = m_pHead;
669 m_pHead = pOld->GetNext();
674 // Allocate handles from the large heap handle table.
675 OBJECTHANDLE ThreadStaticHandleTable::AllocateHandles(DWORD nRequested)
682 PRECONDITION(nRequested > 0);
683 INJECT_FAULT(COMPlusThrowOM(););
687 // create a new bucket for this allocation
688 m_pHead = new ThreadStaticHandleBucket(m_pHead, nRequested, m_pDomain);
690 return m_pHead->GetHandles();
693 #endif // CROSSGEN_COMPILE
696 //*****************************************************************************
698 //*****************************************************************************
699 void BaseDomain::Attach()
701 m_SpecialStaticsCrst.Init(CrstSpecialStatics);
704 BaseDomain::BaseDomain()
706 // initialize fields so the domain can be safely destructed
707 // shouldn't call anything that can fail here - use ::Init instead
717 m_fDisableInterfaceCache = FALSE;
719 m_pFusionContext = NULL;
720 m_pTPABinderContext = NULL;
722 // Make sure the container is set to NULL so that it gets loaded when it is used.
723 m_pLargeHeapHandleTable = NULL;
725 #ifndef CROSSGEN_COMPILE
726 // Note that m_handleStore is overridden by app domains
727 m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
729 m_handleStore = NULL;
732 m_pMarshalingData = NULL;
734 m_dwContextStatics = 0;
735 #ifdef FEATURE_COMINTEROP
736 m_pMngStdInterfacesInfo = NULL;
737 m_pWinRtBinder = NULL;
739 m_FileLoadLock.PreInit();
741 m_ClassInitLock.PreInit();
742 m_ILStubGenLock.PreInit();
744 #ifdef FEATURE_CODE_VERSIONING
745 m_codeVersionManager.PreInit(this == (BaseDomain *)g_pSharedDomainMemory);
748 } //BaseDomain::BaseDomain
750 //*****************************************************************************
751 void BaseDomain::Init()
758 INJECT_FAULT(COMPlusThrowOM(););
763 // Initialize the domain locks
766 if (this == reinterpret_cast<BaseDomain*>(&g_pSharedDomainMemory[0]))
767 m_DomainCrst.Init(CrstSharedBaseDomain);
768 else if (this == reinterpret_cast<BaseDomain*>(&g_pSystemDomainMemory[0]))
769 m_DomainCrst.Init(CrstSystemBaseDomain);
771 m_DomainCrst.Init(CrstBaseDomain);
773 m_DomainCacheCrst.Init(CrstAppDomainCache);
774 m_DomainLocalBlockCrst.Init(CrstDomainLocalBlock);
776 m_InteropDataCrst.Init(CrstInteropData, CRST_REENTRANCY);
778 m_WinRTFactoryCacheCrst.Init(CrstWinRTFactoryCache, CRST_UNSAFE_COOPGC);
780 // NOTE: CRST_UNSAFE_COOPGC prevents a GC mode switch to preemptive when entering this crst.
781 // If you remove this flag, we will switch to preemptive mode when entering
782 // m_FileLoadLock, which means all functions that enter it will become
783 // GC_TRIGGERS. (This includes all uses of PEFileListLockHolder, LoadLockHolder, etc.) So be sure
784 // to update the contracts if you remove this flag.
785 m_FileLoadLock.Init(CrstAssemblyLoader,
786 CrstFlags(CRST_HOST_BREAKABLE), TRUE);
789 // The JIT lock and the CCtor locks are at the same level (and marked as
790 // UNSAFE_SAME_LEVEL) because they are all part of the same deadlock detection mechanism. We
791 // see through cycles of JITting and .cctor execution and then explicitly allow the cycle to
792 // be broken by giving access to uninitialized classes. If there is no cycle or if the cycle
793 // involves other locks that arent part of this special deadlock-breaking semantics, then
794 // we continue to block.
796 m_JITLock.Init(CrstJit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
797 m_ClassInitLock.Init(CrstClassInit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
799 m_ILStubGenLock.Init(CrstILStubGen, CrstFlags(CRST_REENTRANCY), TRUE);
801 // Large heap handle table CRST.
802 m_LargeHeapHandleTableCrst.Init(CrstAppDomainHandleTable);
804 m_crstLoaderAllocatorReferences.Init(CrstLoaderAllocatorReferences);
805 // Has to switch thread to GC_NOTRIGGER while being held (see code:BaseDomain#AssemblyListLock)
806 m_crstAssemblyList.Init(CrstAssemblyList, CrstFlags(
807 CRST_GC_NOTRIGGER_WHEN_TAKEN | CRST_DEBUGGER_THREAD | CRST_TAKEN_DURING_SHUTDOWN));
809 // Initialize the EE marshaling data to NULL.
810 m_pMarshalingData = NULL;
812 #ifdef FEATURE_COMINTEROP
813 // Allocate the managed standard interfaces information.
814 m_pMngStdInterfacesInfo = new MngStdInterfacesInfo();
817 CLRPrivBinderWinRT::NamespaceResolutionKind fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_WindowsAPI;
818 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DesignerNamespaceResolutionEnabled) != FALSE)
820 fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_DesignerResolveEvent;
822 CLRPrivTypeCacheWinRT * pWinRtTypeCache = CLRPrivTypeCacheWinRT::GetOrCreateTypeCache();
823 m_pWinRtBinder = CLRPrivBinderWinRT::GetOrCreateBinder(pWinRtTypeCache, fNamespaceResolutionKind);
825 #endif // FEATURE_COMINTEROP
827 // Init the COM Interop data hash
829 LockOwner lock = {&m_InteropDataCrst, IsOwnerOfCrst};
830 m_interopDataHash.Init(0, NULL, false, &lock);
833 m_dwSizedRefHandles = 0;
834 if (!m_iNumberOfProcessors)
836 m_iNumberOfProcessors = GetCurrentProcessCpuCount();
840 #undef LOADERHEAP_PROFILE_COUNTER
842 #ifndef CROSSGEN_COMPILE
843 //*****************************************************************************
844 void BaseDomain::Terminate()
854 m_crstLoaderAllocatorReferences.Destroy();
855 m_DomainCrst.Destroy();
856 m_DomainCacheCrst.Destroy();
857 m_DomainLocalBlockCrst.Destroy();
858 m_InteropDataCrst.Destroy();
860 JitListLockEntry* pJitElement;
861 ListLockEntry* pElement;
863 // All the threads that are in this domain had better be stopped by this
866 // We might be jitting or running a .cctor so we need to empty that queue.
867 pJitElement = m_JITLock.Pop(TRUE);
870 #ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
871 _ASSERTE ((m_JITLock.m_pHead->m_dwRefCount == 1
872 && m_JITLock.m_pHead->m_hrResultCode == E_FAIL) ||
873 dbg_fDrasticShutdown || g_fInControlC);
874 #endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
876 pJitElement = m_JITLock.Pop(TRUE);
881 pElement = m_ClassInitLock.Pop(TRUE);
884 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
885 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
888 pElement = m_ClassInitLock.Pop(TRUE);
890 m_ClassInitLock.Destroy();
892 FileLoadLock* pFileElement;
893 pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
896 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
897 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
899 pFileElement->Release();
900 pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
902 m_FileLoadLock.Destroy();
904 pElement = m_ILStubGenLock.Pop(TRUE);
907 #ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
908 _ASSERTE ((m_ILStubGenLock.m_pHead->m_dwRefCount == 1
909 && m_ILStubGenLock.m_pHead->m_hrResultCode == E_FAIL) ||
910 dbg_fDrasticShutdown || g_fInControlC);
911 #endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
913 pElement = m_ILStubGenLock.Pop(TRUE);
915 m_ILStubGenLock.Destroy();
917 m_LargeHeapHandleTableCrst.Destroy();
919 if (m_pLargeHeapHandleTable != NULL)
921 delete m_pLargeHeapHandleTable;
922 m_pLargeHeapHandleTable = NULL;
927 // Kind of a workaround - during unloading, we need to have an EE halt
928 // around deleting this stuff. So it gets deleted in AppDomain::Terminate()
929 // for those things (because there is a convenient place there.)
930 GetLoaderAllocator()->CleanupStringLiteralMap();
933 #ifdef FEATURE_COMINTEROP
934 if (m_pMngStdInterfacesInfo)
936 delete m_pMngStdInterfacesInfo;
937 m_pMngStdInterfacesInfo = NULL;
940 if (m_pWinRtBinder != NULL)
942 m_pWinRtBinder->Release();
944 #endif // FEATURE_COMINTEROP
946 ClearFusionContext();
948 m_dwSizedRefHandles = 0;
950 #endif // CROSSGEN_COMPILE
952 void BaseDomain::InitVSD()
954 STANDARD_VM_CONTRACT;
956 // This is a workaround for gcc, since it fails to successfully resolve
957 // "TypeIDMap::STARTING_SHARED_DOMAIN_ID" when used within the ?: operator.
959 if (IsSharedDomain())
961 startingId = TypeIDMap::STARTING_SHARED_DOMAIN_ID;
965 startingId = TypeIDMap::STARTING_UNSHARED_DOMAIN_ID;
968 // By passing false as the last parameter, interfaces loaded in the
969 // shared domain will not be given fat type ids if RequiresFatDispatchTokens
970 // is set. This is correct, as the fat dispatch tokens are only needed to solve
971 // uniqueness problems involving domain specific types.
972 m_typeIDMap.Init(startingId, 2, !IsSharedDomain());
974 #ifndef CROSSGEN_COMPILE
975 GetLoaderAllocator()->InitVirtualCallStubManager(this);
979 #ifndef CROSSGEN_COMPILE
981 DWORD BaseDomain::AllocateContextStaticsOffset(DWORD* pOffsetSlot)
990 CrstHolder ch(&m_SpecialStaticsCrst);
992 DWORD dwOffset = *pOffsetSlot;
994 if (dwOffset == (DWORD)-1)
997 dwOffset = m_dwContextStatics++;
998 *pOffsetSlot = dwOffset;
1004 void BaseDomain::ClearFusionContext()
1014 if(m_pFusionContext) {
1015 m_pFusionContext->Release();
1016 m_pFusionContext = NULL;
1018 if (m_pTPABinderContext) {
1019 m_pTPABinderContext->Release();
1020 m_pTPABinderContext = NULL;
1024 #ifdef FEATURE_PREJIT
1025 void AppDomain::DeleteNativeCodeRanges()
1036 // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized
1037 // and yet we are destroying it. (This is the case if we OOM during AppDomain creation.)
1038 if (m_Assemblies.IsEmpty())
1041 // Shutdown assemblies
1042 AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad) );
1043 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1045 while (i.Next(pDomainAssembly.This()))
1047 Assembly * assembly = pDomainAssembly->m_pAssembly;
1048 if ((assembly != NULL) && !assembly->IsDomainNeutral())
1049 assembly->DeleteNativeCodeRanges();
1054 void AppDomain::ShutdownAssemblies()
1064 // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized
1065 // and yet we are destroying it. (This is the case if we OOM during AppDomain creation.)
1066 if (m_Assemblies.IsEmpty())
1069 // Shutdown assemblies
1070 // has two stages because Terminate needs info from the Assembly's dependencies
1072 // Stage 1: call code:Assembly::Terminate
1073 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1074 kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
1075 DomainAssembly * pDomainAssembly = NULL;
1077 while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1079 // Note: cannot use DomainAssembly::GetAssembly() here as it asserts that the assembly has been
1080 // loaded to at least the FILE_LOAD_ALLOCATE level. Since domain shutdown can take place
1081 // asynchronously this property cannot be guaranteed. Access the m_pAssembly field directly instead.
1082 Assembly * assembly = pDomainAssembly->m_pAssembly;
1083 if (assembly && !assembly->IsDomainNeutral())
1084 assembly->Terminate();
1087 // Stage 2: Clear the list of assemblies
1088 i = IterateAssembliesEx((AssemblyIterationFlags)(
1089 kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
1090 while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1092 // We are in shutdown path, no one else can get to the list anymore
1093 delete pDomainAssembly;
1095 m_Assemblies.Clear(this);
1097 // Stage 2: Clear the loader allocators registered for deletion from code:Assembly:Terminate calls in
1099 // Note: It is not clear to me why we cannot delete the loader allocator from within
1100 // code:DomainAssembly::~DomainAssembly
1101 ShutdownFreeLoaderAllocators(FALSE);
1102 } // AppDomain::ShutdownAssemblies
1104 void AppDomain::ShutdownFreeLoaderAllocators(BOOL bFromManagedCode)
1106 // If we're called from managed code (i.e. the finalizer thread) we take a lock in
1107 // LoaderAllocator::CleanupFailedTypeInit, which may throw. Otherwise we're called
1108 // from the app-domain shutdown path in which we can avoid taking the lock.
1112 if (bFromManagedCode) THROWS; else NOTHROW;
1118 CrstHolder ch(GetLoaderAllocatorReferencesLock());
1120 // Shutdown the LoaderAllocators associated with collectible assemblies
1121 while (m_pDelayedLoaderAllocatorUnloadList != NULL)
1123 LoaderAllocator * pCurrentLoaderAllocator = m_pDelayedLoaderAllocatorUnloadList;
1124 // Remove next loader allocator from the list
1125 m_pDelayedLoaderAllocatorUnloadList = m_pDelayedLoaderAllocatorUnloadList->m_pLoaderAllocatorDestroyNext;
1127 if (bFromManagedCode)
1129 // For loader allocator finalization, we need to be careful about cleaning up per-appdomain allocations
1130 // and synchronizing with GC using delay unload list. We need to wait for next Gen2 GC to finish to ensure
1131 // that GC heap does not have any references to the MethodTables being unloaded.
1133 pCurrentLoaderAllocator->CleanupFailedTypeInit();
1135 pCurrentLoaderAllocator->CleanupHandles();
1138 SystemDomain::System()->AddToDelayedUnloadList(pCurrentLoaderAllocator);
1142 // For appdomain unload, delete the loader allocator right away
1143 delete pCurrentLoaderAllocator;
1146 } // AppDomain::ShutdownFreeLoaderAllocators
1148 //---------------------------------------------------------------------------------------
1150 // Register the loader allocator for deletion in code:AppDomain::ShutdownFreeLoaderAllocators.
1152 void AppDomain::RegisterLoaderAllocatorForDeletion(LoaderAllocator * pLoaderAllocator)
1163 CrstHolder ch(GetLoaderAllocatorReferencesLock());
1165 pLoaderAllocator->m_pLoaderAllocatorDestroyNext = m_pDelayedLoaderAllocatorUnloadList;
1166 m_pDelayedLoaderAllocatorUnloadList = pLoaderAllocator;
1169 void AppDomain::ShutdownNativeDllSearchDirectories()
1171 LIMITED_METHOD_CONTRACT;
1172 // Shutdown assemblies
1173 PathIterator i = IterateNativeDllSearchDirectories();
1180 m_NativeDllSearchDirectories.Clear();
1183 void AppDomain::ReleaseDomainBoundInfo()
1192 // Shutdown assemblies
1193 m_AssemblyCache.OnAppDomainUnload();
1195 AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeFailedToLoad) );
1196 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1198 while (i.Next(pDomainAssembly.This()))
1200 pDomainAssembly->ReleaseManagedData();
1204 void AppDomain::ReleaseFiles()
1206 STANDARD_VM_CONTRACT;
1208 // Shutdown assemblies
1209 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1210 kIncludeLoaded | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeLoading));
1211 CollectibleAssemblyHolder<DomainAssembly *> pAsm;
1213 while (i.Next(pAsm.This()))
1215 if (pAsm->GetCurrentAssembly() == NULL)
1217 // Might be domain neutral or not, but should have no live objects as it has not been
1218 // really loaded yet. Just reset it.
1219 _ASSERTE(FitsIn<DWORD>(i.GetIndex()));
1220 m_Assemblies.Set(this, static_cast<DWORD>(i.GetIndex()), NULL);
1221 delete pAsm.Extract();
1225 if (!pAsm->GetCurrentAssembly()->IsDomainNeutral())
1226 pAsm->ReleaseFiles();
1229 } // AppDomain::ReleaseFiles
1232 OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate, BOOL bCrossAD)
1239 PRECONDITION((nRequested > 0));
1240 INJECT_FAULT(COMPlusThrowOM(););
1244 if (ppLazyAllocate && *ppLazyAllocate)
1246 // Allocation already happened
1247 return *ppLazyAllocate;
1250 // Enter preemptive state, take the lock and go back to cooperative mode.
1252 CrstHolder ch(&m_LargeHeapHandleTableCrst);
1255 if (ppLazyAllocate && *ppLazyAllocate)
1257 // Allocation already happened
1258 return *ppLazyAllocate;
1261 // Make sure the large heap handle table is initialized.
1262 if (!m_pLargeHeapHandleTable)
1263 InitLargeHeapHandleTable();
1265 // Allocate the handles.
1266 OBJECTREF* result = m_pLargeHeapHandleTable->AllocateHandles(nRequested, bCrossAD);
1270 *ppLazyAllocate = result;
1276 #endif // CROSSGEN_COMPILE
1278 #endif // !DACCESS_COMPILE
1281 PTR_BaseDomain BaseDomain::ComputeBaseDomain(
1282 BaseDomain * pGenericDefinitionDomain, // the domain that owns the generic type or method
1283 Instantiation classInst, // the type arguments to the type (if any)
1284 Instantiation methodInst) // the type arguments to the method (if any)
1286 CONTRACT(PTR_BaseDomain)
1292 POSTCONDITION(CheckPointer(RETVAL));
1298 if (pGenericDefinitionDomain && pGenericDefinitionDomain->IsAppDomain())
1299 RETURN PTR_BaseDomain(pGenericDefinitionDomain);
1301 for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
1303 PTR_BaseDomain pArgDomain = classInst[i].GetDomain();
1304 if (pArgDomain->IsAppDomain())
1308 for (DWORD i = 0; i < methodInst.GetNumArgs(); i++)
1310 PTR_BaseDomain pArgDomain = methodInst[i].GetDomain();
1311 if (pArgDomain->IsAppDomain())
1314 RETURN (pGenericDefinitionDomain ?
1315 PTR_BaseDomain(pGenericDefinitionDomain) :
1316 PTR_BaseDomain(SystemDomain::System()));
1319 PTR_BaseDomain BaseDomain::ComputeBaseDomain(TypeKey * pKey)
1331 if (pKey->GetKind() == ELEMENT_TYPE_CLASS)
1332 return BaseDomain::ComputeBaseDomain(pKey->GetModule()->GetDomain(),
1333 pKey->GetInstantiation());
1334 else if (pKey->GetKind() != ELEMENT_TYPE_FNPTR)
1335 return pKey->GetElementType().GetDomain();
1337 return BaseDomain::ComputeBaseDomain(NULL,Instantiation(pKey->GetRetAndArgTypes(), pKey->GetNumArgs()+1));
1344 #ifndef DACCESS_COMPILE
1346 // Insert class in the hash table
1347 void AppDomain::InsertClassForCLSID(MethodTable* pMT, BOOL fForceInsert /*=FALSE*/)
1354 INJECT_FAULT(COMPlusThrowOM(););
1360 // Ensure that registered classes are activated for allocation
1361 pMT->EnsureInstanceActive();
1363 // Note that it is possible for multiple classes to claim the same CLSID, and in such a
1364 // case it is arbitrary which one we will return for a future query for a given app domain.
1366 pMT->GetGuid(&cvid, fForceInsert);
1368 if (!IsEqualIID(cvid, GUID_NULL))
1370 //<TODO>@todo get a better key</TODO>
1371 LPVOID val = (LPVOID)pMT;
1373 LockHolder lh(this);
1375 if (LookupClass(cvid) != pMT)
1377 m_clsidHash.InsertValue(GetKeyFromGUID(&cvid), val);
1383 void AppDomain::InsertClassForCLSID(MethodTable* pMT, GUID *pGuid)
1388 PRECONDITION(CheckPointer(pMT));
1389 PRECONDITION(CheckPointer(pGuid));
1393 LPVOID val = (LPVOID)pMT;
1395 LockHolder lh(this);
1398 if (LookupClass(*cvid) != pMT)
1400 m_clsidHash.InsertValue(GetKeyFromGUID(pGuid), val);
1406 #endif // DACCESS_COMPILE
1408 #ifdef FEATURE_COMINTEROP
1410 #ifndef DACCESS_COMPILE
1411 void AppDomain::CacheTypeByName(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1413 WRAPPER_NO_CONTRACT;
1414 LockHolder lh(this);
1415 CacheTypeByNameWorker(ssClassName, vCacheVersion, typeHandle, bFlags, bReplaceExisting);
1418 void AppDomain::CacheTypeByNameWorker(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1424 PRECONDITION(!typeHandle.IsNull());
1428 NewArrayHolder<WCHAR> wzClassName(DuplicateStringThrowing(ssClassName.GetUnicode()));
1430 if (m_vNameToTypeMapVersion != vCacheVersion)
1433 if (m_pNameToTypeMap == nullptr)
1435 m_pNameToTypeMap = new NameToTypeMapTable();
1438 NameToTypeMapEntry e;
1439 e.m_key.m_wzName = wzClassName;
1440 e.m_key.m_cchName = ssClassName.GetCount();
1441 e.m_typeHandle = typeHandle;
1442 e.m_nEpoch = this->m_nEpoch;
1443 e.m_bFlags = bFlags;
1444 if (!bReplaceExisting)
1445 m_pNameToTypeMap->Add(e);
1447 m_pNameToTypeMap->AddOrReplace(e);
1449 wzClassName.SuppressRelease();
1451 #endif // DACCESS_COMPILE
1453 TypeHandle AppDomain::LookupTypeByName(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1455 WRAPPER_NO_CONTRACT;
1456 LockHolder lh(this);
1457 return LookupTypeByNameWorker(ssClassName, pvCacheVersion, pbFlags);
1460 TypeHandle AppDomain::LookupTypeByNameWorker(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1467 PRECONDITION(CheckPointer(pbFlags, NULL_OK));
1471 *pvCacheVersion = m_vNameToTypeMapVersion;
1473 if (m_pNameToTypeMap == nullptr)
1474 return TypeHandle(); // a null TypeHandle
1476 NameToTypeMapEntry::Key key;
1477 key.m_cchName = ssClassName.GetCount();
1478 key.m_wzName = ssClassName.GetUnicode();
1480 const NameToTypeMapEntry * pEntry = m_pNameToTypeMap->LookupPtr(key);
1482 return TypeHandle(); // a null TypeHandle
1484 if (pbFlags != NULL)
1485 *pbFlags = pEntry->m_bFlags;
1487 return pEntry->m_typeHandle;
1490 PTR_MethodTable AppDomain::LookupTypeByGuid(const GUID & guid)
1504 GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1505 sGuid.Append(wszGuid);
1508 TypeHandle th = LookupTypeByName(sGuid, &ver, NULL);
1512 _ASSERTE(!th.IsTypeDesc());
1513 return th.AsMethodTable();
1516 #ifdef FEATURE_PREJIT
1519 // Next look in each ngen'ed image in turn
1520 AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1521 kIncludeLoaded | kIncludeExecution));
1522 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1523 while (assemblyIterator.Next(pDomainAssembly.This()))
1525 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1527 DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1530 Module * pModule = i.GetLoadedModule();
1531 if (!pModule->HasNativeImage())
1533 _ASSERTE(!pModule->IsCollectible());
1534 PTR_MethodTable pMT = pModule->LookupTypeByGuid(guid);
1542 #endif // FEATURE_PREJIT
1546 #ifndef DACCESS_COMPILE
1547 void AppDomain::CacheWinRTTypeByGuid(TypeHandle typeHandle)
1554 PRECONDITION(!typeHandle.IsTypeDesc());
1555 PRECONDITION(CanCacheWinRTTypeByGuid(typeHandle));
1559 PTR_MethodTable pMT = typeHandle.AsMethodTable();
1562 if (pMT->GetGuidForWinRT(&guid))
1568 GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1569 sGuid.Append(wszGuid);
1576 LockHolder lh(this);
1577 th = LookupTypeByNameWorker(sGuid, &vCacheVersion, &bFlags);
1581 // no other entry with the same GUID exists in the cache
1582 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags);
1584 else if (typeHandle.AsMethodTable() != th.AsMethodTable() && th.IsProjectedFromWinRT())
1586 // If we found a native WinRT type cached with the same GUID, replace it.
1587 // Otherwise simply add the new mapping to the cache.
1588 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags, TRUE);
1593 #endif // DACCESS_COMPILE
1595 void AppDomain::GetCachedWinRTTypes(
1596 SArray<PTR_MethodTable> * pTypes,
1597 SArray<GUID> * pGuids,
1610 LockHolder lh(this);
1612 for (auto it = m_pNameToTypeMap->Begin(), end = m_pNameToTypeMap->End();
1616 NameToTypeMapEntry entry = (NameToTypeMapEntry)(*it);
1617 TypeHandle th = entry.m_typeHandle;
1618 if (th.AsMethodTable() != NULL &&
1619 entry.m_key.m_wzName[0] == W('{') &&
1620 entry.m_nEpoch >= minEpoch)
1622 _ASSERTE(!th.IsTypeDesc());
1623 PTR_MethodTable pMT = th.AsMethodTable();
1624 // we're parsing the GUID value from the cache, because projected types do not cache the
1625 // COM GUID in their GetGuid() but rather the legacy GUID
1627 if (LPWSTRToGuid(&iid, entry.m_key.m_wzName, 38) && iid != GUID_NULL)
1629 pTypes->Append(pMT);
1630 pGuids->Append(iid);
1635 #ifdef FEATURE_PREJIT
1636 // Next look in each ngen'ed image in turn
1637 AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1638 kIncludeLoaded | kIncludeExecution));
1639 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1640 while (assemblyIterator.Next(pDomainAssembly.This()))
1642 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1644 DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1647 Module * pModule = i.GetLoadedModule();
1648 if (!pModule->HasNativeImage())
1650 _ASSERTE(!pModule->IsCollectible());
1652 pModule->GetCachedWinRTTypes(pTypes, pGuids);
1655 #endif // FEATURE_PREJIT
1657 if (pCurEpoch != NULL)
1658 *pCurEpoch = m_nEpoch;
1662 #ifndef CROSSGEN_COMPILE
1663 #ifndef DACCESS_COMPILE
1665 void WinRTFactoryCacheTraits::OnDestructPerEntryCleanupAction(const WinRTFactoryCacheEntry& e)
1667 WRAPPER_NO_CONTRACT;
1668 if (e.m_pCtxEntry != NULL)
1670 e.m_pCtxEntry->Release();
1672 // the AD is going away, no need to destroy the OBJECTHANDLE
1675 void AppDomain::CacheWinRTFactoryObject(MethodTable *pClassMT, OBJECTREF *refFactory, LPVOID lpCtxCookie)
1682 PRECONDITION(CheckPointer(pClassMT));
1686 CtxEntryHolder pNewCtxEntry;
1687 if (lpCtxCookie != NULL)
1689 // We don't want to insert the context cookie in the cache because it's just an address
1690 // of an internal COM data structure which will be freed when the apartment is torn down.
1691 // What's worse, if another apartment is later created, its context cookie may have exactly
1692 // the same value leading to incorrect cache hits. We'll use our CtxEntry instead which
1693 // is ref-counted and keeps the COM data structure alive even after the apartment ceases
1695 pNewCtxEntry = CtxEntryCache::GetCtxEntryCache()->FindCtxEntry(lpCtxCookie, GetThread());
1698 WinRTFactoryCacheLockHolder lh(this);
1700 if (m_pWinRTFactoryCache == nullptr)
1702 m_pWinRTFactoryCache = new WinRTFactoryCache();
1705 WinRTFactoryCacheEntry *pEntry = const_cast<WinRTFactoryCacheEntry*>(m_pWinRTFactoryCache->LookupPtr(pClassMT));
1709 // No existing entry for this cache
1712 WinRTFactoryCacheEntry e;
1714 OBJECTHANDLEHolder ohNewHandle(CreateHandle(*refFactory));
1717 e.m_pCtxEntry = pNewCtxEntry;
1718 e.m_ohFactoryObject = ohNewHandle;
1720 m_pWinRTFactoryCache->Add(e);
1722 // suppress release of the CtxEntry and handle after we successfully inserted the new entry
1723 pNewCtxEntry.SuppressRelease();
1724 ohNewHandle.SuppressRelease();
1731 // release the old CtxEntry and update the entry
1732 CtxEntry *pTemp = pNewCtxEntry.Extract();
1733 pNewCtxEntry = pEntry->m_pCtxEntry;
1734 pEntry->m_pCtxEntry = pTemp;
1736 IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
1737 mgr->StoreObjectInHandle(pEntry->m_ohFactoryObject, OBJECTREFToObject(*refFactory));
1741 OBJECTREF AppDomain::LookupWinRTFactoryObject(MethodTable *pClassMT, LPVOID lpCtxCookie)
1748 PRECONDITION(CheckPointer(pClassMT));
1749 PRECONDITION(CheckPointer(m_pWinRTFactoryCache, NULL_OK));
1754 if (m_pWinRTFactoryCache == nullptr)
1758 // Retrieve cached factory
1760 WinRTFactoryCacheLockHolder lh(this);
1762 const WinRTFactoryCacheEntry *pEntry = m_pWinRTFactoryCache->LookupPtr(pClassMT);
1767 // Ignore factories from a different context, unless lpCtxCookie == NULL,
1768 // which means the factory is free-threaded
1769 // Note that we cannot touch the RCW to retrieve cookie at this point
1770 // because the RCW might belong to a STA thread and that STA thread might die
1771 // and take the RCW with it. Therefore we have to save cookie in this cache
1773 if (pEntry->m_pCtxEntry == NULL || pEntry->m_pCtxEntry->GetCtxCookie() == lpCtxCookie)
1774 return ObjectFromHandle(pEntry->m_ohFactoryObject);
1779 void AppDomain::RemoveWinRTFactoryObjects(LPVOID pCtxCookie)
1789 if (m_pWinRTFactoryCache == nullptr)
1792 // helper class for delayed CtxEntry cleanup
1793 class CtxEntryListReleaseHolder
1796 CQuickArrayList<CtxEntry *> m_list;
1798 ~CtxEntryListReleaseHolder()
1808 for (SIZE_T i = 0; i < m_list.Size(); i++)
1810 m_list[i]->Release();
1813 } ctxEntryListReleaseHolder;
1817 WinRTFactoryCacheLockHolder lh(this);
1819 // Go through the hash table and remove items in the given context
1820 for (WinRTFactoryCache::Iterator it = m_pWinRTFactoryCache->Begin(); it != m_pWinRTFactoryCache->End(); it++)
1822 if (it->m_pCtxEntry != NULL && it->m_pCtxEntry->GetCtxCookie() == pCtxCookie)
1824 // Releasing the CtxEntry may trigger GC which we can't do under the lock so we push
1825 // it on our local list and release them all after we're done iterating the hashtable.
1826 ctxEntryListReleaseHolder.m_list.Push(it->m_pCtxEntry);
1828 DestroyHandle(it->m_ohFactoryObject);
1829 m_pWinRTFactoryCache->Remove(it);
1835 OBJECTREF AppDomain::GetMissingObject()
1848 FieldDesc *pValueFD = MscorlibBinder::GetField(FIELD__MISSING__VALUE);
1850 pValueFD->CheckRunClassInitThrowing();
1852 // Retrieve the value static field and store it.
1853 OBJECTHANDLE hndMissing = CreateHandle(pValueFD->GetStaticOBJECTREF());
1855 if (FastInterlockCompareExchangePointer(&m_hndMissing, hndMissing, NULL) != NULL)
1857 // Exchanged failed. The m_hndMissing did not equal NULL and was returned.
1858 DestroyHandle(hndMissing);
1862 return ObjectFromHandle(m_hndMissing);
1865 #endif // DACCESS_COMPILE
1866 #endif //CROSSGEN_COMPILE
1867 #endif // FEATURE_COMINTEROP
1869 #ifndef DACCESS_COMPILE
1871 EEMarshalingData *BaseDomain::GetMarshalingData()
1873 CONTRACT (EEMarshalingData*)
1878 INJECT_FAULT(COMPlusThrowOM());
1879 POSTCONDITION(CheckPointer(m_pMarshalingData));
1883 if (!m_pMarshalingData)
1886 CrstHolder holder(&m_InteropDataCrst);
1888 if (!m_pMarshalingData)
1890 LoaderHeap* pHeap = GetLoaderAllocator()->GetLowFrequencyHeap();
1891 m_pMarshalingData = new (pHeap) EEMarshalingData(this, pHeap, &m_DomainCrst);
1895 RETURN m_pMarshalingData;
1898 void BaseDomain::DeleteMarshalingData()
1908 // We are in shutdown - no need to take any lock
1909 if (m_pMarshalingData)
1911 delete m_pMarshalingData;
1912 m_pMarshalingData = NULL;
1916 #ifndef CROSSGEN_COMPILE
1918 STRINGREF *BaseDomain::IsStringInterned(STRINGREF *pString)
1925 PRECONDITION(CheckPointer(pString));
1926 INJECT_FAULT(COMPlusThrowOM(););
1930 return GetLoaderAllocator()->IsStringInterned(pString);
1933 STRINGREF *BaseDomain::GetOrInternString(STRINGREF *pString)
1940 PRECONDITION(CheckPointer(pString));
1941 INJECT_FAULT(COMPlusThrowOM(););
1945 return GetLoaderAllocator()->GetOrInternString(pString);
1948 void BaseDomain::InitLargeHeapHandleTable()
1955 PRECONDITION(m_pLargeHeapHandleTable==NULL);
1956 INJECT_FAULT(COMPlusThrowOM(););
1960 m_pLargeHeapHandleTable = new LargeHeapHandleTable(this, STATIC_OBJECT_TABLE_BUCKET_SIZE);
1963 m_pLargeHeapHandleTable->RegisterCrstDebug(&m_LargeHeapHandleTableCrst);
1967 #ifdef FEATURE_COMINTEROP
1968 MethodTable* AppDomain::GetLicenseInteropHelperMethodTable()
1977 if(m_pLicenseInteropHelperMT == NULL)
1979 // Do this work outside of the lock so we don't have an unbreakable lock condition
1981 TypeHandle licenseMgrTypeHnd;
1982 MethodDescCallSite loadLM(METHOD__MARSHAL__LOAD_LICENSE_MANAGER);
1984 licenseMgrTypeHnd = (MethodTable*) loadLM.Call_RetLPVOID((ARG_SLOT*)NULL);
1987 // Look up this method by name, because the type is actually declared in System.dll. <TODO>@todo: why?</TODO>
1990 MethodDesc *pGetLIHMD = MemberLoader::FindMethod(licenseMgrTypeHnd.AsMethodTable(),
1991 "GetLicenseInteropHelperType", &gsig_SM_Void_RetIntPtr);
1992 _ASSERTE(pGetLIHMD);
1994 TypeHandle lihTypeHnd;
1996 MethodDescCallSite getLIH(pGetLIHMD);
1997 lihTypeHnd = (MethodTable*) getLIH.Call_RetLPVOID((ARG_SLOT*)NULL);
1999 BaseDomain::LockHolder lh(this);
2001 if(m_pLicenseInteropHelperMT == NULL)
2002 m_pLicenseInteropHelperMT = lihTypeHnd.AsMethodTable();
2004 return m_pLicenseInteropHelperMT;
2007 COMorRemotingFlag AppDomain::GetComOrRemotingFlag()
2017 // 0. check if the value is already been set
2018 if (m_COMorRemotingFlag != COMorRemoting_NotInitialized)
2019 return m_COMorRemotingFlag;
2021 // 1. check whether the process is AppX
2022 if (AppX::IsAppXProcess())
2024 // do not use Remoting in AppX
2025 m_COMorRemotingFlag = COMorRemoting_COM;
2026 return m_COMorRemotingFlag;
2029 // 2. check the xml file
2030 m_COMorRemotingFlag = GetPreferComInsteadOfManagedRemotingFromConfigFile();
2031 if (m_COMorRemotingFlag != COMorRemoting_NotInitialized)
2033 return m_COMorRemotingFlag;
2036 // 3. check the global setting
2037 if (NULL != g_pConfig && g_pConfig->ComInsteadOfManagedRemoting())
2039 m_COMorRemotingFlag = COMorRemoting_COM;
2043 m_COMorRemotingFlag = COMorRemoting_Remoting;
2046 return m_COMorRemotingFlag;
2049 BOOL AppDomain::GetPreferComInsteadOfManagedRemoting()
2051 WRAPPER_NO_CONTRACT;
2053 return (GetComOrRemotingFlag() == COMorRemoting_COM);
2056 COMorRemotingFlag AppDomain::GetPreferComInsteadOfManagedRemotingFromConfigFile()
2066 return COMorRemoting_COM;
2068 #endif // FEATURE_COMINTEROP
2070 #endif // CROSSGEN_COMPILE
2072 //*****************************************************************************
2073 //*****************************************************************************
2074 //*****************************************************************************
2076 void *SystemDomain::operator new(size_t size, void *pInPlace)
2078 LIMITED_METHOD_CONTRACT;
2083 void SystemDomain::operator delete(void *pMem)
2085 LIMITED_METHOD_CONTRACT;
2086 // Do nothing - new() was in-place
2090 void SystemDomain::SetCompilationOverrides(BOOL fForceDebug,
2091 BOOL fForceProfiling,
2092 BOOL fForceInstrument)
2094 LIMITED_METHOD_CONTRACT;
2095 s_fForceDebug = fForceDebug;
2096 s_fForceProfiling = fForceProfiling;
2097 s_fForceInstrument = fForceInstrument;
2100 #endif //!DACCESS_COMPILE
2102 void SystemDomain::GetCompilationOverrides(BOOL * fForceDebug,
2103 BOOL * fForceProfiling,
2104 BOOL * fForceInstrument)
2106 LIMITED_METHOD_DAC_CONTRACT;
2107 *fForceDebug = s_fForceDebug;
2108 *fForceProfiling = s_fForceProfiling;
2109 *fForceInstrument = s_fForceInstrument;
2112 #ifndef DACCESS_COMPILE
2114 void SystemDomain::Attach()
2121 PRECONDITION(m_pSystemDomain == NULL);
2122 INJECT_FAULT(COMPlusThrowOM(););
2126 #ifndef CROSSGEN_COMPILE
2127 // Initialize stub managers
2128 PrecodeStubManager::Init();
2129 DelegateInvokeStubManager::Init();
2130 JumpStubStubManager::Init();
2131 RangeSectionStubManager::Init();
2132 ILStubManager::Init();
2133 InteropDispatchStubManager::Init();
2134 StubLinkStubManager::Init();
2136 ThunkHeapStubManager::Init();
2138 TailCallStubManager::Init();
2140 PerAppDomainTPCountList::InitAppDomainIndexList();
2141 #endif // CROSSGEN_COMPILE
2143 m_appDomainIndexList.Init();
2144 m_appDomainIdList.Init();
2146 m_SystemDomainCrst.Init(CrstSystemDomain, (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN));
2147 m_DelayedUnloadCrst.Init(CrstSystemDomainDelayedUnloadList, CRST_UNSAFE_COOPGC);
2149 // Initialize the ID dispenser that is used for domain neutral module IDs
2150 g_pModuleIndexDispenser = new IdDispenser();
2152 // Create the global SystemDomain and initialize it.
2153 m_pSystemDomain = new (&g_pSystemDomainMemory[0]) SystemDomain();
2154 // No way it can fail since g_pSystemDomainMemory is a static array.
2155 CONSISTENCY_CHECK(CheckPointer(m_pSystemDomain));
2157 LOG((LF_CLASSLOADER,
2159 "Created system domain at %p\n",
2162 // We need to initialize the memory pools etc. for the system domain.
2163 m_pSystemDomain->BaseDomain::Init(); // Setup the memory heaps
2165 // Create the default domain
2166 m_pSystemDomain->CreateDefaultDomain();
2167 SharedDomain::Attach();
2169 // Each domain gets its own ReJitManager, and ReJitManager has its own static
2170 // initialization to run
2171 ReJitManager::InitStatic();
2174 #ifndef CROSSGEN_COMPILE
2176 void SystemDomain::DetachBegin()
2178 WRAPPER_NO_CONTRACT;
2179 // Shut down the domain and its children (but don't deallocate anything just
2182 // TODO: we should really not running managed DLLMain during process detach.
2183 if (GetThread() == NULL)
2189 m_pSystemDomain->Stop();
2192 void SystemDomain::DetachEnd()
2201 // Shut down the domain and its children (but don't deallocate anything just
2206 m_pSystemDomain->ClearFusionContext();
2207 if (m_pSystemDomain->m_pDefaultDomain)
2208 m_pSystemDomain->m_pDefaultDomain->ClearFusionContext();
2212 void SystemDomain::Stop()
2214 WRAPPER_NO_CONTRACT;
2215 AppDomainIterator i(TRUE);
2218 if (i.GetDomain()->m_Stage < AppDomain::STAGE_CLEARED)
2219 i.GetDomain()->Stop();
2223 void SystemDomain::Terminate() // bNotifyProfiler is ignored
2233 // This ignores the refences and terminates the appdomains
2234 AppDomainIterator i(FALSE);
2238 delete i.GetDomain();
2239 // Keep the iterator from Releasing the current domain
2240 i.m_pCurrent = NULL;
2243 if (m_pSystemFile != NULL) {
2244 m_pSystemFile->Release();
2245 m_pSystemFile = NULL;
2248 m_pSystemAssembly = NULL;
2251 delete[] m_pwDevpath;
2257 if (m_pGlobalStringLiteralMap) {
2258 delete m_pGlobalStringLiteralMap;
2259 m_pGlobalStringLiteralMap = NULL;
2263 SharedDomain::Detach();
2265 BaseDomain::Terminate();
2267 #ifdef FEATURE_COMINTEROP
2268 if (g_pRCWCleanupList != NULL)
2269 delete g_pRCWCleanupList;
2270 #endif // FEATURE_COMINTEROP
2271 m_GlobalAllocator.Terminate();
2275 void SystemDomain::PreallocateSpecialObjects()
2282 INJECT_FAULT(COMPlusThrowOM(););
2286 _ASSERTE(g_pPreallocatedSentinelObject == NULL);
2288 OBJECTREF pPreallocatedSentinalObject = AllocateObject(g_pObjectClass);
2289 g_pPreallocatedSentinelObject = CreatePinningHandle( pPreallocatedSentinalObject );
2291 #ifdef FEATURE_PREJIT
2292 if (SystemModule()->HasNativeImage())
2294 CORCOMPILE_EE_INFO_TABLE *pEEInfo = SystemModule()->GetNativeImage()->GetNativeEEInfoTable();
2295 pEEInfo->emptyString = (CORINFO_Object **)StringObject::GetEmptyStringRefPtr();
2300 void SystemDomain::CreatePreallocatedExceptions()
2307 INJECT_FAULT(COMPlusThrowOM(););
2311 EXCEPTIONREF pBaseException = (EXCEPTIONREF)AllocateObject(g_pExceptionClass);
2312 pBaseException->SetHResult(COR_E_EXCEPTION);
2313 pBaseException->SetXCode(EXCEPTION_COMPLUS);
2314 _ASSERTE(g_pPreallocatedBaseException == NULL);
2315 g_pPreallocatedBaseException = CreateHandle(pBaseException);
2318 EXCEPTIONREF pOutOfMemory = (EXCEPTIONREF)AllocateObject(g_pOutOfMemoryExceptionClass);
2319 pOutOfMemory->SetHResult(COR_E_OUTOFMEMORY);
2320 pOutOfMemory->SetXCode(EXCEPTION_COMPLUS);
2321 _ASSERTE(g_pPreallocatedOutOfMemoryException == NULL);
2322 g_pPreallocatedOutOfMemoryException = CreateHandle(pOutOfMemory);
2325 EXCEPTIONREF pStackOverflow = (EXCEPTIONREF)AllocateObject(g_pStackOverflowExceptionClass);
2326 pStackOverflow->SetHResult(COR_E_STACKOVERFLOW);
2327 pStackOverflow->SetXCode(EXCEPTION_COMPLUS);
2328 _ASSERTE(g_pPreallocatedStackOverflowException == NULL);
2329 g_pPreallocatedStackOverflowException = CreateHandle(pStackOverflow);
2332 EXCEPTIONREF pExecutionEngine = (EXCEPTIONREF)AllocateObject(g_pExecutionEngineExceptionClass);
2333 pExecutionEngine->SetHResult(COR_E_EXECUTIONENGINE);
2334 pExecutionEngine->SetXCode(EXCEPTION_COMPLUS);
2335 _ASSERTE(g_pPreallocatedExecutionEngineException == NULL);
2336 g_pPreallocatedExecutionEngineException = CreateHandle(pExecutionEngine);
2339 EXCEPTIONREF pRudeAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2340 pRudeAbortException->SetHResult(COR_E_THREADABORTED);
2341 pRudeAbortException->SetXCode(EXCEPTION_COMPLUS);
2342 _ASSERTE(g_pPreallocatedRudeThreadAbortException == NULL);
2343 g_pPreallocatedRudeThreadAbortException = CreateHandle(pRudeAbortException);
2346 EXCEPTIONREF pAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2347 pAbortException->SetHResult(COR_E_THREADABORTED);
2348 pAbortException->SetXCode(EXCEPTION_COMPLUS);
2349 _ASSERTE(g_pPreallocatedThreadAbortException == NULL);
2350 g_pPreallocatedThreadAbortException = CreateHandle( pAbortException );
2352 #endif // CROSSGEN_COMPILE
2354 void SystemDomain::Init()
2356 STANDARD_VM_CONTRACT;
2364 "sizeof(EEClass) = %d\n"
2365 "sizeof(MethodTable) = %d\n"
2366 "sizeof(MethodDesc)= %d\n"
2367 "sizeof(FieldDesc) = %d\n"
2368 "sizeof(Module) = %d\n",
2370 sizeof(MethodTable),
2377 // The base domain is initialized in SystemDomain::Attach()
2378 // to allow stub caches to use the memory pool. Do not
2379 // initialze it here!
2381 #ifndef CROSSGEN_COMPILE
2383 Context *curCtx = GetCurrentContext();
2386 _ASSERTE(curCtx->GetDomain() != NULL);
2389 #ifdef FEATURE_PREJIT
2390 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapDisable) != 0)
2391 g_fAllowNativeImages = false;
2394 m_pSystemFile = NULL;
2395 m_pSystemAssembly = NULL;
2400 // Get the install directory so we can find mscorlib
2401 hr = GetInternalSystemDirectory(NULL, &size);
2402 if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
2405 // GetInternalSystemDirectory returns a size, including the null!
2406 WCHAR *buffer = m_SystemDirectory.OpenUnicodeBuffer(size-1);
2407 IfFailThrow(GetInternalSystemDirectory(buffer, &size));
2408 m_SystemDirectory.CloseBuffer();
2409 m_SystemDirectory.Normalize();
2411 // At this point m_SystemDirectory should already be canonicalized
2414 m_BaseLibrary.Append(m_SystemDirectory);
2415 if (!m_BaseLibrary.EndsWith(DIRECTORY_SEPARATOR_CHAR_W))
2417 m_BaseLibrary.Append(DIRECTORY_SEPARATOR_CHAR_W);
2419 m_BaseLibrary.Append(g_pwBaseLibrary);
2420 m_BaseLibrary.Normalize();
2422 LoadBaseSystemClasses();
2425 // We are about to start allocating objects, so we must be in cooperative mode.
2426 // However, many of the entrypoints to the system (DllGetClassObject and all
2427 // N/Direct exports) get called multiple times. Sometimes they initialize the EE,
2428 // but generally they remain in preemptive mode. So we really want to push/pop
2432 #ifndef CROSSGEN_COMPILE
2433 if (!NingenEnabled())
2435 CreatePreallocatedExceptions();
2437 PreallocateSpecialObjects();
2441 // Finish loading mscorlib now.
2442 m_pSystemAssembly->GetDomainAssembly()->EnsureActive();
2446 BOOL fPause = EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_PauseOnLoad, FALSE);
2450 ClrSleepEx(20, TRUE);
2455 #ifndef CROSSGEN_COMPILE
2456 void SystemDomain::LazyInitGlobalStringLiteralMap()
2463 INJECT_FAULT(COMPlusThrowOM(););
2467 // Allocate the global string literal map.
2468 NewHolder<GlobalStringLiteralMap> pGlobalStringLiteralMap(new GlobalStringLiteralMap());
2470 // Initialize the global string literal map.
2471 pGlobalStringLiteralMap->Init();
2473 if (InterlockedCompareExchangeT<GlobalStringLiteralMap *>(&m_pGlobalStringLiteralMap, pGlobalStringLiteralMap, NULL) == NULL)
2475 pGlobalStringLiteralMap.SuppressRelease();
2479 void AppDomain::CreateADUnloadStartEvent()
2490 g_pUnloadStartEvent = new CLREvent();
2491 g_pUnloadStartEvent->CreateAutoEvent(FALSE);
2494 /*static*/ void SystemDomain::EnumAllStaticGCRefs(promote_func* fn, ScanContext* sc)
2504 // We don't do a normal AppDomainIterator because we can't take the SystemDomain lock from
2506 // We're only supposed to call this from a Server GC. We're walking here m_appDomainIdList
2507 // m_appDomainIdList will have an AppDomain* or will be NULL. So the only danger is if we
2508 // Fetch an AppDomain and then in some other thread the AppDomain is deleted.
2510 // If the thread deleting the AppDomain (AppDomain::~AppDomain)was in Preemptive mode
2511 // while doing SystemDomain::EnumAllStaticGCRefs we will issue a GCX_COOP(), which will wait
2512 // for the GC to finish, so we are safe
2514 // If the thread is in cooperative mode, it must have been suspended for the GC so a delete
2517 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
2518 GCHeapUtilities::IsServerHeap() &&
2519 IsGCSpecialThread());
2521 SystemDomain* sysDomain = SystemDomain::System();
2525 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2526 for (i = 0 ; i < count ; i++)
2528 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2529 if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
2531 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2534 sc->pCurrentDomain = pAppDomain;
2536 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2537 pAppDomain->EnumStaticGCRefs(fn, sc);
2545 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2546 void SystemDomain::ResetADSurvivedBytes()
2556 _ASSERTE(GCHeapUtilities::IsGCInProgress());
2558 SystemDomain* sysDomain = SystemDomain::System();
2562 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2563 for (i = 0 ; i < count ; i++)
2565 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2566 if (pAppDomain && pAppDomain->IsUserActive())
2568 pAppDomain->ResetSurvivedBytes();
2576 ULONGLONG SystemDomain::GetADSurvivedBytes()
2586 SystemDomain* sysDomain = SystemDomain::System();
2587 ULONGLONG ullTotalADSurvived = 0;
2591 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2592 for (i = 0 ; i < count ; i++)
2594 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2595 if (pAppDomain && pAppDomain->IsUserActive())
2597 ULONGLONG ullSurvived = pAppDomain->GetSurvivedBytes();
2598 ullTotalADSurvived += ullSurvived;
2603 return ullTotalADSurvived;
2606 void SystemDomain::RecordTotalSurvivedBytes(size_t totalSurvivedBytes)
2616 m_totalSurvivedBytes = totalSurvivedBytes;
2618 SystemDomain* sysDomain = SystemDomain::System();
2622 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2623 for (i = 0 ; i < count ; i++)
2625 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2626 if (pAppDomain && pAppDomain->IsUserActive())
2628 FireEtwAppDomainMemSurvived((ULONGLONG)pAppDomain, pAppDomain->GetSurvivedBytes(), totalSurvivedBytes, GetClrInstanceId());
2635 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2637 // Only called when EE is suspended.
2638 DWORD SystemDomain::GetTotalNumSizedRefHandles()
2648 SystemDomain* sysDomain = SystemDomain::System();
2649 DWORD dwTotalNumSizedRefHandles = 0;
2653 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2654 for (i = 0 ; i < count ; i++)
2656 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2657 if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
2659 dwTotalNumSizedRefHandles += pAppDomain->GetNumSizedRefHandles();
2664 return dwTotalNumSizedRefHandles;
2666 #endif // CROSSGEN_COMPILE
2668 void SystemDomain::LoadBaseSystemClasses()
2670 STANDARD_VM_CONTRACT;
2672 ETWOnStartup(LdSysBases_V1, LdSysBasesEnd_V1);
2675 m_pSystemFile = PEAssembly::OpenSystem(NULL);
2677 // Only partially load the system assembly. Other parts of the code will want to access
2678 // the globals in this function before finishing the load.
2679 m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemFile, FILE_LOAD_POST_LOADLIBRARY)->GetCurrentAssembly();
2681 // Set up binder for mscorlib
2682 MscorlibBinder::AttachModule(m_pSystemAssembly->GetManifestModule());
2685 g_pObjectClass = MscorlibBinder::GetClass(CLASS__OBJECT);
2687 // Now that ObjectClass is loaded, we can set up
2688 // the system for finalizers. There is no point in deferring this, since we need
2689 // to know this before we allocate our first object.
2690 g_pObjectFinalizerMD = MscorlibBinder::GetMethod(METHOD__OBJECT__FINALIZE);
2693 g_pCanonMethodTableClass = MscorlibBinder::GetClass(CLASS____CANON);
2695 // NOTE: !!!IMPORTANT!!! ValueType and Enum MUST be loaded one immediately after
2696 // the other, because we have coded MethodTable::IsChildValueType
2697 // in such a way that it depends on this behaviour.
2698 // Load the ValueType class
2699 g_pValueTypeClass = MscorlibBinder::GetClass(CLASS__VALUE_TYPE);
2701 // Load the enum class
2702 g_pEnumClass = MscorlibBinder::GetClass(CLASS__ENUM);
2703 _ASSERTE(!g_pEnumClass->IsValueType());
2705 // Load System.RuntimeType
2706 g_pRuntimeTypeClass = MscorlibBinder::GetClass(CLASS__CLASS);
2707 _ASSERTE(g_pRuntimeTypeClass->IsFullyLoaded());
2710 g_pArrayClass = MscorlibBinder::GetClass(CLASS__ARRAY);
2712 // Calling a method on IList<T> for an array requires redirection to a method on
2713 // the SZArrayHelper class. Retrieving such methods means calling
2714 // GetActualImplementationForArrayGenericIListMethod, which calls FetchMethod for
2715 // the corresponding method on SZArrayHelper. This basically results in a class
2716 // load due to a method call, which the debugger cannot handle, so we pre-load
2717 // the SZArrayHelper class here.
2718 g_pSZArrayHelperClass = MscorlibBinder::GetClass(CLASS__SZARRAYHELPER);
2720 // Load ByReference class
2722 // NOTE: ByReference<T> must be the first by-ref-like system type to be loaded,
2723 // because MethodTable::ClassifyEightBytesWithManagedLayout depends on it.
2724 g_pByReferenceClass = MscorlibBinder::GetClass(CLASS__BYREFERENCE);
2726 // Load Nullable class
2727 g_pNullableClass = MscorlibBinder::GetClass(CLASS__NULLABLE);
2729 // Load the Object array class.
2730 g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pObjectClass)).AsArray();
2732 // We have delayed allocation of mscorlib's static handles until we load the object class
2733 MscorlibBinder::GetModule()->AllocateRegularStaticHandles(DefaultDomain());
2735 g_TypedReferenceMT = MscorlibBinder::GetClass(CLASS__TYPED_REFERENCE);
2737 // Make sure all primitive types are loaded
2738 for (int et = ELEMENT_TYPE_VOID; et <= ELEMENT_TYPE_R8; et++)
2739 MscorlibBinder::LoadPrimitiveType((CorElementType)et);
2741 MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_I);
2742 MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_U);
2744 // unfortunately, the following cannot be delay loaded since the jit
2745 // uses it to compute method attributes within a function that cannot
2746 // handle Complus exception and the following call goes through a path
2747 // where a complus exception can be thrown. It is unfortunate, because
2748 // we know that the delegate class and multidelegate class are always
2749 // guaranteed to be found.
2750 g_pDelegateClass = MscorlibBinder::GetClass(CLASS__DELEGATE);
2751 g_pMulticastDelegateClass = MscorlibBinder::GetClass(CLASS__MULTICAST_DELEGATE);
2753 // used by IsImplicitInterfaceOfSZArray
2754 MscorlibBinder::GetClass(CLASS__IENUMERABLEGENERIC);
2755 MscorlibBinder::GetClass(CLASS__ICOLLECTIONGENERIC);
2756 MscorlibBinder::GetClass(CLASS__ILISTGENERIC);
2757 MscorlibBinder::GetClass(CLASS__IREADONLYCOLLECTIONGENERIC);
2758 MscorlibBinder::GetClass(CLASS__IREADONLYLISTGENERIC);
2761 g_pStringClass = MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_STRING);
2762 _ASSERTE(g_pStringClass->GetBaseSize() == ObjSizeOf(StringObject)+sizeof(WCHAR));
2763 _ASSERTE(g_pStringClass->GetComponentSize() == 2);
2765 // Used by Buffer::BlockCopy
2766 g_pByteArrayMT = ClassLoader::LoadArrayTypeThrowing(
2767 TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1))).AsArray()->GetMethodTable();
2769 #ifndef CROSSGEN_COMPILE
2770 ECall::PopulateManagedStringConstructors();
2771 #endif // CROSSGEN_COMPILE
2773 g_pExceptionClass = MscorlibBinder::GetClass(CLASS__EXCEPTION);
2774 g_pOutOfMemoryExceptionClass = MscorlibBinder::GetException(kOutOfMemoryException);
2775 g_pStackOverflowExceptionClass = MscorlibBinder::GetException(kStackOverflowException);
2776 g_pExecutionEngineExceptionClass = MscorlibBinder::GetException(kExecutionEngineException);
2777 g_pThreadAbortExceptionClass = MscorlibBinder::GetException(kThreadAbortException);
2780 // used by gc to handle predefined agility checking
2781 g_pThreadClass = MscorlibBinder::GetClass(CLASS__THREAD);
2783 #ifdef FEATURE_COMINTEROP
2784 g_pBaseCOMObject = MscorlibBinder::GetClass(CLASS__COM_OBJECT);
2785 g_pBaseRuntimeClass = MscorlibBinder::GetClass(CLASS__RUNTIME_CLASS);
2787 MscorlibBinder::GetClass(CLASS__IDICTIONARYGENERIC);
2788 MscorlibBinder::GetClass(CLASS__IREADONLYDICTIONARYGENERIC);
2789 MscorlibBinder::GetClass(CLASS__ATTRIBUTE);
2790 MscorlibBinder::GetClass(CLASS__EVENT_HANDLERGENERIC);
2792 MscorlibBinder::GetClass(CLASS__IENUMERABLE);
2793 MscorlibBinder::GetClass(CLASS__ICOLLECTION);
2794 MscorlibBinder::GetClass(CLASS__ILIST);
2795 MscorlibBinder::GetClass(CLASS__IDISPOSABLE);
2798 WinRTInterfaceRedirector::VerifyRedirectedInterfaceStubs();
2802 #ifdef FEATURE_ICASTABLE
2803 g_pICastableInterface = MscorlibBinder::GetClass(CLASS__ICASTABLE);
2804 #endif // FEATURE_ICASTABLE
2806 // Load a special marker method used to detect Constrained Execution Regions
2808 g_pExecuteBackoutCodeHelperMethod = MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__EXECUTE_BACKOUT_CODE_HELPER);
2810 // Make sure that FCall mapping for Monitor.Enter is initialized. We need it in case Monitor.Enter is used only as JIT helper.
2811 // For more details, see comment in code:JITutil_MonEnterWorker around "__me = GetEEFuncEntryPointMacro(JIT_MonEnter)".
2812 ECall::GetFCallImpl(MscorlibBinder::GetMethod(METHOD__MONITOR__ENTER));
2814 #ifdef PROFILING_SUPPORTED
2815 // Note that g_profControlBlock.fBaseSystemClassesLoaded must be set to TRUE only after
2816 // all base system classes are loaded. Profilers are not allowed to call any type-loading
2817 // APIs until g_profControlBlock.fBaseSystemClassesLoaded is TRUE. It is important that
2818 // all base system classes need to be loaded before profilers can trigger the type loading.
2819 g_profControlBlock.fBaseSystemClassesLoaded = TRUE;
2820 #endif // PROFILING_SUPPORTED
2822 #if defined(_DEBUG) && !defined(CROSSGEN_COMPILE)
2823 if (!NingenEnabled())
2829 #if defined(HAVE_GCCOVER) && defined(FEATURE_PREJIT)
2830 if (GCStress<cfg_instr_ngen>::IsEnabled())
2832 // Setting up gc coverage requires the base system classes
2833 // to be initialized. So we have deferred it until now for mscorlib.
2834 Module *pModule = MscorlibBinder::GetModule();
2835 _ASSERTE(pModule->IsSystem());
2836 if(pModule->HasNativeImage())
2838 SetupGcCoverageForNativeImage(pModule);
2841 #endif // defined(HAVE_GCCOVER) && !defined(FEATURE_PREJIT)
2845 void SystemDomain::LoadDomain(AppDomain *pDomain)
2852 PRECONDITION(CheckPointer(System()));
2853 INJECT_FAULT(COMPlusThrowOM(););
2857 pDomain->SetCanUnload(); // by default can unload any domain
2858 SystemDomain::System()->AddDomain(pDomain);
2861 ADIndex SystemDomain::GetNewAppDomainIndex(AppDomain *pAppDomain)
2863 STANDARD_VM_CONTRACT;
2865 DWORD count = m_appDomainIndexList.GetCount();
2871 // So that we can keep AD index inside object header.
2872 // We do not want to create syncblock unless needed.
2879 // Look for an unused index. Note that in a checked build,
2880 // we never reuse indexes - this makes it easier to tell
2881 // when we are looking at a stale app domain.
2884 i = m_appDomainIndexList.FindElement(m_dwLowestFreeIndex, NULL);
2885 if (i == (DWORD) ArrayList::NOT_FOUND)
2887 m_dwLowestFreeIndex = i+1;
2889 if (m_dwLowestFreeIndex >= 2000)
2891 m_dwLowestFreeIndex = 0;
2897 IfFailThrow(m_appDomainIndexList.Append(pAppDomain));
2899 m_appDomainIndexList.Set(i, pAppDomain);
2901 _ASSERTE(i < m_appDomainIndexList.GetCount());
2903 // Note that index 0 means domain agile.
2904 return ADIndex(i+1);
2907 void SystemDomain::ReleaseAppDomainIndex(ADIndex index)
2909 WRAPPER_NO_CONTRACT;
2910 SystemDomain::LockHolder lh;
2911 // Note that index 0 means domain agile.
2914 _ASSERTE(m_appDomainIndexList.Get(index.m_dwIndex) != NULL);
2916 m_appDomainIndexList.Set(index.m_dwIndex, NULL);
2919 if (index.m_dwIndex < m_dwLowestFreeIndex)
2920 m_dwLowestFreeIndex = index.m_dwIndex;
2924 #endif // !DACCESS_COMPILE
2926 PTR_AppDomain SystemDomain::GetAppDomainAtIndex(ADIndex index)
2928 LIMITED_METHOD_CONTRACT;
2930 _ASSERTE(index.m_dwIndex != 0);
2932 PTR_AppDomain pAppDomain = TestGetAppDomainAtIndex(index);
2934 _ASSERTE(pAppDomain || !"Attempt to access unloaded app domain");
2939 PTR_AppDomain SystemDomain::TestGetAppDomainAtIndex(ADIndex index)
2941 LIMITED_METHOD_CONTRACT;
2943 _ASSERTE(index.m_dwIndex != 0);
2946 #ifndef DACCESS_COMPILE
2947 _ASSERTE(index.m_dwIndex < (DWORD)m_appDomainIndexList.GetCount());
2948 AppDomain *pAppDomain = (AppDomain*) m_appDomainIndexList.Get(index.m_dwIndex);
2949 #else // DACCESS_COMPILE
2950 PTR_ArrayListStatic pList = &m_appDomainIndexList;
2951 AppDomain *pAppDomain = dac_cast<PTR_AppDomain>(pList->Get(index.m_dwIndex));
2952 #endif // DACCESS_COMPILE
2953 return PTR_AppDomain(pAppDomain);
2956 #ifndef DACCESS_COMPILE
2958 // See also code:SystemDomain::ReleaseAppDomainId
2959 ADID SystemDomain::GetNewAppDomainId(AppDomain *pAppDomain)
2966 INJECT_FAULT(COMPlusThrowOM(););
2970 DWORD i = m_appDomainIdList.GetCount();
2972 IfFailThrow(m_appDomainIdList.Append(pAppDomain));
2974 _ASSERTE(i < m_appDomainIdList.GetCount());
2979 AppDomain *SystemDomain::GetAppDomainAtId(ADID index)
2984 if (!SystemDomain::IsUnderDomainLock() && !IsGCThread()) { MODE_COOPERATIVE;} else { DISABLED(MODE_ANY);}
2992 if(index.m_dwId == 0)
2994 DWORD requestedID = index.m_dwId - 1;
2996 if(requestedID >= (DWORD)m_appDomainIdList.GetCount())
2999 AppDomain * result = (AppDomain *)m_appDomainIdList.Get(requestedID);
3001 #ifndef CROSSGEN_COMPILE
3002 if(result==NULL && GetThread() == FinalizerThread::GetFinalizerThread() &&
3003 SystemDomain::System()->AppDomainBeingUnloaded()!=NULL &&
3004 SystemDomain::System()->AppDomainBeingUnloaded()->GetId()==index)
3005 result=SystemDomain::System()->AppDomainBeingUnloaded();
3006 // If the current thread can't enter the AppDomain, then don't return it.
3007 if (!result || !result->CanThreadEnter(GetThread()))
3009 #endif // CROSSGEN_COMPILE
3014 // Releases an appdomain index. Note that today we have code that depends on these
3015 // indexes not being recycled, so we don't actually shrink m_appDomainIdList, but
3016 // simply zero out an entry. THus we 'leak' the memory associated the slot in
3017 // m_appDomainIdList.
3019 // TODO make this a sparse structure so that we avoid that leak.
3021 void SystemDomain::ReleaseAppDomainId(ADID index)
3023 LIMITED_METHOD_CONTRACT;
3026 _ASSERTE(index.m_dwId < (DWORD)m_appDomainIdList.GetCount());
3028 m_appDomainIdList.Set(index.m_dwId, NULL);
3031 #if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3034 int g_fMainThreadApartmentStateSet = 0;
3037 Thread::ApartmentState SystemDomain::GetEntryPointThreadAptState(IMDInternalImport* pScope, mdMethodDef mdMethod)
3039 STANDARD_VM_CONTRACT;
3042 IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
3043 DEFAULTDOMAIN_MTA_TYPE,
3046 BOOL fIsMTA = FALSE;
3050 IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
3051 DEFAULTDOMAIN_STA_TYPE,
3054 BOOL fIsSTA = FALSE;
3058 if (fIsSTA && fIsMTA)
3059 COMPlusThrowHR(COR_E_CUSTOMATTRIBUTEFORMAT);
3062 return Thread::AS_InSTA;
3064 return Thread::AS_InMTA;
3066 return Thread::AS_Unknown;
3069 void SystemDomain::SetThreadAptState (Thread::ApartmentState state)
3071 STANDARD_VM_CONTRACT;
3073 Thread* pThread = GetThread();
3076 if(state == Thread::AS_InSTA)
3078 Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InSTA, TRUE);
3079 _ASSERTE(pState == Thread::AS_InSTA);
3081 else if (state == Thread::AS_InMTA)
3083 Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InMTA, TRUE);
3084 _ASSERTE(pState == Thread::AS_InMTA);
3088 g_fMainThreadApartmentStateSet++;
3091 #endif // defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3093 // Looks in all the modules for the DefaultDomain attribute
3094 // The order is assembly and then the modules. It is first
3095 // come, first serve.
3096 BOOL SystemDomain::SetGlobalSharePolicyUsingAttribute(IMDInternalImport* pScope, mdMethodDef mdMethod)
3098 STANDARD_VM_CONTRACT;
3104 void SystemDomain::SetupDefaultDomain()
3111 INJECT_FAULT(COMPlusThrowOM(););
3116 Thread *pThread = GetThread();
3120 pDomain = pThread->GetDomain();
3125 ENTER_DOMAIN_PTR(SystemDomain::System()->DefaultDomain(),ADV_DEFAULTAD)
3127 // Push this frame around loading the main assembly to ensure the
3128 // debugger can properly recgonize any managed code that gets run
3129 // as "class initializaion" code.
3130 FrameWithCookie<DebuggerClassInitMarkFrame> __dcimf;
3134 InitializeDefaultDomain(TRUE);
3139 END_DOMAIN_TRANSITION;
3144 HRESULT SystemDomain::SetupDefaultDomainNoThrow()
3157 SystemDomain::SetupDefaultDomain();
3159 EX_CATCH_HRESULT(hr);
3165 int g_fInitializingInitialAD = 0;
3168 // This routine completes the initialization of the default domaine.
3169 // After this call mananged code can be executed.
3170 void SystemDomain::InitializeDefaultDomain(
3171 BOOL allowRedirects,
3172 ICLRPrivBinder * pBinder)
3174 STANDARD_VM_CONTRACT;
3176 WCHAR* pwsConfig = NULL;
3177 WCHAR* pwsPath = NULL;
3179 ETWOnStartup (InitDefaultDomain_V1, InitDefaultDomainEnd_V1);
3182 // Setup the default AppDomain.
3185 g_fInitializingInitialAD++;
3188 AppDomain* pDefaultDomain = SystemDomain::System()->DefaultDomain();
3190 if (pBinder != nullptr)
3192 pDefaultDomain->SetLoadContextHostBinder(pBinder);
3198 pDefaultDomain->InitializeDomainContext(allowRedirects, pwsPath, pwsConfig);
3200 #ifndef CROSSGEN_COMPILE
3201 if (!NingenEnabled())
3204 if (!IsSingleAppDomain())
3206 pDefaultDomain->InitializeDefaultDomainManager();
3209 #endif // CROSSGEN_COMPILE
3212 // DefaultDomain Load event
3213 ETW::LoaderLog::DomainLoad(pDefaultDomain);
3216 g_fInitializingInitialAD--;
3219 TESTHOOKCALL(RuntimeStarted(RTS_DEFAULTADREADY));
3224 #ifndef CROSSGEN_COMPILE
3227 Volatile<LONG> g_fInExecuteMainMethod = 0;
3233 #endif // CROSSGEN_COMPILE
3237 // Helper function to load an assembly. This is called from LoadCOMClass.
3240 Assembly *AppDomain::LoadAssemblyHelper(LPCWSTR wszAssembly,
3241 LPCWSTR wszCodeBase)
3243 CONTRACT(Assembly *)
3246 POSTCONDITION(CheckPointer(RETVAL));
3247 PRECONDITION(wszAssembly || wszCodeBase);
3248 INJECT_FAULT(COMPlusThrowOM(););
3254 #define MAKE_TRANSLATIONFAILED { ThrowOutOfMemory(); }
3255 MAKE_UTF8PTR_FROMWIDE(szAssembly,wszAssembly);
3256 #undef MAKE_TRANSLATIONFAILED
3258 IfFailThrow(spec.Init(szAssembly));
3262 spec.SetCodeBase(wszCodeBase);
3264 RETURN spec.LoadAssembly(FILE_LOADED);
3267 #if defined(FEATURE_CLASSIC_COMINTEROP) && !defined(CROSSGEN_COMPILE)
3269 MethodTable *AppDomain::LoadCOMClass(GUID clsid,
3270 BOOL bLoadRecord/*=FALSE*/,
3271 BOOL* pfAssemblyInReg/*=NULL*/)
3273 // @CORESYSTODO: what to do here?
3277 #endif // FEATURE_CLASSIC_COMINTEROP && !CROSSGEN_COMPILE
3281 bool SystemDomain::IsReflectionInvocationMethod(MethodDesc* pMeth)
3291 MethodTable* pCaller = pMeth->GetMethodTable();
3293 // All Reflection Invocation methods are defined in mscorlib.dll
3294 if (!pCaller->GetModule()->IsSystem())
3297 /* List of types that should be skipped to identify true caller */
3298 static const BinderClassID reflectionInvocationTypes[] = {
3303 CLASS__CONSTRUCTOR_INFO,
3306 CLASS__METHOD_HANDLE,
3307 CLASS__FIELD_HANDLE,
3310 CLASS__RT_FIELD_INFO,
3315 CLASS__PROPERTY_INFO,
3318 CLASS__ASSEMBLYBASE,
3320 CLASS__TYPE_DELEGATOR,
3321 CLASS__RUNTIME_HELPERS,
3322 CLASS__LAZY_INITIALIZER,
3323 CLASS__DYNAMICMETHOD,
3325 CLASS__MULTICAST_DELEGATE,
3329 static const BinderClassID genericReflectionInvocationTypes[] = {
3333 static mdTypeDef genericReflectionInvocationTypeDefs[NumItems(genericReflectionInvocationTypes)];
3335 static bool fInited = false;
3337 if (!VolatileLoad(&fInited))
3339 // Make sure all types are loaded so that we can use faster GetExistingClass()
3340 for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3342 MscorlibBinder::GetClass(reflectionInvocationTypes[i]);
3345 // Make sure all types are loaded so that we can use faster GetExistingClass()
3346 for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypes); i++)
3348 genericReflectionInvocationTypeDefs[i] = MscorlibBinder::GetClass(genericReflectionInvocationTypes[i])->GetCl();
3351 MscorlibBinder::GetClass(CLASS__APP_DOMAIN);
3353 VolatileStore(&fInited, true);
3356 if (pCaller->HasInstantiation())
3358 // For generic types, pCaller will be an instantiated type and never equal to the type definition.
3359 // So we compare their TypeDef tokens instead.
3360 for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypeDefs); i++)
3362 if (pCaller->GetCl() == genericReflectionInvocationTypeDefs[i])
3368 for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3370 if (MscorlibBinder::GetExistingClass(reflectionInvocationTypes[i]) == pCaller)
3378 #ifndef CROSSGEN_COMPILE
3379 struct CallersDataWithStackMark
3381 StackCrawlMark* stackMark;
3383 MethodDesc* pFoundMethod;
3384 MethodDesc* pPrevMethod;
3385 AppDomain* pAppDomain;
3389 MethodDesc* SystemDomain::GetCallersMethod(StackCrawlMark* stackMark,
3390 AppDomain **ppAppDomain/*=NULL*/)
3398 INJECT_FAULT(COMPlusThrowOM(););
3404 CallersDataWithStackMark cdata;
3405 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3406 cdata.stackMark = stackMark;
3408 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3410 if(cdata.pFoundMethod) {
3412 *ppAppDomain = cdata.pAppDomain;
3413 return cdata.pFoundMethod;
3419 MethodTable* SystemDomain::GetCallersType(StackCrawlMark* stackMark,
3420 AppDomain **ppAppDomain/*=NULL*/)
3428 INJECT_FAULT(COMPlusThrowOM(););
3432 CallersDataWithStackMark cdata;
3433 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3434 cdata.stackMark = stackMark;
3436 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3438 if(cdata.pFoundMethod) {
3440 *ppAppDomain = cdata.pAppDomain;
3441 return cdata.pFoundMethod->GetMethodTable();
3447 Module* SystemDomain::GetCallersModule(StackCrawlMark* stackMark,
3448 AppDomain **ppAppDomain/*=NULL*/)
3456 INJECT_FAULT(COMPlusThrowOM(););
3462 CallersDataWithStackMark cdata;
3463 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3464 cdata.stackMark = stackMark;
3466 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3468 if(cdata.pFoundMethod) {
3470 *ppAppDomain = cdata.pAppDomain;
3471 return cdata.pFoundMethod->GetModule();
3479 MethodDesc* pMethod;
3483 Assembly* SystemDomain::GetCallersAssembly(StackCrawlMark *stackMark,
3484 AppDomain **ppAppDomain/*=NULL*/)
3486 WRAPPER_NO_CONTRACT;
3487 Module* mod = GetCallersModule(stackMark, ppAppDomain);
3489 return mod->GetAssembly();
3494 Module* SystemDomain::GetCallersModule(int skip)
3501 INJECT_FAULT(COMPlusThrowOM(););
3508 ZeroMemory(&cdata, sizeof(CallersData));
3511 StackWalkFunctions(GetThread(), CallersMethodCallback, &cdata);
3514 return cdata.pMethod->GetModule();
3520 StackWalkAction SystemDomain::CallersMethodCallbackWithStackMark(CrawlFrame* pCf, VOID* data)
3528 INJECT_FAULT(COMPlusThrowOM(););
3533 MethodDesc *pFunc = pCf->GetFunction();
3535 /* We asked to be called back only for functions */
3538 CallersDataWithStackMark* pCaller = (CallersDataWithStackMark*) data;
3539 if (pCaller->stackMark)
3541 if (!pCf->IsInCalleesFrames(pCaller->stackMark))
3543 // save the current in case it is the one we want
3544 pCaller->pPrevMethod = pFunc;
3545 pCaller->pAppDomain = pCf->GetAppDomain();
3546 return SWA_CONTINUE;
3549 // LookForMe stack crawl marks needn't worry about reflection or
3550 // remoting frames on the stack. Each frame above (newer than) the
3551 // target will be captured by the logic above. Once we transition to
3552 // finding the stack mark below the AofRA, we know that we hit the
3553 // target last time round and immediately exit with the cached result.
3555 if (*(pCaller->stackMark) == LookForMe)
3557 pCaller->pFoundMethod = pCaller->pPrevMethod;
3562 // Skip reflection and remoting frames that could lie between a stack marked
3563 // method and its true caller (or that caller and its own caller). These
3564 // frames are infrastructure and logically transparent to the stack crawling
3567 // Skipping remoting frames. We always skip entire client to server spans
3568 // (though we see them in the order server then client during a stack crawl
3571 // We spot the server dispatcher end because all calls are dispatched
3572 // through a single method: StackBuilderSink._PrivateProcessMessage.
3574 Frame* frame = pCf->GetFrame();
3575 _ASSERTE(pCf->IsFrameless() || frame);
3579 // Skipping reflection frames. We don't need to be quite as exhaustive here
3580 // as the security or reflection stack walking code since we know this logic
3581 // is only invoked for selected methods in mscorlib itself. So we're
3582 // reasonably sure we won't have any sensitive methods late bound invoked on
3583 // constructors, properties or events. This leaves being invoked via
3584 // MethodInfo, Type or Delegate (and depending on which invoke overload is
3585 // being used, several different reflection classes may be involved).
3587 g_IBCLogger.LogMethodDescAccess(pFunc);
3589 if (SystemDomain::IsReflectionInvocationMethod(pFunc))
3590 return SWA_CONTINUE;
3592 if (frame && frame->GetFrameType() == Frame::TYPE_MULTICAST)
3594 // This must be either a secure delegate frame or a true multicast delegate invocation.
3596 _ASSERTE(pFunc->GetMethodTable()->IsDelegate());
3598 DELEGATEREF del = (DELEGATEREF)((SecureDelegateFrame*)frame)->GetThis(); // This can throw.
3600 if (COMDelegate::IsSecureDelegate(del))
3602 if (del->IsWrapperDelegate())
3604 // On ARM, we use secure delegate infrastructure to preserve R4 register.
3605 return SWA_CONTINUE;
3607 // For a secure delegate frame, we should return the delegate creator instead
3608 // of the delegate method itself.
3609 pFunc = (MethodDesc*) del->GetMethodPtrAux();
3613 _ASSERTE(COMDelegate::IsTrueMulticastDelegate(del));
3614 return SWA_CONTINUE;
3618 // Return the first non-reflection/remoting frame if no stack mark was
3620 if (!pCaller->stackMark)
3622 pCaller->pFoundMethod = pFunc;
3623 pCaller->pAppDomain = pCf->GetAppDomain();
3627 // If we got here, we must already be in the frame containing the stack mark and we are not looking for "me".
3628 _ASSERTE(pCaller->stackMark &&
3629 pCf->IsInCalleesFrames(pCaller->stackMark) &&
3630 *(pCaller->stackMark) != LookForMe);
3632 // When looking for caller's caller, we delay returning results for another
3633 // round (the way this is structured, we will still be able to skip
3634 // reflection and remoting frames between the caller and the caller's
3637 if ((*(pCaller->stackMark) == LookForMyCallersCaller) &&
3638 (pCaller->pFoundMethod == NULL))
3640 pCaller->pFoundMethod = pFunc;
3641 return SWA_CONTINUE;
3644 // If remoting is not available, we only set the caller if the crawlframe is from the same domain.
3645 // Why? Because if the callerdomain is different from current domain,
3646 // there have to be interop/native frames in between.
3647 // For example, in the CORECLR, if we find the caller to be in a different domain, then the
3648 // call into reflection is due to an unmanaged call into mscorlib. For that
3649 // case, the caller really is an INTEROP method.
3650 // In general, if the caller is INTEROP, we set the caller/callerdomain to be NULL
3651 // (To be precise: they are already NULL and we don't change them).
3652 if (pCf->GetAppDomain() == GetAppDomain())
3653 // We must either be looking for the caller, or the caller's caller when
3654 // we've already found the caller (we used a non-null value in pFoundMethod
3655 // simply as a flag, the correct method to return in both case is the
3658 pCaller->pFoundMethod = pFunc;
3659 pCaller->pAppDomain = pCf->GetAppDomain();
3666 StackWalkAction SystemDomain::CallersMethodCallback(CrawlFrame* pCf, VOID* data)
3668 LIMITED_METHOD_CONTRACT;
3669 STATIC_CONTRACT_SO_TOLERANT;
3670 MethodDesc *pFunc = pCf->GetFunction();
3672 /* We asked to be called back only for functions */
3675 CallersData* pCaller = (CallersData*) data;
3676 if(pCaller->skip == 0) {
3677 pCaller->pMethod = pFunc;
3682 return SWA_CONTINUE;
3686 #endif // CROSSGEN_COMPILE
3688 #ifdef CROSSGEN_COMPILE
3689 // defined in compile.cpp
3690 extern CompilationDomain * theDomain;
3693 void SystemDomain::CreateDefaultDomain()
3695 STANDARD_VM_CONTRACT;
3697 #ifdef CROSSGEN_COMPILE
3698 AppDomainRefHolder pDomain(theDomain);
3700 AppDomainRefHolder pDomain(new AppDomain());
3703 SystemDomain::LockHolder lh;
3706 // need to make this assignment here since we'll be releasing
3707 // the lock before calling AddDomain. So any other thread
3708 // grabbing this lock after we release it will find that
3709 // the COM Domain has already been created
3710 m_pDefaultDomain = pDomain;
3711 _ASSERTE (pDomain->GetId().m_dwId == DefaultADID);
3713 // allocate a Virtual Call Stub Manager for the default domain
3714 m_pDefaultDomain->InitVSD();
3716 pDomain->SetStage(AppDomain::STAGE_OPEN);
3717 pDomain.SuppressRelease();
3719 LOG((LF_CLASSLOADER | LF_CORDB,
3721 "Created default domain at %p\n", m_pDefaultDomain));
3724 #ifdef DEBUGGING_SUPPORTED
3726 void SystemDomain::PublishAppDomainAndInformDebugger (AppDomain *pDomain)
3730 if(!g_fEEInit) {THROWS;} else {DISABLED(NOTHROW);};
3731 if(!g_fEEInit) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);};
3736 LOG((LF_CORDB, LL_INFO100, "SD::PADAID: Adding 0x%x\n", pDomain));
3738 // Call the publisher API to add this appdomain entry to the list
3739 // The publisher will handle failures, so we don't care if this succeeds or fails.
3740 if (g_pDebugInterface != NULL)
3742 g_pDebugInterface->AddAppDomainToIPC(pDomain);
3746 #endif // DEBUGGING_SUPPORTED
3748 void SystemDomain::AddDomain(AppDomain* pDomain)
3755 PRECONDITION(CheckPointer((pDomain)));
3762 _ASSERTE (pDomain->m_Stage != AppDomain::STAGE_CREATING);
3763 if (pDomain->m_Stage == AppDomain::STAGE_READYFORMANAGEDCODE ||
3764 pDomain->m_Stage == AppDomain::STAGE_ACTIVE)
3766 pDomain->SetStage(AppDomain::STAGE_OPEN);
3767 IncrementNumAppDomains(); // Maintain a count of app domains added to the list.
3771 // Note that if you add another path that can reach here without calling
3772 // PublishAppDomainAndInformDebugger, then you should go back & make sure
3773 // that PADAID gets called. Right after this call, if not sooner.
3774 LOG((LF_CORDB, LL_INFO1000, "SD::AD:Would have added domain here! 0x%x\n",
3778 BOOL SystemDomain::RemoveDomain(AppDomain* pDomain)
3785 PRECONDITION(CheckPointer(pDomain));
3786 PRECONDITION(!pDomain->IsDefaultDomain());
3790 // You can not remove the default domain.
3793 if (!pDomain->IsActive())
3802 #ifdef PROFILING_SUPPORTED
3803 void SystemDomain::NotifyProfilerStartup()
3814 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3816 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System());
3821 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3823 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System(), S_OK);
3828 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3829 _ASSERTE(System()->DefaultDomain());
3830 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System()->DefaultDomain());
3835 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3836 _ASSERTE(System()->DefaultDomain());
3837 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3842 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3843 _ASSERTE(SharedDomain::GetDomain());
3844 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) SharedDomain::GetDomain());
3849 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3850 _ASSERTE(SharedDomain::GetDomain());
3851 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) SharedDomain::GetDomain(), S_OK);
3856 HRESULT SystemDomain::NotifyProfilerShutdown()
3867 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3869 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System());
3874 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3876 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System(), S_OK);
3881 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3882 _ASSERTE(System()->DefaultDomain());
3883 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System()->DefaultDomain());
3888 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3889 _ASSERTE(System()->DefaultDomain());
3890 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3895 #endif // PROFILING_SUPPORTED
3899 struct AppDomain::ThreadTrackInfo {
3901 CDynArray<Frame *> frameStack;
3905 AppDomain::AppDomain()
3907 // initialize fields so the appdomain can be safely destructed
3908 // shouldn't call anything that can fail here - use ::Init instead
3919 m_pNextInDelayedUnloadList = NULL;
3920 m_fRudeUnload = FALSE;
3921 m_pUnloadRequestThread = NULL;
3922 m_ADUnloadSink=NULL;
3925 // Initialize Shared state. Assemblies are loaded
3926 // into each domain by default.
3927 #ifdef FEATURE_LOADER_OPTIMIZATION
3928 m_SharePolicy = SHARE_POLICY_UNSPECIFIED;
3931 m_pRootAssembly = NULL;
3933 m_pwDynamicDir = NULL;
3936 m_pDefaultContext = NULL;
3937 #ifdef FEATURE_COMINTEROP
3938 m_pComCallWrapperCache = NULL;
3940 m_pRCWRefCache = NULL;
3941 m_pLicenseInteropHelperMT = NULL;
3942 m_COMorRemotingFlag = COMorRemoting_NotInitialized;
3943 memset(m_rpCLRTypes, 0, sizeof(m_rpCLRTypes));
3944 #endif // FEATURE_COMINTEROP
3946 m_pUMEntryThunkCache = NULL;
3948 m_pAsyncPool = NULL;
3949 m_handleStore = NULL;
3951 m_ExposedObject = NULL;
3952 m_pComIPForExposedObject = NULL;
3955 m_pThreadTrackInfoList = NULL;
3956 m_TrackSpinLock = 0;
3957 m_Assemblies.Debug_SetAppDomain(this);
3960 m_dwThreadEnterCount = 0;
3961 m_dwThreadsStillInAppDomain = (ULONG)-1;
3963 #ifdef FEATURE_COMINTEROP
3964 m_pRefDispIDCache = NULL;
3965 m_hndMissing = NULL;
3968 m_pRefClassFactHash = NULL;
3969 m_anonymouslyHostedDynamicMethodsAssembly = NULL;
3971 m_ReversePInvokeCanEnter=TRUE;
3972 m_ForceTrivialWaitOperations = false;
3973 m_Stage=STAGE_CREATING;
3975 m_bForceGCOnUnload=FALSE;
3976 m_bUnloadingFromUnloadEvent=FALSE;
3980 m_dwCreationHolders=0;
3983 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3984 m_ullTotalProcessorUsage = 0;
3985 m_pullAllocBytes = NULL;
3986 m_pullSurvivedBytes = NULL;
3987 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3989 #ifdef FEATURE_TYPEEQUIVALENCE
3990 m_pTypeEquivalenceTable = NULL;
3991 #endif // FEATURE_TYPEEQUIVALENCE
3993 #ifdef FEATURE_COMINTEROP
3994 m_pNameToTypeMap = NULL;
3995 m_vNameToTypeMapVersion = 0;
3997 m_pWinRTFactoryCache = NULL;
3998 #endif // FEATURE_COMINTEROP
4000 #ifdef FEATURE_PREJIT
4001 m_pDomainFileWithNativeImageList = NULL;
4004 m_fIsBindingModelLocked.Store(FALSE);
4006 } // AppDomain::AppDomain
4008 AppDomain::~AppDomain()
4018 #ifndef CROSSGEN_COMPILE
4020 _ASSERTE(m_dwCreationHolders == 0);
4022 // release the TPIndex. note that since TPIndex values are recycled the TPIndex
4023 // can only be released once all threads in the AppDomain have exited.
4024 if (GetTPIndex().m_dwIndex != 0)
4025 PerAppDomainTPCountList::ResetAppDomainIndex(GetTPIndex());
4027 if (m_dwId.m_dwId!=0)
4028 SystemDomain::ReleaseAppDomainId(m_dwId);
4030 m_AssemblyCache.Clear();
4033 m_ADUnloadSink->Release();
4041 #ifdef FEATURE_COMINTEROP
4042 if (m_pNameToTypeMap != nullptr)
4044 delete m_pNameToTypeMap;
4045 m_pNameToTypeMap = nullptr;
4047 if (m_pWinRTFactoryCache != nullptr)
4049 delete m_pWinRTFactoryCache;
4050 m_pWinRTFactoryCache = nullptr;
4052 #endif //FEATURE_COMINTEROP
4055 // If we were tracking thread AD transitions, cleanup the list on shutdown
4056 if (m_pThreadTrackInfoList)
4058 while (m_pThreadTrackInfoList->Count() > 0)
4060 // Get the very last element
4061 ThreadTrackInfo *pElem = *(m_pThreadTrackInfoList->Get(m_pThreadTrackInfoList->Count() - 1));
4067 // Remove pointer entry from the list
4068 m_pThreadTrackInfoList->Delete(m_pThreadTrackInfoList->Count() - 1);
4071 // Now delete the list itself
4072 delete m_pThreadTrackInfoList;
4073 m_pThreadTrackInfoList = NULL;
4077 #endif // CROSSGEN_COMPILE
4080 //*****************************************************************************
4081 //*****************************************************************************
4082 //*****************************************************************************
4083 void AppDomain::Init()
4088 PRECONDITION(SystemDomain::IsUnderDomainLock());
4092 m_pDelayedLoaderAllocatorUnloadList = NULL;
4094 SetStage( STAGE_CREATING);
4097 // The lock is taken also during stack walking (GC or profiler)
4098 // - To prevent deadlock with GC thread, we cannot trigger GC while holding the lock
4099 // - To prevent deadlock with profiler thread, we cannot allow thread suspension
4100 m_crstHostAssemblyMap.Init(
4101 CrstHostAssemblyMap,
4102 (CrstFlags)(CRST_GC_NOTRIGGER_WHEN_TAKEN
4103 | CRST_DEBUGGER_THREAD
4104 INDEBUG(| CRST_DEBUG_ONLY_CHECK_FORBID_SUSPEND_THREAD)));
4105 m_crstHostAssemblyMapAdd.Init(CrstHostAssemblyMapAdd);
4107 m_dwId = SystemDomain::GetNewAppDomainId(this);
4109 m_LoaderAllocator.Init(this);
4111 #ifndef CROSSGEN_COMPILE
4112 //Allocate the threadpool entry before the appdomin id list. Otherwise,
4113 //the thread pool list will be out of sync if insertion of id in
4114 //the appdomain fails.
4115 m_tpIndex = PerAppDomainTPCountList::AddNewTPIndex();
4116 #endif // CROSSGEN_COMPILE
4118 m_dwIndex = SystemDomain::GetNewAppDomainIndex(this);
4120 #ifndef CROSSGEN_COMPILE
4121 PerAppDomainTPCountList::SetAppDomainId(m_tpIndex, m_dwId);
4123 m_ADUnloadSink=new ADUnloadSink();
4128 // Set up the IL stub cache
4129 m_ILStubCache.Init(GetLoaderAllocator()->GetHighFrequencyHeap());
4131 // Set up the binding caches
4132 m_AssemblyCache.Init(&m_DomainCacheCrst, GetHighFrequencyHeap());
4133 m_UnmanagedCache.InitializeTable(this, &m_DomainCacheCrst);
4135 m_MemoryPressure = 0;
4137 m_sDomainLocalBlock.Init(this);
4139 #ifndef CROSSGEN_COMPILE
4141 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4142 // NOTE: it's important that we initialize ARM data structures before calling
4143 // Ref_CreateHandleTableBucket, this is because AD::Init() can race with GC
4144 // and once we add ourselves to the handle table map the GC can start walking
4145 // our handles and calling AD::RecordSurvivedBytes() which touches ARM data.
4146 if (GCHeapUtilities::IsServerHeap())
4147 m_dwNumHeaps = CPUGroupInfo::CanEnableGCCPUGroups() ?
4148 CPUGroupInfo::GetNumActiveProcessors() :
4149 GetCurrentProcessCpuCount();
4152 m_pullAllocBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
4153 m_pullSurvivedBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
4154 for (DWORD i = 0; i < m_dwNumHeaps; i++)
4156 m_pullAllocBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
4157 m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
4159 m_ullLastEtwAllocBytes = 0;
4160 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4162 // Default domain reuses the handletablemap that was created during EEStartup since
4163 // default domain cannot be unloaded.
4164 if (GetId().m_dwId == DefaultADID)
4166 m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
4170 m_handleStore = GCHandleUtilities::GetGCHandleManager()->CreateHandleStore((void*)(uintptr_t)m_dwIndex.m_dwIndex);
4178 #endif // CROSSGEN_COMPILE
4180 #ifdef FEATURE_TYPEEQUIVALENCE
4181 m_TypeEquivalenceCrst.Init(CrstTypeEquivalenceMap);
4184 m_ReflectionCrst.Init(CrstReflection, CRST_UNSAFE_ANYMODE);
4185 m_RefClassFactCrst.Init(CrstClassFactInfoHash);
4188 LockOwner lock = {&m_DomainCrst, IsOwnerOfCrst};
4189 m_clsidHash.Init(0,&CompareCLSID,true, &lock); // init hash table
4192 SetStage(STAGE_READYFORMANAGEDCODE);
4194 #ifndef CROSSGEN_COMPILE
4195 m_pDefaultContext = new Context(this);
4197 m_ExposedObject = CreateHandle(NULL);
4199 // Create the Application Security Descriptor
4201 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains++);
4203 #ifdef FEATURE_COMINTEROP
4204 if (!AppX::IsAppXProcess())
4207 #endif //FEATURE_COMINTEROP
4209 #ifdef FEATURE_TIERED_COMPILATION
4210 m_tieredCompilationManager.Init(GetId());
4212 #endif // CROSSGEN_COMPILE
4213 } // AppDomain::Init
4216 /*********************************************************************/
4218 BOOL AppDomain::IsCompilationDomain()
4220 LIMITED_METHOD_CONTRACT;
4222 BOOL isCompilationDomain = (m_dwFlags & COMPILATION_DOMAIN) != 0;
4223 #ifdef FEATURE_PREJIT
4224 _ASSERTE(!isCompilationDomain ||
4225 (IsCompilationProcess() && IsPassiveDomain()));
4226 #endif // FEATURE_PREJIT
4227 return isCompilationDomain;
4230 #ifndef CROSSGEN_COMPILE
4232 extern int g_fADUnloadWorkerOK;
4235 // This helper will send the AppDomain creation notifications for profiler / debugger.
4236 // If it throws, its backout code will also send a notification.
4237 // If it succeeds, then we still need to send a AppDomainCreateFinished notification.
4238 void AppDomain::CreateUnmanagedObject(AppDomainCreationHolder<AppDomain>& pDomain)
4245 INJECT_FAULT(COMPlusThrowOM(););
4251 pDomain.Assign(new AppDomain());
4252 if (g_fADUnloadWorkerOK<0)
4254 AppDomain::CreateADUnloadWorker();
4258 // We addref Appdomain object here and notify a profiler that appdomain
4259 // creation has started, then return to managed code which will call
4260 // the function that releases the appdomain and notifies a profiler that we finished
4261 // creating the appdomain. If an exception is raised while we're in that managed code
4262 // we will leak memory and the profiler will not be notified about the failure
4264 #ifdef PROFILING_SUPPORTED
4265 // Signal profile if present.
4267 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
4268 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) (AppDomain*) pDomain);
4272 #endif // PROFILING_SUPPORTED
4275 SystemDomain::LockHolder lh;
4277 // allocate a Virtual Call Stub Manager for this domain
4281 pDomain->SetCanUnload(); // by default can unload any domain
4283 #ifdef DEBUGGING_SUPPORTED
4284 // Notify the debugger here, before the thread transitions into the
4285 // AD to finish the setup, and before any assemblies are loaded into it.
4286 SystemDomain::PublishAppDomainAndInformDebugger(pDomain);
4287 #endif // DEBUGGING_SUPPORTED
4289 STRESS_LOG2 (LF_APPDOMAIN, LL_INFO100, "Create domain [%d] %p\n", pDomain->GetId().m_dwId, (AppDomain*)pDomain);
4290 pDomain->LoadSystemAssemblies();
4291 pDomain->SetupSharedStatics();
4293 pDomain->SetStage(AppDomain::STAGE_ACTIVE);
4295 #ifdef PROFILING_SUPPORTED
4298 // Need the first assembly loaded in to get any data on an app domain.
4300 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
4301 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID)(AppDomain*) pDomain, GET_EXCEPTION()->GetHR());
4307 // On success, caller must still send the AppDomainCreationFinished notification.
4308 #endif // PROFILING_SUPPORTED
4311 void AppDomain::Stop()
4321 #ifdef FEATURE_MULTICOREJIT
4322 GetMulticoreJitManager().StopProfile(true);
4325 // Set the unloaded flag before notifying the debugger
4326 GetLoaderAllocator()->SetIsUnloaded();
4328 #ifdef DEBUGGING_SUPPORTED
4329 if (IsDebuggerAttached())
4330 NotifyDebuggerUnload();
4331 #endif // DEBUGGING_SUPPORTED
4333 m_pRootAssembly = NULL; // This assembly is in the assembly list;
4335 #ifdef DEBUGGING_SUPPORTED
4336 if (NULL != g_pDebugInterface)
4338 // Call the publisher API to delete this appdomain entry from the list
4339 CONTRACT_VIOLATION(ThrowsViolation);
4340 g_pDebugInterface->RemoveAppDomainFromIPC (this);
4342 #endif // DEBUGGING_SUPPORTED
4345 void AppDomain::Terminate()
4358 _ASSERTE(m_dwThreadEnterCount == 0 || IsDefaultDomain());
4360 if (m_pComIPForExposedObject)
4362 m_pComIPForExposedObject->Release();
4363 m_pComIPForExposedObject = NULL;
4366 delete m_pDefaultContext;
4367 m_pDefaultContext = NULL;
4369 if (m_pUMEntryThunkCache)
4371 delete m_pUMEntryThunkCache;
4372 m_pUMEntryThunkCache = NULL;
4375 #ifdef FEATURE_COMINTEROP
4384 delete m_pRCWRefCache;
4385 m_pRCWRefCache = NULL;
4388 if (m_pComCallWrapperCache)
4390 m_pComCallWrapperCache->Neuter();
4391 m_pComCallWrapperCache->Release();
4394 // if the above released the wrapper cache, then it will call back and reset our
4395 // m_pComCallWrapperCache to null. If not null, then need to set it's domain pointer to
4397 if (! m_pComCallWrapperCache)
4399 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::Terminate ComCallWrapperCache released\n"));
4404 m_pComCallWrapperCache = NULL;
4405 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::Terminate ComCallWrapperCache not released\n"));
4409 #endif // FEATURE_COMINTEROP
4412 if (!IsAtProcessExit())
4414 // if we're not shutting down everything then clean up the string literals associated
4415 // with this appdomain -- note that is no longer needs to happen while suspended
4416 // because the appropriate locks are taken in the GlobalStringLiteralMap
4417 // this is important as this locks have a higher lock number than does the
4418 // thread-store lock which is taken when we suspend.
4419 GetLoaderAllocator()->CleanupStringLiteralMap();
4421 // Suspend the EE to do some clean up that can only occur
4422 // while no threads are running.
4423 GCX_COOP (); // SuspendEE may require current thread to be in Coop mode
4424 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
4427 // Note that this must be performed before restarting the EE. It will clean
4428 // the cache and prevent others from using stale cache entries.
4429 //@TODO: Would be nice to get this back to BaseDomain, but need larger fix for that.
4430 // NOTE: Must have the runtime suspended to unlink managers
4431 // NOTE: May be NULL due to OOM during initialization. Can skip in that case.
4432 GetLoaderAllocator()->UninitVirtualCallStubManager();
4433 MethodTable::ClearMethodDataCache();
4434 ClearJitGenericHandleCache(this);
4436 // @TODO s_TPMethodTableCrst prevents us from from keeping the whole
4437 // assembly shutdown logic here. See if we can do better in the next milestone
4438 #ifdef FEATURE_PREJIT
4439 DeleteNativeCodeRanges();
4442 if (!IsAtProcessExit())
4445 ThreadSuspend::RestartEE(FALSE, TRUE);
4448 ShutdownAssemblies();
4449 ShutdownNativeDllSearchDirectories();
4451 if (m_pRefClassFactHash)
4453 m_pRefClassFactHash->Destroy();
4454 // storage for m_pRefClassFactHash itself is allocated on the loader heap
4457 #ifdef FEATURE_TYPEEQUIVALENCE
4458 m_TypeEquivalenceCrst.Destroy();
4461 m_ReflectionCrst.Destroy();
4462 m_RefClassFactCrst.Destroy();
4464 m_LoaderAllocator.Terminate();
4466 BaseDomain::Terminate();
4470 GCHandleUtilities::GetGCHandleManager()->DestroyHandleStore(m_handleStore);
4471 m_handleStore = NULL;
4474 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4475 if (m_pullAllocBytes)
4477 delete [] m_pullAllocBytes;
4479 if (m_pullSurvivedBytes)
4481 delete [] m_pullSurvivedBytes;
4483 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4485 if(m_dwIndex.m_dwIndex != 0)
4486 SystemDomain::ReleaseAppDomainIndex(m_dwIndex);
4487 } // AppDomain::Terminate
4489 void AppDomain::CloseDomain()
4500 BOOL bADRemoved=FALSE;;
4502 AddRef(); // Hold a reference
4503 AppDomainRefHolder AdHolder(this);
4505 SystemDomain::LockHolder lh;
4507 SystemDomain::System()->DecrementNumAppDomains(); // Maintain a count of app domains added to the list.
4508 bADRemoved = SystemDomain::System()->RemoveDomain(this);
4515 /*********************************************************************/
4517 struct GetExposedObject_Args
4523 static void GetExposedObject_Wrapper(LPVOID ptr)
4532 GetExposedObject_Args *args = (GetExposedObject_Args *) ptr;
4533 *(args->ref) = args->pDomain->GetExposedObject();
4537 OBJECTREF AppDomain::GetExposedObject()
4544 INJECT_FAULT(COMPlusThrowOM(););
4548 OBJECTREF ref = GetRawExposedObject();
4551 APPDOMAINREF obj = NULL;
4553 Thread *pThread = GetThread();
4554 if (pThread->GetDomain() != this)
4556 GCPROTECT_BEGIN(ref);
4557 GetExposedObject_Args args = {this, &ref};
4558 // call through DoCallBack with a domain transition
4559 pThread->DoADCallBack(this,GetExposedObject_Wrapper, &args,ADV_CREATING|ADV_RUNNINGIN);
4563 MethodTable *pMT = MscorlibBinder::GetClass(CLASS__APP_DOMAIN);
4565 // Create the module object
4566 obj = (APPDOMAINREF) AllocateObject(pMT);
4567 obj->SetDomain(this);
4569 if (!StoreFirstObjectInHandle(m_ExposedObject, (OBJECTREF) obj))
4571 obj = (APPDOMAINREF) GetRawExposedObject();
4575 return (OBJECTREF) obj;
4583 OBJECTREF AppDomain::DoSetup(OBJECTREF* setupInfo)
4590 INJECT_FAULT(COMPlusThrowOM(););
4594 ADID adid=GetAppDomain()->GetId();
4596 OBJECTREF retval=NULL;
4597 GCPROTECT_BEGIN(retval);
4599 ENTER_DOMAIN_PTR(this,ADV_CREATING);
4601 MethodDescCallSite setup(METHOD__APP_DOMAIN__SETUP);
4605 args[0]=ObjToArgSlot(*setupInfo);
4607 OBJECTREF activator;
4608 activator=setup.Call_RetOBJECTREF(args);
4609 _ASSERTE(activator==NULL);
4611 #if defined(FEATURE_MULTICOREJIT)
4612 // Disable AutoStartProfile in default domain from this code path.
4613 // It's called from SystemDomain::ExecuteMainMethod for normal program, not needed for SL and Asp.Net
4614 if (! IsDefaultDomain())
4618 GetMulticoreJitManager().AutoStartProfile(this);
4622 END_DOMAIN_TRANSITION;
4627 #endif // !CROSSGEN_COMPILE
4629 #ifdef FEATURE_COMINTEROP
4630 #ifndef CROSSGEN_COMPILE
4631 HRESULT AppDomain::GetComIPForExposedObject(IUnknown **pComIP)
4633 // Assumption: This function is called for AppDomain's that the current
4634 // thread is in or has entered, or the AppDomain is kept alive.
4636 // Assumption: This function can now throw. The caller is responsible for any
4637 // BEGIN_EXTERNAL_ENTRYPOINT, EX_TRY, or other
4638 // techniques to convert to a COM HRESULT protocol.
4648 Thread *pThread = GetThread();
4649 if (m_pComIPForExposedObject)
4651 GCX_PREEMP_THREAD_EXISTS(pThread);
4652 m_pComIPForExposedObject->AddRef();
4653 *pComIP = m_pComIPForExposedObject;
4657 IUnknown* punk = NULL;
4659 OBJECTREF ref = NULL;
4660 GCPROTECT_BEGIN(ref);
4664 ENTER_DOMAIN_PTR(this,ADV_DEFAULTAD)
4666 ref = GetExposedObject();
4667 punk = GetComIPFromObjectRef(&ref);
4668 if (FastInterlockCompareExchangePointer(&m_pComIPForExposedObject, punk, NULL) == NULL)
4670 GCX_PREEMP_THREAD_EXISTS(pThread);
4671 m_pComIPForExposedObject->AddRef();
4674 END_DOMAIN_TRANSITION;
4680 *pComIP = m_pComIPForExposedObject;
4685 #endif //#ifndef CROSSGEN_COMPILE
4687 MethodTable *AppDomain::GetRedirectedType(WinMDAdapter::RedirectedTypeIndex index)
4697 // If we have the type loaded already, use that
4698 if (m_rpCLRTypes[index] != nullptr)
4700 return m_rpCLRTypes[index];
4703 WinMDAdapter::FrameworkAssemblyIndex frameworkAssemblyIndex;
4704 WinMDAdapter::GetRedirectedTypeInfo(index, nullptr, nullptr, nullptr, &frameworkAssemblyIndex, nullptr, nullptr);
4705 MethodTable * pMT = LoadRedirectedType(index, frameworkAssemblyIndex);
4706 m_rpCLRTypes[index] = pMT;
4710 MethodTable* AppDomain::LoadRedirectedType(WinMDAdapter::RedirectedTypeIndex index, WinMDAdapter::FrameworkAssemblyIndex assembly)
4717 PRECONDITION(index < WinMDAdapter::RedirectedTypeIndex_Count);
4721 LPCSTR szClrNamespace;
4723 LPCSTR szFullWinRTName;
4724 WinMDAdapter::FrameworkAssemblyIndex nFrameworkAssemblyIndex;
4726 WinMDAdapter::GetRedirectedTypeInfo(index, &szClrNamespace, &szClrName, &szFullWinRTName, &nFrameworkAssemblyIndex, nullptr, nullptr);
4728 _ASSERTE(nFrameworkAssemblyIndex >= WinMDAdapter::FrameworkAssembly_Mscorlib &&
4729 nFrameworkAssemblyIndex < WinMDAdapter::FrameworkAssembly_Count);
4731 if (assembly != nFrameworkAssemblyIndex)
4733 // The framework type does not live in the assembly we were requested to load redirected types from
4736 else if (nFrameworkAssemblyIndex == WinMDAdapter::FrameworkAssembly_Mscorlib)
4738 return ClassLoader::LoadTypeByNameThrowing(MscorlibBinder::GetModule()->GetAssembly(),
4741 ClassLoader::ThrowIfNotFound,
4742 ClassLoader::LoadTypes,
4743 CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4748 AssemblyMetaDataInternal context;
4749 const BYTE * pbKeyToken;
4750 DWORD cbKeyTokenLength;
4753 WinMDAdapter::GetExtraAssemblyRefProps(nFrameworkAssemblyIndex,
4760 Assembly* pAssembly = AssemblySpec::LoadAssembly(pSimpleName,
4766 return ClassLoader::LoadTypeByNameThrowing(
4770 ClassLoader::ThrowIfNotFound,
4771 ClassLoader::LoadTypes,
4772 CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4775 #endif //FEATURE_COMINTEROP
4777 #endif //!DACCESS_COMPILE
4779 #ifndef DACCESS_COMPILE
4781 bool IsPlatformAssembly(LPCSTR szName, DomainAssembly *pDomainAssembly)
4788 PRECONDITION(CheckPointer(szName));
4789 PRECONDITION(CheckPointer(pDomainAssembly));
4793 PEAssembly *pPEAssembly = pDomainAssembly->GetFile();
4795 if (strcmp(szName, pPEAssembly->GetSimpleName()) != 0)
4801 const BYTE *pbPublicKey = static_cast<const BYTE *>(pPEAssembly->GetPublicKey(&cbPublicKey));
4802 if (pbPublicKey == nullptr)
4807 return StrongNameIsSilverlightPlatformKey(pbPublicKey, cbPublicKey);
4810 void AppDomain::AddAssembly(DomainAssembly * assem)
4817 INJECT_FAULT(COMPlusThrowOM(););
4822 CrstHolder ch(GetAssemblyListLock());
4824 // Attempt to find empty space in assemblies list
4825 DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4826 for (DWORD i = 0; i < asmCount; ++i)
4828 if (m_Assemblies.Get_UnlockedNoReference(i) == NULL)
4830 m_Assemblies.Set_Unlocked(i, assem);
4835 // If empty space not found, simply add to end of list
4836 IfFailThrow(m_Assemblies.Append_Unlocked(assem));
4840 void AppDomain::RemoveAssembly_Unlocked(DomainAssembly * pAsm)
4849 _ASSERTE(GetAssemblyListLock()->OwnedByCurrentThread());
4851 DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4852 for (DWORD i = 0; i < asmCount; ++i)
4854 if (m_Assemblies.Get_UnlockedNoReference(i) == pAsm)
4856 m_Assemblies.Set_Unlocked(i, NULL);
4861 _ASSERTE(!"Unreachable");
4864 BOOL AppDomain::ContainsAssembly(Assembly * assem)
4866 WRAPPER_NO_CONTRACT;
4867 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
4869 (assem->IsIntrospectionOnly() ? kIncludeIntrospection : kIncludeExecution)));
4870 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
4872 while (i.Next(pDomainAssembly.This()))
4874 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
4875 if (pAssembly == assem)
4882 EEClassFactoryInfoHashTable* AppDomain::SetupClassFactHash()
4889 INJECT_FAULT(COMPlusThrowOM(););
4893 CrstHolder ch(&m_ReflectionCrst);
4895 if (m_pRefClassFactHash == NULL)
4897 AllocMemHolder<void> pCache(GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (EEClassFactoryInfoHashTable))));
4898 EEClassFactoryInfoHashTable *tmp = new (pCache) EEClassFactoryInfoHashTable;
4899 LockOwner lock = {&m_RefClassFactCrst,IsOwnerOfCrst};
4900 if (!tmp->Init(20, &lock))
4902 pCache.SuppressRelease();
4903 m_pRefClassFactHash = tmp;
4906 return m_pRefClassFactHash;
4909 #ifdef FEATURE_COMINTEROP
4910 DispIDCache* AppDomain::SetupRefDispIDCache()
4917 INJECT_FAULT(COMPlusThrowOM(););
4921 CrstHolder ch(&m_ReflectionCrst);
4923 if (m_pRefDispIDCache == NULL)
4925 AllocMemHolder<void> pCache = GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (DispIDCache)));
4927 DispIDCache *tmp = new (pCache) DispIDCache;
4930 pCache.SuppressRelease();
4931 m_pRefDispIDCache = tmp;
4934 return m_pRefDispIDCache;
4937 #endif // FEATURE_COMINTEROP
4939 FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
4946 PRECONDITION(pLock->HasLock());
4947 PRECONDITION(pLock->FindFileLock(pFile) == NULL);
4948 INJECT_FAULT(COMPlusThrowOM(););
4952 NewHolder<FileLoadLock> result(new FileLoadLock(pLock, pFile, pDomainFile));
4954 pLock->AddElement(result);
4955 result->AddRef(); // Add one ref on behalf of the ListLock's reference. The corresponding Release() happens in FileLoadLock::CompleteLoadLevel.
4956 return result.Extract();
4959 FileLoadLock::~FileLoadLock()
4969 ((PEFile *) m_data)->Release();
4972 DomainFile *FileLoadLock::GetDomainFile()
4974 LIMITED_METHOD_CONTRACT;
4975 return m_pDomainFile;
4978 FileLoadLevel FileLoadLock::GetLoadLevel()
4980 LIMITED_METHOD_CONTRACT;
4984 ADID FileLoadLock::GetAppDomainId()
4986 LIMITED_METHOD_CONTRACT;
4987 return m_AppDomainId;
4990 // Acquire will return FALSE and not take the lock if the file
4991 // has already been loaded to the target level. Otherwise,
4992 // it will return TRUE and take the lock.
4994 // Note that the taker must release the lock via IncrementLoadLevel.
4996 BOOL FileLoadLock::Acquire(FileLoadLevel targetLevel)
4998 WRAPPER_NO_CONTRACT;
5000 // If we are already loaded to the desired level, the lock is "free".
5001 if (m_level >= targetLevel)
5004 if (!DeadlockAwareEnter())
5006 // We failed to get the lock due to a deadlock.
5010 if (m_level >= targetLevel)
5019 BOOL FileLoadLock::CanAcquire(FileLoadLevel targetLevel)
5021 // If we are already loaded to the desired level, the lock is "free".
5022 if (m_level >= targetLevel)
5025 return CanDeadlockAwareEnter();
5028 #if !defined(DACCESS_COMPILE) && (defined(LOGGING) || defined(STRESS_LOG))
5029 static const char *fileLoadLevelName[] =
5031 "CREATE", // FILE_LOAD_CREATE
5032 "BEGIN", // FILE_LOAD_BEGIN
5033 "FIND_NATIVE_IMAGE", // FILE_LOAD_FIND_NATIVE_IMAGE
5034 "VERIFY_NATIVE_IMAGE_DEPENDENCIES", // FILE_LOAD_VERIFY_NATIVE_IMAGE_DEPENDENCIES
5035 "ALLOCATE", // FILE_LOAD_ALLOCATE
5036 "ADD_DEPENDENCIES", // FILE_LOAD_ADD_DEPENDENCIES
5037 "PRE_LOADLIBRARY", // FILE_LOAD_PRE_LOADLIBRARY
5038 "LOADLIBRARY", // FILE_LOAD_LOADLIBRARY
5039 "POST_LOADLIBRARY", // FILE_LOAD_POST_LOADLIBRARY
5040 "EAGER_FIXUPS", // FILE_LOAD_EAGER_FIXUPS
5041 "VTABLE FIXUPS", // FILE_LOAD_VTABLE_FIXUPS
5042 "DELIVER_EVENTS", // FILE_LOAD_DELIVER_EVENTS
5043 "LOADED", // FILE_LOADED
5044 "VERIFY_EXECUTION", // FILE_LOAD_VERIFY_EXECUTION
5045 "ACTIVE", // FILE_ACTIVE
5047 #endif // !DACCESS_COMPILE && (LOGGING || STRESS_LOG)
5049 BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success)
5056 PRECONDITION(HasLock());
5060 // Increment may happen more than once if reentrancy occurs (e.g. LoadLibrary)
5061 if (level > m_level)
5063 // Must complete each level in turn, unless we have an error
5064 CONSISTENCY_CHECK(m_pDomainFile->IsError() || (level == (m_level+1)));
5065 // Remove the lock from the list if the load is completed
5066 if (level >= FILE_ACTIVE)
5070 PEFileListLockHolder lock((PEFileListLock*)m_pList);
5073 BOOL fDbgOnly_SuccessfulUnlink =
5075 m_pList->Unlink(this);
5076 _ASSERTE(fDbgOnly_SuccessfulUnlink);
5078 m_pDomainFile->ClearLoading();
5080 CONSISTENCY_CHECK(m_dwRefCount >= 2); // Caller (LoadDomainFile) should have 1 refcount and m_pList should have another which was acquired in FileLoadLock::Create.
5082 m_level = (FileLoadLevel)level;
5085 // In AppDomain::IsLoading, if the lock is taken on m_pList and then FindFileLock returns NULL,
5086 // we depend on the DomainFile's load level being up to date. Hence we must update the load
5087 // level while the m_pList lock is held.
5089 m_pDomainFile->SetLoadLevel(level);
5093 Release(); // Release m_pList's refcount on this lock, which was acquired in FileLoadLock::Create
5098 m_level = (FileLoadLevel)level;
5101 m_pDomainFile->SetLoadLevel(level);
5104 #ifndef DACCESS_COMPILE
5107 case FILE_LOAD_ALLOCATE:
5108 case FILE_LOAD_ADD_DEPENDENCIES:
5109 case FILE_LOAD_DELIVER_EVENTS:
5111 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.
5112 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);
5125 void FileLoadLock::SetError(Exception *ex)
5132 PRECONDITION(CheckPointer(ex));
5133 PRECONDITION(HasLock());
5134 INJECT_FAULT(COMPlusThrowOM(););
5138 m_cachedHR = ex->GetHR();
5140 LOG((LF_LOADER, LL_WARNING, "LOADER: %x:***%s*\t!!!Non-transient error 0x%x\n",
5141 m_pDomainFile->GetAppDomain(), m_pDomainFile->GetSimpleName(), m_cachedHR));
5143 m_pDomainFile->SetError(ex);
5145 CompleteLoadLevel(FILE_ACTIVE, FALSE);
5148 void FileLoadLock::AddRef()
5150 LIMITED_METHOD_CONTRACT;
5151 FastInterlockIncrement((LONG *) &m_dwRefCount);
5154 UINT32 FileLoadLock::Release()
5164 LONG count = FastInterlockDecrement((LONG *) &m_dwRefCount);
5171 FileLoadLock::FileLoadLock(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
5172 : ListLockEntry(pLock, pFile, "File load lock"),
5173 m_level((FileLoadLevel) (FILE_LOAD_CREATE)),
5174 m_pDomainFile(pDomainFile),
5176 m_AppDomainId(pDomainFile->GetAppDomain()->GetId())
5178 WRAPPER_NO_CONTRACT;
5182 void FileLoadLock::HolderLeave(FileLoadLock *pThis)
5184 LIMITED_METHOD_CONTRACT;
5194 // Assembly loading:
5196 // Assembly loading is carefully layered to avoid deadlocks in the
5197 // presence of circular loading dependencies.
5198 // A LoadLevel is associated with each assembly as it is being loaded. During the
5199 // act of loading (abstractly, increasing its load level), its lock is
5200 // held, and the current load level is stored on the thread. Any
5201 // recursive loads during that period are automatically restricted to
5202 // only partially load the dependent assembly to the same level as the
5203 // caller (or to one short of that level in the presence of a deadlock
5206 // Each loading stage must be carfully constructed so that
5207 // this constraint is expected and can be dealt with.
5209 // Note that there is one case where this still doesn't handle recursion, and that is the
5210 // security subsytem. The security system runs managed code, and thus must typically fully
5211 // initialize assemblies of permission sets it is trying to use. (And of course, these may be used
5212 // while those assemblies are initializing.) This is dealt with in the historical manner - namely
5213 // the security system passes in a special flag which says that it will deal with null return values
5214 // in the case where a load cannot be safely completed due to such issues.
5217 void AppDomain::LoadSystemAssemblies()
5219 STANDARD_VM_CONTRACT;
5221 // The only reason to make an assembly a "system assembly" is if the EE is caching
5222 // pointers to stuff in the assembly. Because this is going on, we need to preserve
5223 // the invariant that the assembly is loaded into every app domain.
5225 // Right now we have only one system assembly. We shouldn't need to add any more.
5227 LoadAssembly(NULL, SystemDomain::System()->SystemFile(), FILE_ACTIVE);
5230 FileLoadLevel AppDomain::GetDomainFileLoadLevel(DomainFile *pFile)
5240 LoadLockHolder lock(this);
5242 FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5244 if (pLockEntry == NULL)
5245 return pFile->GetLoadLevel();
5247 return pLockEntry->GetLoadLevel();
5250 // This checks if the thread has initiated (or completed) loading at the given level. A false guarantees that
5251 // (a) The current thread (or a thread blocking on the current thread) has not started loading the file
5252 // at the given level, and
5253 // (b) No other thread had started loading the file at this level at the start of this function call.
5255 // Note that another thread may start loading the file at that level in a race with the completion of
5256 // this function. However, the caller still has the guarantee that such a load started after this
5257 // function was called (and e.g. any state in place before the function call will be seen by the other thread.)
5259 // Conversely, a true guarantees that either the current thread has started the load step, or another
5260 // thread has completed the load step.
5263 BOOL AppDomain::IsLoading(DomainFile *pFile, FileLoadLevel level)
5266 if (pFile->GetLoadLevel() < level)
5268 FileLoadLock *pLock = NULL;
5270 LoadLockHolder lock(this);
5272 pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5276 // No thread involved with loading
5277 return pFile->GetLoadLevel() >= level;
5283 FileLoadLockRefHolder lockRef(pLock);
5285 if (pLock->Acquire(level))
5287 // We got the lock - therefore no other thread has started this loading step yet.
5292 // We didn't get the lock - either this thread is already doing the load,
5293 // or else the load has already finished.
5298 // CheckLoading is a weaker form of IsLoading, which will not block on
5299 // other threads waiting for their status. This is appropriate for asserts.
5300 CHECK AppDomain::CheckLoading(DomainFile *pFile, FileLoadLevel level)
5303 if (pFile->GetLoadLevel() < level)
5305 FileLoadLock *pLock = NULL;
5307 LoadLockHolder lock(this);
5309 pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5312 && pLock->CanAcquire(level))
5314 // We can get the lock - therefore no other thread has started this loading step yet.
5315 CHECK_FAILF(("Loading step %d has not been initiated yet", level));
5318 // We didn't get the lock - either this thread is already doing the load,
5319 // or else the load has already finished.
5325 CHECK AppDomain::CheckCanLoadTypes(Assembly *pAssembly)
5334 CHECK_MSG(CheckValidModule(pAssembly->GetManifestModule()),
5335 "Type loading can occur only when executing in the assembly's app domain");
5339 CHECK AppDomain::CheckCanExecuteManagedCode(MethodDesc* pMD)
5349 Module* pModule=pMD->GetModule();
5351 CHECK_MSG(CheckValidModule(pModule),
5352 "Managed code can only run when executing in the module's app domain");
5354 if (!pMD->IsInterface() || pMD->IsStatic()) //interfaces require no activation for instance methods
5356 //cctor could have been interupted by ADU
5357 CHECK_MSG(HasUnloadStarted() || pModule->CheckActivated(),
5358 "Managed code can only run when its module has been activated in the current app domain");
5361 CHECK_MSG(!IsPassiveDomain() || pModule->CanExecuteCode(),
5362 "Executing managed code from an unsafe assembly in a Passive AppDomain");
5367 #endif // !DACCESS_COMPILE
5369 void AppDomain::LoadDomainFile(DomainFile *pFile,
5370 FileLoadLevel targetLevel)
5374 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
5375 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
5376 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM();); }
5377 INJECT_FAULT(COMPlusThrowOM(););
5381 // Quick exit if finished
5382 if (pFile->GetLoadLevel() >= targetLevel)
5385 // Handle the error case
5386 pFile->ThrowIfError(targetLevel);
5389 #ifndef DACCESS_COMPILE
5391 if (pFile->IsLoading())
5395 // Load some more if appropriate
5396 LoadLockHolder lock(this);
5398 FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5399 if (pLockEntry == NULL)
5401 _ASSERTE (!pFile->IsLoading());
5405 pLockEntry->AddRef();
5409 LoadDomainFile(pLockEntry, targetLevel);
5412 #else // DACCESS_COMPILE
5414 #endif // DACCESS_COMPILE
5417 #ifndef DACCESS_COMPILE
5419 FileLoadLevel AppDomain::GetThreadFileLoadLevel()
5421 WRAPPER_NO_CONTRACT;
5422 if (GetThread()->GetLoadLevelLimiter() == NULL)
5425 return (FileLoadLevel)(GetThread()->GetLoadLevelLimiter()->GetLoadLevel()-1);
5429 Assembly *AppDomain::LoadAssembly(AssemblySpec* pIdentity,
5431 FileLoadLevel targetLevel)
5433 CONTRACT(Assembly *)
5438 PRECONDITION(CheckPointer(pFile));
5439 POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // May be NULL in recursive load case
5440 INJECT_FAULT(COMPlusThrowOM(););
5444 DomainAssembly *pAssembly = LoadDomainAssembly(pIdentity, pFile, targetLevel);
5445 PREFIX_ASSUME(pAssembly != NULL);
5447 RETURN pAssembly->GetAssembly();
5450 #ifndef CROSSGEN_COMPILE
5452 class LoadDomainAssemblyStress : APIThreadStress
5456 AssemblySpec* pSpec;
5458 FileLoadLevel targetLevel;
5460 LoadDomainAssemblyStress(AppDomain *pThis, AssemblySpec* pSpec, PEAssembly *pFile, FileLoadLevel targetLevel)
5461 : pThis(pThis), pSpec(pSpec), pFile(pFile), targetLevel(targetLevel) {LIMITED_METHOD_CONTRACT;}
5465 WRAPPER_NO_CONTRACT;
5466 STATIC_CONTRACT_SO_INTOLERANT;
5468 pThis->LoadDomainAssembly(pSpec, pFile, targetLevel);
5471 #endif // CROSSGEN_COMPILE
5473 extern BOOL AreSameBinderInstance(ICLRPrivBinder *pBinderA, ICLRPrivBinder *pBinderB);
5475 DomainAssembly* AppDomain::LoadDomainAssembly( AssemblySpec* pSpec,
5477 FileLoadLevel targetLevel)
5479 STATIC_CONTRACT_THROWS;
5481 if (pSpec == nullptr)
5483 // skip caching, since we don't have anything to base it on
5484 return LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
5487 DomainAssembly* pRetVal = NULL;
5490 pRetVal = LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
5494 Exception* pEx=GET_EXCEPTION();
5495 if (!pEx->IsTransient())
5497 // Setup the binder reference in AssemblySpec from the PEAssembly if one is not already set.
5498 ICLRPrivBinder* pCurrentBindingContext = pSpec->GetBindingContext();
5499 ICLRPrivBinder* pBindingContextFromPEAssembly = pFile->GetBindingContext();
5501 if (pCurrentBindingContext == NULL)
5503 // Set the binding context we got from the PEAssembly if AssemblySpec does not
5504 // have that information
5505 _ASSERTE(pBindingContextFromPEAssembly != NULL);
5506 pSpec->SetBindingContext(pBindingContextFromPEAssembly);
5511 // Binding context in the spec should be the same as the binding context in the PEAssembly
5512 _ASSERTE(AreSameBinderInstance(pCurrentBindingContext, pBindingContextFromPEAssembly));
5516 if (!EEFileLoadException::CheckType(pEx))
5519 pSpec->GetFileOrDisplayName(0, name);
5520 pEx=new EEFileLoadException(name, pEx->GetHR(), NULL, pEx);
5521 AddExceptionToCache(pSpec, pEx);
5522 PAL_CPP_THROW(Exception *, pEx);
5525 AddExceptionToCache(pSpec, pEx);
5534 DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
5536 FileLoadLevel targetLevel)
5538 CONTRACT(DomainAssembly *)
5543 PRECONDITION(CheckPointer(pFile));
5544 PRECONDITION(pFile->IsSystem() || ::GetAppDomain()==this);
5545 POSTCONDITION(CheckPointer(RETVAL));
5546 POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
5547 || RETVAL->GetLoadLevel() >= targetLevel);
5548 POSTCONDITION(RETVAL->CheckNoError(targetLevel));
5549 INJECT_FAULT(COMPlusThrowOM(););
5554 DomainAssembly * result;
5556 #ifndef CROSSGEN_COMPILE
5557 LoadDomainAssemblyStress ts (this, pIdentity, pFile, targetLevel);
5560 // Go into preemptive mode since this may take a while.
5563 // Check for existing fully loaded assembly, or for an assembly which has failed during the loading process.
5564 result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
5568 // Allocate the DomainAssembly a bit early to avoid GC mode problems. We could potentially avoid
5569 // a rare redundant allocation by moving this closer to FileLoadLock::Create, but it's not worth it.
5571 NewHolder<DomainAssembly> pDomainAssembly;
5572 pDomainAssembly = new DomainAssembly(this, pFile, this->GetLoaderAllocator());
5574 LoadLockHolder lock(this);
5576 // Find the list lock entry
5577 FileLoadLock * fileLock = (FileLoadLock *)lock->FindFileLock(pFile);
5578 if (fileLock == NULL)
5580 // Check again in case we were racing
5581 result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
5584 // We are the first one in - create the DomainAssembly
5585 fileLock = FileLoadLock::Create(lock, pFile, pDomainAssembly);
5586 pDomainAssembly.SuppressRelease();
5598 // We pass our ref on fileLock to LoadDomainFile to release.
5600 // Note that if we throw here, we will poison fileLock with an error condition,
5601 // so it will not be removed until app domain unload. So there is no need
5602 // to release our ref count.
5603 result = (DomainAssembly *)LoadDomainFile(fileLock, targetLevel);
5607 result->EnsureLoadLevel(targetLevel);
5611 result->EnsureLoadLevel(targetLevel);
5613 // Malformed metadata may contain a Module reference to what is actually
5614 // an Assembly. In this case we need to throw an exception, since returning
5615 // a DomainModule as a DomainAssembly is a type safety violation.
5616 if (!result->IsAssembly())
5618 ThrowHR(COR_E_ASSEMBLYEXPECTED);
5621 // Cache result in all cases, since found pFile could be from a different AssemblyRef than pIdentity
5622 // Do not cache WindowsRuntime assemblies, they are cached in code:CLRPrivTypeCacheWinRT
5623 if ((pIdentity != NULL) && (pIdentity->CanUseWithBindingCache()) && (result->CanUseWithBindingCache()))
5624 GetAppDomain()->AddAssemblyToCache(pIdentity, result);
5627 } // AppDomain::LoadDomainAssembly
5632 FileLoadLock *pLock;
5633 FileLoadLevel targetLevel;
5637 #ifndef CROSSGEN_COMPILE
5638 static void LoadDomainFile_Wrapper(void *ptr)
5640 WRAPPER_NO_CONTRACT;
5641 STATIC_CONTRACT_SO_INTOLERANT;
5643 LoadFileArgs *args = (LoadFileArgs *) ptr;
5644 args->result = GetAppDomain()->LoadDomainFile(args->pLock, args->targetLevel);
5646 #endif // !CROSSGEN_COMPILE
5648 DomainFile *AppDomain::LoadDomainFile(FileLoadLock *pLock, FileLoadLevel targetLevel)
5650 CONTRACT(DomainFile *)
5653 PRECONDITION(CheckPointer(pLock));
5654 PRECONDITION(pLock->GetDomainFile()->GetAppDomain() == this);
5655 POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
5656 || RETVAL->GetLoadLevel() >= targetLevel);
5657 POSTCONDITION(RETVAL->CheckNoError(targetLevel));
5663 COMPlusThrow(kAppDomainUnloadedException);
5666 APIThreadStress::SyncThreadStress();
5668 DomainFile *pFile = pLock->GetDomainFile();
5670 // Make sure we release the lock on exit
5671 FileLoadLockRefHolder lockRef(pLock);
5673 // We need to perform the early steps of loading mscorlib without a domain transition. This is
5674 // important for bootstrapping purposes - we need to get mscorlib at least partially loaded
5675 // into a domain before we can run serialization code to do the transition.
5677 // Note that we cannot do this in general for all assemblies, because some of the security computations
5678 // require the managed exposed object, which must be created in the correct app domain.
5680 if (this != GetAppDomain()
5681 && pFile->GetFile()->IsSystem()
5682 && targetLevel > FILE_LOAD_ALLOCATE)
5684 // Re-call the routine with a limited load level. This will cause the first part of the load to
5685 // get performed in the current app domain.
5688 LoadDomainFile(pLock, targetLevel > FILE_LOAD_ALLOCATE ? FILE_LOAD_ALLOCATE : targetLevel);
5690 // Now continue on to complete the rest of the load, if any.
5693 // Do a quick out check for the already loaded case.
5694 if (pLock->GetLoadLevel() >= targetLevel)
5696 pFile->ThrowIfError(targetLevel);
5701 #ifndef CROSSGEN_COMPILE
5702 // Make sure we are in the right domain. Many of the load operations require the target domain
5703 // to be the current app domain, most notably anything involving managed code or managed object
5705 if (this != GetAppDomain()
5706 && (!pFile->GetFile()->IsSystem() || targetLevel > FILE_LOAD_ALLOCATE))
5708 // Transition to the correct app domain and perform the load there.
5711 // we will release the lock in the other app domain
5712 lockRef.SuppressRelease();
5714 if(!CanLoadCode() || GetDefaultContext() ==NULL)
5715 COMPlusThrow(kAppDomainUnloadedException);
5716 LoadFileArgs args = {pLock, targetLevel, NULL};
5717 GetThread()->DoADCallBack(this, LoadDomainFile_Wrapper, (void *) &args, ADV_CREATING);
5721 #endif // CROSSGEN_COMPILE
5723 // Initialize a loading queue. This will hold any loads which are triggered recursively but
5724 // which cannot be immediately satisfied due to anti-deadlock constraints.
5726 // PendingLoadQueues are allocated on the stack during a load, and
5727 // shared with all nested loads on the same thread. (Note that we won't use
5728 // "candidate" if we are in a recursive load; that's OK since they are cheap to
5730 FileLoadLevel immediateTargetLevel = targetLevel;
5732 LoadLevelLimiter limit;
5735 // We cannot set a target level higher than that allowed by the limiter currently.
5736 // This is because of anti-deadlock constraints.
5737 if (immediateTargetLevel > limit.GetLoadLevel())
5738 immediateTargetLevel = limit.GetLoadLevel();
5740 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t>>>Load initiated, %s/%s\n",
5741 pFile->GetAppDomain(), pFile->GetSimpleName(),
5742 fileLoadLevelName[immediateTargetLevel], fileLoadLevelName[targetLevel]));
5744 // Now loop and do the load incrementally to the target level.
5745 if (pLock->GetLoadLevel() < immediateTargetLevel)
5748 APIThreadStress::SyncThreadStress();
5750 while (pLock->Acquire(immediateTargetLevel))
5752 FileLoadLevel workLevel;
5754 FileLoadLockHolder fileLock(pLock);
5756 // Work level is next step to do
5757 workLevel = (FileLoadLevel)(fileLock->GetLoadLevel()+1);
5759 // Set up the anti-deadlock constraint: we cannot safely recursively load any assemblies
5760 // on this thread to a higher level than this assembly is being loaded now.
5761 // Note that we do allow work at a parallel level; any deadlocks caused here will
5762 // be resolved by the deadlock detection in the FileLoadLocks.
5763 limit.SetLoadLevel(workLevel);
5766 (workLevel == FILE_LOAD_BEGIN
5767 || workLevel == FILE_LOADED
5768 || workLevel == FILE_ACTIVE)
5769 ? LL_INFO10 : LL_INFO1000,
5770 "LOADER: %p:***%s*\t loading at level %s\n",
5771 this, pFile->GetSimpleName(), fileLoadLevelName[workLevel]));
5773 TryIncrementalLoad(pFile, workLevel, fileLock);
5775 TESTHOOKCALL(CompletedFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5778 if (pLock->GetLoadLevel() == immediateTargetLevel-1)
5780 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load limited due to detected deadlock, %s\n",
5781 pFile->GetAppDomain(), pFile->GetSimpleName(),
5782 fileLoadLevelName[immediateTargetLevel-1]));
5786 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load completed, %s\n",
5787 pFile->GetAppDomain(), pFile->GetSimpleName(),
5788 fileLoadLevelName[pLock->GetLoadLevel()]));
5792 // There may have been an error stored on the domain file by another thread, or from a previous load
5793 pFile->ThrowIfError(targetLevel);
5795 // There are two normal results from the above loop.
5797 // 1. We succeeded in loading the file to the current thread's load level.
5798 // 2. We succeeded in loading the file to the current thread's load level - 1, due
5799 // to deadlock condition with another thread loading the same assembly.
5801 // Either of these are considered satisfactory results, as code inside a load must expect
5802 // a parial load result.
5804 // However, if load level elevation has occurred, then it is possible for a deadlock to
5805 // prevent us from loading an assembly which was loading before the elevation at a radically
5806 // lower level. In such a case, we throw an exception which transiently fails the current
5807 // load, since it is likely we have not satisfied the caller.
5808 // (An alternate, and possibly preferable, strategy here would be for all callers to explicitly
5809 // identify the minimum load level acceptable via CheckLoadDomainFile and throw from there.)
5811 pFile->RequireLoadLevel((FileLoadLevel)(immediateTargetLevel-1));
5817 void AppDomain::TryIncrementalLoad(DomainFile *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder)
5819 STANDARD_VM_CONTRACT;
5821 // This is factored out so we don't call EX_TRY in a loop (EX_TRY can _alloca)
5823 BOOL released = FALSE;
5824 FileLoadLock* pLoadLock = lockHolder.GetValue();
5829 // Special case: for LoadLibrary, we cannot hold the lock during the
5830 // actual LoadLibrary call, because we might get a callback from _CorDllMain on any
5831 // other thread. (Note that this requires DomainFile's LoadLibrary to be independently threadsafe.)
5833 if (workLevel == FILE_LOAD_LOADLIBRARY)
5835 lockHolder.Release();
5840 TESTHOOKCALL(NextFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5841 BOOL success = pFile->DoIncrementalLoad(workLevel);
5842 TESTHOOKCALL(CompletingFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5845 // Reobtain lock to increment level. (Note that another thread may
5846 // have already done it which is OK.
5847 if (pLoadLock->Acquire(workLevel))
5849 // note lockHolder.Acquire isn't wired up to actually take the lock
5850 lockHolder = pLoadLock;
5857 // Complete the level.
5858 if (pLoadLock->CompleteLoadLevel(workLevel, success) &&
5859 pLoadLock->GetLoadLevel()==FILE_LOAD_DELIVER_EVENTS)
5861 lockHolder.Release();
5863 pFile->DeliverAsyncEvents();
5869 Exception *pEx = GET_EXCEPTION();
5872 //We will cache this error and wire this load to forever fail,
5873 // unless the exception is transient or the file is loaded OK but just cannot execute
5874 if (!pEx->IsTransient() && !pFile->IsLoaded())
5879 // Reobtain lock to increment level. (Note that another thread may
5880 // have already done it which is OK.
5881 if (pLoadLock->Acquire(workLevel)) // note pLockHolder->Acquire isn't wired up to actually take the lock
5883 // note lockHolder.Acquire isn't wired up to actually take the lock
5884 lockHolder = pLoadLock;
5891 // Report the error in the lock
5892 pLoadLock->SetError(pEx);
5895 if (!EEFileLoadException::CheckType(pEx))
5896 EEFileLoadException::Throw(pFile->GetFile(), pEx->GetHR(), pEx);
5899 // Otherwise, we simply abort this load, and can retry later on.
5900 // @todo cleanup: make sure that each level is restartable after an exception, and
5901 // leaves no bad side effects
5906 // Checks whether the module is valid to be in the given app domain (need not be yet loaded)
5907 CHECK AppDomain::CheckValidModule(Module * pModule)
5917 if (pModule->FindDomainFile(this) != NULL)
5922 Assembly * pAssembly = pModule->GetAssembly();
5924 CCHECK(pAssembly->IsDomainNeutral());
5925 #ifdef FEATURE_LOADER_OPTIMIZATION
5926 Assembly * pSharedAssembly = NULL;
5927 _ASSERTE(this == ::GetAppDomain());
5929 SharedAssemblyLocator locator(pAssembly->GetManifestFile());
5930 pSharedAssembly = SharedDomain::GetDomain()->FindShareableAssembly(&locator);
5933 CCHECK(pAssembly == pSharedAssembly);
5941 #ifdef FEATURE_LOADER_OPTIMIZATION
5942 // Loads an existing Module into an AppDomain
5943 // WARNING: this can only be done in a very limited scenario - the Module must be an unloaded domain neutral
5944 // dependency in the app domain in question. Normal code should not call this!
5945 DomainFile *AppDomain::LoadDomainNeutralModuleDependency(Module *pModule, FileLoadLevel targetLevel)
5947 CONTRACT(DomainFile *)
5952 PRECONDITION(::GetAppDomain()==this);
5953 PRECONDITION(CheckPointer(pModule));
5954 POSTCONDITION(CheckValidModule(pModule));
5955 POSTCONDITION(CheckPointer(RETVAL));
5956 POSTCONDITION(RETVAL->GetModule() == pModule);
5960 DomainFile *pDomainFile = pModule->FindDomainFile(this);
5962 STRESS_LOG3(LF_CLASSLOADER, LL_INFO100,"LDNMD: DomainFile %p for module %p in AppDomain %i\n",pDomainFile,pModule,GetId().m_dwId);
5964 if (pDomainFile == NULL)
5968 Assembly *pAssembly = pModule->GetAssembly();
5970 DomainAssembly *pDomainAssembly = pAssembly->FindDomainAssembly(this);
5971 if (pDomainAssembly == NULL)
5973 AssemblySpec spec(this);
5974 spec.InitializeSpec(pAssembly->GetManifestFile());
5976 pDomainAssembly = spec.LoadDomainAssembly(targetLevel);
5980 //if the domain assembly already exists, we need to load it to the target level
5981 pDomainAssembly->EnsureLoadLevel (targetLevel);
5984 if(pAssembly != pDomainAssembly->GetAssembly())
5986 ThrowHR(SECURITY_E_INCOMPATIBLE_SHARE);
5989 _ASSERTE (pModule == pAssembly->GetManifestModule());
5990 pDomainFile = pDomainAssembly;
5994 // If the DomainFile already exists, we need to load it to the target level.
5995 pDomainFile->EnsureLoadLevel (targetLevel);
6001 AppDomain::SharePolicy AppDomain::GetSharePolicy()
6003 LIMITED_METHOD_CONTRACT;
6005 return SHARE_POLICY_NEVER;
6007 #endif // FEATURE_LOADER_OPTIMIZATION
6010 void AppDomain::CheckForMismatchedNativeImages(AssemblySpec * pSpec, const GUID * pGuid)
6012 STANDARD_VM_CONTRACT;
6015 // The native images are ever used only for trusted images in CoreCLR.
6016 // We don't wish to open the IL file at runtime so we just forgo any
6017 // eager consistency checking. But we still want to prevent mistmatched
6018 // NGen images from being used. We record all mappings between assembly
6019 // names and MVID, and fail once we detect mismatch.
6022 if (pSpec->IsStrongNamed() && pSpec->HasPublicKey())
6024 pSpec->ConvertPublicKeyToToken();
6028 // CoreCLR binder unifies assembly versions. Ignore assembly version here to
6029 // detect more types of potential mismatches.
6031 AssemblyMetaDataInternal * pContext = pSpec->GetContext();
6032 pContext->usMajorVersion = (USHORT)-1;
6033 pContext->usMinorVersion = (USHORT)-1;
6034 pContext->usBuildNumber = (USHORT)-1;
6035 pContext->usRevisionNumber = (USHORT)-1;
6037 // Ignore the WinRT type while considering if two assemblies have the same identity.
6038 pSpec->SetWindowsRuntimeType(NULL, NULL);
6040 CrstHolder ch(&m_DomainCrst);
6042 const NativeImageDependenciesEntry * pEntry = m_NativeImageDependencies.Lookup(pSpec);
6046 if (*pGuid != pEntry->m_guidMVID)
6049 msg.Printf("ERROR: Native images generated against multiple versions of assembly %s. ", pSpec->GetName());
6050 WszOutputDebugString(msg.GetUnicode());
6051 COMPlusThrowNonLocalized(kFileLoadException, msg.GetUnicode());
6057 // No entry yet - create one
6059 AllocMemTracker amTracker;
6060 AllocMemTracker *pamTracker = &amTracker;
6062 NativeImageDependenciesEntry * pNewEntry =
6063 new (pamTracker->Track(GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(NativeImageDependenciesEntry)))))
6064 NativeImageDependenciesEntry();
6066 pNewEntry->m_AssemblySpec.CopyFrom(pSpec);
6067 pNewEntry->m_AssemblySpec.CloneFieldsToLoaderHeap(AssemblySpec::ALL_OWNED, GetLowFrequencyHeap(), pamTracker);
6069 pNewEntry->m_guidMVID = *pGuid;
6071 m_NativeImageDependencies.Add(pNewEntry);
6072 amTracker.SuppressRelease();
6077 void AppDomain::SetupSharedStatics()
6084 INJECT_FAULT(COMPlusThrowOM(););
6088 #ifndef CROSSGEN_COMPILE
6089 if (NingenEnabled())
6092 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: SetupSharedStatics()"));
6094 // don't do any work in init stage. If not init only do work in non-shared case if are default domain
6095 _ASSERTE(!g_fEEInit);
6097 // Because we are allocating/referencing objects, need to be in cooperative mode
6100 static OBJECTHANDLE hSharedStaticsHandle = NULL;
6102 if (hSharedStaticsHandle == NULL) {
6103 // Note that there is no race here since the default domain is always set up first
6104 _ASSERTE(IsDefaultDomain());
6106 MethodTable *pMT = MscorlibBinder::GetClass(CLASS__SHARED_STATICS);
6107 _ASSERTE(pMT->IsClassPreInited());
6109 hSharedStaticsHandle = CreateGlobalHandle(AllocateObject(pMT));
6112 DomainLocalModule *pLocalModule;
6114 if (IsSingleAppDomain())
6116 pLocalModule = MscorlibBinder::GetModule()->GetDomainLocalModule();
6120 pLocalModule = GetDomainLocalBlock()->GetModuleSlot(
6121 MscorlibBinder::GetModule()->GetModuleIndex());
6124 FieldDesc *pFD = MscorlibBinder::GetField(FIELD__SHARED_STATICS__SHARED_STATICS);
6126 OBJECTREF* pHandle = (OBJECTREF*)
6127 ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pFD->GetOffset());
6128 SetObjectReference( pHandle, ObjectFromHandle(hSharedStaticsHandle), this );
6130 // This is a convenient place to initialize String.Empty.
6131 // It is treated as intrinsic by the JIT as so the static constructor would never run.
6132 // Leaving it uninitialized would confuse debuggers.
6134 // String should not have any static constructors.
6135 _ASSERTE(g_pStringClass->IsClassPreInited());
6137 FieldDesc * pEmptyStringFD = MscorlibBinder::GetField(FIELD__STRING__EMPTY);
6138 OBJECTREF* pEmptyStringHandle = (OBJECTREF*)
6139 ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pEmptyStringFD->GetOffset());
6140 SetObjectReference( pEmptyStringHandle, StringObject::GetEmptyString(), this );
6141 #endif // CROSSGEN_COMPILE
6144 DomainAssembly * AppDomain::FindAssembly(PEAssembly * pFile, FindAssemblyOptions options/* = FindAssemblyOptions_None*/)
6151 INJECT_FAULT(COMPlusThrowOM(););
6155 const bool includeFailedToLoad = (options & FindAssemblyOptions_IncludeFailedToLoad) != 0;
6157 if (pFile->HasHostAssembly())
6159 DomainAssembly * pDA = FindAssembly(pFile->GetHostAssembly());
6160 if (pDA != nullptr && (pDA->IsLoaded() || (includeFailedToLoad && pDA->IsError())))
6167 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
6169 (includeFailedToLoad ? kIncludeFailedToLoad : 0) |
6170 (pFile->IsIntrospectionOnly() ? kIncludeIntrospection : kIncludeExecution)));
6171 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
6173 while (i.Next(pDomainAssembly.This()))
6175 PEFile * pManifestFile = pDomainAssembly->GetFile();
6176 if (pManifestFile &&
6177 !pManifestFile->IsResource() &&
6178 pManifestFile->Equals(pFile))
6180 // Caller already has PEAssembly, so we can give DomainAssembly away freely without AddRef
6181 return pDomainAssembly.Extract();
6187 static const AssemblyIterationFlags STANDARD_IJW_ITERATOR_FLAGS =
6188 (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kExcludeCollectible);
6191 void AppDomain::SetFriendlyName(LPCWSTR pwzFriendlyName, BOOL fDebuggerCares/*=TRUE*/)
6196 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6198 INJECT_FAULT(COMPlusThrowOM(););
6202 // Do all computations into a temporary until we're ensured of success
6203 SString tmpFriendlyName;
6206 if (pwzFriendlyName)
6207 tmpFriendlyName.Set(pwzFriendlyName);
6210 // If there is an assembly, try to get the name from it.
6211 // If no assembly, but if it's the DefaultDomain, then give it a name
6213 if (m_pRootAssembly)
6215 tmpFriendlyName.SetUTF8(m_pRootAssembly->GetSimpleName());
6217 SString::Iterator i = tmpFriendlyName.End();
6218 if (tmpFriendlyName.FindBack(i, '.'))
6219 tmpFriendlyName.Truncate(i);
6223 if (IsDefaultDomain())
6224 tmpFriendlyName.Set(DEFAULT_DOMAIN_FRIENDLY_NAME);
6226 // This is for the profiler - if they call GetFriendlyName on an AppdomainCreateStarted
6227 // event, then we want to give them a temporary name they can use.
6228 else if (GetId().m_dwId != 0)
6230 tmpFriendlyName.Clear();
6231 tmpFriendlyName.Printf(W("%s %d"), OTHER_DOMAIN_FRIENDLY_NAME_PREFIX, GetId().m_dwId);
6237 tmpFriendlyName.Normalize();
6240 m_friendlyName = tmpFriendlyName;
6241 m_friendlyName.Normalize();
6243 if(g_pDebugInterface)
6245 // update the name in the IPC publishing block
6246 if (SUCCEEDED(g_pDebugInterface->UpdateAppDomainEntryInIPC(this)))
6248 // inform the attached debugger that the name of this appdomain has changed.
6249 if (IsDebuggerAttached() && fDebuggerCares)
6250 g_pDebugInterface->NameChangeEvent(this, NULL);
6255 void AppDomain::ResetFriendlyName(BOOL fDebuggerCares/*=TRUE*/)
6257 WRAPPER_NO_CONTRACT;
6258 SetFriendlyName(NULL, fDebuggerCares);
6261 LPCWSTR AppDomain::GetFriendlyName(BOOL fDebuggerCares/*=TRUE*/)
6266 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6268 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6269 INJECT_FAULT(COMPlusThrowOM(););
6274 // Handle NULL this pointer - this happens sometimes when printing log messages
6275 // but in general shouldn't occur in real code
6280 if (m_friendlyName.IsEmpty())
6281 SetFriendlyName(NULL, fDebuggerCares);
6283 RETURN m_friendlyName;
6286 LPCWSTR AppDomain::GetFriendlyNameForLogging()
6293 POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
6297 // Handle NULL this pointer - this happens sometimes when printing log messages
6298 // but in general shouldn't occur in real code
6302 RETURN (m_friendlyName.IsEmpty() ?W(""):(LPCWSTR)m_friendlyName);
6305 LPCWSTR AppDomain::GetFriendlyNameForDebugger()
6310 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6312 POSTCONDITION(CheckPointer(RETVAL));
6317 if (m_friendlyName.IsEmpty())
6319 BOOL fSuccess = FALSE;
6323 SetFriendlyName(NULL);
6329 // Gobble all exceptions.
6331 EX_END_CATCH(SwallowAllExceptions);
6339 RETURN m_friendlyName;
6343 #endif // !DACCESS_COMPILE
6345 #ifdef DACCESS_COMPILE
6347 PVOID AppDomain::GetFriendlyNameNoSet(bool* isUtf8)
6351 if (!m_friendlyName.IsEmpty())
6354 return m_friendlyName.DacGetRawContent();
6356 else if (m_pRootAssembly)
6359 return (PVOID)m_pRootAssembly->GetSimpleName();
6361 else if (dac_cast<TADDR>(this) ==
6362 dac_cast<TADDR>(SystemDomain::System()->DefaultDomain()))
6365 return (PVOID)DEFAULT_DOMAIN_FRIENDLY_NAME;
6373 #endif // DACCESS_COMPILE
6375 #ifndef DACCESS_COMPILE
6377 BOOL AppDomain::AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAllowFailure)
6384 PRECONDITION(CheckPointer(pSpec));
6385 // Hosted fusion binder makes an exception here, so we cannot assert.
6386 //PRECONDITION(pSpec->CanUseWithBindingCache());
6387 //PRECONDITION(pFile->CanUseWithBindingCache());
6388 INJECT_FAULT(COMPlusThrowOM(););
6392 CrstHolder holder(&m_DomainCacheCrst);
6393 // !!! suppress exceptions
6394 if(!m_AssemblyCache.StoreFile(pSpec, pFile) && !fAllowFailure)
6396 // TODO: Disabling the below assertion as currently we experience
6397 // inconsistency on resolving the Microsoft.Office.Interop.MSProject.dll
6398 // This causes below assertion to fire and crashes the VS. This issue
6399 // is being tracked with Dev10 Bug 658555. Brought back it when this bug
6403 EEFileLoadException::Throw(pSpec, FUSION_E_CACHEFILE_FAILED, NULL);
6409 BOOL AppDomain::AddAssemblyToCache(AssemblySpec* pSpec, DomainAssembly *pAssembly)
6416 PRECONDITION(CheckPointer(pSpec));
6417 PRECONDITION(CheckPointer(pAssembly));
6418 PRECONDITION(pSpec->CanUseWithBindingCache());
6419 PRECONDITION(pAssembly->CanUseWithBindingCache());
6420 INJECT_FAULT(COMPlusThrowOM(););
6424 CrstHolder holder(&m_DomainCacheCrst);
6425 // !!! suppress exceptions
6426 BOOL bRetVal = m_AssemblyCache.StoreAssembly(pSpec, pAssembly);
6430 BOOL AppDomain::AddExceptionToCache(AssemblySpec* pSpec, Exception *ex)
6437 PRECONDITION(CheckPointer(pSpec));
6438 PRECONDITION(pSpec->CanUseWithBindingCache());
6439 INJECT_FAULT(COMPlusThrowOM(););
6443 if (ex->IsTransient())
6446 CrstHolder holder(&m_DomainCacheCrst);
6447 // !!! suppress exceptions
6448 return m_AssemblyCache.StoreException(pSpec, ex);
6451 void AppDomain::AddUnmanagedImageToCache(LPCWSTR libraryName, HMODULE hMod)
6458 PRECONDITION(CheckPointer(libraryName));
6459 INJECT_FAULT(COMPlusThrowOM(););
6465 spec.SetCodeBase(libraryName);
6466 m_UnmanagedCache.InsertEntry(&spec, hMod);
6472 HMODULE AppDomain::FindUnmanagedImageInCache(LPCWSTR libraryName)
6479 PRECONDITION(CheckPointer(libraryName,NULL_OK));
6480 POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
6481 INJECT_FAULT(COMPlusThrowOM(););
6484 if(libraryName == NULL) RETURN NULL;
6487 spec.SetCodeBase(libraryName);
6488 RETURN (HMODULE) m_UnmanagedCache.LookupEntry(&spec, 0);
6492 BOOL AppDomain::IsCached(AssemblySpec *pSpec)
6494 WRAPPER_NO_CONTRACT;
6496 // Check to see if this fits our rather loose idea of a reference to mscorlib.
6497 // If so, don't use fusion to bind it - do it ourselves.
6498 if (pSpec->IsMscorlib())
6501 return m_AssemblyCache.Contains(pSpec);
6504 void AppDomain::GetCacheAssemblyList(SetSHash<PTR_DomainAssembly>& assemblyList)
6506 CrstHolder holder(&m_DomainCacheCrst);
6507 m_AssemblyCache.GetAllAssemblies(assemblyList);
6510 PEAssembly* AppDomain::FindCachedFile(AssemblySpec* pSpec, BOOL fThrow /*=TRUE*/)
6526 // Check to see if this fits our rather loose idea of a reference to mscorlib.
6527 // If so, don't use fusion to bind it - do it ourselves.
6528 if (fThrow && pSpec->IsMscorlib())
6530 CONSISTENCY_CHECK(SystemDomain::System()->SystemAssembly() != NULL);
6531 PEAssembly *pFile = SystemDomain::System()->SystemFile();
6536 return m_AssemblyCache.LookupFile(pSpec, fThrow);
6540 BOOL AppDomain::PostBindResolveAssembly(AssemblySpec *pPrePolicySpec,
6541 AssemblySpec *pPostPolicySpec,
6542 HRESULT hrBindResult,
6543 AssemblySpec **ppFailedSpec)
6545 STATIC_CONTRACT_THROWS;
6546 STATIC_CONTRACT_GC_TRIGGERS;
6547 PRECONDITION(CheckPointer(pPrePolicySpec));
6548 PRECONDITION(CheckPointer(pPostPolicySpec));
6549 PRECONDITION(CheckPointer(ppFailedSpec));
6551 BOOL fFailure = TRUE;
6552 *ppFailedSpec = pPrePolicySpec;
6555 PEAssemblyHolder result;
6557 if ((EEFileLoadException::GetFileLoadKind(hrBindResult) == kFileNotFoundException) ||
6558 (hrBindResult == FUSION_E_REF_DEF_MISMATCH) ||
6559 (hrBindResult == FUSION_E_INVALID_NAME))
6561 result = TryResolveAssembly(*ppFailedSpec, FALSE /* fPreBind */);
6563 if (result != NULL && pPrePolicySpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
6567 // Given the post-policy resolve event construction of the CLR binder,
6568 // chained managed resolve events can race with each other, therefore we do allow
6569 // the adding of the result to fail. Checking for already chached specs
6570 // is not an option as it would introduce another race window.
6571 // The binder does a re-fetch of the
6572 // orignal binding spec and therefore will not cause inconsistency here.
6573 // For the purposes of the resolve event, failure to add to the cache still is a success.
6574 AddFileToCache(pPrePolicySpec, result, TRUE /* fAllowFailure */);
6575 if (*ppFailedSpec != pPrePolicySpec && pPostPolicySpec->CanUseWithBindingCache())
6577 AddFileToCache(pPostPolicySpec, result, TRUE /* fAllowFailure */ );
6585 //----------------------------------------------------------------------------------------
6586 // Helper class for hosted binder
6588 class PEAssemblyAsPrivAssemblyInfo : public IUnknownCommon<ICLRPrivAssemblyInfo>
6591 //------------------------------------------------------------------------------------
6594 PEAssemblyAsPrivAssemblyInfo(PEAssembly *pPEAssembly)
6596 LIMITED_METHOD_CONTRACT;
6597 STATIC_CONTRACT_THROWS;
6599 if (pPEAssembly == nullptr)
6600 ThrowHR(E_UNEXPECTED);
6602 pPEAssembly->AddRef();
6603 m_pPEAssembly = pPEAssembly;
6606 //------------------------------------------------------------------------------------
6607 // ICLRPrivAssemblyInfo methods
6609 //------------------------------------------------------------------------------------
6610 STDMETHOD(GetAssemblyName)(
6611 __in DWORD cchBuffer,
6612 __out_opt LPDWORD pcchBuffer,
6613 __out_ecount_part_opt(cchBuffer, *pcchBuffer) LPWSTR wzBuffer)
6625 if ((cchBuffer == 0) != (wzBuffer == nullptr))
6627 return E_INVALIDARG;
6630 LPCUTF8 szName = m_pPEAssembly->GetSimpleName();
6634 IfFailRet(FString::Utf8_Unicode_Length(szName, &bIsAscii, &cchName));
6636 if (cchBuffer < cchName + 1)
6638 if (pcchBuffer != nullptr)
6640 *pcchBuffer = cchName + 1;
6642 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6646 IfFailRet(FString::Utf8_Unicode(szName, bIsAscii, wzBuffer, cchName));
6647 if (pcchBuffer != nullptr)
6649 *pcchBuffer = cchName;
6655 //------------------------------------------------------------------------------------
6656 STDMETHOD(GetAssemblyVersion)(
6662 WRAPPER_NO_CONTRACT;
6663 return m_pPEAssembly->GetVersion(pMajor, pMinor, pBuild, pRevision);
6666 //------------------------------------------------------------------------------------
6667 STDMETHOD(GetAssemblyPublicKey)(
6672 STATIC_CONTRACT_LIMITED_METHOD;
6673 STATIC_CONTRACT_CAN_TAKE_LOCK;
6675 VALIDATE_PTR_RET(pcbBuffer);
6676 VALIDATE_CONDITION((pbBuffer == nullptr) == (cbBuffer == 0), return E_INVALIDARG);
6682 // Note: PEAssembly::GetPublicKey will return bogus data pointer when *pcbBuffer == 0
6683 LPCVOID pbKey = m_pPEAssembly->GetPublicKey(pcbBuffer);
6685 if (*pcbBuffer != 0)
6687 if (pbBuffer != nullptr && cbBuffer >= *pcbBuffer)
6689 memcpy(pbBuffer, pbKey, *pcbBuffer);
6694 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6699 hr = S_FALSE; // ==> No public key
6702 EX_CATCH_HRESULT(hr);
6708 ReleaseHolder<PEAssembly> m_pPEAssembly;
6711 //-----------------------------------------------------------------------------------------------------------------
6712 static HRESULT VerifyBindHelper(
6713 ICLRPrivAssembly *pPrivAssembly,
6714 IAssemblyName *pAssemblyName,
6715 PEAssembly *pPEAssembly)
6717 STATIC_CONTRACT_THROWS;
6718 STATIC_CONTRACT_GC_TRIGGERS;
6721 // Create an ICLRPrivAssemblyInfo to call to ICLRPrivAssembly::VerifyBind
6722 NewHolder<PEAssemblyAsPrivAssemblyInfo> pPrivAssemblyInfoImpl = new PEAssemblyAsPrivAssemblyInfo(pPEAssembly);
6723 ReleaseHolder<ICLRPrivAssemblyInfo> pPrivAssemblyInfo;
6724 IfFailRet(pPrivAssemblyInfoImpl->QueryInterface(__uuidof(ICLRPrivAssemblyInfo), (LPVOID *)&pPrivAssemblyInfo));
6725 pPrivAssemblyInfoImpl.SuppressRelease();
6727 // Call VerifyBind to give the host a chance to reject the bind based on assembly image contents.
6728 IfFailRet(pPrivAssembly->VerifyBind(pAssemblyName, pPrivAssembly, pPrivAssemblyInfo));
6733 //-----------------------------------------------------------------------------------------------------------------
6734 HRESULT AppDomain::BindAssemblySpecForHostedBinder(
6735 AssemblySpec * pSpec,
6736 IAssemblyName * pAssemblyName,
6737 ICLRPrivBinder * pBinder,
6738 PEAssembly ** ppAssembly)
6740 STANDARD_VM_CONTRACT;
6742 PRECONDITION(CheckPointer(pSpec));
6743 PRECONDITION(pSpec->GetAppDomain() == this);
6744 PRECONDITION(CheckPointer(ppAssembly));
6745 PRECONDITION(pSpec->GetCodeBase() == nullptr);
6750 // The Fusion binder can throw (to preserve compat, since it will actually perform an assembly
6751 // load as part of it's bind), so we need to be careful here to catch any FileNotFoundException
6752 // objects if fThrowIfNotFound is false.
6753 ReleaseHolder<ICLRPrivAssembly> pPrivAssembly;
6755 // We return HRESULTs here on failure instead of throwing as failures here are not necessarily indicative
6756 // of an actual application problem. Returning an error code is substantially faster than throwing, and
6757 // should be used when possible.
6758 IfFailRet(pBinder->BindAssemblyByName(pAssemblyName, &pPrivAssembly));
6760 IfFailRet(BindHostedPrivAssembly(nullptr, pPrivAssembly, pAssemblyName, ppAssembly));
6766 //-----------------------------------------------------------------------------------------------------------------
6768 AppDomain::BindHostedPrivAssembly(
6769 PEAssembly * pParentAssembly,
6770 ICLRPrivAssembly * pPrivAssembly,
6771 IAssemblyName * pAssemblyName,
6772 PEAssembly ** ppAssembly,
6773 BOOL fIsIntrospectionOnly) // = FALSE
6775 STANDARD_VM_CONTRACT;
6777 PRECONDITION(CheckPointer(pPrivAssembly));
6778 PRECONDITION(CheckPointer(ppAssembly));
6782 *ppAssembly = nullptr;
6784 // See if result has been previously loaded.
6786 DomainAssembly* pDomainAssembly = FindAssembly(pPrivAssembly);
6787 if (pDomainAssembly != nullptr)
6789 *ppAssembly = clr::SafeAddRef(pDomainAssembly->GetFile());
6793 if (*ppAssembly != nullptr)
6794 { // Already exists: ask the binder to verify and return the assembly.
6795 return VerifyBindHelper(pPrivAssembly, pAssemblyName, *ppAssembly);
6798 // Get the IL PEFile.
6799 PEImageHolder pPEImageIL;
6801 // Does not already exist, so get the resource for the assembly and load it.
6803 ReleaseHolder<ICLRPrivResource> pIResourceIL;
6805 IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_IL, &dwImageType, &pIResourceIL));
6806 _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_IL);
6808 pPEImageIL = PEImage::OpenImage(pIResourceIL, MDInternalImport_Default);
6811 // See if an NI is available.
6812 DWORD dwAvailableImages;
6813 IfFailRet(pPrivAssembly->GetAvailableImageTypes(&dwAvailableImages));
6814 _ASSERTE(dwAvailableImages & ASSEMBLY_IMAGE_TYPE_IL); // Just double checking that IL bit is always set.
6816 // Get the NI PEFile if available.
6817 PEImageHolder pPEImageNI;
6818 if (dwAvailableImages & ASSEMBLY_IMAGE_TYPE_NATIVE)
6821 ReleaseHolder<ICLRPrivResource> pIResourceNI;
6823 IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_NATIVE, &dwImageType, &pIResourceNI));
6824 _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_NATIVE || FAILED(hr));
6826 pPEImageNI = PEImage::OpenImage(pIResourceNI, MDInternalImport_TrustedNativeImage);
6828 _ASSERTE(pPEImageIL != nullptr);
6830 // Create a PEAssembly using the IL and NI images.
6831 PEAssemblyHolder pPEAssembly = PEAssembly::Open(pParentAssembly, pPEImageIL, pPEImageNI, pPrivAssembly, fIsIntrospectionOnly);
6834 // Ask the binder to verify.
6835 IfFailRet(VerifyBindHelper(pPrivAssembly, pAssemblyName, pPEAssembly));
6838 *ppAssembly = pPEAssembly.Extract();
6841 } // AppDomain::BindHostedPrivAssembly
6843 //---------------------------------------------------------------------------------------------------------------------
6844 PEAssembly * AppDomain::BindAssemblySpec(
6845 AssemblySpec * pSpec,
6846 BOOL fThrowOnFileNotFound,
6847 BOOL fRaisePrebindEvents,
6848 StackCrawlMark * pCallerStackMark,
6849 BOOL fUseHostBinderIfAvailable)
6851 STATIC_CONTRACT_THROWS;
6852 STATIC_CONTRACT_GC_TRIGGERS;
6853 PRECONDITION(CheckPointer(pSpec));
6854 PRECONDITION(pSpec->GetAppDomain() == this);
6855 PRECONDITION(this==::GetAppDomain());
6859 BOOL fForceReThrow = FALSE;
6861 #if defined(FEATURE_COMINTEROP)
6862 // Handle WinRT assemblies in the classic/hybrid scenario. If this is an AppX process,
6863 // then this case will be handled by the previous block as part of the full set of
6864 // available binding hosts.
6865 if (pSpec->IsContentType_WindowsRuntime())
6869 // Get the assembly display name.
6870 ReleaseHolder<IAssemblyName> pAssemblyName;
6872 IfFailThrow(pSpec->CreateFusionName(&pAssemblyName, TRUE, TRUE));
6875 PEAssemblyHolder pAssembly;
6879 hr = BindAssemblySpecForHostedBinder(pSpec, pAssemblyName, m_pWinRtBinder, &pAssembly);
6881 goto EndTry2; // Goto end of try block.
6884 // The combination of this conditional catch/ the following if statement which will throw reduces the count of exceptions
6885 // thrown in scenarios where the exception does not escape the method. We cannot get rid of the try/catch block, as
6886 // there are cases within some of the clrpriv binder's which throw.
6887 // Note: In theory, FileNotFound should always come here as HRESULT, never as exception.
6888 EX_CATCH_HRESULT_IF(hr,
6889 !fThrowOnFileNotFound && Assembly::FileNotFound(hr))
6891 if (FAILED(hr) && (fThrowOnFileNotFound || !Assembly::FileNotFound(hr)))
6893 if (Assembly::FileNotFound(hr))
6895 _ASSERTE(fThrowOnFileNotFound);
6896 // Uses defaultScope
6897 EEFileLoadException::Throw(pSpec, hr);
6900 // WinRT type bind failures
6901 _ASSERTE(pSpec->IsContentType_WindowsRuntime());
6902 if (hr == HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE)) // Returned by RoResolveNamespace when using 3rd party WinRT types in classic process
6904 if (fThrowOnFileNotFound)
6905 { // Throw NotSupportedException (with custom message) wrapped by TypeLoadException to give user type name for diagnostics
6906 // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6907 EEMessageException ex(kNotSupportedException, IDS_EE_WINRT_THIRDPARTY_NOTSUPPORTED);
6908 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
6911 else if ((hr == CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT) || // Returned e.g. for WinRT type name without namespace
6912 (hr == COR_E_PLATFORMNOTSUPPORTED)) // Using WinRT on pre-Win8 OS
6914 if (fThrowOnFileNotFound)
6915 { // Throw ArgumentException/PlatformNotSupportedException wrapped by TypeLoadException to give user type name for diagnostics
6916 // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6917 EEMessageException ex(hr);
6918 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
6926 _ASSERTE((FAILED(hr) && !fThrowOnFileNotFound) || pAssembly != nullptr);
6928 return pAssembly.Extract();
6931 #endif // FEATURE_COMINTEROP
6932 if (pSpec->HasUniqueIdentity())
6934 HRESULT hrBindResult = S_OK;
6935 PEAssemblyHolder result;
6940 if (!IsCached(pSpec))
6944 bool fAddFileToCache = false;
6946 BOOL fIsWellKnown = FALSE;
6948 // Use CoreClr's fusion alternative
6949 CoreBindResult bindResult;
6951 pSpec->Bind(this, fThrowOnFileNotFound, &bindResult, FALSE /* fNgenExplicitBind */, FALSE /* fExplicitBindToNativeImage */, pCallerStackMark);
6952 hrBindResult = bindResult.GetHRBindResult();
6954 if (bindResult.Found())
6956 if (SystemDomain::SystemFile() && bindResult.IsMscorlib())
6958 // Avoid rebinding to another copy of mscorlib
6959 result = SystemDomain::SystemFile();
6960 result.SuppressRelease(); // Didn't get a refcount
6964 // IsSystem on the PEFile should be false, even for mscorlib satellites
6965 result = PEAssembly::Open(&bindResult,
6966 FALSE, pSpec->IsIntrospectionOnly());
6968 fAddFileToCache = true;
6970 // Setup the reference to the binder, which performed the bind, into the AssemblySpec
6971 ICLRPrivBinder* pBinder = result->GetBindingContext();
6972 _ASSERTE(pBinder != NULL);
6973 pSpec->SetBindingContext(pBinder);
6977 if (fAddFileToCache)
6981 if (pSpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
6983 // Failure to add simply means someone else beat us to it. In that case
6984 // the FindCachedFile call below (after catch block) will update result
6985 // to the cached value.
6986 AddFileToCache(pSpec, result, TRUE /*fAllowFailure*/);
6989 else if (!fIsWellKnown)
6991 _ASSERTE(fThrowOnFileNotFound == FALSE);
6993 // Don't trigger the resolve event for the CoreLib satellite assembly. A misbehaving resolve event may
6994 // return an assembly that does not match, and this can cause recursive resource lookups during error
6995 // reporting. The CoreLib satellite assembly is loaded from relative locations based on the culture, see
6996 // AssemblySpec::Bind().
6997 if (!pSpec->IsMscorlibSatellite())
6999 // Trigger the resolve event also for non-throw situation.
7000 // However, this code path will behave as if the resolve handler has thrown,
7001 // that is, not trigger an MDA.
7003 AssemblySpec NewSpec(this);
7004 AssemblySpec *pFailedSpec = NULL;
7006 fForceReThrow = TRUE; // Managed resolve event handler can throw
7008 // Purposly ignore return value
7009 PostBindResolveAssembly(pSpec, &NewSpec, hrBindResult, &pFailedSpec);
7017 Exception *ex = GET_EXCEPTION();
7019 AssemblySpec NewSpec(this);
7020 AssemblySpec *pFailedSpec = NULL;
7022 // Let transient exceptions or managed resolve event handler exceptions propagate
7023 if (ex->IsTransient() || fForceReThrow)
7029 // This is not executed for SO exceptions so we need to disable the backout
7030 // stack validation to prevent false violations from being reported.
7031 DISABLE_BACKOUT_STACK_VALIDATION;
7033 BOOL fFailure = PostBindResolveAssembly(pSpec, &NewSpec, ex->GetHR(), &pFailedSpec);
7036 BOOL bFileNotFoundException =
7037 (EEFileLoadException::GetFileLoadKind(ex->GetHR()) == kFileNotFoundException);
7039 if (!bFileNotFoundException)
7041 fFailure = AddExceptionToCache(pFailedSpec, ex);
7042 } // else, fFailure stays TRUE
7043 // Effectively, fFailure == bFileNotFoundException || AddExceptionToCache(pFailedSpec, ex)
7045 // Only throw this exception if we are the first in the cache
7049 // If the BindingFailure MDA is enabled, trigger one for this failure
7050 // Note: TryResolveAssembly() can also throw if an AssemblyResolve event subscriber throws
7051 // and the MDA isn't sent in this case (or for transient failure cases)
7053 #ifdef MDA_SUPPORTED
7054 MdaBindingFailure* pProbe = MDA_GET_ASSISTANT(BindingFailure);
7057 // Transition to cooperative GC mode before using any OBJECTREFs.
7060 OBJECTREF exceptionObj = GET_THROWABLE();
7061 GCPROTECT_BEGIN(exceptionObj)
7063 pProbe->BindFailed(pFailedSpec, &exceptionObj);
7069 // In the same cases as for the MDA, store the failure information for DAC to read
7070 if (IsDebuggerAttached()) {
7071 FailedAssembly *pFailed = new FailedAssembly();
7072 pFailed->Initialize(pFailedSpec, ex);
7073 IfFailThrow(m_failedAssemblies.Append(pFailed));
7076 if (!bFileNotFoundException || fThrowOnFileNotFound)
7079 // V1.1 App-compatibility workaround. See VSW530166 if you want to whine about it.
7081 // In Everett, if we failed to download an assembly because of a broken network cable,
7082 // we returned a FileNotFoundException with a COR_E_FILENOTFOUND hr embedded inside
7083 // (which would be exposed when marshaled to native.)
7085 // In Whidbey, we now set the more appropriate INET_E_RESOURCE_NOT_FOUND hr. But
7086 // the online/offline switch code in VSTO for Everett hardcoded a check for
7087 // COR_E_FILENOTFOUND.
7089 // So now, to keep that code from breaking, we have to remap INET_E_RESOURCE_NOT_FOUND
7090 // back to COR_E_FILENOTFOUND. We're doing it here rather down in Fusion so as to affect
7091 // the least number of callers.
7093 if (ex->GetHR() == INET_E_RESOURCE_NOT_FOUND)
7095 EEFileLoadException::Throw(pFailedSpec, COR_E_FILENOTFOUND, ex);
7098 if (EEFileLoadException::CheckType(ex))
7100 if (pFailedSpec == pSpec)
7102 EX_RETHROW; //preserve the information
7106 StackSString exceptionDisplayName, failedSpecDisplayName;
7108 ((EEFileLoadException*)ex)->GetName(exceptionDisplayName);
7109 pFailedSpec->GetFileOrDisplayName(0, failedSpecDisplayName);
7111 if (exceptionDisplayName.CompareCaseInsensitive(failedSpecDisplayName) == 0)
7113 EX_RETHROW; // Throw the original exception. Otherwise, we'd throw an exception that contains the same message twice.
7118 EEFileLoadException::Throw(pFailedSpec, ex->GetHR(), ex);
7125 EX_END_CATCH(RethrowTerminalExceptions);
7127 // 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
7128 // thread to store our result. Note that we may throw from here, if there is a cached exception.
7129 // This will release the refcount of the current result holder (if any), and will replace
7130 // it with a non-addref'ed result
7131 if (pSpec->CanUseWithBindingCache() && (result== NULL || result->CanUseWithBindingCache()))
7133 result = FindCachedFile(pSpec);
7139 return result.Extract();
7143 // Unsupported content type
7144 if (fThrowOnFileNotFound)
7146 ThrowHR(COR_E_BADIMAGEFORMAT);
7150 } // AppDomain::BindAssemblySpec
7154 PEAssembly *AppDomain::TryResolveAssembly(AssemblySpec *pSpec, BOOL fPreBind)
7156 STATIC_CONTRACT_THROWS;
7157 STATIC_CONTRACT_GC_TRIGGERS;
7158 STATIC_CONTRACT_MODE_ANY;
7160 PEAssembly *result = NULL;
7164 result = pSpec->ResolveAssemblyFile(this, fPreBind);
7168 Exception *pEx = GET_EXCEPTION();
7170 if (!pEx->IsTransient())
7172 AddExceptionToCache(pSpec, pEx);
7173 if (!EEFileLoadException::CheckType(pEx))
7174 EEFileLoadException::Throw(pSpec, pEx->GetHR(), pEx);
7183 ULONG AppDomain::AddRef()
7185 LIMITED_METHOD_CONTRACT;
7186 return InterlockedIncrement(&m_cRef);
7189 ULONG AppDomain::Release()
7196 PRECONDITION(m_cRef > 0);
7200 ULONG cRef = InterlockedDecrement(&m_cRef);
7203 _ASSERTE (m_Stage == STAGE_CREATING || m_Stage == STAGE_CLOSED);
7206 TESTHOOKCALL(AppDomainDestroyed(adid.m_dwId));
7212 AppDomain* AppDomain::s_pAppDomainToRaiseUnloadEvent;
7213 BOOL AppDomain::s_fProcessUnloadDomainEvent = FALSE;
7215 #ifndef CROSSGEN_COMPILE
7217 void AppDomain::RaiseUnloadDomainEvent_Wrapper(LPVOID ptr)
7224 INJECT_FAULT(COMPlusThrowOM(););
7229 AppDomain* pDomain = (AppDomain *) ptr;
7230 pDomain->RaiseUnloadDomainEvent();
7233 void AppDomain::ProcessUnloadDomainEventOnFinalizeThread()
7242 Thread *pThread = GetThread();
7243 _ASSERTE (pThread && IsFinalizerThread());
7245 // if we are not unloading domain now, do not process the event
7246 if (SystemDomain::AppDomainBeingUnloaded() == NULL)
7248 s_pAppDomainToRaiseUnloadEvent->SetStage(STAGE_UNLOAD_REQUESTED);
7249 s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
7250 s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7251 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
7254 FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, TRUE);
7255 AppDomain::EnableADUnloadWorkerForFinalizer();
7256 pThread->SetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
7257 s_pAppDomainToRaiseUnloadEvent->RaiseUnloadDomainEvent();
7258 pThread->ResetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
7259 s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
7260 s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7261 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
7262 FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, FALSE);
7264 if (pThread->IsAbortRequested())
7266 pThread->UnmarkThreadForAbort(Thread::TAR_Thread);
7270 void AppDomain::RaiseUnloadDomainEvent()
7281 Thread *pThread = GetThread();
7282 if (this != pThread->GetDomain())
7284 pThread->DoADCallBack(this, AppDomain::RaiseUnloadDomainEvent_Wrapper, this,ADV_FINALIZER|ADV_COMPILATION);
7290 APPDOMAINREF Domain;
7293 ZeroMemory(&gc, sizeof(gc));
7295 GCPROTECT_BEGIN(gc);
7296 gc.Domain = (APPDOMAINREF) GetRawExposedObject();
7297 if (gc.Domain != NULL)
7299 gc.Delegate = gc.Domain->m_pDomainUnloadEventHandler;
7300 if (gc.Delegate != NULL)
7301 DistributeEvent(&gc.Delegate, (OBJECTREF *) &gc.Domain);
7307 void AppDomain::RaiseLoadingAssemblyEvent(DomainAssembly *pAssembly)
7313 PRECONDITION(this == GetAppDomain());
7320 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
7325 APPDOMAINREF AppDomainRef;
7328 ZeroMemory(&gc, sizeof(gc));
7330 if ((gc.AppDomainRef = (APPDOMAINREF) GetRawExposedObject()) != NULL) {
7331 if (gc.AppDomainRef->m_pAssemblyEventHandler != NULL)
7334 GCPROTECT_BEGIN(gc);
7336 gc.orThis = pAssembly->GetExposedAssemblyObject();
7338 MethodDescCallSite onAssemblyLoad(METHOD__APP_DOMAIN__ON_ASSEMBLY_LOAD, &gc.orThis);
7340 // GetExposedAssemblyObject may cause a gc, so call this before filling args[0]
7341 args[1] = ObjToArgSlot(gc.orThis);
7342 args[0] = ObjToArgSlot(gc.AppDomainRef);
7344 onAssemblyLoad.Call(args);
7353 EX_END_CATCH(SwallowAllExceptions);
7357 BOOL AppDomain::OnUnhandledException(OBJECTREF *pThrowable, BOOL isTerminating/*=TRUE*/)
7359 STATIC_CONTRACT_NOTHROW;
7360 STATIC_CONTRACT_GC_TRIGGERS;
7361 STATIC_CONTRACT_MODE_ANY;
7367 // The Everett behavior was to send the unhandled exception event only to the Default
7368 // AppDomain (since that's the only place that exceptions actually went unhandled).
7370 // During Whidbey development, we broadcast the event to all AppDomains in the process.
7372 // But the official shipping Whidbey behavior is that the unhandled exception event is
7373 // sent to the Default AppDomain and to whatever AppDomain the exception went unhandled
7374 // in. To achieve this, we declare the exception to be unhandled *BEFORE* we marshal
7375 // it back to the Default AppDomain at the base of the Finalizer, threadpool and managed
7378 // The rationale for sending the event to the Default AppDomain as well as the one the
7379 // exception went unhandled in is:
7381 // 1) This is compatible with the pre-Whidbey behavior, where only the Default AppDomain
7382 // received the notification.
7384 // 2) This is convenient for hosts, which don't want to bother injecting listeners into
7385 // every single AppDomain.
7387 AppDomain *pAppDomain = GetAppDomain();
7388 OBJECTREF orSender = 0;
7390 GCPROTECT_BEGIN(orSender);
7392 orSender = pAppDomain->GetRawExposedObject();
7394 retVal = pAppDomain->RaiseUnhandledExceptionEventNoThrow(&orSender, pThrowable, isTerminating);
7402 // Move outside of the AppDomain iteration, to avoid issues with the GC Frames being outside
7403 // the domain transition. This is a chronic issue that causes us to report roots for an AppDomain
7404 // after we have left it. This causes problems with AppDomain unloading that we only find
7405 // with stress coverage..
7406 void AppDomain::RaiseOneExitProcessEvent()
7418 APPDOMAINREF Domain;
7421 ZeroMemory(&gc, sizeof(gc));
7423 GCPROTECT_BEGIN(gc);
7424 gc.Domain = (APPDOMAINREF) SystemDomain::GetCurrentDomain()->GetRawExposedObject();
7425 if (gc.Domain != NULL)
7427 gc.Delegate = gc.Domain->m_pProcessExitEventHandler;
7428 if (gc.Delegate != NULL)
7429 DistributeEvent(&gc.Delegate, (OBJECTREF *) &gc.Domain);
7434 // Local wrapper used in AppDomain::RaiseExitProcessEvent,
7435 // introduced solely to avoid stack overflow because of _alloca in the loop.
7436 // It's just factored out body of the loop, but it has to be a member method of AppDomain,
7437 // because it calls private RaiseOneExitProcessEvent
7438 /*static*/ void AppDomain::RaiseOneExitProcessEvent_Wrapper(AppDomainIterator* pi)
7440 STATIC_CONTRACT_MODE_COOPERATIVE;
7441 STATIC_CONTRACT_THROWS;
7442 STATIC_CONTRACT_GC_TRIGGERS;
7444 ENTER_DOMAIN_PTR(pi->GetDomain(), ADV_ITERATOR)
7445 AppDomain::RaiseOneExitProcessEvent();
7446 END_DOMAIN_TRANSITION;
7449 static LONG s_ProcessedExitProcessEventCount = 0;
7451 LONG GetProcessedExitProcessEventCount()
7453 LIMITED_METHOD_CONTRACT;
7454 return s_ProcessedExitProcessEventCount;
7457 void AppDomain::RaiseExitProcessEvent()
7462 STATIC_CONTRACT_MODE_COOPERATIVE;
7463 STATIC_CONTRACT_THROWS;
7464 STATIC_CONTRACT_GC_TRIGGERS;
7466 // Only finalizer thread during shutdown can call this function.
7467 _ASSERTE ((g_fEEShutDown&ShutDown_Finalize1) && GetThread() == FinalizerThread::GetFinalizerThread());
7469 _ASSERTE (GetThread()->PreemptiveGCDisabled());
7471 _ASSERTE (GetThread()->GetDomain()->IsDefaultDomain());
7473 AppDomainIterator i(TRUE);
7476 RaiseOneExitProcessEvent_Wrapper(&i);
7477 FastInterlockIncrement(&s_ProcessedExitProcessEventCount);
7483 AppDomain::RaiseUnhandledExceptionEventNoThrow(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating)
7496 bRetVal = RaiseUnhandledExceptionEvent(pSender, pThrowable, isTerminating);
7501 EX_END_CATCH(SwallowAllExceptions) // Swallow any errors.
7507 AppDomain::HasUnhandledExceptionEventHandler()
7512 GC_NOTRIGGER; //essential
7516 if (!CanThreadEnter(GetThread()))
7518 if (GetRawExposedObject()==NULL)
7520 return (((APPDOMAINREF)GetRawExposedObject())->m_pUnhandledExceptionEventHandler!=NULL);
7524 AppDomain::RaiseUnhandledExceptionEvent(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating)
7531 INJECT_FAULT(COMPlusThrowOM(););
7535 if (!HasUnhandledExceptionEventHandler())
7538 BOOL result = FALSE;
7540 _ASSERTE(pThrowable != NULL && IsProtectedByGCFrame(pThrowable));
7541 _ASSERTE(pSender != NULL && IsProtectedByGCFrame(pSender));
7543 _ASSERTE(this == GetThread()->GetDomain());
7546 OBJECTREF orDelegate = NULL;
7548 GCPROTECT_BEGIN(orDelegate);
7550 APPDOMAINREF orAD = (APPDOMAINREF) GetAppDomain()->GetRawExposedObject();
7554 orDelegate = orAD->m_pUnhandledExceptionEventHandler;
7555 if (orDelegate != NULL)
7558 DistributeUnhandledExceptionReliably(&orDelegate, pSender, pThrowable, isTerminating);
7567 #endif // CROSSGEN_COMPILE
7569 // You must be in the correct context before calling this
7570 // routine. Therefore, it is only good for initializing the
7572 void AppDomain::InitializeDomainContext(BOOL allowRedirects,
7581 INJECT_FAULT(COMPlusThrowOM(););
7585 if (NingenEnabled())
7588 CreateFusionContext();
7593 #ifndef CROSSGEN_COMPILE
7595 STRINGREF pFilePath;
7598 PTRARRAYREF propertyNames;
7599 PTRARRAYREF propertyValues;
7601 ZeroMemory(&gc, sizeof(gc));
7603 GCPROTECT_BEGIN(gc);
7606 gc.pFilePath = StringObject::NewString(pwszPath);
7611 gc.pConfig = StringObject::NewString(pwszConfig);
7615 if ((gc.ref = GetExposedObject()) != NULL)
7617 MethodDescCallSite setupDomain(METHOD__APP_DOMAIN__SETUP_DOMAIN);
7621 ObjToArgSlot(gc.ref),
7622 BoolToArgSlot(allowRedirects),
7623 ObjToArgSlot(gc.pFilePath),
7624 ObjToArgSlot(gc.pConfig),
7625 ObjToArgSlot(gc.propertyNames),
7626 ObjToArgSlot(gc.propertyValues)
7628 setupDomain.Call(args);
7631 #endif // CROSSGEN_COMPILE
7635 IUnknown *AppDomain::CreateFusionContext()
7637 CONTRACT(IUnknown *)
7642 POSTCONDITION(CheckPointer(RETVAL));
7643 INJECT_FAULT(COMPlusThrowOM(););
7647 if (!m_pFusionContext)
7649 ETWOnStartup (FusionAppCtx_V1, FusionAppCtxEnd_V1);
7650 CLRPrivBinderCoreCLR *pTPABinder = NULL;
7654 // Initialize the assembly binder for the default context loads for CoreCLR.
7655 IfFailThrow(CCoreCLRBinderHelper::DefaultBinderSetupContext(GetId().m_dwId, &pTPABinder));
7656 m_pFusionContext = reinterpret_cast<IUnknown *>(pTPABinder);
7658 // By default, initial binding context setup for CoreCLR is also the TPABinding context
7659 (m_pTPABinderContext = pTPABinder)->AddRef();
7663 RETURN m_pFusionContext;
7668 //---------------------------------------------------------------------------------------
7670 // AppDomain::IsDebuggerAttached - is a debugger attached to this process
7676 // TRUE if a debugger is attached to this process, FALSE otherwise.
7679 // This is identical to CORDebuggerAttached. This exists idependantly for legacy reasons - we used to
7680 // support attaching to individual AppDomains. This should probably go away eventually.
7683 BOOL AppDomain::IsDebuggerAttached()
7685 LIMITED_METHOD_CONTRACT;
7687 if (CORDebuggerAttached())
7697 #ifdef DEBUGGING_SUPPORTED
7699 // This is called from the debugger to request notification events from
7700 // Assemblies, Modules, Types in this appdomain.
7701 BOOL AppDomain::NotifyDebuggerLoad(int flags, BOOL attaching)
7703 WRAPPER_NO_CONTRACT;
7704 BOOL result = FALSE;
7706 if (!attaching && !IsDebuggerAttached())
7711 // Attach to our assemblies
7712 LOG((LF_CORDB, LL_INFO100, "AD::NDA: Iterating assemblies\n"));
7713 i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution));
7714 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7715 while (i.Next(pDomainAssembly.This()))
7717 result = (pDomainAssembly->NotifyDebuggerLoad(flags, attaching) ||
7724 void AppDomain::NotifyDebuggerUnload()
7726 WRAPPER_NO_CONTRACT;
7727 if (!IsDebuggerAttached())
7730 LOG((LF_CORDB, LL_INFO10, "AD::NDD domain [%d] %#08x %ls\n",
7731 GetId().m_dwId, this, GetFriendlyNameForLogging()));
7733 LOG((LF_CORDB, LL_INFO100, "AD::NDD: Interating domain bound assemblies\n"));
7734 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution));
7735 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7737 // Detach from our assemblies
7738 while (i.Next(pDomainAssembly.This()))
7740 LOG((LF_CORDB, LL_INFO100, "AD::NDD: Iterating assemblies\n"));
7741 pDomainAssembly->NotifyDebuggerUnload();
7744 #endif // DEBUGGING_SUPPORTED
7746 void AppDomain::SetSystemAssemblyLoadEventSent(BOOL fFlag)
7748 LIMITED_METHOD_CONTRACT;
7750 m_dwFlags |= LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
7752 m_dwFlags &= ~LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
7755 BOOL AppDomain::WasSystemAssemblyLoadEventSent(void)
7757 LIMITED_METHOD_CONTRACT;
7758 return ((m_dwFlags & LOAD_SYSTEM_ASSEMBLY_EVENT_SENT) == 0) ? FALSE : TRUE;
7761 #ifndef CROSSGEN_COMPILE
7762 // U->M thunks created in this domain and not associated with a delegate.
7763 UMEntryThunkCache *AppDomain::GetUMEntryThunkCache()
7770 INJECT_FAULT(COMPlusThrowOM(););
7774 if (!m_pUMEntryThunkCache)
7776 UMEntryThunkCache *pUMEntryThunkCache = new UMEntryThunkCache(this);
7778 if (FastInterlockCompareExchangePointer(&m_pUMEntryThunkCache, pUMEntryThunkCache, NULL) != NULL)
7780 // some thread swooped in and set the field
7781 delete pUMEntryThunkCache;
7784 _ASSERTE(m_pUMEntryThunkCache);
7785 return m_pUMEntryThunkCache;
7788 #ifdef FEATURE_COMINTEROP
7790 ComCallWrapperCache *AppDomain::GetComCallWrapperCache()
7797 INJECT_FAULT(COMPlusThrowOM(););
7801 if (! m_pComCallWrapperCache)
7803 BaseDomain::LockHolder lh(this);
7805 if (! m_pComCallWrapperCache)
7806 m_pComCallWrapperCache = ComCallWrapperCache::Create(this);
7808 _ASSERTE(m_pComCallWrapperCache);
7809 return m_pComCallWrapperCache;
7812 RCWRefCache *AppDomain::GetRCWRefCache()
7814 CONTRACT(RCWRefCache*)
7819 POSTCONDITION(CheckPointer(RETVAL));
7823 if (!m_pRCWRefCache) {
7824 NewHolder<RCWRefCache> pRCWRefCache = new RCWRefCache(this);
7825 if (FastInterlockCompareExchangePointer(&m_pRCWRefCache, (RCWRefCache *)pRCWRefCache, NULL) == NULL)
7827 pRCWRefCache.SuppressRelease();
7830 RETURN m_pRCWRefCache;
7833 RCWCache *AppDomain::CreateRCWCache()
7840 INJECT_FAULT(COMPlusThrowOM(););
7841 POSTCONDITION(CheckPointer(RETVAL));
7845 // Initialize the global RCW cleanup list here as well. This is so that it
7846 // it guaranteed to exist if any RCW's are created, but it is not created
7848 if (!g_pRCWCleanupList)
7850 SystemDomain::LockHolder lh;
7852 if (!g_pRCWCleanupList)
7853 g_pRCWCleanupList = new RCWCleanupList();
7855 _ASSERTE(g_pRCWCleanupList);
7858 BaseDomain::LockHolder lh(this);
7861 m_pRCWCache = new RCWCache(this);
7867 void AppDomain::ReleaseRCWs(LPVOID pCtxCookie)
7869 WRAPPER_NO_CONTRACT;
7871 m_pRCWCache->ReleaseWrappersWorker(pCtxCookie);
7873 RemoveWinRTFactoryObjects(pCtxCookie);
7876 void AppDomain::DetachRCWs()
7878 WRAPPER_NO_CONTRACT;
7880 m_pRCWCache->DetachWrappersWorker();
7883 #endif // FEATURE_COMINTEROP
7885 BOOL AppDomain::CanThreadEnter(Thread *pThread)
7887 WRAPPER_NO_CONTRACT;
7889 if (m_Stage < STAGE_EXITED)
7892 if (pThread == SystemDomain::System()->GetUnloadingThread())
7893 return m_Stage < STAGE_FINALIZING;
7894 if (pThread == FinalizerThread::GetFinalizerThread())
7895 return m_Stage < STAGE_FINALIZED;
7900 void AppDomain::AllowThreadEntrance(AppDomain * pApp)
7908 PRECONDITION(CheckPointer(pApp));
7912 if (pApp->GetUnloadRequestThread() == NULL)
7914 // This is asynchonous unload, either by a host, or by AppDomain.Unload from AD unload event.
7915 if (!pApp->IsUnloadingFromUnloadEvent())
7917 pApp->SetStage(STAGE_UNLOAD_REQUESTED);
7918 pApp->EnableADUnloadWorker(
7919 pApp->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7924 SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
7926 #ifdef FEATURE_COMINTEROP
7927 if (pApp->m_pComCallWrapperCache)
7928 pApp->m_pComCallWrapperCache->ResetDomainIsUnloading();
7929 #endif // FEATURE_COMINTEROP
7931 pApp->SetStage(STAGE_OPEN);
7934 void AppDomain::RestrictThreadEntrance(AppDomain * pApp)
7939 DISABLED(GC_TRIGGERS);
7941 DISABLED(FORBID_FAULT);
7942 PRECONDITION(CheckPointer(pApp));
7946 #ifdef FEATURE_COMINTEROP
7947 // Set the flag on our CCW cache so stubs won't enter
7948 if (pApp->m_pComCallWrapperCache)
7949 pApp->m_pComCallWrapperCache->SetDomainIsUnloading();
7950 #endif // FEATURE_COMINTEROP
7952 SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
7953 // Release our ID so remoting and thread pool won't enter
7954 pApp->SetStage(STAGE_EXITED);
7957 void AppDomain::Exit(BOOL fRunFinalizers, BOOL fAsyncExit)
7967 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Exiting domain [%d] %#08x %ls\n",
7968 GetId().m_dwId, this, GetFriendlyNameForLogging()));
7970 RestrictEnterHolder RestrictEnter(this);
7973 SystemDomain::LockHolder lh; // we don't want to close appdomain if other thread can be preparing to unload it
7974 SetStage(STAGE_EXITING); // Note that we're trying to exit
7977 // Raise the event indicating the domain is being unloaded.
7978 if (GetDefaultContext())
7980 FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, this);
7982 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
7983 //if (timeout == INFINITE)
7985 // timeout = 20000; // 20 seconds
7987 DWORD timeoutForFinalizer = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
7988 ULONGLONG curTime = CLRGetTickCount64();
7989 ULONGLONG endTime = 0;
7990 if (timeout != INFINITE)
7992 endTime = curTime + timeout;
7993 // We will try to kill AD unload event if it takes too long, and then we move on to the next registered caller.
7997 while (s_pAppDomainToRaiseUnloadEvent != NULL)
7999 FinalizerThread::FinalizerThreadWait(s_fProcessUnloadDomainEvent?timeout:timeoutForFinalizer);
8000 if (endTime != 0 && s_pAppDomainToRaiseUnloadEvent != NULL)
8002 if (CLRGetTickCount64() >= endTime)
8005 sThreadId.Printf(W("%x"), FinalizerThread::GetFinalizerThread()->GetThreadId());
8006 COMPlusThrow(kCannotUnloadAppDomainException,
8007 IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD,
8014 // Tell the tiered compilation manager to stop initiating any new work for background
8015 // jit optimization. Its possible the standard thread unwind mechanisms would pre-emptively
8016 // evacuate the jit threadpool worker threads from the domain on their own, but I see no reason
8017 // to take the risk of relying on them when we can easily augment with a cooperative
8018 // shutdown check. This notification only initiates the process of evacuating the threads
8019 // and then the UnwindThreads() call below is where blocking will occur to ensure the threads
8020 // have exited the domain.
8022 #ifdef FEATURE_TIERED_COMPILATION
8023 m_tieredCompilationManager.Shutdown();
8027 // Set up blocks so no threads can enter except for the finalizer and the thread
8028 // doing the unload.
8031 RestrictThreadEntrance(this);
8033 // Cause existing threads to abort out of this domain. This should ensure all
8034 // normal threads are outside the domain, and we've already ensured that no new threads
8037 PerAppDomainTPCountList::AppDomainUnloadingHolder tpAdUnloadHolder(GetTPIndex());
8040 if (!NingenEnabled())
8045 TESTHOOKCALL(UnwoundThreads(GetId().m_dwId)) ;
8046 ProcessEventForHost(Event_DomainUnload, (PVOID)(UINT_PTR)GetId().m_dwId);
8048 RestrictEnter.SuppressRelease(); //after this point we don't guarantee appdomain consistency
8049 #ifdef PROFILING_SUPPORTED
8050 // Signal profile if present.
8052 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
8054 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) this);
8057 #endif // PROFILING_SUPPORTED
8058 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains--);
8059 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomainsUnloaded++);
8061 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is exited.\n",
8062 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8064 // Send ETW events for this domain's unload and potentially iterate through this
8065 // domain's modules & assemblies to send events for their unloads as well. This
8066 // needs to occur before STAGE_FINALIZED (to ensure everything is there), so we do
8067 // this before any finalization occurs at all.
8068 ETW::LoaderLog::DomainUnload(this);
8070 CodeVersionManager::OnAppDomainExit(this);
8073 // Spin running finalizers until we flush them all. We need to make multiple passes
8074 // in case the finalizers create more finalizable objects. This is important to clear
8075 // the finalizable objects as roots, as well as to actually execute the finalizers. This
8076 // will only finalize instances instances of types that aren't potentially agile becuase we can't
8077 // risk finalizing agile objects. So we will be left with instances of potentially agile types
8078 // in handles or statics.
8080 // <TODO>@todo: Need to ensure this will terminate in a reasonable amount of time. Eventually
8081 // we should probably start passing FALSE for fRunFinalizers. Also I'm not sure we
8082 // guarantee that FinalizerThreadWait will ever terminate in general.</TODO>
8085 SetStage(STAGE_FINALIZING);
8087 // Flush finalizers now.
8088 FinalizerThread::UnloadAppDomain(this, fRunFinalizers);
8090 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8091 ULONGLONG startTime = CLRGetTickCount64();
8092 ULONGLONG elapsedTime = 0;
8093 DWORD finalizerWait = 0;
8095 while (FinalizerThread::GetUnloadingAppDomain() != NULL)
8098 if (timeout != INFINITE)
8100 elapsedTime = CLRGetTickCount64() - startTime;
8102 if (timeout > elapsedTime)
8104 finalizerWait = timeout - static_cast<DWORD>(elapsedTime);
8106 FinalizerThread::FinalizerThreadWait(finalizerWait); //will set stage to finalized
8107 if (timeout != INFINITE && FinalizerThread::GetUnloadingAppDomain() != NULL)
8109 elapsedTime = CLRGetTickCount64() - startTime;
8110 if (timeout <= elapsedTime)
8113 // TODO: Consider escalation from RudeAppDomain
8119 tpAdUnloadHolder.SuppressRelease();
8120 PerAppDomainTPCountList::ResetAppDomainTPCounts(GetTPIndex());
8122 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is finalized.\n",
8123 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8126 AppDomainRefHolder This(this);
8127 AddRef(); // Hold a reference so CloseDomain won't delete us yet
8128 CloseDomain(); // Remove ourself from the list of app domains
8130 // This needs to be done prior to destroying the handle tables below.
8131 ReleaseDomainBoundInfo();
8134 // It should be impossible to run non-mscorlib code in this domain now.
8135 // Cleanup all of our roots except the handles. We do this to allow as many
8136 // finalizers as possible to run correctly. If we delete the handles, they
8139 if (!NingenEnabled())
8146 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is cleared.\n",
8147 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8149 if (fAsyncExit && fRunFinalizers)
8152 m_AssemblyCache.Clear();
8153 ClearFusionContext();
8155 if (!NingenEnabled())
8157 AddMemoryPressure();
8160 SystemDomain::System()->AddToDelayedUnloadList(this, fAsyncExit);
8161 SystemDomain::SetUnloadDomainCleared();
8162 if (m_dwId.m_dwId!=0)
8163 SystemDomain::ReleaseAppDomainId(m_dwId);
8164 #ifdef PROFILING_SUPPORTED
8165 // Always signal profile if present, even when failed.
8167 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
8169 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) this, S_OK);
8172 #endif // PROFILING_SUPPORTED
8176 void AppDomain::Close()
8185 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is collected.\n",
8186 GetId().m_dwId, this, GetFriendlyNameForLogging()));
8190 RemoveMemoryPressure();
8192 _ASSERTE(m_cRef>0); //should be alive at this point otherwise iterator can revive us and crash
8194 SystemDomain::LockHolder lh; // Avoid races with AppDomainIterator
8195 SetStage(STAGE_CLOSED);
8198 // CONSIDER: move releasing remoting cache from managed code to here.
8202 void AppDomain::ResetUnloadRequestThread(ADID Id)
8208 PRECONDITION(!IsADUnloadHelperThread());
8213 AppDomainFromIDHolder ad(Id, TRUE);
8214 if(!ad.IsUnloaded() && ad->m_Stage < STAGE_UNLOAD_REQUESTED)
8216 Thread *pThread = ad->GetUnloadRequestThread();
8217 if(pThread==GetThread())
8219 ad->m_dwThreadsStillInAppDomain=(ULONG)-1;
8223 if (pThread->GetUnloadBoundaryFrame() && pThread->IsBeingAbortedForADUnload())
8225 pThread->UnmarkThreadForAbort(Thread::TAR_ADUnload);
8227 ad->GetUnloadRequestThread()->ResetUnloadBoundaryFrame();
8228 pThread->ResetBeginAbortedForADUnload();
8231 ad->SetUnloadRequestThread(NULL);
8237 int g_fADUnloadWorkerOK = -1;
8239 HRESULT AppDomain::UnloadById(ADID dwId, BOOL fSync,BOOL fExceptionsPassThrough)
8243 if(fExceptionsPassThrough) {THROWS;} else {NOTHROW;}
8245 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
8250 if (dwId==(ADID)DefaultADID)
8251 return COR_E_CANNOTUNLOADAPPDOMAIN;
8253 Thread *pThread = GetThread();
8255 // Finalizer thread can not wait until AD unload is done,
8256 // because AD unload is going to wait for Finalizer Thread.
8257 if (fSync && pThread == FinalizerThread::GetFinalizerThread() &&
8258 !pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent))
8259 return COR_E_CANNOTUNLOADAPPDOMAIN;
8262 // AD unload helper thread should have been created.
8263 _ASSERTE (g_fADUnloadWorkerOK == 1);
8265 _ASSERTE (!IsADUnloadHelperThread());
8267 BOOL fIsRaisingUnloadEvent = (pThread != NULL && pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent));
8269 if (fIsRaisingUnloadEvent)
8271 AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_GC);
8273 if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
8274 return COR_E_APPDOMAINUNLOADED;
8276 pApp->EnableADUnloadWorker();
8282 ADUnloadSinkHolder pSink;
8285 SystemDomain::LockHolder ulh;
8287 AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_ADLock);
8289 if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
8290 return COR_E_APPDOMAINUNLOADED;
8292 if (g_fADUnloadWorkerOK != 1)
8295 return E_UNEXPECTED;
8300 pApp->EnableADUnloadWorker();
8304 pSink = pApp->PrepareForWaitUnloadCompletion();
8306 pApp->EnableADUnloadWorker();
8308 // release the holders - we don't care anymore if the appdomain is gone
8311 #ifdef FEATURE_TESTHOOKS
8312 if (fExceptionsPassThrough)
8314 CONTRACT_VIOLATION(FaultViolation);
8315 return UnloadWaitNoCatch(dwId,pSink);
8319 return UnloadWait(dwId,pSink);
8322 HRESULT AppDomain::UnloadWait(ADID Id, ADUnloadSink * pSink)
8328 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
8335 // IF you ever try to change this to something not using events, please address the fact that
8336 // AppDomain::StopEEAndUnwindThreads relies on that events are used.
8338 pSink->WaitUnloadCompletion();
8340 EX_CATCH_HRESULT(hr);
8343 hr=pSink->GetUnloadResult();
8347 ResetUnloadRequestThread(Id);
8352 #ifdef FEATURE_TESTHOOKS
8353 HRESULT AppDomain::UnloadWaitNoCatch(ADID Id, ADUnloadSink * pSink)
8355 STATIC_CONTRACT_THROWS;
8356 STATIC_CONTRACT_MODE_ANY;
8358 Holder<ADID, DoNothing<ADID>, AppDomain::ResetUnloadRequestThread> resetUnloadHolder(Id);
8360 // IF you ever try to change this to something not using events, please address the fact that
8361 // AppDomain::StopEEAndUnwindThreads relies on that events are used.
8362 pSink->WaitUnloadCompletion();
8364 HRESULT hr = pSink->GetUnloadResult();
8367 resetUnloadHolder.SuppressRelease();
8373 void AppDomain::Unload(BOOL fForceUnload)
8380 INJECT_FAULT(COMPlusThrowOM(););
8384 #ifdef FEATURE_MULTICOREJIT
8386 // Avoid profiling file is partially written in ASP.net scenarios, call it earlier
8387 GetMulticoreJitManager().StopProfile(true);
8391 Thread *pThread = GetThread();
8394 if (! fForceUnload && !g_pConfig->AppDomainUnload())
8397 EPolicyAction action;
8398 EClrOperation operation;
8399 if (!IsRudeUnload())
8401 operation = OPR_AppDomainUnload;
8405 operation = OPR_AppDomainRudeUnload;
8407 action = GetEEPolicy()->GetDefaultAction(operation,NULL);
8408 GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
8412 case eUnloadAppDomain:
8414 case eRudeUnloadAppDomain:
8418 case eFastExitProcess:
8419 case eRudeExitProcess:
8420 case eDisableRuntime:
8421 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_ADUNLOAD);
8422 _ASSERTE (!"Should not get here");
8428 #if (defined(_DEBUG) || defined(BREAK_ON_UNLOAD) || defined(AD_LOG_MEMORY) || defined(AD_SNAPSHOT))
8429 static int unloadCount = 0;
8432 #ifdef AD_LOG_MEMORY
8435 static int logMemory = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADLogMemory);
8436 typedef void (__cdecl *LogItFcn) ( int );
8437 static LogItFcn pLogIt = NULL;
8439 if (logMemory && ! pLogIt)
8441 HMODULE hMod = CLRLoadLibrary(W("mpdh.dll"));
8444 pLogIt = (LogItFcn)GetProcAddress(hMod, "logIt");
8453 #endif // AD_LOG_MEMORY
8455 if (IsDefaultDomain() && !IsSingleAppDomain())
8456 COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_DEFAULT);
8458 _ASSERTE(CanUnload());
8460 if (pThread == FinalizerThread::GetFinalizerThread() || GetUnloadRequestThread() == FinalizerThread::GetFinalizerThread())
8461 COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_IN_FINALIZER);
8463 _ASSERTE(! SystemDomain::AppDomainBeingUnloaded());
8465 // should not be running in this AD because unload spawned thread in default domain
8466 if (!NingenEnabled())
8468 _ASSERTE(!pThread->IsRunningIn(this, NULL));
8472 #ifdef APPDOMAIN_STATE
8473 _ASSERTE_ALL_BUILDS("clr/src/VM/AppDomain.cpp", pThread->GetDomain()->IsDefaultDomain());
8476 LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Unloading domain [%d] %#08x %ls\n", GetId().m_dwId, this, GetFriendlyName()));
8478 STRESS_LOG3 (LF_APPDOMAIN, LL_INFO100, "Unload domain [%d, %d] %p\n", GetId().m_dwId, GetIndex().m_dwIndex, this);
8480 UnloadHolder hold(this);
8482 SystemDomain::System()->SetUnloadRequestingThread(GetUnloadRequestThread());
8483 SystemDomain::System()->SetUnloadingThread(pThread);
8487 static int dumpSB = -1;
8490 dumpSB = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADDumpSB);
8494 LogSpewAlways("Starting unload %3.3d\n", unloadCount);
8495 DumpSyncBlockCache();
8499 BOOL bForceGC=m_bForceGCOnUnload;
8501 #ifdef AD_LOG_MEMORY
8504 #endif // AD_LOG_MEMORY
8507 static int takeSnapShot = -1;
8509 if (takeSnapShot == -1)
8510 takeSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeSnapShot);
8514 #endif // AD_SNAPSHOT
8520 static int cfgForceGC = -1;
8522 if (cfgForceGC == -1)
8523 cfgForceGC =!CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ADULazyMemoryRelease);
8525 bForceGC=bForceGC||cfgForceGC;
8526 AppDomainRefHolder This(this);
8529 // Do the actual unloading
8531 // We do not want other threads to abort the current one.
8532 ThreadPreventAsyncHolder preventAsync;
8533 Exit(TRUE, !bForceGC);
8537 GCHeapUtilities::GetGCHeap()->GarbageCollect();
8538 FinalizerThread::FinalizerThreadWait();
8539 SetStage(STAGE_COLLECTED);
8543 #ifdef AD_LOG_MEMORY
8547 pLogIt(unloadCount);
8549 #endif // AD_LOG_MEMORY
8555 sprintf_s(buffer, _countof(buffer), "vadump -p %d -o > vadump.%d", GetCurrentProcessId(), unloadCount);
8557 sprintf_s(buffer, _countof(buffer), "umdh -p:%d -d -i:1 -f:umdh.%d", GetCurrentProcessId(), unloadCount);
8559 int takeDHSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeDHSnapShot);
8562 sprintf_s(buffer, _countof(buffer), "dh -p %d -s -g -h -b -f dh.%d", GetCurrentProcessId(), unloadCount);
8566 #endif // AD_SNAPSHOT
8571 // do extra finalizer wait to remove any leftover sb entries
8572 FinalizerThread::FinalizerThreadWait();
8573 GCHeapUtilities::GetGCHeap()->GarbageCollect();
8574 FinalizerThread::FinalizerThreadWait();
8575 LogSpewAlways("Done unload %3.3d\n", unloadCount);
8576 DumpSyncBlockCache();
8579 swprintf_s(buffer, NumItems(buffer), W("DumpSB.%d"), unloadCount);
8580 _ASSERTE(WszMoveFileEx(W("COMPLUS.LOG"), buffer, MOVEFILE_REPLACE_EXISTING));
8581 // this will open a new file
8587 void AppDomain::ExceptionUnwind(Frame *pFrame)
8591 DISABLED(GC_TRIGGERS); // EEResourceException
8592 DISABLED(THROWS); // EEResourceException
8597 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind for %8.8x\n", pFrame));
8599 printf("%x AppDomain::ExceptionUnwind for %8.8p\n", GetThread()->GetThreadId(), pFrame);
8601 Thread *pThread = GetThread();
8604 if (! pThread->ShouldChangeAbortToUnload(pFrame))
8606 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: not first transition or abort\n"));
8610 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: changing to unload\n"));
8613 OBJECTREF throwable = NULL;
8614 EEResourceException e(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded_ThreadUnwound"));
8615 throwable = e.GetThrowable();
8617 // reset the exception to an AppDomainUnloadedException
8618 if (throwable != NULL)
8620 GetThread()->SafeSetThrowables(throwable);
8624 BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread)
8635 Thread *pThread = NULL;
8636 DWORD nThreadsNeedMoreWork=0;
8637 if (retryCount != (unsigned int)-1 && retryCount < g_pConfig->AppDomainUnloadRetryCount())
8639 Thread *pCurThread = GetThread();
8640 if (pCurThread->CatchAtSafePoint())
8641 pCurThread->PulseGCMode();
8644 // We know which thread is not in the domain now. We just need to
8645 // work on those threads. We do not need to suspend the runtime.
8646 ThreadStoreLockHolder tsl;
8648 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8650 if (pThread == pCurThread)
8655 if (pThread == FinalizerThread::GetFinalizerThread())
8660 if (pThread->GetUnloadBoundaryFrame() == NULL)
8665 // A thread may have UnloadBoundaryFrame set if
8666 // 1. Being unloaded by AD unload helper thread
8667 // 2. Escalation from OOM or SO triggers AD unload
8668 // Here we only need to work on threads that are in the domain. If we work on other threads,
8669 // those threads may be stucked in a finally, and we will not be able to escalate for them,
8670 // therefore AD unload is blocked.
8671 if (pThread->IsBeingAbortedForADUnload() ||
8672 pThread == SystemDomain::System()->GetUnloadRequestingThread())
8674 nThreadsNeedMoreWork++;
8677 if (!(IsRudeUnload() ||
8678 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())))
8683 if ((pThread == SystemDomain::System()->GetUnloadRequestingThread()) && *pFMarkUnloadRequestThread)
8685 // Mark thread for abortion only once; later on interrupt only
8686 *pFMarkUnloadRequestThread = FALSE;
8687 pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
8691 if (pThread->m_State & Thread::TS_Interruptible)
8693 pThread->UserInterrupt(Thread::TI_Abort);
8697 if (pThread->PreemptiveGCDisabledOther())
8699 #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
8700 Thread::SuspendThreadResult str = pThread->SuspendThread();
8701 if (str == Thread::STR_Success)
8703 if (pThread->PreemptiveGCDisabledOther() &&
8704 (!pThread->IsAbortInitiated() || pThread->IsRudeAbort()))
8706 pThread->HandleJITCaseForAbort();
8708 pThread->ResumeThread();
8713 } // ThreadStoreLockHolder
8715 m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
8716 return !nThreadsNeedMoreWork;
8719 // For now piggyback on the GC's suspend EE mechanism
8720 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
8722 // <TODO>@todo: what to do with any threads that didn't stop?</TODO>
8723 _ASSERTE(ThreadStore::s_pThreadStore->DbgBackgroundThreadCount() > 0);
8726 int totalADCount = 0;
8727 int finalizerADCount = 0;
8730 RuntimeExceptionKind reKind = kLastException;
8732 SmallStackSString ssThreadId;
8734 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8736 // we already checked that we're not running in the unload domain
8737 if (pThread == GetThread())
8743 void PrintStackTraceWithADToLog(Thread *pThread);
8744 if (LoggingOn(LF_APPDOMAIN, LL_INFO100)) {
8745 LOG((LF_APPDOMAIN, LL_INFO100, "\nStackTrace for %x\n", pThread->GetThreadId()));
8746 PrintStackTraceWithADToLog(pThread);
8750 Frame *pFrame = pThread->GetFirstTransitionInto(this, &count);
8752 _ASSERTE(count == 0);
8753 if (pThread->IsBeingAbortedForADUnload())
8755 pThread->ResetBeginAbortedForADUnload();
8760 if (pThread != FinalizerThread::GetFinalizerThread())
8762 totalADCount += count;
8763 nThreadsNeedMoreWork++;
8764 pThread->SetUnloadBoundaryFrame(pFrame);
8768 finalizerADCount = count;
8771 // don't setup the exception info for the unloading thread unless it's the last one in
8772 if (retryCount != ((unsigned int) -1) && retryCount > g_pConfig->AppDomainUnloadRetryCount() && reKind == kLastException &&
8773 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft()))
8775 #ifdef AD_BREAK_ON_CANNOT_UNLOAD
8776 static int breakOnCannotUnload = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADBreakOnCannotUnload);
8777 if (breakOnCannotUnload)
8778 _ASSERTE(!"Cannot unload AD");
8779 #endif // AD_BREAK_ON_CANNOT_UNLOAD
8780 reKind = kCannotUnloadAppDomainException;
8781 resId = IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD;
8782 ssThreadId.Printf(W("%x"), pThread->GetThreadId());
8783 STRESS_LOG2(LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads cannot stop thread %x with %d transitions\n", pThread->GetThreadId(), count);
8784 // don't break out of this early or the assert totalADCount == (int)m_dwThreadEnterCount below will fire
8785 // it's better to chew a little extra time here and make sure our counts are consistent
8787 // only abort the thread requesting the unload if it's the last one in, that way it will get
8788 // notification that the unload failed for some other thread not being aborted. And don't abort
8789 // the finalizer thread - let it finish it's work as it's allowed to be in there. If it won't finish,
8790 // then we will eventually get a CannotUnloadException on it.
8792 if (pThread != FinalizerThread::GetFinalizerThread() &&
8793 // If the domain is rudely unloaded, we will unwind the requesting thread out
8794 // Rude unload is going to succeed, or escalated to disable runtime or higher.
8796 (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())
8801 STRESS_LOG2(LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count);
8802 LOG((LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count));
8804 printf("AppDomain::UnwindThreads %x stopping %x with first frame %8.8p\n", GetThread()->GetThreadId(), pThread->GetThreadId(), pFrame);
8806 if (pThread == SystemDomain::System()->GetUnloadRequestingThread())
8808 // Mark thread for abortion only once; later on interrupt only
8809 *pFMarkUnloadRequestThread = FALSE;
8811 pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
8813 TESTHOOKCALL(UnwindingThreads(GetId().m_dwId)) ;
8815 _ASSERTE(totalADCount + finalizerADCount == (int)m_dwThreadEnterCount);
8817 //@TODO: This is intended to catch a stress bug. Remove when no longer needed.
8818 if (totalADCount + finalizerADCount != (int)m_dwThreadEnterCount)
8819 FreeBuildDebugBreak();
8821 // if our count did get messed up, set it to whatever count we actually found in the domain to avoid looping
8822 // or other problems related to incorrect count. This is very much a bug if this happens - a thread should always
8823 // exit the domain gracefully.
8824 // m_dwThreadEnterCount = totalADCount;
8826 if (reKind != kLastException)
8829 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8831 if (pThread->IsBeingAbortedForADUnload())
8833 pThread->ResetBeginAbortedForADUnload();
8838 // CommonTripThread will handle the abort for any threads that we've marked
8839 ThreadSuspend::RestartEE(FALSE, TRUE);
8840 if (reKind != kLastException)
8841 COMPlusThrow(reKind, resId, ssThreadId.GetUnicode());
8843 _ASSERTE((totalADCount==0 && nThreadsNeedMoreWork==0) ||(totalADCount!=0 && nThreadsNeedMoreWork!=0));
8845 m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
8846 return (totalADCount == 0);
8849 void AppDomain::UnwindThreads()
8851 // This function should guarantee appdomain
8852 // consistency even if it fails. Everything that is going
8853 // to make the appdomain impossible to reenter
8854 // should be factored out
8856 // <TODO>@todo: need real synchronization here!!!</TODO>
8865 int retryCount = -1;
8866 m_dwThreadsStillInAppDomain=(ULONG)-1;
8867 ULONGLONG startTime = CLRGetTickCount64();
8869 if (GetEEPolicy()->GetDefaultAction(OPR_AppDomainUnload, NULL) == eRudeUnloadAppDomain &&
8872 GetEEPolicy()->NotifyHostOnDefaultAction(OPR_AppDomainUnload, eRudeUnloadAppDomain);
8876 // Force threads to go through slow path during AD unload.
8877 TSSuspendHolder shTrap;
8879 BOOL fCurrentUnloadMode = IsRudeUnload();
8880 BOOL fMarkUnloadRequestThread = TRUE;
8882 // now wait for all the threads running in our AD to get out
8885 DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8886 EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, NULL);
8887 if (timeout != INFINITE && action > eUnloadAppDomain) {
8888 // Escalation policy specified.
8889 ULONGLONG curTime = CLRGetTickCount64();
8890 ULONGLONG elapseTime = curTime - startTime;
8891 if (elapseTime > timeout)
8896 case eRudeUnloadAppDomain:
8897 GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
8899 STRESS_LOG1(LF_APPDOMAIN, LL_INFO100,"Escalating to RADU, adid=%d",GetId().m_dwId);
8902 case eFastExitProcess:
8903 case eRudeExitProcess:
8904 case eDisableRuntime:
8905 GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
8906 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
8907 _ASSERTE (!"Should not reach here");
8915 if (LoggingOn(LF_APPDOMAIN, LL_INFO100))
8916 DumpADThreadTrack();
8918 BOOL fNextUnloadMode = IsRudeUnload();
8919 if (fCurrentUnloadMode != fNextUnloadMode)
8921 // We have changed from normal unload to rude unload. We need to mark the thread
8922 // with RudeAbort, but we can only do this safely if the runtime is suspended.
8923 fCurrentUnloadMode = fNextUnloadMode;
8926 if (StopEEAndUnwindThreads(retryCount, &fMarkUnloadRequestThread))
8928 if (timeout != INFINITE)
8930 // Turn off the timeout used by AD.
8935 // GCStress takes a long time to unwind, due to expensive creation of
8936 // a threadabort exception.
8937 if (!GCStress<cfg_any>::IsEnabled())
8939 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount));
8941 printf("AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount);
8945 if (m_dwThreadEnterCount != 0)
8948 GetThread()->UserSleep(20);
8950 GetThread()->UserSleep(10);
8957 void AppDomain::ClearGCHandles()
8967 SetStage(STAGE_HANDLETABLE_NOACCESS);
8969 GCHeapUtilities::GetGCHeap()->WaitUntilConcurrentGCComplete();
8971 // Keep async pin handles alive by moving them to default domain
8972 HandleAsyncPinHandles();
8974 // Remove our handle store as a source of GC roots
8975 m_handleStore->Uproot();
8978 // When an AD is unloaded, we will release all objects in this AD.
8979 // If a future asynchronous operation, like io completion port function,
8980 // we need to keep the memory space fixed so that the gc heap is not corrupted.
8981 void AppDomain::HandleAsyncPinHandles()
8991 IGCHandleStore *pBucket = m_handleStore;
8993 // IO completion port picks IO job using FIFO. Here is how we know which AsyncPinHandle can be freed.
8994 // 1. We mark all non-pending AsyncPinHandle with READYTOCLEAN.
8995 // 2. We queue a dump Overlapped to the IO completion as a marker.
8996 // 3. When the Overlapped is picked up by completion port, we wait until all previous IO jobs are processed.
8997 // 4. Then we can delete all AsyncPinHandle marked with READYTOCLEAN.
8998 IGCHandleStore *pBucketInDefault = SystemDomain::System()->DefaultDomain()->m_handleStore;
9000 auto clearIfComplete = [](Object* object)
9002 LIMITED_METHOD_CONTRACT;
9004 assert(object != nullptr);
9005 if (object->GetGCSafeMethodTable() != g_pOverlappedDataClass)
9010 OVERLAPPEDDATAREF overlapped = (OVERLAPPEDDATAREF)(ObjectToOBJECTREF((Object*)object));
9011 if (overlapped->HasCompleted())
9013 // IO has finished. We don't need to pin the user buffer any longer.
9014 overlapped->m_userObject = NULL;
9017 BashMTForPinnedObject(ObjectToOBJECTREF(object));
9020 auto setHandle = [](Object* object, OBJECTHANDLE handle)
9022 LIMITED_METHOD_CONTRACT;
9024 assert(object != nullptr);
9027 if (object->GetGCSafeMethodTable() != g_pOverlappedDataClass)
9032 OverlappedDataObject* overlapped = (OverlappedDataObject*)object;
9033 overlapped->m_pinSelf = handle;
9036 pBucket->RelocateAsyncPinnedHandles(pBucketInDefault, clearIfComplete, setHandle);
9038 OverlappedDataObject::RequestCleanup();
9041 void AppDomain::ClearGCRoots()
9051 Thread *pThread = NULL;
9052 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
9054 // Tell the JIT managers to delete any entries in their structures. All the cooperative mode threads are stopped at
9055 // this point, so only need to synchronize the preemptive mode threads.
9056 ExecutionManager::Unload(GetLoaderAllocator());
9058 while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL)
9060 // Delete the thread local static store
9061 pThread->DeleteThreadStaticData(this);
9063 // <TODO>@TODO: A pre-allocated AppDomainUnloaded exception might be better.</TODO>
9064 if (m_handleStore->ContainsHandle(pThread->m_LastThrownObjectHandle))
9066 // Never delete a handle to a preallocated exception object.
9067 if (!CLRException::IsPreallocatedExceptionHandle(pThread->m_LastThrownObjectHandle))
9069 DestroyHandle(pThread->m_LastThrownObjectHandle);
9072 pThread->m_LastThrownObjectHandle = NULL;
9075 // Clear out the exceptions objects held by a thread.
9076 pThread->GetExceptionState()->ClearThrowablesForUnload(m_handleStore);
9079 //delete them while we still have the runtime suspended
9080 // This must be deleted before the loader heaps are deleted.
9081 if (m_pMarshalingData != NULL)
9083 delete m_pMarshalingData;
9084 m_pMarshalingData = NULL;
9087 if (m_pLargeHeapHandleTable != NULL)
9089 delete m_pLargeHeapHandleTable;
9090 m_pLargeHeapHandleTable = NULL;
9093 ThreadSuspend::RestartEE(FALSE, TRUE);
9098 void AppDomain::TrackADThreadEnter(Thread *pThread, Frame *pFrame)
9105 PRECONDITION(CheckPointer(pThread));
9106 PRECONDITION(pFrame != (Frame*)(size_t) INVALID_POINTER_CD);
9110 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9112 if (m_pThreadTrackInfoList == NULL)
9113 m_pThreadTrackInfoList = new (nothrow) ThreadTrackInfoList;
9114 // If we don't assert here, we will AV in the for loop below
9115 _ASSERTE(m_pThreadTrackInfoList);
9117 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9119 ThreadTrackInfo *pTrack = NULL;
9121 for (i=0; i < pTrackList->Count(); i++) {
9122 if ((*(pTrackList->Get(i)))->pThread == pThread) {
9123 pTrack = *(pTrackList->Get(i));
9128 pTrack = new (nothrow) ThreadTrackInfo;
9129 // If we don't assert here, we will AV in the for loop below.
9131 pTrack->pThread = pThread;
9132 ThreadTrackInfo **pSlot = pTrackList->Append();
9136 InterlockedIncrement((LONG*)&m_dwThreadEnterCount);
9140 pSlot = pTrack->frameStack.Insert(0);
9144 for (i=0; i < pTrackList->Count(); i++)
9145 totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
9146 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9148 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9152 void AppDomain::TrackADThreadExit(Thread *pThread, Frame *pFrame)
9156 if (GetThread()) {MODE_COOPERATIVE;}
9162 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9164 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9165 _ASSERTE(pTrackList);
9166 ThreadTrackInfo *pTrack = NULL;
9168 for (i=0; i < pTrackList->Count(); i++)
9170 if ((*(pTrackList->Get(i)))->pThread == pThread)
9172 pTrack = *(pTrackList->Get(i));
9177 _ASSERTE(*(pTrack->frameStack.Get(0)) == pFrame);
9178 pTrack->frameStack.Delete(0);
9179 InterlockedDecrement((LONG*)&m_dwThreadEnterCount);
9182 for (i=0; i < pTrackList->Count(); i++)
9183 totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
9184 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9186 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9189 void AppDomain::DumpADThreadTrack()
9199 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9201 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9206 LOG((LF_APPDOMAIN, LL_INFO10000, "\nThread dump of %d threads for [%d] %#08x %S\n",
9207 m_dwThreadEnterCount, GetId().m_dwId, this, GetFriendlyNameForLogging()));
9209 for (int i=0; i < pTrackList->Count(); i++)
9211 ThreadTrackInfo *pTrack = *(pTrackList->Get(i));
9212 if (pTrack->frameStack.Count()==0)
9214 LOG((LF_APPDOMAIN, LL_INFO100, " ADEnterCount for %x is %d\n", pTrack->pThread->GetThreadId(), pTrack->frameStack.Count()));
9215 totThreads += pTrack->frameStack.Count();
9216 for (int j=0; j < pTrack->frameStack.Count(); j++)
9217 LOG((LF_APPDOMAIN, LL_INFO100, " frame %8.8x\n", *(pTrack->frameStack.Get(j))));
9219 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9222 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9227 #endif // CROSSGEN_COMPILE
9229 void *SharedDomain::operator new(size_t size, void *pInPlace)
9231 LIMITED_METHOD_CONTRACT;
9235 void SharedDomain::operator delete(void *pMem)
9237 LIMITED_METHOD_CONTRACT;
9238 // Do nothing - new() was in-place
9242 void SharedDomain::Attach()
9249 INJECT_FAULT(COMPlusThrowOM(););
9253 // Create the global SharedDomain and initialize it.
9254 m_pSharedDomain = new (&g_pSharedDomainMemory[0]) SharedDomain();
9255 SystemDomain::GetGlobalLoaderAllocator()->m_pDomain = m_pSharedDomain;
9256 // This cannot fail since g_pSharedDomainMemory is a static array.
9257 CONSISTENCY_CHECK(CheckPointer(m_pSharedDomain));
9259 LOG((LF_CLASSLOADER,
9261 "Created shared domain at %p\n",
9264 // We need to initialize the memory pools etc. for the system domain.
9265 m_pSharedDomain->Init(); // Setup the memory heaps
9267 // allocate a Virtual Call Stub Manager for the shared domain
9268 m_pSharedDomain->InitVSD();
9271 #ifndef CROSSGEN_COMPILE
9272 void SharedDomain::Detach()
9274 if (m_pSharedDomain)
9276 m_pSharedDomain->Terminate();
9277 delete m_pSharedDomain;
9278 m_pSharedDomain = NULL;
9281 #endif // CROSSGEN_COMPILE
9283 #endif // !DACCESS_COMPILE
9285 SharedDomain *SharedDomain::GetDomain()
9287 LIMITED_METHOD_DAC_CONTRACT;
9289 return m_pSharedDomain;
9292 #ifndef DACCESS_COMPILE
9294 #define INITIAL_ASSEMBLY_MAP_SIZE 17
9295 void SharedDomain::Init()
9302 INJECT_FAULT(COMPlusThrowOM(););
9308 #ifdef FEATURE_LOADER_OPTIMIZATION
9309 m_FileCreateLock.Init(CrstSharedAssemblyCreate, CRST_DEFAULT,TRUE);
9311 LockOwner lock = { &m_DomainCrst, IsOwnerOfCrst };
9312 m_assemblyMap.Init(INITIAL_ASSEMBLY_MAP_SIZE, CompareSharedAssembly, TRUE, &lock);
9313 #endif // FEATURE_LOADER_OPTIMIZATION
9315 ETW::LoaderLog::DomainLoad(this);
9318 #ifndef CROSSGEN_COMPILE
9319 void SharedDomain::Terminate()
9321 // make sure we delete the StringLiteralMap before unloading
9322 // the asemblies since the string literal map entries can
9323 // point to metadata string literals.
9324 GetLoaderAllocator()->CleanupStringLiteralMap();
9326 #ifdef FEATURE_LOADER_OPTIMIZATION
9327 PtrHashMap::PtrIterator i = m_assemblyMap.begin();
9331 Assembly *pAssembly = (Assembly*) i.GetValue();
9336 ListLockEntry* pElement;
9337 pElement = m_FileCreateLock.Pop(TRUE);
9340 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
9341 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
9344 pElement = (FileLoadLock*) m_FileCreateLock.Pop(TRUE);
9346 m_FileCreateLock.Destroy();
9347 #endif // FEATURE_LOADER_OPTIMIZATION
9348 BaseDomain::Terminate();
9350 #endif // CROSSGEN_COMPILE
9354 #ifdef FEATURE_LOADER_OPTIMIZATION
9356 BOOL SharedDomain::CompareSharedAssembly(UPTR u1, UPTR u2)
9366 // This is the input to the lookup
9367 SharedAssemblyLocator *pLocator = (SharedAssemblyLocator *) (u1<<1);
9369 // This is the value stored in the table
9370 Assembly *pAssembly = (Assembly *) u2;
9371 if (pLocator->GetType()==SharedAssemblyLocator::DOMAINASSEMBLY)
9373 if (!pAssembly->GetManifestFile()->Equals(pLocator->GetDomainAssembly()->GetFile()))
9376 return pAssembly->CanBeShared(pLocator->GetDomainAssembly());
9379 if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLY)
9380 return pAssembly->GetManifestFile()->Equals(pLocator->GetPEAssembly());
9382 if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLYEXACT)
9383 return pAssembly->GetManifestFile() == pLocator->GetPEAssembly();
9384 _ASSERTE(!"Unexpected type of assembly locator");
9388 DWORD SharedAssemblyLocator::Hash()
9395 INJECT_FAULT(COMPlusThrowOM(););
9398 if (m_type==DOMAINASSEMBLY)
9399 return GetDomainAssembly()->HashIdentity();
9400 if (m_type==PEASSEMBLY||m_type==PEASSEMBLYEXACT)
9401 return GetPEAssembly()->HashIdentity();
9402 _ASSERTE(!"Unexpected type of assembly locator");
9406 Assembly * SharedDomain::FindShareableAssembly(SharedAssemblyLocator * pLocator)
9413 INJECT_FAULT(COMPlusThrowOM(););
9417 Assembly * match= (Assembly *) m_assemblyMap.LookupValue(pLocator->Hash(), pLocator);
9418 if (match != (Assembly *) INVALIDENTRY)
9424 SIZE_T SharedDomain::GetShareableAssemblyCount()
9426 LIMITED_METHOD_CONTRACT;
9428 return m_assemblyMap.GetCount();
9431 void SharedDomain::AddShareableAssembly(Assembly * pAssembly)
9438 INJECT_FAULT(COMPlusThrowOM(););
9442 // We have a lock on the file. There should be no races to add the same assembly.
9445 LockHolder holder(this);
9449 pAssembly->SetIsTenured();
9450 m_assemblyMap.InsertValue(pAssembly->HashIdentity(), pAssembly);
9454 // There was an error adding the assembly to the assembly hash (probably an OOM),
9455 // so we need to unset the tenured bit so that correct cleanup can happen.
9456 pAssembly->UnsetIsTenured();
9461 LOG((LF_CODESHARING,
9463 "Successfully added shareable assembly \"%s\".\n",
9464 pAssembly->GetManifestFile()->GetSimpleName()));
9467 #endif // FEATURE_LOADER_OPTIMIZATION
9468 #endif // !DACCESS_COMPILE
9470 DWORD DomainLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex /*=(DWORD)-1*/)
9478 { // SO tolerance exception for debug-only assertion.
9479 CONTRACT_VIOLATION(SOToleranceViolation);
9480 CONSISTENCY_CHECK(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9483 if (pMT->IsDynamicStatics())
9485 _ASSERTE(!pMT->ContainsGenericVariables());
9486 DWORD dynamicClassID = pMT->GetModuleDynamicEntryID();
9487 if(m_aDynamicEntries <= dynamicClassID)
9489 return (m_pDynamicClassTable[dynamicClassID].m_dwFlags);
9493 if (iClassIndex == (DWORD)-1)
9494 iClassIndex = pMT->GetClassIndex();
9495 return GetPrecomputedStaticsClassData()[iClassIndex];
9499 #ifndef DACCESS_COMPILE
9501 void DomainLocalModule::SetClassInitialized(MethodTable* pMT)
9511 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9513 _ASSERTE(!IsClassInitialized(pMT));
9514 _ASSERTE(!IsClassInitError(pMT));
9516 SetClassFlags(pMT, ClassInitFlags::INITIALIZED_FLAG);
9519 void DomainLocalModule::SetClassInitError(MethodTable* pMT)
9521 WRAPPER_NO_CONTRACT;
9523 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9525 SetClassFlags(pMT, ClassInitFlags::ERROR_FLAG);
9528 void DomainLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags)
9533 PRECONDITION(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9534 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9535 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9538 if (pMT->IsDynamicStatics())
9540 _ASSERTE(!pMT->ContainsGenericVariables());
9541 DWORD dwID = pMT->GetModuleDynamicEntryID();
9542 EnsureDynamicClassIndex(dwID);
9543 m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags;
9547 GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags;
9551 void DomainLocalModule::EnsureDynamicClassIndex(DWORD dwID)
9558 INJECT_FAULT(COMPlusThrowOM(););
9559 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9560 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9564 if (dwID < m_aDynamicEntries)
9566 _ASSERTE(m_pDynamicClassTable.Load() != NULL);
9570 SIZE_T aDynamicEntries = max(16, m_aDynamicEntries.Load());
9571 while (aDynamicEntries <= dwID)
9573 aDynamicEntries *= 2;
9576 DynamicClassInfo* pNewDynamicClassTable;
9577 pNewDynamicClassTable = (DynamicClassInfo*)
9578 (void*)GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
9579 S_SIZE_T(sizeof(DynamicClassInfo)) * S_SIZE_T(aDynamicEntries));
9581 memcpy(pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * m_aDynamicEntries);
9583 // Note: Memory allocated on loader heap is zero filled
9584 // memset(pNewDynamicClassTable + m_aDynamicEntries, 0, (aDynamicEntries - m_aDynamicEntries) * sizeof(DynamicClassInfo));
9586 _ASSERTE(m_aDynamicEntries%2 == 0);
9588 // Commit new dynamic table. The lock-free helpers depend on the order.
9590 m_pDynamicClassTable = pNewDynamicClassTable;
9592 m_aDynamicEntries = aDynamicEntries;
9595 #ifndef CROSSGEN_COMPILE
9596 void DomainLocalModule::AllocateDynamicClass(MethodTable *pMT)
9602 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9603 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9607 _ASSERTE(!pMT->ContainsGenericVariables());
9608 _ASSERTE(!pMT->IsSharedByGenericInstantiations());
9609 _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9610 _ASSERTE(pMT->IsDynamicStatics());
9612 DWORD dynamicEntryIDIndex = pMT->GetModuleDynamicEntryID();
9614 EnsureDynamicClassIndex(dynamicEntryIDIndex);
9616 _ASSERTE(m_aDynamicEntries > dynamicEntryIDIndex);
9618 EEClass *pClass = pMT->GetClass();
9620 DWORD dwStaticBytes = pClass->GetNonGCRegularStaticFieldBytes();
9621 DWORD dwNumHandleStatics = pClass->GetNumHandleRegularStatics();
9623 _ASSERTE(!IsClassAllocated(pMT));
9624 _ASSERTE(!IsClassInitialized(pMT));
9625 _ASSERTE(!IsClassInitError(pMT));
9627 DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry;
9629 // We need this check because maybe a class had a cctor but no statics
9630 if (dwStaticBytes > 0 || dwNumHandleStatics > 0)
9632 if (pDynamicStatics == NULL)
9634 LoaderHeap * pLoaderAllocator = GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap();
9636 if (pMT->Collectible())
9638 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(sizeof(CollectibleDynamicEntry)));
9642 SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes;
9644 #ifdef FEATURE_64BIT_ALIGNMENT
9645 // Allocate memory with extra alignment only if it is really necessary
9646 if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
9648 static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0);
9649 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE);
9653 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(dynamicEntrySize));
9656 // Note: Memory allocated on loader heap is zero filled
9658 m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry = pDynamicStatics;
9661 if (pMT->Collectible() && (dwStaticBytes != 0))
9664 OBJECTREF nongcStaticsArray = NULL;
9665 GCPROTECT_BEGIN(nongcStaticsArray);
9666 #ifdef FEATURE_64BIT_ALIGNMENT
9667 // Allocate memory with extra alignment only if it is really necessary
9668 if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
9669 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8)-1)) / (sizeof(CLR_I8)));
9672 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes);
9673 ((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray);
9676 if (dwNumHandleStatics > 0)
9678 if (!pMT->Collectible())
9680 GetAppDomain()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
9681 &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics);
9686 OBJECTREF gcStaticsArray = NULL;
9687 GCPROTECT_BEGIN(gcStaticsArray);
9688 gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass);
9689 ((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(gcStaticsArray);
9697 void DomainLocalModule::PopulateClass(MethodTable *pMT)
9706 _ASSERTE(!pMT->ContainsGenericVariables());
9708 // <todo> the only work actually done here for non-dynamics is the freezing related work.
9709 // See if we can eliminate this and make this a dynamic-only path </todo>
9710 DWORD iClassIndex = pMT->GetClassIndex();
9712 if (!IsClassAllocated(pMT, iClassIndex))
9714 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9716 if (!IsClassAllocated(pMT, iClassIndex))
9718 // Allocate dynamic space if necessary
9719 if (pMT->IsDynamicStatics())
9720 AllocateDynamicClass(pMT);
9722 // determine flags to set on the statics block
9723 DWORD dwFlags = ClassInitFlags::ALLOCATECLASS_FLAG;
9725 if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics())
9727 _ASSERTE(!IsClassInitialized(pMT));
9728 _ASSERTE(!IsClassInitError(pMT));
9729 dwFlags |= ClassInitFlags::INITIALIZED_FLAG;
9732 if (pMT->Collectible())
9734 dwFlags |= ClassInitFlags::COLLECTIBLE_FLAG;
9737 // Set all flags at the same time to avoid races
9738 SetClassFlags(pMT, dwFlags);
9744 #endif // CROSSGEN_COMPILE
9746 void DomainLocalBlock::EnsureModuleIndex(ModuleIndex index)
9753 INJECT_FAULT(COMPlusThrowOM(););
9754 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9755 PRECONDITION(m_pDomain->OwnDomainLocalBlockLock());
9759 if (m_aModuleIndices > index.m_dwIndex)
9761 _ASSERTE(m_pModuleSlots != NULL);
9765 SIZE_T aModuleIndices = max(16, m_aModuleIndices);
9766 while (aModuleIndices <= index.m_dwIndex)
9768 aModuleIndices *= 2;
9771 PTR_DomainLocalModule* pNewModuleSlots = (PTR_DomainLocalModule*) (void*)m_pDomain->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(PTR_DomainLocalModule)) * S_SIZE_T(aModuleIndices));
9773 memcpy(pNewModuleSlots, m_pModuleSlots, sizeof(SIZE_T)*m_aModuleIndices);
9775 // Note: Memory allocated on loader heap is zero filled
9776 // memset(pNewModuleSlots + m_aModuleIndices, 0 , (aModuleIndices - m_aModuleIndices)*sizeof(PTR_DomainLocalModule) );
9778 // Commit new table. The lock-free helpers depend on the order.
9780 m_pModuleSlots = pNewModuleSlots;
9782 m_aModuleIndices = aModuleIndices;
9786 void DomainLocalBlock::SetModuleSlot(ModuleIndex index, PTR_DomainLocalModule pLocalModule)
9788 // Need to synchronize with table growth in this domain
9789 BaseDomain::DomainLocalBlockLockHolder lh(m_pDomain);
9791 EnsureModuleIndex(index);
9793 _ASSERTE(index.m_dwIndex < m_aModuleIndices);
9795 // We would like this assert here, unfortunately, loading a module in this appdomain can fail
9796 // after here and we will keep the module around and reuse the slot when we retry (if
9797 // the failure happened due to a transient error, such as OOM). In that case the slot wont
9799 //_ASSERTE(m_pModuleSlots[index.m_dwIndex] == 0);
9801 m_pModuleSlots[index.m_dwIndex] = pLocalModule;
9804 #ifndef CROSSGEN_COMPILE
9806 DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef)
9813 INJECT_FAULT(COMPlusThrowOM(););
9817 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
9820 DomainAssembly* pResolvedAssembly = NULL;
9821 _ASSERTE(strcmp(szName, g_AppDomainClassName));
9826 OBJECTREF AppDomainRef;
9827 OBJECTREF AssemblyRef;
9830 ZeroMemory(&gc, sizeof(gc));
9832 GCPROTECT_BEGIN(gc);
9833 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9835 if (pAssembly != NULL)
9836 gc.AssemblyRef = pAssembly->GetExposedAssemblyObject();
9838 MethodDescCallSite onTypeResolve(METHOD__APP_DOMAIN__ON_TYPE_RESOLVE, &gc.AppDomainRef);
9840 gc.str = StringObject::NewString(szName);
9843 ObjToArgSlot(gc.AppDomainRef),
9844 ObjToArgSlot(gc.AssemblyRef),
9845 ObjToArgSlot(gc.str)
9847 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onTypeResolve.Call_RetOBJECTREF(args);
9849 if (ResultingAssemblyRef != NULL)
9851 pResolvedAssembly = ResultingAssemblyRef->GetDomainAssembly();
9853 if (pResultingAssemblyRef)
9854 *pResultingAssemblyRef = ResultingAssemblyRef;
9857 if (pResolvedAssembly->IsCollectible())
9859 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
9866 return pResolvedAssembly;
9870 Assembly* AppDomain::RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName)
9877 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9878 INJECT_FAULT(COMPlusThrowOM(););
9882 Assembly* pResolvedAssembly = NULL;
9887 OBJECTREF AppDomainRef;
9888 OBJECTREF AssemblyRef;
9891 ZeroMemory(&gc, sizeof(gc));
9893 GCPROTECT_BEGIN(gc);
9894 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9896 if (pAssembly != NULL)
9897 gc.AssemblyRef=pAssembly->GetExposedAssemblyObject();
9899 MethodDescCallSite onResourceResolve(METHOD__APP_DOMAIN__ON_RESOURCE_RESOLVE, &gc.AppDomainRef);
9900 gc.str = StringObject::NewString(szName);
9903 ObjToArgSlot(gc.AppDomainRef),
9904 ObjToArgSlot(gc.AssemblyRef),
9905 ObjToArgSlot(gc.str)
9907 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onResourceResolve.Call_RetOBJECTREF(args);
9908 if (ResultingAssemblyRef != NULL)
9910 pResolvedAssembly = ResultingAssemblyRef->GetAssembly();
9911 if (pResolvedAssembly->IsCollectible())
9913 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
9919 RETURN pResolvedAssembly;
9924 AppDomain::RaiseAssemblyResolveEvent(
9925 AssemblySpec * pSpec,
9926 BOOL fIntrospection,
9934 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9935 INJECT_FAULT(COMPlusThrowOM(););
9939 BinderMethodID methodId;
9940 StackSString ssName;
9941 pSpec->GetFileOrDisplayName(0, ssName);
9945 methodId = METHOD__APP_DOMAIN__ON_ASSEMBLY_RESOLVE; // post-bind execution event (the classic V1.0 event)
9953 // Elevate threads allowed loading level. This allows the host to load an assembly even in a restricted
9954 // condition. Note, however, that this exposes us to possible recursion failures, if the host tries to
9955 // load the assemblies currently being loaded. (Such cases would then throw an exception.)
9957 OVERRIDE_LOAD_LEVEL_LIMIT(FILE_ACTIVE);
9958 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
9962 Assembly* pAssembly = NULL;
9965 OBJECTREF AppDomainRef;
9966 OBJECTREF AssemblyRef;
9969 ZeroMemory(&gc, sizeof(gc));
9971 GCPROTECT_BEGIN(gc);
9972 if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9974 if (pSpec->GetParentAssembly() != NULL)
9977 gc.AssemblyRef=pSpec->GetParentAssembly()->GetExposedAssemblyObject();
9980 MethodDescCallSite onAssemblyResolve(methodId, &gc.AppDomainRef);
9982 gc.str = StringObject::NewString(ssName);
9983 ARG_SLOT args[3] = {
9984 ObjToArgSlot(gc.AppDomainRef),
9985 ObjToArgSlot(gc.AssemblyRef),
9986 ObjToArgSlot(gc.str)
9989 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onAssemblyResolve.Call_RetOBJECTREF(args);
9991 if (ResultingAssemblyRef != NULL)
9993 pAssembly = ResultingAssemblyRef->GetAssembly();
9994 if (pAssembly->IsCollectible())
9996 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
10002 if (pAssembly != NULL)
10004 if ((!(pAssembly->IsIntrospectionOnly())) != (!fIntrospection))
10006 // Cannot return an introspection assembly from an execution callback or vice-versa
10007 COMPlusThrow(kFileLoadException, pAssembly->IsIntrospectionOnly() ? IDS_CLASSLOAD_ASSEMBLY_RESOLVE_RETURNED_INTROSPECTION : IDS_CLASSLOAD_ASSEMBLY_RESOLVE_RETURNED_EXECUTION);
10010 // Check that the public key token matches the one specified in the spec
10011 // MatchPublicKeys throws as appropriate
10012 pSpec->MatchPublicKeys(pAssembly);
10016 } // AppDomain::RaiseAssemblyResolveEvent
10019 //---------------------------------------------------------------------------------------
10021 // Determine the type of AppDomainManager to use for the default AppDomain
10024 // v2.0 of the CLR used environment variables APPDOMAIN_MANAGER_ASM and APPDOMAIN_MANAGER_TYPE to set the
10025 // domain manager. For compatibility these are still supported, along with appDomainManagerAsm and
10026 // appDomainManagerType config file switches. If the config switches are supplied, the entry point must be
10030 void AppDomain::InitializeDefaultDomainManager()
10037 INJECT_FAULT(COMPlusThrowOM(););
10038 PRECONDITION(GetId().m_dwId == DefaultADID);
10042 OBJECTREF orThis = GetExposedObject();
10043 GCPROTECT_BEGIN(orThis);
10045 MethodDescCallSite initCompatFlags(METHOD__APP_DOMAIN__INITIALIZE_COMPATIBILITY_FLAGS);
10048 ObjToArgSlot(orThis)
10051 initCompatFlags.Call(args);
10056 CLREvent * AppDomain::g_pUnloadStartEvent;
10058 void AppDomain::CreateADUnloadWorker()
10060 STANDARD_VM_CONTRACT;
10062 // Do not create adUnload thread if there is only default domain
10063 if(IsSingleAppDomain())
10067 BOOL fCreator = FALSE;
10068 if (FastInterlockCompareExchange((LONG *)&g_fADUnloadWorkerOK,-2,-1)==-1) //we're first
10070 #ifdef _TARGET_X86_ // use the smallest possible stack on X86
10071 DWORD stackSize = 128 * 1024;
10073 DWORD stackSize = 512 * 1024; // leave X64 unchanged since we have plenty of VM
10075 Thread *pThread = SetupUnstartedThread();
10076 if (pThread->CreateNewThread(stackSize, ADUnloadThreadStart, pThread))
10080 dwRet = pThread->StartThread();
10082 // When running under a user mode native debugger there is a race
10083 // between the moment we've created the thread (in CreateNewThread) and
10084 // the moment we resume it (in StartThread); the debugger may receive
10085 // the "ct" (create thread) notification, and it will attempt to
10086 // suspend/resume all threads in the process. Now imagine the debugger
10087 // resumes this thread first, and only later does it try to resume the
10088 // newly created thread (the ADU worker thread). In these conditions our
10089 // call to ResumeThread may come before the debugger's call to ResumeThread
10090 // actually causing dwRet to equal 2.
10091 // We cannot use IsDebuggerPresent() in the condition below because the
10092 // debugger may have been detached between the time it got the notification
10093 // and the moment we execute the test below.
10094 _ASSERTE(dwRet == 1 || dwRet == 2);
10098 pThread->DecExternalCount(FALSE);
10099 FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK, -1);
10100 ThrowOutOfMemory();
10104 YIELD_WHILE (g_fADUnloadWorkerOK == -2);
10106 if (g_fADUnloadWorkerOK == -1) {
10109 ThrowOutOfMemory();
10118 /*static*/ void AppDomain::ADUnloadWorkerHelper(AppDomain *pDomain)
10120 STATIC_CONTRACT_NOTHROW;
10121 STATIC_CONTRACT_GC_TRIGGERS;
10122 STATIC_CONTRACT_MODE_COOPERATIVE;
10123 ADUnloadSink* pADUnloadSink=pDomain->GetADUnloadSinkForUnload();
10128 pDomain->Unload(FALSE);
10130 EX_CATCH_HRESULT(hr);
10134 SystemDomain::LockHolder lh;
10135 pADUnloadSink->ReportUnloadResult(hr,NULL);
10136 pADUnloadSink->Release();
10140 void AppDomain::DoADUnloadWork()
10147 INJECT_FAULT(COMPlusThrowOM(););
10154 AppDomain *pDomainToUnload = NULL;
10157 // Take the lock so that no domain can be added or removed from the system domain
10158 SystemDomain::LockHolder lh;
10160 DWORD numDomain = SystemDomain::GetCurrentAppDomainMaxIndex();
10161 for (; i <= numDomain; i ++) {
10162 AppDomain * pDomain = SystemDomain::TestGetAppDomainAtIndex(ADIndex(i));
10164 // @todo: We used to also select a domain if pDomain->IsUnload() returned true. But that causes
10165 // problems when we've failed to completely unload the AD in the past. If we've reached the CLEARED
10166 // stage, for instance, then there will be no default context and AppDomain::Exit() will simply crash.
10168 if (pDomain && pDomain->IsUnloadRequested())
10170 pDomainToUnload = pDomain;
10177 if (!pDomainToUnload) {
10181 // We are the only thread that can unload domains so no one else can delete the appdomain
10182 ADUnloadWorkerHelper(pDomainToUnload);
10186 static void DoADUnloadWorkHelper()
10188 STATIC_CONTRACT_NOTHROW;
10189 STATIC_CONTRACT_GC_TRIGGERS;
10190 STATIC_CONTRACT_MODE_COOPERATIVE;
10193 AppDomain::DoADUnloadWork();
10198 EX_END_CATCH(SwallowAllExceptions);
10201 ULONGLONG g_ObjFinalizeStartTime = 0;
10202 Volatile<BOOL> g_FinalizerIsRunning = FALSE;
10203 Volatile<ULONG> g_FinalizerLoopCount = 0;
10205 ULONGLONG GetObjFinalizeStartTime()
10207 LIMITED_METHOD_CONTRACT;
10208 return g_ObjFinalizeStartTime;
10211 void FinalizerThreadAbortOnTimeout()
10213 STATIC_CONTRACT_NOTHROW;
10214 STATIC_CONTRACT_MODE_COOPERATIVE;
10215 STATIC_CONTRACT_GC_TRIGGERS;
10218 // If finalizer thread is blocked because scheduler is running another task,
10219 // or it is waiting for another thread, we first see if we get finalizer thread
10221 Thread::ThreadAbortWatchDog();
10226 Thread *pFinalizerThread = FinalizerThread::GetFinalizerThread();
10227 EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(OPR_FinalizerRun, pFinalizerThread);
10231 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10232 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10235 Thread::UAC_FinalizerTimeout);
10237 case eRudeAbortThread:
10238 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10239 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10242 Thread::UAC_FinalizerTimeout);
10244 case eUnloadAppDomain:
10246 AppDomain *pDomain = pFinalizerThread->GetDomain();
10247 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10250 Thread::UAC_FinalizerTimeout);
10251 if (!pDomain->IsDefaultDomain())
10253 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10254 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
10258 case eRudeUnloadAppDomain:
10260 AppDomain *pDomain = pFinalizerThread->GetDomain();
10261 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10264 Thread::UAC_FinalizerTimeout);
10265 if (!pDomain->IsDefaultDomain())
10267 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10268 pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
10273 case eFastExitProcess:
10274 case eRudeExitProcess:
10275 case eDisableRuntime:
10276 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10277 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
10278 _ASSERTE (!"Should not get here");
10287 EX_END_CATCH(SwallowAllExceptions);
10292 WT_UnloadDomain = 0x1,
10293 WT_ThreadAbort = 0x2,
10294 WT_FinalizerThread = 0x4,
10295 WT_ClearCollectedDomains=0x8
10298 static Volatile<DWORD> s_WorkType = 0;
10301 DWORD WINAPI AppDomain::ADUnloadThreadStart(void *args)
10306 DISABLED(GC_TRIGGERS);
10308 // This function will always be at the very bottom of the stack. The only
10309 // user code it calls is the AppDomainUnload notifications which we will
10310 // not be hardenning for Whidbey.
10316 BEGIN_ENTRYPOINT_NOTHROW;
10318 ClrFlsSetThreadType (ThreadType_ADUnloadHelper);
10320 Thread *pThread = (Thread*)args;
10321 bool fOK = (pThread->HasStarted() != 0);
10324 GCX_MAYBE_PREEMP(fOK);
10326 _ASSERTE (g_fADUnloadWorkerOK == -2);
10328 FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK,fOK?1:-1);
10332 DestroyThread(pThread);
10336 pThread->SetBackground(TRUE);
10338 pThread->SetThreadStateNC(Thread::TSNC_ADUnloadHelper);
10341 DWORD TAtimeout = INFINITE;
10342 ULONGLONG endTime = Thread::GetNextSelfAbortEndTime();
10343 ULONGLONG curTime = CLRGetTickCount64();
10344 if (endTime <= curTime) {
10349 ULONGLONG diff = endTime - curTime;
10350 if (diff < MAXULONG)
10352 TAtimeout = (DWORD)diff;
10355 ULONGLONG finalizeStartTime = GetObjFinalizeStartTime();
10356 DWORD finalizeTimeout = INFINITE;
10357 DWORD finalizeTimeoutSetting = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
10358 if (finalizeTimeoutSetting != INFINITE && g_FinalizerIsRunning)
10360 if (finalizeStartTime == 0)
10362 finalizeTimeout = finalizeTimeoutSetting;
10366 endTime = finalizeStartTime + finalizeTimeoutSetting;
10367 if (endTime <= curTime) {
10368 finalizeTimeout = 0;
10372 ULONGLONG diff = endTime - curTime;
10373 if (diff < MAXULONG)
10375 finalizeTimeout = (DWORD)diff;
10381 if (AppDomain::HasWorkForFinalizerThread())
10383 if (finalizeTimeout > finalizeTimeoutSetting)
10385 finalizeTimeout = finalizeTimeoutSetting;
10389 DWORD timeout = INFINITE;
10390 if (finalizeTimeout <= TAtimeout)
10392 timeout = finalizeTimeout;
10396 timeout = TAtimeout;
10401 LOG((LF_APPDOMAIN, LL_INFO10, "Waiting to start unload\n"));
10402 g_pUnloadStartEvent->Wait(timeout,FALSE);
10405 if (finalizeTimeout != INFINITE || (s_WorkType & WT_FinalizerThread) != 0)
10407 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for Finalizer thread\n");
10408 FastInterlockAnd(&s_WorkType, ~WT_FinalizerThread);
10409 // only watch finalizer thread is finalizer method or unloadevent is being processed
10410 if (GetObjFinalizeStartTime() == finalizeStartTime && finalizeStartTime != 0 && g_FinalizerIsRunning)
10412 if (CLRGetTickCount64() >= finalizeStartTime+finalizeTimeoutSetting)
10415 FinalizerThreadAbortOnTimeout();
10418 if (s_fProcessUnloadDomainEvent && g_FinalizerIsRunning)
10421 FinalizerThreadAbortOnTimeout();
10425 if (TAtimeout != INFINITE || (s_WorkType & WT_ThreadAbort) != 0)
10427 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for thread abort\n");
10428 FastInterlockAnd(&s_WorkType, ~WT_ThreadAbort);
10430 Thread::ThreadAbortWatchDog();
10433 if ((s_WorkType & WT_UnloadDomain) != 0 && !AppDomain::HasWorkForFinalizerThread())
10435 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD unload\n");
10436 FastInterlockAnd(&s_WorkType, ~WT_UnloadDomain);
10438 DoADUnloadWorkHelper();
10441 if ((s_WorkType & WT_ClearCollectedDomains) != 0)
10443 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD cleanup\n");
10444 FastInterlockAnd(&s_WorkType, ~WT_ClearCollectedDomains);
10446 SystemDomain::System()->ClearCollectedDomains();
10453 END_ENTRYPOINT_NOTHROW;
10458 void AppDomain::EnableADUnloadWorker()
10464 SO_TOLERANT; // Called during a SO
10468 EEPolicy::AppDomainUnloadTypes type = EEPolicy::ADU_Safe;
10471 DWORD hostTestADUnload = g_pConfig->GetHostTestADUnload();
10472 if (hostTestADUnload == 2) {
10473 type = EEPolicy::ADU_Rude;
10477 EnableADUnloadWorker(type);
10480 void AppDomain::EnableADUnloadWorker(EEPolicy::AppDomainUnloadTypes type, BOOL fHasStack)
10486 SO_TOLERANT; // Called during a SO
10490 FastInterlockOr (&s_WorkType, WT_UnloadDomain);
10492 LONG stage = m_Stage;
10493 static_assert_no_msg(sizeof(m_Stage) == sizeof(int));
10495 _ASSERTE(!IsDefaultDomain());
10497 // Mark unload requested.
10498 if (type == EEPolicy::ADU_Rude) {
10501 while (stage < STAGE_UNLOAD_REQUESTED) {
10502 stage = FastInterlockCompareExchange((LONG*)&m_Stage,STAGE_UNLOAD_REQUESTED,stage);
10507 // Can not call Set due to limited stack.
10510 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker\n"));
10511 g_pUnloadStartEvent->Set();
10514 void AppDomain::EnableADUnloadWorkerForThreadAbort()
10516 LIMITED_METHOD_CONTRACT;
10517 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "Enabling unload worker for thread abort\n");
10518 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for thread abort\n"));
10519 FastInterlockOr (&s_WorkType, WT_ThreadAbort);
10520 g_pUnloadStartEvent->Set();
10524 void AppDomain::EnableADUnloadWorkerForFinalizer()
10526 LIMITED_METHOD_CONTRACT;
10527 if (GetEEPolicy()->GetTimeout(OPR_FinalizerRun) != INFINITE)
10529 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for Finalizer Thread\n"));
10530 FastInterlockOr (&s_WorkType, WT_FinalizerThread);
10531 g_pUnloadStartEvent->Set();
10535 void AppDomain::EnableADUnloadWorkerForCollectedADCleanup()
10537 LIMITED_METHOD_CONTRACT;
10538 LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for collected domains\n"));
10539 FastInterlockOr (&s_WorkType, WT_ClearCollectedDomains);
10540 g_pUnloadStartEvent->Set();
10544 void SystemDomain::ClearCollectedDomains()
10554 AppDomain* pDomainsToClear=NULL;
10556 CrstHolder lh(&m_DelayedUnloadCrst);
10557 for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
10559 if ((*ppDomain)->m_Stage==AppDomain::STAGE_COLLECTED)
10561 AppDomain* pAppDomain=*ppDomain;
10562 *ppDomain=(*ppDomain)->m_pNextInDelayedUnloadList;
10563 pAppDomain->m_pNextInDelayedUnloadList=pDomainsToClear;
10564 pDomainsToClear=pAppDomain;
10567 ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
10571 for (AppDomain* pDomain=pDomainsToClear;pDomain!=NULL;)
10573 AppDomain* pNext=pDomain->m_pNextInDelayedUnloadList;
10574 pDomain->Close(); //NOTHROW!
10575 pDomain->Release();
10580 void SystemDomain::ProcessClearingDomains()
10589 CrstHolder lh(&m_DelayedUnloadCrst);
10591 for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
10593 if ((*ppDomain)->m_Stage==AppDomain::STAGE_HANDLETABLE_NOACCESS)
10595 AppDomain* pAppDomain=*ppDomain;
10596 pAppDomain->SetStage(AppDomain::STAGE_CLEARED);
10598 ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
10601 if (!m_UnloadIsAsync)
10603 // For synchronous mode, we are now done with the list.
10604 m_pDelayedUnloadList = NULL;
10608 void SystemDomain::ProcessDelayedUnloadDomains()
10618 int iGCRefPoint=GCHeapUtilities::GetGCHeap()->CollectionCount(GCHeapUtilities::GetGCHeap()->GetMaxGeneration());
10619 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCInProgress())
10622 BOOL bAppDomainToCleanup = FALSE;
10623 LoaderAllocator * pAllocatorsToDelete = NULL;
10626 CrstHolder lh(&m_DelayedUnloadCrst);
10628 for (AppDomain* pDomain=m_pDelayedUnloadList; pDomain!=NULL; pDomain=pDomain->m_pNextInDelayedUnloadList)
10630 if (pDomain->m_Stage==AppDomain::STAGE_CLEARED)
10632 // Compare with 0 to handle overflows gracefully
10633 if (0 < iGCRefPoint - pDomain->GetGCRefPoint())
10635 bAppDomainToCleanup=TRUE;
10636 pDomain->SetStage(AppDomain::STAGE_COLLECTED);
10641 LoaderAllocator ** ppAllocator=&m_pDelayedUnloadListOfLoaderAllocators;
10642 while (*ppAllocator!= NULL)
10644 LoaderAllocator * pAllocator = *ppAllocator;
10645 if (0 < iGCRefPoint - pAllocator->GetGCRefPoint())
10647 *ppAllocator = pAllocator->m_pLoaderAllocatorDestroyNext;
10649 pAllocator->m_pLoaderAllocatorDestroyNext = pAllocatorsToDelete;
10650 pAllocatorsToDelete = pAllocator;
10654 ppAllocator = &pAllocator->m_pLoaderAllocatorDestroyNext;
10659 if (bAppDomainToCleanup)
10660 AppDomain::EnableADUnloadWorkerForCollectedADCleanup();
10662 // Delete collected loader allocators on the finalizer thread. We cannot offload it to appdomain unload thread because of
10663 // there is not guaranteed to be one, and it is not that expensive operation anyway.
10664 while (pAllocatorsToDelete != NULL)
10666 LoaderAllocator * pAllocator = pAllocatorsToDelete;
10667 pAllocatorsToDelete = pAllocator->m_pLoaderAllocatorDestroyNext;
10672 #endif // CROSSGEN_COMPILE
10674 AppDomainFromIDHolder::AppDomainFromIDHolder(ADID adId, BOOL bUnsafePoint, SyncType synctype)
10676 WRAPPER_NO_CONTRACT;
10677 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
10684 Assign(adId, bUnsafePoint);
10687 AppDomainFromIDHolder::AppDomainFromIDHolder(SyncType synctype)
10689 LIMITED_METHOD_CONTRACT;
10690 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
10699 #ifndef CROSSGEN_COMPILE
10700 void ADUnloadSink::ReportUnloadResult (HRESULT hr, OBJECTREF* pException)
10706 PRECONDITION(CheckPointer(this));
10707 PRECONDITION(m_UnloadCompleteEvent.IsValid());
10711 //pException is unused;
10713 m_UnloadCompleteEvent.Set();
10716 void ADUnloadSink::WaitUnloadCompletion()
10722 PRECONDITION(CheckPointer(this));
10723 PRECONDITION(m_UnloadCompleteEvent.IsValid());
10727 CONTRACT_VIOLATION(FaultViolation);
10728 m_UnloadCompleteEvent.WaitEx(INFINITE, (WaitMode)(WaitMode_Alertable | WaitMode_ADUnload));
10731 ADUnloadSink* AppDomain::PrepareForWaitUnloadCompletion()
10737 PRECONDITION(SystemDomain::IsUnderDomainLock());
10742 ADUnloadSink* pADSink=GetADUnloadSink();
10743 PREFIX_ASSUME(pADSink!=NULL);
10744 if (m_Stage < AppDomain::STAGE_UNLOAD_REQUESTED) //we're first
10747 SetUnloadRequestThread(GetThread());
10752 ADUnloadSink::ADUnloadSink()
10760 INJECT_FAULT(COMPlusThrowOM(););
10765 m_UnloadCompleteEvent.CreateManualEvent(FALSE);
10766 m_UnloadResult=S_OK;
10769 ADUnloadSink::~ADUnloadSink()
10779 m_UnloadCompleteEvent.CloseEvent();
10784 ULONG ADUnloadSink::AddRef()
10786 LIMITED_METHOD_CONTRACT;
10787 return InterlockedIncrement(&m_cRef);
10790 ULONG ADUnloadSink::Release()
10792 LIMITED_METHOD_CONTRACT;
10793 ULONG ulRef = InterlockedDecrement(&m_cRef);
10801 void ADUnloadSink::Reset()
10803 LIMITED_METHOD_CONTRACT;
10804 m_UnloadResult=S_OK;
10805 m_UnloadCompleteEvent.Reset();
10808 ADUnloadSink* AppDomain::GetADUnloadSink()
10810 LIMITED_METHOD_CONTRACT;
10811 _ASSERTE(SystemDomain::IsUnderDomainLock());
10813 m_ADUnloadSink->AddRef();
10814 return m_ADUnloadSink;
10817 ADUnloadSink* AppDomain::GetADUnloadSinkForUnload()
10819 // unload thread only. Doesn't need to have AD lock
10820 LIMITED_METHOD_CONTRACT;
10822 m_ADUnloadSink->AddRef();
10823 return m_ADUnloadSink;
10825 #endif // CROSSGEN_COMPILE
10827 void AppDomain::EnumStaticGCRefs(promote_func* fn, ScanContext* sc)
10836 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
10837 GCHeapUtilities::IsServerHeap() &&
10838 IsGCSpecialThread());
10840 AppDomain::AssemblyIterator asmIterator = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution));
10841 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
10842 while (asmIterator.Next(pDomainAssembly.This()))
10844 // @TODO: Review when DomainAssemblies get added.
10845 _ASSERTE(pDomainAssembly != NULL);
10846 pDomainAssembly->EnumStaticGCRefs(fn, sc);
10852 #endif // !DACCESS_COMPILE
10854 //------------------------------------------------------------------------
10855 UINT32 BaseDomain::GetTypeID(PTR_MethodTable pMT) {
10859 PRECONDITION(pMT->GetDomain() == this);
10862 return m_typeIDMap.GetTypeID(pMT);
10865 //------------------------------------------------------------------------
10866 // Returns the ID of the type if found. If not found, returns INVALID_TYPE_ID
10867 UINT32 BaseDomain::LookupTypeID(PTR_MethodTable pMT)
10872 WRAPPER(GC_TRIGGERS);
10873 PRECONDITION(pMT->GetDomain() == this);
10876 return m_typeIDMap.LookupTypeID(pMT);
10879 //------------------------------------------------------------------------
10880 PTR_MethodTable BaseDomain::LookupType(UINT32 id) {
10884 WRAPPER(GC_TRIGGERS);
10885 CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS);
10888 PTR_MethodTable pMT = m_typeIDMap.LookupType(id);
10889 if (pMT == NULL && !IsSharedDomain()) {
10890 pMT = SharedDomain::GetDomain()->LookupType(id);
10893 CONSISTENCY_CHECK(CheckPointer(pMT));
10894 CONSISTENCY_CHECK(pMT->IsInterface());
10898 //---------------------------------------------------------------------------------------
10901 AppDomain::AssemblyIterator::Next(
10902 CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
10906 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
10910 CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
10911 return Next_Unlocked(pDomainAssemblyHolder);
10914 //---------------------------------------------------------------------------------------
10916 // Note: Does not lock the assembly list, but locks collectible assemblies for adding references.
10919 AppDomain::AssemblyIterator::Next_Unlocked(
10920 CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
10928 #ifndef DACCESS_COMPILE
10929 _ASSERTE(m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
10932 while (m_Iterator.Next())
10934 // Get element from the list/iterator (without adding reference to the assembly)
10935 DomainAssembly * pDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
10936 if (pDomainAssembly == NULL)
10941 if (pDomainAssembly->IsError())
10943 if (m_assemblyIterationFlags & kIncludeFailedToLoad)
10945 *pDomainAssemblyHolder = pDomainAssembly;
10948 continue; // reject
10951 // First, reject DomainAssemblies whose load status is not to be included in
10954 if (pDomainAssembly->IsAvailableToProfilers() &&
10955 (m_assemblyIterationFlags & kIncludeAvailableToProfilers))
10957 // The assembly has reached the state at which we would notify profilers,
10958 // and we're supposed to include such assemblies in the enumeration. So
10959 // don't reject it (i.e., noop here, and don't bother with the rest of
10960 // the load status checks). Check for this first, since
10961 // kIncludeAvailableToProfilers contains some loaded AND loading
10964 else if (pDomainAssembly->IsLoaded())
10966 // A loaded assembly
10967 if (!(m_assemblyIterationFlags & kIncludeLoaded))
10969 continue; // reject
10974 // A loading assembly
10975 if (!(m_assemblyIterationFlags & kIncludeLoading))
10977 continue; // reject
10981 // Next, reject DomainAssemblies whose execution / introspection status is
10982 // not to be included in the enumeration
10984 if (pDomainAssembly->IsIntrospectionOnly())
10986 // introspection assembly
10987 if (!(m_assemblyIterationFlags & kIncludeIntrospection))
10989 continue; // reject
10994 // execution assembly
10995 if (!(m_assemblyIterationFlags & kIncludeExecution))
10997 continue; // reject
11001 // Next, reject collectible assemblies
11002 if (pDomainAssembly->IsCollectible())
11004 if (m_assemblyIterationFlags & kExcludeCollectible)
11006 _ASSERTE(!(m_assemblyIterationFlags & kIncludeCollected));
11007 continue; // reject
11010 // Un-tenured collectible assemblies should not be returned. (This can only happen in a brief
11011 // window during collectible assembly creation. No thread should need to have a pointer
11012 // to the just allocated DomainAssembly at this stage.)
11013 if (!pDomainAssembly->GetAssembly()->GetManifestModule()->IsTenured())
11015 continue; // reject
11018 if (pDomainAssembly->GetLoaderAllocator()->AddReferenceIfAlive())
11019 { // The assembly is alive
11021 // Set the holder value (incl. increasing ref-count)
11022 *pDomainAssemblyHolder = pDomainAssembly;
11024 // Now release the reference we took in the if-condition
11025 pDomainAssembly->GetLoaderAllocator()->Release();
11028 // The assembly is not alive anymore (and we didn't increase its ref-count in the
11031 if (!(m_assemblyIterationFlags & kIncludeCollected))
11033 continue; // reject
11035 // Set the holder value to assembly with 0 ref-count without increasing the ref-count (won't
11036 // call Release either)
11037 pDomainAssemblyHolder->Assign(pDomainAssembly, FALSE);
11041 *pDomainAssemblyHolder = pDomainAssembly;
11045 *pDomainAssemblyHolder = NULL;
11047 } // AppDomain::AssemblyIterator::Next_Unlocked
11049 #ifndef DACCESS_COMPILE
11051 //---------------------------------------------------------------------------------------
11053 // Can be called only from AppDomain shutdown code:AppDomain::ShutdownAssemblies.
11054 // Does not add-ref collectible assemblies (as the LoaderAllocator might not be reachable from the
11055 // DomainAssembly anymore).
11058 AppDomain::AssemblyIterator::Next_UnsafeNoAddRef(
11059 DomainAssembly ** ppDomainAssembly)
11067 // Make sure we are iterating all assemblies (see the only caller code:AppDomain::ShutdownAssemblies)
11068 _ASSERTE(m_assemblyIterationFlags ==
11069 (kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
11070 // It also means that we do not exclude anything
11071 _ASSERTE((m_assemblyIterationFlags & kExcludeCollectible) == 0);
11073 // We are on shutdown path, so lock shouldn't be neccessary, but all _Unlocked methods on AssemblyList
11074 // have asserts that the lock is held, so why not to take it ...
11075 CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
11077 while (m_Iterator.Next())
11079 // Get element from the list/iterator (without adding reference to the assembly)
11080 *ppDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
11081 if (*ppDomainAssembly == NULL)
11089 *ppDomainAssembly = NULL;
11091 } // AppDomain::AssemblyIterator::Next_UnsafeNoAddRef
11094 //---------------------------------------------------------------------------------------
11096 BOOL AppDomain::IsImageFromTrustedPath(PEImage* pPEImage)
11103 PRECONDITION(CheckPointer(pPEImage));
11107 const SString &sImagePath = pPEImage->GetPath();
11109 return !sImagePath.IsEmpty();
11112 #endif //!DACCESS_COMPILE
11114 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
11116 // Returns a BOOL indicating if the binding model has been locked for the AppDomain
11117 BOOL AppDomain::IsBindingModelLocked()
11127 return m_fIsBindingModelLocked.Load();
11130 // Marks the binding model locked for AppDomain
11131 BOOL AppDomain::LockBindingModel()
11133 LIMITED_METHOD_CONTRACT;
11135 BOOL fDidWeLockBindingModel = FALSE;
11137 if (InterlockedCompareExchangeT<BOOL>(&m_fIsBindingModelLocked, TRUE, FALSE) == FALSE)
11139 fDidWeLockBindingModel = TRUE;
11142 return fDidWeLockBindingModel;
11145 BOOL AppDomain::IsHostAssemblyResolverInUse()
11147 LIMITED_METHOD_CONTRACT;
11149 return (GetFusionContext() != GetTPABinderContext());
11152 // Helper used by the assembly binder to check if the specified AppDomain can use apppath assembly resolver
11153 BOOL RuntimeCanUseAppPathAssemblyResolver(DWORD adid)
11157 NOTHROW; // Cannot throw since it is invoked by the Binder that expects to get a hresult
11165 // We need to be in COOP mode to get the AppDomain*
11168 AppDomain *pTargetDomain = SystemDomain::GetAppDomainFromId(id, ADV_CURRENTAD);
11169 _ASSERTE(pTargetDomain != NULL);
11171 pTargetDomain->LockBindingModel();
11173 return !pTargetDomain->IsHostAssemblyResolverInUse();
11176 // Returns S_OK if the assembly was successfully loaded
11177 HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, IAssemblyName *pIAssemblyName, CLRPrivBinderCoreCLR *pTPABinder, BINDER_SPACE::AssemblyName *pAssemblyName, ICLRPrivAssembly **ppLoadedAssembly)
11184 PRECONDITION(ppLoadedAssembly != NULL);
11188 HRESULT hr = E_FAIL;
11190 // DevDiv #933506: Exceptions thrown during AssemblyLoadContext.Load should propagate
11193 // Switch to COOP mode since we are going to work with managed references
11198 ASSEMBLYNAMEREF oRefAssemblyName;
11199 ASSEMBLYREF oRefLoadedAssembly;
11202 ZeroMemory(&_gcRefs, sizeof(_gcRefs));
11204 GCPROTECT_BEGIN(_gcRefs);
11206 ICLRPrivAssembly *pAssemblyBindingContext = NULL;
11208 bool fInvokedForTPABinder = (pTPABinder == NULL)?true:false;
11210 // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.Resolve method.
11212 // First, initialize an assembly spec for the requested assembly
11215 hr = spec.Init(pIAssemblyName);
11218 bool fResolvedAssembly = false;
11219 bool fResolvedAssemblyViaTPALoadContext = false;
11221 // Allocate an AssemblyName managed object
11222 _gcRefs.oRefAssemblyName = (ASSEMBLYNAMEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME));
11224 // Initialize the AssemblyName object from the AssemblySpec
11225 spec.AssemblyNameInit(&_gcRefs.oRefAssemblyName, NULL);
11227 if (!fInvokedForTPABinder)
11229 // Step 2 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName) - Invoke Load method
11230 // This is not invoked for TPA Binder since it always returns NULL.
11232 // Finally, setup arguments for invocation
11233 BinderMethodID idHAR_Resolve = METHOD__ASSEMBLYLOADCONTEXT__RESOLVE;
11234 MethodDescCallSite methLoadAssembly(idHAR_Resolve);
11236 // Setup the arguments for the call
11239 PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
11240 ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
11244 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
11245 if (_gcRefs.oRefLoadedAssembly != NULL)
11247 fResolvedAssembly = true;
11250 // Step 3 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
11251 if (!fResolvedAssembly)
11253 // If we could not resolve the assembly using Load method, then attempt fallback with TPA Binder.
11254 // Since TPA binder cannot fallback to itself, this fallback does not happen for binds within TPA binder.
11256 // Switch to pre-emp mode before calling into the binder
11258 ICLRPrivAssembly *pCoreCLRFoundAssembly = NULL;
11259 hr = pTPABinder->BindAssemblyByName(pIAssemblyName, &pCoreCLRFoundAssembly);
11262 pAssemblyBindingContext = pCoreCLRFoundAssembly;
11263 fResolvedAssembly = true;
11264 fResolvedAssemblyViaTPALoadContext = true;
11269 if (!fResolvedAssembly)
11271 // Step 4 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
11273 // If we couldnt resolve the assembly using TPA LoadContext as well, then
11274 // attempt to resolve it using the Resolving event.
11275 // Finally, setup arguments for invocation
11276 BinderMethodID idHAR_ResolveUsingEvent = METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUSINGEVENT;
11277 MethodDescCallSite methLoadAssembly(idHAR_ResolveUsingEvent);
11279 // Setup the arguments for the call
11282 PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
11283 ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
11287 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
11288 if (_gcRefs.oRefLoadedAssembly != NULL)
11290 // Set the flag indicating we found the assembly
11291 fResolvedAssembly = true;
11295 if (fResolvedAssembly && !fResolvedAssemblyViaTPALoadContext)
11297 // If we are here, assembly was successfully resolved via Load or Resolving events.
11298 _ASSERTE(_gcRefs.oRefLoadedAssembly != NULL);
11300 // We were able to get the assembly loaded. Now, get its name since the host could have
11301 // performed the resolution using an assembly with different name.
11302 DomainAssembly *pDomainAssembly = _gcRefs.oRefLoadedAssembly->GetDomainAssembly();
11303 PEAssembly *pLoadedPEAssembly = NULL;
11304 bool fFailLoad = false;
11305 if (!pDomainAssembly)
11307 // Reflection emitted assemblies will not have a domain assembly.
11312 pLoadedPEAssembly = pDomainAssembly->GetFile();
11313 if (pLoadedPEAssembly->HasHostAssembly() != true)
11315 // Reflection emitted assemblies will not have a domain assembly.
11320 // The loaded assembly's ICLRPrivAssembly* is saved as HostAssembly in PEAssembly
11324 spec.GetFileOrDisplayName(0, name);
11325 COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_DYNAMICALLY_EMITTED_ASSEMBLIES_UNSUPPORTED, name);
11328 // Is the assembly already bound using a binding context that will be incompatible?
11329 // An example is attempting to consume an assembly bound to WinRT binder.
11330 pAssemblyBindingContext = pLoadedPEAssembly->GetHostAssembly();
11333 #ifdef FEATURE_COMINTEROP
11334 if (AreSameBinderInstance(pAssemblyBindingContext, GetAppDomain()->GetWinRtBinder()))
11336 // It is invalid to return an assembly bound to an incompatible binder
11337 *ppLoadedAssembly = NULL;
11339 spec.GetFileOrDisplayName(0, name);
11340 COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_BINDING_CONTEXT, name);
11342 #endif // FEATURE_COMINTEROP
11344 // Get the ICLRPrivAssembly reference to return back to.
11345 *ppLoadedAssembly = clr::SafeAddRef(pAssemblyBindingContext);
11351 // EX_CATCH_HRESULT(hr);
11356 #endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
11358 //approximate size of loader data
11359 //maintained for each assembly
11360 #define APPROX_LOADER_DATA_PER_ASSEMBLY 8196
11362 size_t AppDomain::EstimateSize()
11372 size_t retval = sizeof(AppDomain);
11373 retval += GetLoaderAllocator()->EstimateSize();
11374 //very rough estimate
11375 retval += GetAssemblyCount() * APPROX_LOADER_DATA_PER_ASSEMBLY;
11379 #ifdef DACCESS_COMPILE
11382 DomainLocalModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
11386 // Enumerate the DomainLocalModule itself. DLMs are allocated to be larger than
11387 // sizeof(DomainLocalModule) to make room for ClassInit flags and non-GC statics.
11388 // "DAC_ENUM_DTHIS()" probably does not account for this, so we might not enumerate
11389 // all of the ClassInit flags and non-GC statics.
11390 // sizeof(DomainLocalModule) == 0x28
11393 if (m_pDomainFile.IsValid())
11395 m_pDomainFile->EnumMemoryRegions(flags);
11398 if (m_pDynamicClassTable.Load().IsValid())
11400 DacEnumMemoryRegion(dac_cast<TADDR>(m_pDynamicClassTable.Load()),
11401 m_aDynamicEntries * sizeof(DynamicClassInfo));
11403 for (SIZE_T i = 0; i < m_aDynamicEntries; i++)
11405 PTR_DynamicEntry entry = dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[i].m_pDynamicEntry.Load());
11406 if (entry.IsValid())
11408 // sizeof(DomainLocalModule::DynamicEntry) == 8
11416 DomainLocalBlock::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
11419 // Block is contained in AppDomain, don't enum this.
11421 if (m_pModuleSlots.IsValid())
11423 DacEnumMemoryRegion(dac_cast<TADDR>(m_pModuleSlots),
11424 m_aModuleIndices * sizeof(TADDR));
11426 for (SIZE_T i = 0; i < m_aModuleIndices; i++)
11428 PTR_DomainLocalModule domMod = m_pModuleSlots[i];
11429 if (domMod.IsValid())
11431 domMod->EnumMemoryRegions(flags);
11438 BaseDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11444 // This is wrong. Don't do it.
11445 // BaseDomain cannot be instantiated.
11446 // The only thing this code can hope to accomplish is to potentially break
11447 // memory enumeration walking through the derived class if we
11448 // explicitly call the base class enum first.
11449 // DAC_ENUM_VTHIS();
11452 EMEM_OUT(("MEM: %p BaseDomain\n", dac_cast<TADDR>(this)));
11456 AppDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11463 //sizeof(AppDomain) == 0xeb0
11466 BaseDomain::EnumMemoryRegions(flags, false);
11468 // We don't need AppDomain name in triage dumps.
11469 if (flags != CLRDATA_ENUM_MEM_TRIAGE)
11471 m_friendlyName.EnumMemoryRegions(flags);
11474 m_Assemblies.EnumMemoryRegions(flags);
11475 AssemblyIterator assem = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution | kIncludeIntrospection));
11476 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
11478 while (assem.Next(pDomainAssembly.This()))
11480 pDomainAssembly->EnumMemoryRegions(flags);
11483 m_sDomainLocalBlock.EnumMemoryRegions(flags);
11485 m_LoaderAllocator.EnumMemoryRegions(flags);
11489 SystemDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11497 BaseDomain::EnumMemoryRegions(flags, false);
11499 if (m_pSystemFile.IsValid())
11501 m_pSystemFile->EnumMemoryRegions(flags);
11503 if (m_pSystemAssembly.IsValid())
11505 m_pSystemAssembly->EnumMemoryRegions(flags);
11507 if (m_pDefaultDomain.IsValid())
11509 m_pDefaultDomain->EnumMemoryRegions(flags, true);
11512 m_appDomainIndexList.EnumMem();
11513 (&m_appDomainIndexList)->EnumMemoryRegions(flags);
11517 SharedDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11525 BaseDomain::EnumMemoryRegions(flags, false);
11526 #ifdef FEATURE_LOADER_OPTIMIZATION
11527 m_assemblyMap.EnumMemoryRegions(flags);
11528 SharedAssemblyIterator assem;
11529 while (assem.Next())
11531 assem.GetAssembly()->EnumMemoryRegions(flags);
11536 #endif //DACCESS_COMPILE
11539 PTR_LoaderAllocator SystemDomain::GetGlobalLoaderAllocator()
11541 return PTR_LoaderAllocator(PTR_HOST_MEMBER_TADDR(SystemDomain,System(),m_GlobalAllocator));
11544 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
11546 #ifndef CROSSGEN_COMPILE
11547 // Return the total processor time (user and kernel) used by threads executing in this AppDomain so far. The
11548 // result is in 100ns units.
11549 ULONGLONG AppDomain::QueryProcessorUsage()
11559 #ifndef DACCESS_COMPILE
11560 Thread *pThread = NULL;
11562 // Need to update our accumulated processor time count with current values from each thread that is
11563 // currently executing in this domain.
11565 // Take the thread store lock while we enumerate threads.
11566 ThreadStoreLockHolder tsl;
11567 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
11569 // Skip unstarted and dead threads and those that are currently executing in a different AppDomain.
11570 if (pThread->IsUnstarted() || pThread->IsDead() || pThread->GetDomain(INDEBUG(TRUE)) != this)
11573 // Add the amount of time spent by the thread in the AppDomain since the last time we asked (calling
11574 // Thread::QueryThreadProcessorUsage() will reset the thread's counter).
11575 UpdateProcessorUsage(pThread->QueryThreadProcessorUsage());
11577 #endif // !DACCESS_COMPILE
11579 // Return the updated total.
11580 return m_ullTotalProcessorUsage;
11583 // Add to the current count of processor time used by threads within this AppDomain. This API is called by
11584 // threads transitioning between AppDomains.
11585 void AppDomain::UpdateProcessorUsage(ULONGLONG ullAdditionalUsage)
11587 LIMITED_METHOD_CONTRACT;
11589 // Need to be careful to synchronize here, multiple threads could be racing to update this count.
11590 ULONGLONG ullOldValue;
11591 ULONGLONG ullNewValue;
11594 ullOldValue = m_ullTotalProcessorUsage;
11595 ullNewValue = ullOldValue + ullAdditionalUsage;
11596 } while (InterlockedCompareExchange64((LONGLONG*)&m_ullTotalProcessorUsage,
11597 (LONGLONG)ullNewValue,
11598 (LONGLONG)ullOldValue) != (LONGLONG)ullOldValue);
11600 #endif // CROSSGEN_COMPILE
11602 #endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
11604 #if defined(FEATURE_TYPEEQUIVALENCE)
11606 #ifndef DACCESS_COMPILE
11607 TypeEquivalenceHashTable * AppDomain::GetTypeEquivalenceCache()
11613 INJECT_FAULT(COMPlusThrowOM());
11618 // Take the critical section all of the time in debug builds to ensure that it is safe to take
11619 // the critical section in the unusual times when it may actually be needed in retail builds
11621 CrstHolder ch(&m_TypeEquivalenceCrst);
11624 if (m_pTypeEquivalenceTable.Load() == NULL)
11627 CrstHolder ch(&m_TypeEquivalenceCrst);
11629 if (m_pTypeEquivalenceTable.Load() == NULL)
11631 m_pTypeEquivalenceTable = TypeEquivalenceHashTable::Create(this, 12, &m_TypeEquivalenceCrst);
11634 return m_pTypeEquivalenceTable;
11636 #endif //!DACCESS_COMPILE
11638 #endif //FEATURE_TYPEEQUIVALENCE
11640 #if !defined(DACCESS_COMPILE)
11642 //---------------------------------------------------------------------------------------------------------------------
11643 void AppDomain::PublishHostedAssembly(
11644 DomainAssembly * pDomainAssembly)
11654 if (pDomainAssembly->GetFile()->HasHostAssembly())
11656 // We have to serialize all Add operations
11657 CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
11658 _ASSERTE(m_hostAssemblyMap.Lookup(pDomainAssembly->GetFile()->GetHostAssembly()) == nullptr);
11660 // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
11661 HostAssemblyMap::AddPhases addCall;
11663 // 1. Preallocate one element
11664 addCall.PreallocateForAdd(&m_hostAssemblyMap);
11666 // 2. Take the reader lock which can be taken during stack walking
11667 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
11668 ForbidSuspendThreadHolder suspend;
11670 CrstHolder lock(&m_crstHostAssemblyMap);
11671 // 3. Add the element to the hash table (no call out into host)
11672 addCall.Add(pDomainAssembly);
11675 // 4. Cleanup the old memory (if any)
11676 addCall.DeleteOldTable();
11683 //---------------------------------------------------------------------------------------------------------------------
11684 void AppDomain::UpdatePublishHostedAssembly(
11685 DomainAssembly * pAssembly,
11697 if (pAssembly->GetFile()->HasHostAssembly())
11699 // We have to serialize all Add operations
11700 CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
11702 // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
11703 OriginalFileHostAssemblyMap::AddPhases addCall;
11704 bool fAddOrigFile = false;
11706 // For cases where the pefile is being updated
11707 // 1. Preallocate one element
11708 if (pFile != pAssembly->GetFile())
11710 addCall.PreallocateForAdd(&m_hostAssemblyMapForOrigFile);
11711 fAddOrigFile = true;
11715 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
11716 ForbidSuspendThreadHolder suspend;
11718 CrstHolder lock(&m_crstHostAssemblyMap);
11720 // Remove from hash table.
11721 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
11722 m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
11724 // Update PEFile on DomainAssembly. (This may cause the key for the hash to change, which is why we need this function)
11725 pAssembly->UpdatePEFileWorker(pFile);
11727 _ASSERTE(fAddOrigFile == (pAssembly->GetOriginalFile() != pAssembly->GetFile()));
11730 // 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)
11731 addCall.Add(pAssembly);
11734 // Add back to the hashtable (the call to Remove above guarantees that we will not call into host for table reallocation)
11735 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) == nullptr);
11736 m_hostAssemblyMap.Add(pAssembly);
11740 // 4. Cleanup the old memory (if any)
11742 addCall.DeleteOldTable();
11748 pAssembly->UpdatePEFileWorker(pFile);
11752 //---------------------------------------------------------------------------------------------------------------------
11753 void AppDomain::UnPublishHostedAssembly(
11754 DomainAssembly * pAssembly)
11765 if (pAssembly->GetFile()->HasHostAssembly())
11767 ForbidSuspendThreadHolder suspend;
11769 CrstHolder lock(&m_crstHostAssemblyMap);
11770 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
11771 m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
11773 // We also have an entry in m_hostAssemblyMapForOrigFile. Handle that case.
11774 if (pAssembly->GetOriginalFile() != pAssembly->GetFile())
11776 m_hostAssemblyMapForOrigFile.Remove(pAssembly->GetOriginalFile()->GetHostAssembly());
11782 // In AppX processes, all PEAssemblies that are reach this stage should have host binders.
11783 _ASSERTE(!AppX::IsAppXProcess());
11787 #if defined(FEATURE_COMINTEROP)
11788 HRESULT AppDomain::SetWinrtApplicationContext(SString &appLocalWinMD)
11790 STANDARD_VM_CONTRACT;
11792 _ASSERTE(WinRTSupported());
11793 _ASSERTE(m_pWinRtBinder != nullptr);
11795 _ASSERTE(GetTPABinderContext() != NULL);
11796 BINDER_SPACE::ApplicationContext *pApplicationContext = GetTPABinderContext()->GetAppContext();
11797 _ASSERTE(pApplicationContext != NULL);
11799 return m_pWinRtBinder->SetApplicationContext(pApplicationContext, appLocalWinMD);
11802 #endif // FEATURE_COMINTEROP
11804 #endif //!DACCESS_COMPILE
11806 //---------------------------------------------------------------------------------------------------------------------
11807 PTR_DomainAssembly AppDomain::FindAssembly(PTR_ICLRPrivAssembly pHostAssembly)
11818 if (pHostAssembly == nullptr)
11822 ForbidSuspendThreadHolder suspend;
11824 CrstHolder lock(&m_crstHostAssemblyMap);
11825 PTR_DomainAssembly returnValue = m_hostAssemblyMap.Lookup(pHostAssembly);
11826 if (returnValue == NULL)
11828 // If not found in the m_hostAssemblyMap, look in the m_hostAssemblyMapForOrigFile
11829 // This is necessary as it may happen during in a second AppDomain that the PEFile
11830 // first discovered in the AppDomain may not be used by the DomainFile, but the CLRPrivBinderFusion
11831 // will in some cases find the pHostAssembly associated with this no longer used PEFile
11832 // instead of the PEFile that was finally decided upon.
11833 returnValue = m_hostAssemblyMapForOrigFile.Lookup(pHostAssembly);
11836 return returnValue;
11841 #if !defined(DACCESS_COMPILE) && defined(FEATURE_NATIVE_IMAGE_GENERATION)
11843 void ZapperSetBindingPaths(ICorCompilationDomain *pDomain, SString &trustedPlatformAssemblies, SString &platformResourceRoots, SString &appPaths, SString &appNiPaths)
11845 CLRPrivBinderCoreCLR *pBinder = static_cast<CLRPrivBinderCoreCLR*>(((CompilationDomain *)pDomain)->GetFusionContext());
11846 _ASSERTE(pBinder != NULL);
11847 pBinder->SetupBindingPaths(trustedPlatformAssemblies, platformResourceRoots, appPaths, appNiPaths);
11848 #ifdef FEATURE_COMINTEROP
11849 SString emptString;
11850 ((CompilationDomain*)pDomain)->SetWinrtApplicationContext(emptString);