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.
5 /*============================================================
7 ** Header: AppDomain.cpp
11 ** Purpose: Implements AppDomain (loader domain) architecture
14 ===========================================================*/
18 #include "eventtrace.h"
19 #include "assembly.hpp"
20 #include "clsload.hpp"
22 #include "arraylist.h"
23 #include "comreflectioncache.hpp"
24 #include "comutilnative.h"
25 #include "domainfile.h"
26 #include "objectlist.h"
27 #include "fptrstubs.h"
28 #include "testhookmgr.h"
29 #include "gcheaputilities.h"
30 #include "gchandleutilities.h"
31 #include "../binder/inc/applicationcontext.hpp"
34 #ifdef FEATURE_MULTICOREJIT
35 #include "multicorejit.h"
38 #ifdef FEATURE_COMINTEROP
39 #include "clrprivbinderwinrt.h"
40 #include "..\md\winmd\inc\adapter.h"
41 #include "winrttypenameconverter.h"
42 #endif // FEATURE_COMINTEROP
46 #include "tieredcompilation.h"
48 #include "codeversion.h"
53 class CompilationDomain;
56 class EEMarshalingData;
57 class GlobalStringLiteralMap;
58 class StringLiteralMap;
59 class MngStdInterfacesInfo;
62 struct InteropMethodTableData;
63 class LoadLevelLimiter;
64 class TypeEquivalenceHashTable;
65 class StringArrayList;
67 extern INT64 g_PauseTime; // Total time in millisecond the CLR has been paused
69 #ifdef FEATURE_COMINTEROP
70 class ComCallWrapperCache;
71 struct SimpleComCallWrapper;
73 #endif // FEATURE_COMINTEROP
77 #pragma warning(disable : 4200) // Disable zero-sized array warning
81 GPTR_DECL(IdDispenser, g_pModuleIndexDispenser);
83 // This enum is aligned to System.ExceptionCatcherType.
84 enum ExceptionCatcher {
85 ExceptionCatcher_ManagedCode = 0,
86 ExceptionCatcher_AppDomainTransition = 1,
87 ExceptionCatcher_COMInterop = 2,
90 // We would like *ALLOCATECLASS_FLAG to AV (in order to catch errors), so don't change it
91 struct ClassInitFlags {
94 INITIALIZED_FLAG_BIT = 0,
95 INITIALIZED_FLAG = 1<<INITIALIZED_FLAG_BIT,
97 ERROR_FLAG = 1<<ERROR_FLAG_BIT,
98 ALLOCATECLASS_FLAG_BIT = 2, // Bit to avoid racing for InstantiateStaticHandles
99 ALLOCATECLASS_FLAG = 1<<ALLOCATECLASS_FLAG_BIT,
100 COLLECTIBLE_FLAG_BIT = 3,
101 COLLECTIBLE_FLAG = 1<<COLLECTIBLE_FLAG_BIT
105 struct DomainLocalModule
107 friend class ClrDataAccess;
108 friend class CheckAsmOffsets;
109 friend struct ThreadLocalModule;
111 // After these macros complete, they may have returned an interior pointer into a gc object. This pointer will have been cast to a byte pointer
112 // It is critically important that no GC is allowed to occur before this pointer is used.
113 #define GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pGCStatics) \
115 DomainLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast<DomainLocalModule::PTR_DynamicClassInfo>(dynamicClassInfoParam);\
116 DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast<DomainLocalModule::PTR_DynamicEntry>((DomainLocalModule::DynamicEntry*)dynamicClassInfo->m_pDynamicEntry.Load()); \
117 if ((dynamicClassInfo->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \
119 PTRARRAYREF objArray;\
120 objArray = (PTRARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \
121 (dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hGCStatics);\
122 *(pGCStatics) = dac_cast<PTR_BYTE>(PTR_READ(PTR_TO_TADDR(OBJECTREFToObject( objArray )) + offsetof(PtrArray, m_Array), objArray->GetNumComponents() * sizeof(void*))) ;\
126 *(pGCStatics) = (dac_cast<DomainLocalModule::PTR_NormalDynamicEntry>(pDynamicEntry))->GetGCStaticsBasePointer();\
130 #define GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pNonGCStatics) \
132 DomainLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast<DomainLocalModule::PTR_DynamicClassInfo>(dynamicClassInfoParam);\
133 DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast<DomainLocalModule::PTR_DynamicEntry>((DomainLocalModule::DynamicEntry*)(dynamicClassInfo)->m_pDynamicEntry.Load()); \
134 if (((dynamicClassInfo)->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \
136 if ((dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hNonGCStatics != 0) \
138 U1ARRAYREF objArray;\
139 objArray = (U1ARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \
140 (dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hNonGCStatics);\
141 *(pNonGCStatics) = dac_cast<PTR_BYTE>(PTR_READ( \
142 PTR_TO_TADDR(OBJECTREFToObject( objArray )) + sizeof(ArrayBase) - DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob(), \
143 objArray->GetNumComponents() * (DWORD)objArray->GetComponentSize() + DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob())); \
144 } else (*pNonGCStatics) = NULL; \
148 *(pNonGCStatics) = dac_cast<DomainLocalModule::PTR_NormalDynamicEntry>(pDynamicEntry)->GetNonGCStaticsBasePointer();\
154 static DWORD GetOffsetOfDataBlob();
156 typedef DPTR(DynamicEntry) PTR_DynamicEntry;
158 struct CollectibleDynamicEntry : public DynamicEntry
160 LOADERHANDLE m_hGCStatics;
161 LOADERHANDLE m_hNonGCStatics;
163 typedef DPTR(CollectibleDynamicEntry) PTR_CollectibleDynamicEntry;
165 struct NormalDynamicEntry : public DynamicEntry
167 PTR_OBJECTREF m_pGCStatics;
168 #ifdef FEATURE_64BIT_ALIGNMENT
169 // Padding to make m_pDataBlob aligned at MAX_PRIMITIVE_FIELD_SIZE
170 // code:MethodTableBuilder::PlaceRegularStaticFields assumes that the start of the data blob is aligned
175 inline PTR_BYTE GetGCStaticsBasePointer()
177 LIMITED_METHOD_CONTRACT;
179 return dac_cast<PTR_BYTE>(m_pGCStatics);
181 inline PTR_BYTE GetNonGCStaticsBasePointer()
183 LIMITED_METHOD_CONTRACT
185 return dac_cast<PTR_BYTE>(this);
188 typedef DPTR(NormalDynamicEntry) PTR_NormalDynamicEntry;
190 struct DynamicClassInfo
192 VolatilePtr<DynamicEntry, PTR_DynamicEntry> m_pDynamicEntry;
193 Volatile<DWORD> m_dwFlags;
195 typedef DPTR(DynamicClassInfo) PTR_DynamicClassInfo;
197 inline UMEntryThunk * GetADThunkTable()
199 LIMITED_METHOD_CONTRACT
200 return m_pADThunkTable;
203 inline void SetADThunkTable(UMEntryThunk* pADThunkTable)
205 LIMITED_METHOD_CONTRACT
206 InterlockedCompareExchangeT(m_pADThunkTable.GetPointer(), pADThunkTable, NULL);
209 // Note the difference between:
211 // GetPrecomputedNonGCStaticsBasePointer() and
212 // GetPrecomputedStaticsClassData()
214 // GetPrecomputedNonGCStaticsBasePointer returns the pointer that should be added to field offsets to retrieve statics
215 // GetPrecomputedStaticsClassData returns a pointer to the first byte of the precomputed statics block
216 inline TADDR GetPrecomputedNonGCStaticsBasePointer()
218 LIMITED_METHOD_CONTRACT
219 return dac_cast<TADDR>(this);
222 inline PTR_BYTE GetPrecomputedStaticsClassData()
224 LIMITED_METHOD_CONTRACT
225 return dac_cast<PTR_BYTE>(this) + offsetof(DomainLocalModule, m_pDataBlob);
228 static SIZE_T GetOffsetOfDataBlob() { return offsetof(DomainLocalModule, m_pDataBlob); }
229 static SIZE_T GetOffsetOfGCStaticPointer() { return offsetof(DomainLocalModule, m_pGCStatics); }
231 inline DomainFile* GetDomainFile()
233 LIMITED_METHOD_CONTRACT
235 return m_pDomainFile;
238 #ifndef DACCESS_COMPILE
239 inline void SetDomainFile(DomainFile* pDomainFile)
241 LIMITED_METHOD_CONTRACT
242 m_pDomainFile = pDomainFile;
246 inline PTR_OBJECTREF GetPrecomputedGCStaticsBasePointer()
248 LIMITED_METHOD_CONTRACT
252 inline PTR_OBJECTREF * GetPrecomputedGCStaticsBasePointerAddress()
254 LIMITED_METHOD_CONTRACT
255 return &m_pGCStatics;
258 // Returns bytes so we can add offsets
259 inline PTR_BYTE GetGCStaticsBasePointer(MethodTable * pMT)
264 if (pMT->IsDynamicStatics())
266 _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
267 return GetDynamicEntryGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator());
271 return dac_cast<PTR_BYTE>(m_pGCStatics);
275 inline PTR_BYTE GetNonGCStaticsBasePointer(MethodTable * pMT)
280 if (pMT->IsDynamicStatics())
282 _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
283 return GetDynamicEntryNonGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator());
287 return dac_cast<PTR_BYTE>(this);
291 inline DynamicClassInfo* GetDynamicClassInfo(DWORD n)
293 LIMITED_METHOD_CONTRACT
295 _ASSERTE(m_pDynamicClassTable.Load() && m_aDynamicEntries > n);
296 dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[n].m_pDynamicEntry.Load());
298 return &m_pDynamicClassTable[n];
301 // These helpers can now return null, as the debugger may do queries on a type
302 // before the calls to PopulateClass happen
303 inline PTR_BYTE GetDynamicEntryGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator)
315 if (n >= m_aDynamicEntries)
320 DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n);
321 if (!pClassInfo->m_pDynamicEntry)
326 PTR_BYTE retval = NULL;
328 GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval);
333 inline PTR_BYTE GetDynamicEntryNonGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator)
345 if (n >= m_aDynamicEntries)
350 DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n);
351 if (!pClassInfo->m_pDynamicEntry)
356 PTR_BYTE retval = NULL;
358 GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval);
363 FORCEINLINE PTR_DynamicClassInfo GetDynamicClassInfoIfInitialized(DWORD n)
367 // m_aDynamicEntries is set last, it needs to be checked first
368 if (n >= m_aDynamicEntries)
373 _ASSERTE(m_pDynamicClassTable.Load() != NULL);
374 PTR_DynamicClassInfo pDynamicClassInfo = (PTR_DynamicClassInfo)(m_pDynamicClassTable.Load() + n);
376 // INITIALIZED_FLAG is set last, it needs to be checked first
377 if ((pDynamicClassInfo->m_dwFlags & ClassInitFlags::INITIALIZED_FLAG) == 0)
382 PREFIX_ASSUME(pDynamicClassInfo != NULL);
383 return pDynamicClassInfo;
386 // iClassIndex is slightly expensive to compute, so if we already know
387 // it, we can use this helper
388 inline BOOL IsClassInitialized(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
391 return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::INITIALIZED_FLAG) != 0;
394 inline BOOL IsPrecomputedClassInitialized(DWORD classID)
396 return GetPrecomputedStaticsClassData()[classID] & ClassInitFlags::INITIALIZED_FLAG;
399 inline BOOL IsClassAllocated(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
402 return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ALLOCATECLASS_FLAG) != 0;
405 BOOL IsClassInitError(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
408 return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ERROR_FLAG) != 0;
411 void SetClassInitialized(MethodTable* pMT);
412 void SetClassInitError(MethodTable* pMT);
414 void EnsureDynamicClassIndex(DWORD dwID);
416 void AllocateDynamicClass(MethodTable *pMT);
418 void PopulateClass(MethodTable *pMT);
420 #ifdef DACCESS_COMPILE
421 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
424 static DWORD OffsetOfDataBlob()
426 LIMITED_METHOD_CONTRACT;
427 return offsetof(DomainLocalModule, m_pDataBlob);
430 FORCEINLINE MethodTable * GetMethodTableFromClassDomainID(DWORD dwClassDomainID)
432 DWORD rid = (DWORD)(dwClassDomainID) + 1;
433 TypeHandle th = GetDomainFile()->GetModule()->LookupTypeDef(TokenFromRid(rid, mdtTypeDef));
434 _ASSERTE(!th.IsNull());
435 MethodTable * pMT = th.AsMethodTable();
436 PREFIX_ASSUME(pMT != NULL);
441 friend void EmitFastGetSharedStaticBase(CPUSTUBLINKER *psl, CodeLabel *init, bool bCCtorCheck);
443 void SetClassFlags(MethodTable* pMT, DWORD dwFlags);
444 DWORD GetClassFlags(MethodTable* pMT, DWORD iClassIndex);
446 PTR_DomainFile m_pDomainFile;
447 VolatilePtr<DynamicClassInfo, PTR_DynamicClassInfo> m_pDynamicClassTable; // used for generics and reflection.emit in memory
448 Volatile<SIZE_T> m_aDynamicEntries; // number of entries in dynamic table
449 VolatilePtr<UMEntryThunk> m_pADThunkTable;
450 PTR_OBJECTREF m_pGCStatics; // Handle to GC statics of the module
452 // In addition to storing the ModuleIndex in the Module class, we also
453 // keep a copy of the ModuleIndex in the DomainLocalModule class. This
454 // allows the thread static JIT helpers to quickly convert a pointer to
455 // a DomainLocalModule into a ModuleIndex.
456 ModuleIndex m_ModuleIndex;
458 // Note that the static offset calculation in code:Module::BuildStaticsOffsets takes the offset m_pDataBlob
459 // into consideration for alignment so we do not need any padding to ensure that the start of the data blob is aligned
461 BYTE m_pDataBlob[0]; // First byte of the statics blob
463 // Layout of m_pDataBlob is:
464 // ClassInit bytes (hold flags for cctor run, cctor error, etc)
469 // The Module class need to be able to initialized ModuleIndex,
470 // so for now I will make it a friend..
473 FORCEINLINE ModuleIndex GetModuleIndex()
475 LIMITED_METHOD_DAC_CONTRACT;
476 return m_ModuleIndex;
479 }; // struct DomainLocalModule
481 #define OFFSETOF__DomainLocalModule__m_pDataBlob_ (6 * TARGET_POINTER_SIZE)
482 #ifdef FEATURE_64BIT_ALIGNMENT
483 #define OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob (TARGET_POINTER_SIZE /* m_pGCStatics */ + TARGET_POINTER_SIZE /* m_padding */)
485 #define OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob TARGET_POINTER_SIZE /* m_pGCStatics */
488 typedef DPTR(class DomainLocalBlock) PTR_DomainLocalBlock;
489 class DomainLocalBlock
491 friend class ClrDataAccess;
492 friend class CheckAsmOffsets;
495 PTR_AppDomain m_pDomain;
496 DPTR(PTR_DomainLocalModule) m_pModuleSlots;
497 SIZE_T m_aModuleIndices; // Module entries the shared block has allocated
499 public: // used by code generators
500 static SIZE_T GetOffsetOfModuleSlotsPointer() { return offsetof(DomainLocalBlock, m_pModuleSlots);}
504 #ifndef DACCESS_COMPILE
506 : m_pDomain(NULL), m_pModuleSlots(NULL), m_aModuleIndices(0) {}
508 void EnsureModuleIndex(ModuleIndex index);
510 void Init(AppDomain *pDomain) { LIMITED_METHOD_CONTRACT; m_pDomain = pDomain; }
513 void SetModuleSlot(ModuleIndex index, PTR_DomainLocalModule pLocalModule);
515 FORCEINLINE PTR_DomainLocalModule GetModuleSlot(ModuleIndex index)
519 _ASSERTE(index.m_dwIndex < m_aModuleIndices);
520 return m_pModuleSlots[index.m_dwIndex];
523 inline PTR_DomainLocalModule GetModuleSlot(MethodTable* pMT)
526 return GetModuleSlot(pMT->GetModuleForStatics()->GetModuleIndex());
529 DomainFile* TryGetDomainFile(ModuleIndex index)
534 // the publishing of m_aModuleIndices and m_pModuleSlots is dependent
535 // on the order of accesses; we must ensure that we read from m_aModuleIndices
536 // before m_pModuleSlots.
537 if (index.m_dwIndex < m_aModuleIndices)
540 if (m_pModuleSlots[index.m_dwIndex])
542 return m_pModuleSlots[index.m_dwIndex]->GetDomainFile();
549 DomainFile* GetDomainFile(SIZE_T ModuleID)
552 ModuleIndex index = Module::IDToIndex(ModuleID);
553 _ASSERTE(index.m_dwIndex < m_aModuleIndices);
554 return m_pModuleSlots[index.m_dwIndex]->GetDomainFile();
557 #ifndef DACCESS_COMPILE
558 void SetDomainFile(ModuleIndex index, DomainFile* pDomainFile)
561 _ASSERTE(index.m_dwIndex < m_aModuleIndices);
562 m_pModuleSlots[index.m_dwIndex]->SetDomainFile(pDomainFile);
566 #ifdef DACCESS_COMPILE
567 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
574 // Low level routines to get & set class entries
584 // The large heap handle bucket class is used to contain handles allocated
585 // from an array contained in the large heap.
586 class LargeHeapHandleBucket
589 // Constructor and desctructor.
590 LargeHeapHandleBucket(LargeHeapHandleBucket *pNext, DWORD Size, BaseDomain *pDomain, BOOL bCrossAD = FALSE);
591 ~LargeHeapHandleBucket();
593 // This returns the next bucket.
594 LargeHeapHandleBucket *GetNext()
596 LIMITED_METHOD_CONTRACT;
601 // This returns the number of remaining handle slots.
602 DWORD GetNumRemainingHandles()
604 LIMITED_METHOD_CONTRACT;
606 return m_ArraySize - m_CurrentPos;
609 void ConsumeRemaining()
611 LIMITED_METHOD_CONTRACT;
613 m_CurrentPos = m_ArraySize;
616 OBJECTREF *TryAllocateEmbeddedFreeHandle();
618 // Allocate handles from the bucket.
619 OBJECTREF* AllocateHandles(DWORD nRequested);
620 OBJECTREF* CurrentPos()
622 LIMITED_METHOD_CONTRACT;
623 return m_pArrayDataPtr + m_CurrentPos;
627 LargeHeapHandleBucket *m_pNext;
630 int m_CurrentEmbeddedFreePos;
631 OBJECTHANDLE m_hndHandleArray;
632 OBJECTREF *m_pArrayDataPtr;
637 // The large heap handle table is used to allocate handles that are pointers
638 // to objects stored in an array in the large object heap.
639 class LargeHeapHandleTable
642 // Constructor and desctructor.
643 LargeHeapHandleTable(BaseDomain *pDomain, DWORD InitialBucketSize);
644 ~LargeHeapHandleTable();
646 // Allocate handles from the large heap handle table.
647 OBJECTREF* AllocateHandles(DWORD nRequested, BOOL bCrossAD = FALSE);
649 // Release object handles allocated using AllocateHandles().
650 void ReleaseHandles(OBJECTREF *pObjRef, DWORD nReleased);
653 // The buckets of object handles.
654 LargeHeapHandleBucket *m_pHead;
656 // We need to know the containing domain so we know where to allocate handles
657 BaseDomain *m_pDomain;
659 // The size of the LargeHeapHandleBuckets.
660 DWORD m_NextBucketSize;
662 // for finding and re-using embedded free items in the list
663 LargeHeapHandleBucket *m_pFreeSearchHint;
664 DWORD m_cEmbeddedFree;
668 // these functions are present to enforce that there is a locking mechanism in place
669 // for each LargeHeapHandleTable even though the code itself does not do the locking
670 // you must tell the table which lock you intend to use and it will verify that it has
671 // in fact been taken before performing any operations
674 void RegisterCrstDebug(CrstBase *pCrst)
676 LIMITED_METHOD_CONTRACT;
678 // this function must be called exactly once
679 _ASSERTE(pCrst != NULL);
680 _ASSERTE(m_pCrstDebug == NULL);
681 m_pCrstDebug = pCrst;
685 // we will assert that this Crst is held before using the object
686 CrstBase *m_pCrstDebug;
692 class LargeHeapHandleBlockHolder;
693 void LargeHeapHandleBlockHolder__StaticFree(LargeHeapHandleBlockHolder*);
696 class LargeHeapHandleBlockHolder:public Holder<LargeHeapHandleBlockHolder*,DoNothing,LargeHeapHandleBlockHolder__StaticFree>
699 LargeHeapHandleTable* m_pTable;
703 FORCEINLINE LargeHeapHandleBlockHolder(LargeHeapHandleTable* pOwner, DWORD nCount)
706 m_Data = pOwner->AllocateHandles(nCount);
711 FORCEINLINE void FreeData()
714 for (DWORD i=0;i< m_Count;i++)
715 ClearObjectReference(m_Data+i);
716 m_pTable->ReleaseHandles(m_Data, m_Count);
718 FORCEINLINE OBJECTREF* operator[] (DWORD idx)
720 LIMITED_METHOD_CONTRACT;
721 _ASSERTE(idx<m_Count);
722 return &(m_Data[idx]);
726 FORCEINLINE void LargeHeapHandleBlockHolder__StaticFree(LargeHeapHandleBlockHolder* pHolder)
736 // The large heap handle bucket class is used to contain handles allocated
737 // from an array contained in the large heap.
738 class ThreadStaticHandleBucket
741 // Constructor and desctructor.
742 ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain);
743 ~ThreadStaticHandleBucket();
745 // This returns the next bucket.
746 ThreadStaticHandleBucket *GetNext()
748 LIMITED_METHOD_CONTRACT;
753 // Allocate handles from the bucket.
754 OBJECTHANDLE GetHandles();
757 ThreadStaticHandleBucket *m_pNext;
759 OBJECTHANDLE m_hndHandleArray;
763 // The large heap handle table is used to allocate handles that are pointers
764 // to objects stored in an array in the large object heap.
765 class ThreadStaticHandleTable
768 // Constructor and desctructor.
769 ThreadStaticHandleTable(BaseDomain *pDomain);
770 ~ThreadStaticHandleTable();
772 // Allocate handles from the large heap handle table.
773 OBJECTHANDLE AllocateHandles(DWORD nRequested);
776 // The buckets of object handles.
777 ThreadStaticHandleBucket *m_pHead;
779 // We need to know the containing domain so we know where to allocate handles
780 BaseDomain *m_pDomain;
786 //--------------------------------------------------------------------------------------
787 // Base class for domains. It provides an abstract way of finding the first assembly and
788 // for creating assemblies in the the domain. The system domain only has one assembly, it
789 // contains the classes that are logically shared between domains. All other domains can
790 // have multiple assemblies. Iteration is done be getting the first assembly and then
791 // calling the Next() method on the assembly.
793 // The system domain should be as small as possible, it includes object, exceptions, etc.
794 // which are the basic classes required to load other assemblies. All other classes
795 // should be loaded into the domain. Of coarse there is a trade off between loading the
796 // same classes multiple times, requiring all domains to load certain assemblies (working
797 // set) and being able to specify specific versions.
800 #define LOW_FREQUENCY_HEAP_RESERVE_SIZE (3 * GetOsPageSize())
801 #define LOW_FREQUENCY_HEAP_COMMIT_SIZE (1 * GetOsPageSize())
803 #define HIGH_FREQUENCY_HEAP_RESERVE_SIZE (10 * GetOsPageSize())
804 #define HIGH_FREQUENCY_HEAP_COMMIT_SIZE (1 * GetOsPageSize())
806 #define STUB_HEAP_RESERVE_SIZE (3 * GetOsPageSize())
807 #define STUB_HEAP_COMMIT_SIZE (1 * GetOsPageSize())
809 // --------------------------------------------------------------------------------
810 // PE File List lock - for creating list locks on PE files
811 // --------------------------------------------------------------------------------
813 class PEFileListLock : public ListLock
816 #ifndef DACCESS_COMPILE
817 ListLockEntry *FindFileLock(PEFile *pFile)
819 STATIC_CONTRACT_NOTHROW;
820 STATIC_CONTRACT_GC_NOTRIGGER;
821 STATIC_CONTRACT_FORBID_FAULT;
823 PRECONDITION(HasLock());
825 ListLockEntry *pEntry;
827 for (pEntry = m_pHead;
829 pEntry = pEntry->m_pNext)
831 if (((PEFile *)pEntry->m_data)->Equals(pFile))
839 #endif // DACCESS_COMPILE
841 DEBUG_NOINLINE static void HolderEnter(PEFileListLock *pThis)
844 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
849 DLLEXPORT DEBUG_NOINLINE static void HolderLeave(PEFileListLock *pThis)
852 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
857 typedef Wrapper<PEFileListLock*, PEFileListLock::HolderEnter, PEFileListLock::HolderLeave> Holder;
860 typedef PEFileListLock::Holder PEFileListLockHolder;
862 // Loading infrastructure:
864 // a DomainFile is a file being loaded. Files are loaded in layers to enable loading in the
865 // presence of dependency loops.
867 // FileLoadLevel describes the various levels available. These are implemented slightly
868 // differently for assemblies and modules, but the basic structure is the same.
870 // LoadLock and FileLoadLock form the ListLock data structures for files. The FileLoadLock
871 // is specialized in that it allows taking a lock at a particular level. Basicall any
872 // thread may obtain the lock at a level at which the file has previously been loaded to, but
873 // only one thread may obtain the lock at its current level.
875 // The PendingLoadQueue is a per thread data structure which serves two purposes. First, it
876 // holds a "load limit" which automatically restricts the level of recursive loads to be
877 // one less than the current load which is preceding. This, together with the AppDomain
878 // LoadLock level behavior, will prevent any deadlocks from occuring due to circular
879 // dependencies. (Note that it is important that the loading logic understands this restriction,
880 // and any given level of loading must deal with the fact that any recursive loads will be partially
881 // unfulfilled in a specific way.)
883 // The second function is to queue up any unfulfilled load requests for the thread. These
884 // are then delivered immediately after the current load request is dealt with.
886 class FileLoadLock : public ListLockEntry
889 FileLoadLevel m_level;
890 DomainFile *m_pDomainFile;
895 static FileLoadLock *Create(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile);
898 DomainFile *GetDomainFile();
899 ADID GetAppDomainId();
900 FileLoadLevel GetLoadLevel();
902 // CanAcquire will return FALSE if Acquire will definitely not take the lock due
903 // to levels or deadlock.
904 // (Note that there is a race exiting from the function, where Acquire may end
905 // up not taking the lock anyway if another thread did work in the meantime.)
906 BOOL CanAcquire(FileLoadLevel targetLevel);
908 // Acquire will return FALSE and not take the lock if the file
909 // has already been loaded to the target level. Otherwise,
910 // it will return TRUE and take the lock.
912 // Note that the taker must release the lock via IncrementLoadLevel.
913 BOOL Acquire(FileLoadLevel targetLevel);
915 // CompleteLoadLevel can be called after Acquire returns true
916 // returns TRUE if it updated load level, FALSE if the level was set already
917 BOOL CompleteLoadLevel(FileLoadLevel level, BOOL success);
919 void SetError(Exception *ex);
922 UINT32 Release() DAC_EMPTY_RET(0);
926 FileLoadLock(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile);
928 static void HolderLeave(FileLoadLock *pThis);
931 typedef Wrapper<FileLoadLock *, DoNothing, FileLoadLock::HolderLeave> Holder;
935 typedef FileLoadLock::Holder FileLoadLockHolder;
937 #ifndef DACCESS_COMPILE
938 typedef ReleaseHolder<FileLoadLock> FileLoadLockRefHolder;
939 #endif // DACCESS_COMPILE
941 typedef ListLockBase<NativeCodeVersion> JitListLock;
942 typedef ListLockEntryBase<NativeCodeVersion> JitListLockEntry;
946 #pragma warning(push)
947 #pragma warning (disable: 4324) //sometimes 64bit compilers complain about alignment
949 class LoadLevelLimiter
951 FileLoadLevel m_currentLevel;
952 LoadLevelLimiter* m_previousLimit;
958 : m_currentLevel(FILE_ACTIVE),
959 m_previousLimit(NULL),
962 LIMITED_METHOD_CONTRACT;
968 m_previousLimit=GetThread()->GetLoadLevelLimiter();
970 m_currentLevel=m_previousLimit->GetLoadLevel();
971 GetThread()->SetLoadLevelLimiter(this);
980 GetThread()->SetLoadLevelLimiter(m_previousLimit);
989 // PendingLoadQueues are allocated on the stack during a load, and
990 // shared with all nested loads on the same thread.
992 // Make sure the thread pointer gets reset after the
993 // top level queue goes out of scope.
1000 FileLoadLevel GetLoadLevel()
1002 LIMITED_METHOD_CONTRACT;
1003 return m_currentLevel;
1006 void SetLoadLevel(FileLoadLevel level)
1008 LIMITED_METHOD_CONTRACT;
1009 m_currentLevel = level;
1013 #pragma warning (pop) //4324
1016 #define OVERRIDE_LOAD_LEVEL_LIMIT(newLimit) \
1017 LoadLevelLimiter __newLimit; \
1018 __newLimit.Activate(); \
1019 __newLimit.SetLoadLevel(newLimit);
1021 // A BaseDomain much basic information in a code:AppDomain including
1023 // * code:#AppdomainHeaps - Heaps for any data structures that will be freed on appdomain unload
1027 friend class Assembly;
1028 friend class AssemblySpec;
1029 friend class AppDomain;
1030 friend class AppDomainNative;
1032 VPTR_BASE_VTABLE_CLASS(BaseDomain)
1033 VPTR_UNIQUE(VPTR_UNIQUE_BaseDomain)
1036 // These 2 variables are only used on the AppDomain, but by placing them here
1037 // we reduce the cost of keeping the asmconstants file up to date.
1039 // The creation sequence number of this app domain (starting from 1)
1040 // This ID is generated by the code:SystemDomain::GetNewAppDomainId routine
1041 // The ID are recycled.
1043 // see also code:ADID
1046 DomainLocalBlock m_sDomainLocalBlock;
1050 class AssemblyIterator;
1051 friend class AssemblyIterator;
1053 // Static initialization.
1054 static void Attach();
1056 //****************************************************************************************
1058 // Initialization/shutdown routines for every instance of an BaseDomain.
1061 virtual ~BaseDomain() {}
1066 // ID to uniquely identify this AppDomain - used by the AppDomain publishing
1067 // service (to publish the list of all appdomains present in the process),
1068 // which in turn is used by, for eg., the debugger (to decide which App-
1069 // Domain(s) to attach to).
1070 // This is also used by Remoting for routing cross-appDomain calls.
1073 LIMITED_METHOD_DAC_CONTRACT;
1077 virtual BOOL IsAppDomain() { LIMITED_METHOD_DAC_CONTRACT; return FALSE; }
1079 BOOL IsSharedDomain() { LIMITED_METHOD_DAC_CONTRACT; return FALSE; }
1080 BOOL IsDefaultDomain() { LIMITED_METHOD_DAC_CONTRACT; return TRUE; }
1082 PTR_LoaderAllocator GetLoaderAllocator();
1083 virtual PTR_AppDomain AsAppDomain()
1085 LIMITED_METHOD_CONTRACT;
1086 _ASSERTE(!"Not an AppDomain");
1090 #ifdef FEATURE_COMINTEROP
1091 //****************************************************************************************
1093 // This will look up interop data for a method table
1096 #endif // FEATURE_COMINTEROP
1098 void SetDisableInterfaceCache()
1100 m_fDisableInterfaceCache = TRUE;
1102 BOOL GetDisableInterfaceCache()
1104 return m_fDisableInterfaceCache;
1107 #ifdef FEATURE_COMINTEROP
1108 MngStdInterfacesInfo * GetMngStdInterfacesInfo()
1110 LIMITED_METHOD_CONTRACT;
1112 return m_pMngStdInterfacesInfo;
1115 PTR_CLRPrivBinderWinRT GetWinRtBinder()
1117 return m_pWinRtBinder;
1119 #endif // FEATURE_COMINTEROP
1122 BOOL OwnDomainLocalBlockLock()
1124 WRAPPER_NO_CONTRACT;
1126 return m_DomainLocalBlockCrst.OwnedByCurrentThread();
1130 //****************************************************************************************
1131 // Get the class init lock. The method is limited to friends because inappropriate use
1132 // will cause deadlocks in the system
1133 ListLock* GetClassInitLock()
1135 LIMITED_METHOD_CONTRACT;
1137 return &m_ClassInitLock;
1140 JitListLock* GetJitLock()
1142 LIMITED_METHOD_CONTRACT;
1146 ListLock* GetILStubGenLock()
1148 LIMITED_METHOD_CONTRACT;
1149 return &m_ILStubGenLock;
1152 STRINGREF *IsStringInterned(STRINGREF *pString);
1153 STRINGREF *GetOrInternString(STRINGREF *pString);
1155 // Returns an array of OBJECTREF* that can be used to store domain specific data.
1156 // Statics and reflection info (Types, MemberInfo,..) are stored this way
1157 // If ppLazyAllocate != 0, allocation will only take place if *ppLazyAllocate != 0 (and the allocation
1158 // will be properly serialized)
1159 OBJECTREF *AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate = NULL, BOOL bCrossAD = FALSE);
1161 #ifdef FEATURE_PREJIT
1162 // Ensures that the file for logging profile data is open (we only open it once)
1163 // return false on failure
1164 static BOOL EnsureNGenLogFileOpen();
1167 //****************************************************************************************
1170 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1171 OBJECTHANDLE CreateTypedHandle(OBJECTREF object, HandleType type)
1173 WRAPPER_NO_CONTRACT;
1174 return ::CreateHandleCommon(m_handleStore, object, type);
1177 OBJECTHANDLE CreateHandle(OBJECTREF object)
1179 WRAPPER_NO_CONTRACT;
1180 CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL)
1181 return ::CreateHandle(m_handleStore, object);
1184 OBJECTHANDLE CreateWeakHandle(OBJECTREF object)
1186 WRAPPER_NO_CONTRACT;
1187 return ::CreateWeakHandle(m_handleStore, object);
1190 OBJECTHANDLE CreateShortWeakHandle(OBJECTREF object)
1192 WRAPPER_NO_CONTRACT;
1193 return ::CreateShortWeakHandle(m_handleStore, object);
1196 OBJECTHANDLE CreateLongWeakHandle(OBJECTREF object)
1198 WRAPPER_NO_CONTRACT;
1199 CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL)
1200 return ::CreateLongWeakHandle(m_handleStore, object);
1203 OBJECTHANDLE CreateStrongHandle(OBJECTREF object)
1205 WRAPPER_NO_CONTRACT;
1206 return ::CreateStrongHandle(m_handleStore, object);
1209 OBJECTHANDLE CreatePinningHandle(OBJECTREF object)
1211 WRAPPER_NO_CONTRACT;
1212 return ::CreatePinningHandle(m_handleStore, object);
1215 OBJECTHANDLE CreateSizedRefHandle(OBJECTREF object)
1217 WRAPPER_NO_CONTRACT;
1219 if (GCHeapUtilities::IsServerHeap())
1221 h = ::CreateSizedRefHandle(m_handleStore, object, m_dwSizedRefHandles % m_iNumberOfProcessors);
1225 h = ::CreateSizedRefHandle(m_handleStore, object);
1228 InterlockedIncrement((LONG*)&m_dwSizedRefHandles);
1232 #ifdef FEATURE_COMINTEROP
1233 OBJECTHANDLE CreateRefcountedHandle(OBJECTREF object)
1235 WRAPPER_NO_CONTRACT;
1236 return ::CreateRefcountedHandle(m_handleStore, object);
1239 OBJECTHANDLE CreateWinRTWeakHandle(OBJECTREF object, IWeakReference* pWinRTWeakReference)
1241 WRAPPER_NO_CONTRACT;
1242 return ::CreateWinRTWeakHandle(m_handleStore, object, pWinRTWeakReference);
1244 #endif // FEATURE_COMINTEROP
1246 OBJECTHANDLE CreateVariableHandle(OBJECTREF object, UINT type)
1248 WRAPPER_NO_CONTRACT;
1249 return ::CreateVariableHandle(m_handleStore, object, type);
1252 OBJECTHANDLE CreateDependentHandle(OBJECTREF primary, OBJECTREF secondary)
1254 WRAPPER_NO_CONTRACT;
1255 return ::CreateDependentHandle(m_handleStore, primary, secondary);
1258 #endif // DACCESS_COMPILE && !CROSSGEN_COMPILE
1260 IUnknown *GetFusionContext() {LIMITED_METHOD_CONTRACT; return m_pFusionContext; }
1262 CLRPrivBinderCoreCLR *GetTPABinderContext() {LIMITED_METHOD_CONTRACT; return m_pTPABinderContext; }
1265 CrstExplicitInit * GetLoaderAllocatorReferencesLock()
1267 LIMITED_METHOD_CONTRACT;
1268 return &m_crstLoaderAllocatorReferences;
1273 //****************************************************************************************
1274 // Helper method to initialize the large heap handle table.
1275 void InitLargeHeapHandleTable();
1277 //****************************************************************************************
1278 // Adds an assembly to the domain.
1279 void AddAssemblyNoLock(Assembly* assem);
1281 //****************************************************************************************
1283 // Hash table that maps a MethodTable to COM Interop compatibility data.
1284 PtrHashMap m_interopDataHash;
1286 // Critical sections & locks
1287 PEFileListLock m_FileLoadLock; // Protects the list of assemblies in the domain
1288 CrstExplicitInit m_DomainCrst; // General Protection for the Domain
1289 CrstExplicitInit m_DomainCacheCrst; // Protects the Assembly and Unmanaged caches
1290 CrstExplicitInit m_DomainLocalBlockCrst;
1291 CrstExplicitInit m_InteropDataCrst; // Used for COM Interop compatiblilty
1292 // Used to protect the reference lists in the collectible loader allocators attached to this appdomain
1293 CrstExplicitInit m_crstLoaderAllocatorReferences;
1294 CrstExplicitInit m_WinRTFactoryCacheCrst; // For WinRT factory cache
1297 // Used to protect the assembly list. Taken also by GC or debugger thread, therefore we have to avoid
1298 // triggering GC while holding this lock (by switching the thread to GC_NOTRIGGER while it is held).
1299 CrstExplicitInit m_crstAssemblyList;
1300 BOOL m_fDisableInterfaceCache; // RCW COM interface cache
1301 ListLock m_ClassInitLock;
1302 JitListLock m_JITLock;
1303 ListLock m_ILStubGenLock;
1305 // Fusion context, used for adding assemblies to the is domain. It defines
1306 // fusion properties for finding assemblyies such as SharedBinPath,
1307 // PrivateBinPath, Application Directory, etc.
1308 IUnknown *m_pFusionContext; // Current binding context for the domain
1310 CLRPrivBinderCoreCLR *m_pTPABinderContext; // Reference to the binding context that holds TPA list details
1312 IGCHandleStore* m_handleStore;
1314 // The large heap handle table.
1315 LargeHeapHandleTable *m_pLargeHeapHandleTable;
1317 // The large heap handle table critical section.
1318 CrstExplicitInit m_LargeHeapHandleTableCrst;
1320 #ifdef FEATURE_COMINTEROP
1321 // Information regarding the managed standard interfaces.
1322 MngStdInterfacesInfo *m_pMngStdInterfacesInfo;
1325 PTR_CLRPrivBinderWinRT m_pWinRtBinder;
1326 #endif // FEATURE_COMINTEROP
1328 // Protects allocation of slot IDs for thread statics
1329 static CrstStatic m_SpecialStaticsCrst;
1332 // Only call this routine when you can guarantee there are no
1333 // loads in progress.
1334 void ClearFusionContext();
1336 //****************************************************************************************
1337 // Synchronization holders.
1339 class LockHolder : public CrstHolder
1342 LockHolder(BaseDomain *pD)
1343 : CrstHolder(&pD->m_DomainCrst)
1345 WRAPPER_NO_CONTRACT;
1348 friend class LockHolder;
1350 class CacheLockHolder : public CrstHolder
1353 CacheLockHolder(BaseDomain *pD)
1354 : CrstHolder(&pD->m_DomainCacheCrst)
1356 WRAPPER_NO_CONTRACT;
1359 friend class CacheLockHolder;
1361 class DomainLocalBlockLockHolder : public CrstHolder
1364 DomainLocalBlockLockHolder(BaseDomain *pD)
1365 : CrstHolder(&pD->m_DomainLocalBlockCrst)
1367 WRAPPER_NO_CONTRACT;
1370 friend class DomainLocalBlockLockHolder;
1372 class LoadLockHolder : public PEFileListLockHolder
1375 LoadLockHolder(BaseDomain *pD, BOOL Take = TRUE)
1376 : PEFileListLockHolder(&pD->m_FileLoadLock, Take)
1388 friend class LoadLockHolder;
1389 class WinRTFactoryCacheLockHolder : public CrstHolder
1392 WinRTFactoryCacheLockHolder(BaseDomain *pD)
1393 : CrstHolder(&pD->m_WinRTFactoryCacheCrst)
1395 WRAPPER_NO_CONTRACT;
1398 friend class WinRTFactoryCacheLockHolder;
1402 RangeList *GetCollectibleVSDRanges() { return &m_collVSDRanges; }
1405 TypeIDMap m_typeIDMap;
1406 // Range list for collectible types. Maps VSD PCODEs back to the VirtualCallStubManager they belong to
1407 LockedRangeList m_collVSDRanges;
1410 UINT32 GetTypeID(PTR_MethodTable pMT);
1411 UINT32 LookupTypeID(PTR_MethodTable pMT);
1412 PTR_MethodTable LookupType(UINT32 id);
1413 #ifndef DACCESS_COMPILE
1414 void RemoveTypesFromTypeIDMap(LoaderAllocator* pLoaderAllocator);
1415 #endif // DACCESS_COMPILE
1418 // I have yet to figure out an efficent way to get the number of handles
1419 // of a particular type that's currently used by the process without
1420 // spending more time looking at the handle table code. We know that
1421 // our only customer (asp.net) in Dev10 is not going to create many of
1422 // these handles so I am taking a shortcut for now and keep the sizedref
1423 // handle count on the AD itself.
1424 DWORD m_dwSizedRefHandles;
1426 static int m_iNumberOfProcessors;
1429 // Called by DestroySizedRefHandle
1430 void DecNumSizedRefHandles()
1432 WRAPPER_NO_CONTRACT;
1434 result = InterlockedDecrement((LONG*)&m_dwSizedRefHandles);
1435 _ASSERTE(result >= 0);
1438 DWORD GetNumSizedRefHandles()
1440 return m_dwSizedRefHandles;
1443 #ifdef FEATURE_CODE_VERSIONING
1445 CodeVersionManager m_codeVersionManager;
1448 CodeVersionManager* GetCodeVersionManager() { return &m_codeVersionManager; }
1449 #endif //FEATURE_CODE_VERSIONING
1451 #ifdef DACCESS_COMPILE
1453 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
1457 }; // class BaseDomain
1461 ATTACH_ASSEMBLY_LOAD = 0x1,
1462 ATTACH_MODULE_LOAD = 0x2,
1463 ATTACH_CLASS_LOAD = 0x4,
1468 // This filters the output of IterateAssemblies. This ought to be declared more locally
1469 // but it would result in really verbose callsites.
1471 // Assemblies can be categorized by their load status (loaded, loading, or loaded just
1472 // enough that they would be made available to profilers)
1473 // Independently, they can also be categorized as execution or introspection.
1475 // An assembly will be included in the results of IterateAssemblies only if
1476 // the appropriate bit is set for *both* characterizations.
1478 // The flags can be combined so if you want all loaded assemblies, you must specify:
1480 /// kIncludeLoaded|kIncludeExecution
1482 enum AssemblyIterationFlags
1484 // load status flags
1485 kIncludeLoaded = 0x00000001, // include assemblies that are already loaded
1486 // (m_level >= code:FILE_LOAD_DELIVER_EVENTS)
1487 kIncludeLoading = 0x00000002, // include assemblies that are still in the process of loading
1488 // (all m_level values)
1489 kIncludeAvailableToProfilers
1490 = 0x00000020, // include assemblies available to profilers
1491 // See comment at code:DomainFile::IsAvailableToProfilers
1493 // Execution / introspection flags
1494 kIncludeExecution = 0x00000004, // include assemblies that are loaded for execution only
1496 kIncludeFailedToLoad = 0x00000010, // include assemblies that failed to load
1498 // Collectible assemblies flags
1499 kExcludeCollectible = 0x00000040, // Exclude all collectible assemblies
1500 kIncludeCollected = 0x00000080,
1501 // Include assemblies which were collected and cannot be referenced anymore. Such assemblies are not
1502 // AddRef-ed. Any manipulation with them should be protected by code:GetAssemblyListLock.
1503 // Should be used only by code:LoaderAllocator::GCLoaderAllocators.
1505 }; // enum AssemblyIterationFlags
1507 //---------------------------------------------------------------------------------------
1509 // Base class for holder code:CollectibleAssemblyHolder (see code:HolderBase).
1510 // Manages AddRef/Release for collectible assemblies. It is no-op for 'normal' non-collectible assemblies.
1512 // Each type of type parameter needs 2 methods implemented:
1513 // code:CollectibleAssemblyHolderBase::GetLoaderAllocator
1514 // code:CollectibleAssemblyHolderBase::IsCollectible
1516 template<typename _Type>
1517 class CollectibleAssemblyHolderBase
1522 CollectibleAssemblyHolderBase(const _Type & value = NULL)
1524 LIMITED_METHOD_CONTRACT;
1537 // We don't need to keep the assembly alive in DAC - see code:#CAH_DAC
1538 #ifndef DACCESS_COMPILE
1539 if (this->IsCollectible(m_value))
1541 LoaderAllocator * pLoaderAllocator = GetLoaderAllocator(m_value);
1542 pLoaderAllocator->AddReference();
1544 #endif //!DACCESS_COMPILE
1556 #ifndef DACCESS_COMPILE
1557 if (this->IsCollectible(m_value))
1559 LoaderAllocator * pLoaderAllocator = GetLoaderAllocator(m_value);
1560 pLoaderAllocator->Release();
1562 #endif //!DACCESS_COMPILE
1566 LoaderAllocator * GetLoaderAllocator(DomainAssembly * pDomainAssembly)
1568 WRAPPER_NO_CONTRACT;
1569 return pDomainAssembly->GetLoaderAllocator();
1571 BOOL IsCollectible(DomainAssembly * pDomainAssembly)
1573 WRAPPER_NO_CONTRACT;
1574 return pDomainAssembly->IsCollectible();
1576 LoaderAllocator * GetLoaderAllocator(Assembly * pAssembly)
1578 WRAPPER_NO_CONTRACT;
1579 return pAssembly->GetLoaderAllocator();
1581 BOOL IsCollectible(Assembly * pAssembly)
1583 WRAPPER_NO_CONTRACT;
1584 return pAssembly->IsCollectible();
1586 }; // class CollectibleAssemblyHolderBase<>
1588 //---------------------------------------------------------------------------------------
1590 // Holder of assembly reference which keeps collectible assembly alive while the holder is valid.
1592 // Collectible assembly can be collected at any point when GC happens. Almost instantly all native data
1593 // structures of the assembly (e.g. code:DomainAssembly, code:Assembly) could be deallocated.
1594 // Therefore any usage of (collectible) assembly data structures from native world, has to prevent the
1595 // deallocation by increasing ref-count on the assembly / associated loader allocator.
1598 // In DAC we don't AddRef/Release as the assembly doesn't have to be kept alive: The process is stopped when
1599 // DAC is used and therefore the assembly cannot just disappear.
1601 template<typename _Type>
1602 class CollectibleAssemblyHolder : public BaseWrapper<_Type, CollectibleAssemblyHolderBase<_Type> >
1606 CollectibleAssemblyHolder(const _Type & value = NULL, BOOL fTake = TRUE)
1607 : BaseWrapper<_Type, CollectibleAssemblyHolderBase<_Type> >(value, fTake)
1609 STATIC_CONTRACT_WRAPPER;
1613 CollectibleAssemblyHolder &
1614 operator=(const _Type & value)
1616 STATIC_CONTRACT_WRAPPER;
1617 BaseWrapper<_Type, CollectibleAssemblyHolderBase<_Type> >::operator=(value);
1621 // Operator & is overloaded in parent, therefore we have to get to 'this' pointer explicitly.
1623 CollectibleAssemblyHolder<_Type> *
1626 LIMITED_METHOD_CONTRACT;
1629 }; // class CollectibleAssemblyHolder<>
1631 //---------------------------------------------------------------------------------------
1633 // Stores binding information about failed assembly loads for DAC
1635 struct FailedAssembly {
1636 SString displayName;
1640 void Initialize(AssemblySpec *pSpec, Exception *ex)
1650 displayName.SetASCII(pSpec->GetName());
1651 location.Set(pSpec->GetCodeBase());
1652 error = ex->GetHR();
1655 // Determine the binding context assembly would have been in.
1656 // If the parent has been set, use its binding context.
1657 // If the parent hasn't been set but the code base has, use LoadFrom.
1658 // Otherwise, use the default.
1663 #ifdef FEATURE_COMINTEROP
1665 // Cache used by COM Interop
1666 struct NameToTypeMapEntry
1668 // Host space representation of the key
1671 LPCWSTR m_wzName; // The type name or registry string representation of the GUID "{<guid>}"
1672 SIZE_T m_cchName; // wcslen(m_wzName) for faster hashtable lookup
1676 PTR_CWSTR m_wzName; // The type name or registry string representation of the GUID "{<guid>}"
1677 SIZE_T m_cchName; // wcslen(m_wzName) for faster hashtable lookup
1679 TypeHandle m_typeHandle; // Using TypeHandle instead of MethodTable* to avoid losing information when sharing method tables.
1680 UINT m_nEpoch; // tracks creation Epoch. This is incremented each time an external reader enumerate the cache
1684 typedef DPTR(NameToTypeMapEntry) PTR_NameToTypeMapEntry;
1686 class NameToTypeMapTraits : public NoRemoveSHashTraits< DefaultSHashTraits<NameToTypeMapEntry> >
1689 typedef NameToTypeMapEntry::Key key_t;
1691 static const NameToTypeMapEntry Null() { NameToTypeMapEntry e; e.m_key.m_wzName = NULL; e.m_key.m_cchName = 0; return e; }
1692 static bool IsNull(const NameToTypeMapEntry &e) { return e.m_key.m_wzName == NULL; }
1693 static const key_t GetKey(const NameToTypeMapEntry &e)
1696 key.m_wzName = (LPCWSTR)(e.m_key.m_wzName); // this cast brings the string over to the host, in a DAC build
1697 key.m_cchName = e.m_key.m_cchName;
1701 static count_t Hash(const key_t &key) { WRAPPER_NO_CONTRACT; return HashStringN(key.m_wzName, key.m_cchName); }
1703 static BOOL Equals(const key_t &lhs, const key_t &rhs)
1705 WRAPPER_NO_CONTRACT;
1706 return (lhs.m_cchName == rhs.m_cchName) && memcmp(lhs.m_wzName, rhs.m_wzName, lhs.m_cchName * sizeof(WCHAR)) == 0;
1709 void OnDestructPerEntryCleanupAction(const NameToTypeMapEntry& e)
1711 WRAPPER_NO_CONTRACT;
1712 _ASSERTE(e.m_key.m_cchName == wcslen(e.m_key.m_wzName));
1713 #ifndef DACCESS_COMPILE
1714 delete [] e.m_key.m_wzName;
1715 #endif // DACCESS_COMPILE
1717 static const bool s_DestructPerEntryCleanupAction = true;
1720 typedef SHash<NameToTypeMapTraits> NameToTypeMapTable;
1722 typedef DPTR(NameToTypeMapTable) PTR_NameToTypeMapTable;
1724 struct WinRTFactoryCacheEntry
1726 typedef MethodTable *Key;
1727 Key key; // Type as KEY
1729 CtxEntry *m_pCtxEntry; // Context entry - used to verify whether the cache is a match
1730 OBJECTHANDLE m_ohFactoryObject; // Handle to factory object
1733 class WinRTFactoryCacheTraits : public DefaultSHashTraits<WinRTFactoryCacheEntry>
1736 typedef WinRTFactoryCacheEntry::Key key_t;
1737 static const WinRTFactoryCacheEntry Null() { WinRTFactoryCacheEntry e; e.key = NULL; return e; }
1738 static bool IsNull(const WinRTFactoryCacheEntry &e) { return e.key == NULL; }
1739 static const WinRTFactoryCacheEntry::Key GetKey(const WinRTFactoryCacheEntry& e) { return e.key; }
1740 static count_t Hash(WinRTFactoryCacheEntry::Key key) { return (count_t)((size_t)key); }
1741 static BOOL Equals(WinRTFactoryCacheEntry::Key lhs, WinRTFactoryCacheEntry::Key rhs)
1742 { return lhs == rhs; }
1743 static const WinRTFactoryCacheEntry Deleted() { WinRTFactoryCacheEntry e; e.key = (MethodTable *)-1; return e; }
1744 static bool IsDeleted(const WinRTFactoryCacheEntry &e) { return e.key == (MethodTable *)-1; }
1746 static void OnDestructPerEntryCleanupAction(const WinRTFactoryCacheEntry& e);
1747 static const bool s_DestructPerEntryCleanupAction = true;
1750 typedef SHash<WinRTFactoryCacheTraits> WinRTFactoryCache;
1752 #endif // FEATURE_COMINTEROP
1754 class AppDomainIterator;
1756 const DWORD DefaultADID = 1;
1758 // An Appdomain is the managed equivalent of a process. It is an isolation unit (conceptually you don't
1759 // have pointers directly from one appdomain to another, but rather go through remoting proxies). It is
1760 // also a unit of unloading.
1762 // Threads are always running in the context of a particular AppDomain. See
1763 // file:threads.h#RuntimeThreadLocals for more details.
1765 // see code:BaseDomain for much of the meat of a AppDomain (heaps locks, etc)
1766 // * code:AppDomain.m_Assemblies - is a list of code:Assembly in the appdomain
1768 class AppDomain : public BaseDomain
1770 friend class SystemDomain;
1771 friend class AssemblySink;
1772 friend class AppDomainNative;
1773 friend class AssemblyNative;
1774 friend class AssemblySpec;
1775 friend class ClassLoader;
1776 friend class ThreadNative;
1777 friend class RCWCache;
1778 friend class ClrDataAccess;
1779 friend class CheckAsmOffsets;
1781 VPTR_VTABLE_CLASS(AppDomain, BaseDomain)
1784 #ifndef DACCESS_COMPILE
1786 virtual ~AppDomain();
1787 static void Create();
1790 DomainAssembly* FindDomainAssembly(Assembly*);
1792 //-----------------------------------------------------------------------------------------------------------------
1793 // Convenience wrapper for ::GetAppDomain to provide better encapsulation.
1794 static PTR_AppDomain GetCurrentDomain()
1795 { return m_pTheAppDomain; }
1797 //-----------------------------------------------------------------------------------------------------------------
1798 // Initializes an AppDomain. (this functions is not called from the SystemDomain)
1801 #if defined(FEATURE_COMINTEROP)
1802 HRESULT SetWinrtApplicationContext(LPCWSTR pwzAppLocalWinMD);
1803 #endif // FEATURE_COMINTEROP
1805 bool MustForceTrivialWaitOperations();
1806 void SetForceTrivialWaitOperations();
1808 //****************************************************************************************
1810 // Stop deletes all the assemblies but does not remove other resources like
1811 // the critical sections
1814 // Gets rid of resources
1817 #ifdef FEATURE_PREJIT
1818 //assembly cleanup that requires suspended runtime
1819 void DeleteNativeCodeRanges();
1822 // final assembly cleanup
1823 void ShutdownAssemblies();
1824 void ShutdownFreeLoaderAllocators(BOOL bFromManagedCode);
1826 void ReleaseDomainBoundInfo();
1827 void ReleaseFiles();
1830 // Remove the Appdomain for the system and cleans up. This call should not be
1831 // called from shut down code.
1834 virtual BOOL IsAppDomain() { LIMITED_METHOD_DAC_CONTRACT; return TRUE; }
1835 virtual PTR_AppDomain AsAppDomain() { LIMITED_METHOD_CONTRACT; return dac_cast<PTR_AppDomain>(this); }
1837 OBJECTREF GetRawExposedObject() { LIMITED_METHOD_CONTRACT; return NULL; }
1838 OBJECTHANDLE GetRawExposedObjectHandleForDebugger() { LIMITED_METHOD_DAC_CONTRACT; return NULL; }
1840 #ifdef FEATURE_COMINTEROP
1841 MethodTable *GetRedirectedType(WinMDAdapter::RedirectedTypeIndex index);
1842 #endif // FEATURE_COMINTEROP
1845 //****************************************************************************************
1848 // Multi-thread safe access to the list of assemblies
1849 class DomainAssemblyList
1854 AppDomain * dbg_m_pAppDomain;
1856 void Debug_SetAppDomain(AppDomain * pAppDomain)
1858 dbg_m_pAppDomain = pAppDomain;
1870 // This function can be reliably called without taking the lock, because the first assembly
1871 // added to the arraylist is non-collectible, and the ArrayList itself allows lockless read access
1872 return (m_array.GetCount() == 0);
1874 void Clear(AppDomain * pAppDomain)
1878 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
1882 _ASSERTE(dbg_m_pAppDomain == pAppDomain);
1884 CrstHolder ch(pAppDomain->GetAssemblyListLock());
1888 DWORD GetCount(AppDomain * pAppDomain)
1892 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
1896 _ASSERTE(dbg_m_pAppDomain == pAppDomain);
1898 CrstHolder ch(pAppDomain->GetAssemblyListLock());
1899 return GetCount_Unlocked();
1901 DWORD GetCount_Unlocked()
1909 #ifndef DACCESS_COMPILE
1910 _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
1912 // code:Append_Unlock guarantees that we do not have more than MAXDWORD items
1913 return m_array.GetCount();
1916 void Get(AppDomain * pAppDomain, DWORD index, CollectibleAssemblyHolder<DomainAssembly *> * pAssemblyHolder)
1920 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
1924 _ASSERTE(dbg_m_pAppDomain == pAppDomain);
1926 CrstHolder ch(pAppDomain->GetAssemblyListLock());
1927 Get_Unlocked(index, pAssemblyHolder);
1929 void Get_Unlocked(DWORD index, CollectibleAssemblyHolder<DomainAssembly *> * pAssemblyHolder)
1937 _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
1938 *pAssemblyHolder = dac_cast<PTR_DomainAssembly>(m_array.Get(index));
1940 // Doesn't lock the assembly list (caller has to hold the lock already).
1941 // Doesn't AddRef the returned assembly (if collectible).
1942 DomainAssembly * Get_UnlockedNoReference(DWORD index)
1951 #ifndef DACCESS_COMPILE
1952 _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
1954 return dac_cast<PTR_DomainAssembly>(m_array.Get(index));
1957 #ifndef DACCESS_COMPILE
1958 void Set(AppDomain * pAppDomain, DWORD index, DomainAssembly * pAssembly)
1962 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
1966 _ASSERTE(dbg_m_pAppDomain == pAppDomain);
1968 CrstHolder ch(pAppDomain->GetAssemblyListLock());
1969 return Set_Unlocked(index, pAssembly);
1971 void Set_Unlocked(DWORD index, DomainAssembly * pAssembly)
1979 _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
1980 m_array.Set(index, pAssembly);
1983 HRESULT Append_Unlocked(DomainAssembly * pAssembly)
1991 _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
1992 return m_array.Append(pAssembly);
1994 #else //DACCESS_COMPILE
1996 EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2000 m_array.EnumMemoryRegions(flags);
2002 #endif // DACCESS_COMPILE
2004 // Should be used only by code:AssemblyIterator::Create
2005 ArrayList::Iterator GetArrayListIterator()
2007 return m_array.Iterate();
2009 }; // class DomainAssemblyList
2011 // Conceptually a list of code:Assembly structures, protected by lock code:GetAssemblyListLock
2012 DomainAssemblyList m_Assemblies;
2015 // Note that this lock switches thread into GC_NOTRIGGER region as GC can take it too.
2016 CrstExplicitInit * GetAssemblyListLock()
2018 LIMITED_METHOD_CONTRACT;
2019 return &m_crstAssemblyList;
2023 class AssemblyIterator
2025 // AppDomain context with the assembly list
2026 AppDomain * m_pAppDomain;
2027 ArrayList::Iterator m_Iterator;
2028 AssemblyIterationFlags m_assemblyIterationFlags;
2031 BOOL Next(CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder);
2032 // Note: Does not lock the assembly list, but AddRefs collectible assemblies.
2033 BOOL Next_Unlocked(CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder);
2034 #ifndef DACCESS_COMPILE
2036 // Can be called only from AppDomain shutdown code:AppDomain::ShutdownAssemblies.
2037 // Note: Does not lock the assembly list and does not AddRefs collectible assemblies.
2038 BOOL Next_UnsafeNoAddRef(DomainAssembly ** ppDomainAssembly);
2042 inline DWORD GetIndex()
2044 LIMITED_METHOD_CONTRACT;
2045 return m_Iterator.GetIndex();
2049 friend class AppDomain;
2050 // Cannot have constructor so this iterator can be used inside a union
2051 static AssemblyIterator Create(AppDomain * pAppDomain, AssemblyIterationFlags assemblyIterationFlags)
2053 LIMITED_METHOD_CONTRACT;
2056 i.m_pAppDomain = pAppDomain;
2057 i.m_Iterator = pAppDomain->m_Assemblies.GetArrayListIterator();
2058 i.m_assemblyIterationFlags = assemblyIterationFlags;
2061 }; // class AssemblyIterator
2063 AssemblyIterator IterateAssembliesEx(AssemblyIterationFlags assemblyIterationFlags)
2065 LIMITED_METHOD_CONTRACT;
2066 return AssemblyIterator::Create(this, assemblyIterationFlags);
2070 struct NativeImageDependenciesEntry
2072 BaseAssemblySpec m_AssemblySpec;
2076 class NativeImageDependenciesTraits : public DeleteElementsOnDestructSHashTraits<DefaultSHashTraits<NativeImageDependenciesEntry *> >
2079 typedef BaseAssemblySpec *key_t;
2080 static key_t GetKey(NativeImageDependenciesEntry * e) { return &(e->m_AssemblySpec); }
2082 static count_t Hash(key_t k)
2087 static BOOL Equals(key_t lhs, key_t rhs)
2089 return lhs->CompareEx(rhs);
2093 SHash<NativeImageDependenciesTraits> m_NativeImageDependencies;
2096 void CheckForMismatchedNativeImages(AssemblySpec * pSpec, const GUID * pGuid);
2097 BOOL RemoveNativeImageDependency(AssemblySpec* pSpec);
2102 friend class AppDomain;
2104 ArrayList::Iterator m_i;
2109 WRAPPER_NO_CONTRACT;
2115 WRAPPER_NO_CONTRACT;
2116 return dac_cast<PTR_SString>(m_i.GetElement());
2120 PathIterator IterateNativeDllSearchDirectories();
2121 void SetNativeDllSearchDirectories(LPCWSTR paths);
2122 BOOL HasNativeDllSearchDirectories();
2123 void ShutdownNativeDllSearchDirectories();
2126 SIZE_T GetAssemblyCount()
2128 WRAPPER_NO_CONTRACT;
2129 return m_Assemblies.GetCount(this);
2132 CHECK CheckCanLoadTypes(Assembly *pAssembly);
2133 CHECK CheckCanExecuteManagedCode(MethodDesc* pMD);
2134 CHECK CheckLoading(DomainFile *pFile, FileLoadLevel level);
2136 FileLoadLevel GetDomainFileLoadLevel(DomainFile *pFile);
2137 BOOL IsLoading(DomainFile *pFile, FileLoadLevel level);
2138 static FileLoadLevel GetThreadFileLoadLevel();
2140 void LoadDomainFile(DomainFile *pFile,
2141 FileLoadLevel targetLevel);
2143 enum FindAssemblyOptions
2145 FindAssemblyOptions_None = 0x0,
2146 FindAssemblyOptions_IncludeFailedToLoad = 0x1
2149 DomainAssembly * FindAssembly(PEAssembly * pFile, FindAssemblyOptions options = FindAssemblyOptions_None) DAC_EMPTY_RET(NULL);
2152 Assembly *LoadAssembly(AssemblySpec* pIdentity,
2154 FileLoadLevel targetLevel);
2156 // this function does not provide caching, you must use LoadDomainAssembly
2157 // unless the call is guaranteed to succeed or you don't need the caching
2158 // (e.g. if you will FailFast or tear down the AppDomain anyway)
2159 // The main point that you should not bypass caching if you might try to load the same file again,
2160 // resulting in multiple DomainAssembly objects that share the same PEAssembly for ngen image
2161 //which is violating our internal assumptions
2162 DomainAssembly *LoadDomainAssemblyInternal( AssemblySpec* pIdentity,
2164 FileLoadLevel targetLevel);
2166 DomainAssembly *LoadDomainAssembly( AssemblySpec* pIdentity,
2168 FileLoadLevel targetLevel);
2171 CHECK CheckValidModule(Module *pModule);
2174 void LoadSystemAssemblies();
2176 DomainFile *LoadDomainFile(FileLoadLock *pLock,
2177 FileLoadLevel targetLevel);
2179 void TryIncrementalLoad(DomainFile *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder);
2181 Assembly *LoadAssemblyHelper(LPCWSTR wszAssembly,
2182 LPCWSTR wszCodeBase);
2184 #ifndef DACCESS_COMPILE // needs AssemblySpec
2186 void GetCacheAssemblyList(SetSHash<PTR_DomainAssembly>& assemblyList);
2188 //****************************************************************************************
2189 // Returns and Inserts assemblies into a lookup cache based on the binding information
2190 // in the AssemblySpec. There can be many AssemblySpecs to a single assembly.
2191 DomainAssembly* FindCachedAssembly(AssemblySpec* pSpec, BOOL fThrow=TRUE)
2193 WRAPPER_NO_CONTRACT;
2194 return m_AssemblyCache.LookupAssembly(pSpec, fThrow);
2197 PEAssembly* FindCachedFile(AssemblySpec* pSpec, BOOL fThrow = TRUE);
2198 BOOL IsCached(AssemblySpec *pSpec);
2199 #endif // DACCESS_COMPILE
2200 void CacheStringsForDAC();
2202 BOOL AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAllowFailure = FALSE);
2203 BOOL RemoveFileFromCache(PEAssembly *pFile);
2205 BOOL AddAssemblyToCache(AssemblySpec* pSpec, DomainAssembly *pAssembly);
2206 BOOL RemoveAssemblyFromCache(DomainAssembly* pAssembly);
2208 BOOL AddExceptionToCache(AssemblySpec* pSpec, Exception *ex);
2209 void AddUnmanagedImageToCache(LPCWSTR libraryName, HMODULE hMod);
2210 HMODULE FindUnmanagedImageInCache(LPCWSTR libraryName);
2211 //****************************************************************************************
2213 // Adds or removes an assembly to the domain.
2214 void AddAssembly(DomainAssembly * assem);
2215 void RemoveAssembly(DomainAssembly * pAsm);
2217 BOOL ContainsAssembly(Assembly * assem);
2219 //****************************************************************************************
2221 // Reference count. When an appdomain is first created the reference is bump
2222 // to one when it is added to the list of domains (see SystemDomain). An explicit
2223 // Removal from the list is necessary before it will be deleted.
2225 ULONG Release(void) DAC_EMPTY_RET(0);
2227 //****************************************************************************************
2228 LPCWSTR GetFriendlyName(BOOL fDebuggerCares = TRUE);
2229 LPCWSTR GetFriendlyNameForDebugger();
2230 LPCWSTR GetFriendlyNameForLogging();
2231 #ifdef DACCESS_COMPILE
2232 PVOID GetFriendlyNameNoSet(bool* isUtf8);
2234 void SetFriendlyName(LPCWSTR pwzFriendlyName, BOOL fDebuggerCares = TRUE);
2236 //****************************************************************************************
2238 // This can be used to override the binding behavior of the appdomain. It
2239 // is overridden in the compilation domain. It is important that all
2240 // static binding goes through this path.
2241 virtual PEAssembly * BindAssemblySpec(
2242 AssemblySpec *pSpec,
2243 BOOL fThrowOnFileNotFound,
2244 BOOL fUseHostBinderIfAvailable = TRUE) DAC_EMPTY_RET(NULL);
2246 HRESULT BindAssemblySpecForHostedBinder(
2247 AssemblySpec * pSpec,
2248 IAssemblyName * pAssemblyName,
2249 ICLRPrivBinder * pBinder,
2250 PEAssembly ** ppAssembly) DAC_EMPTY_RET(E_FAIL);
2252 HRESULT BindHostedPrivAssembly(
2253 PEAssembly * pParentPEAssembly,
2254 ICLRPrivAssembly * pPrivAssembly,
2255 IAssemblyName * pAssemblyName,
2256 PEAssembly ** ppAssembly) DAC_EMPTY_RET(S_OK);
2259 PEAssembly *TryResolveAssembly(AssemblySpec *pSpec);
2261 // Store a successful binding into the cache. This will keep the file from
2262 // being physically unmapped, as well as shortcutting future attempts to bind
2263 // the same spec throught the Cached entry point.
2265 // Right now we only cache assembly binds for "probing" type
2266 // binding situations, basically when loading domain neutral assemblies or
2269 // <TODO>@todo: We may want to be more aggressive about this if
2270 // there are other situations where we are repeatedly binding the
2271 // same assembly specs, though.</TODO>
2273 // Returns TRUE if stored
2274 // FALSE if it's a duplicate (caller should clean up args)
2275 BOOL StoreBindAssemblySpecResult(AssemblySpec *pSpec,
2279 BOOL StoreBindAssemblySpecError(AssemblySpec *pSpec,
2281 OBJECTREF *pThrowable,
2284 //****************************************************************************************
2286 //****************************************************************************************
2288 // Uses the first assembly to add an application base to the Context. This is done
2289 // in a lazy fashion so executables do not take the perf hit unless the load other
2291 #ifndef DACCESS_COMPILE
2292 void OnAssemblyLoad(Assembly *assem);
2293 void OnAssemblyLoadUnlocked(Assembly *assem);
2294 static BOOL OnUnhandledException(OBJECTREF *pThrowable, BOOL isTerminating = TRUE);
2298 // True iff a debugger is attached to the process (same as CORDebuggerAttached)
2299 BOOL IsDebuggerAttached (void);
2301 #ifdef DEBUGGING_SUPPORTED
2302 // Notify debugger of all assemblies, modules, and possibly classes in this AppDomain
2303 BOOL NotifyDebuggerLoad(int flags, BOOL attaching);
2305 // Send unload notifications to the debugger for all assemblies, modules and classes in this AppDomain
2306 void NotifyDebuggerUnload();
2307 #endif // DEBUGGING_SUPPORTED
2309 void SetSystemAssemblyLoadEventSent (BOOL fFlag);
2310 BOOL WasSystemAssemblyLoadEventSent (void);
2312 #ifndef DACCESS_COMPILE
2313 OBJECTREF* AllocateStaticFieldObjRefPtrs(int nRequested, OBJECTREF** ppLazyAllocate = NULL)
2315 WRAPPER_NO_CONTRACT;
2317 return AllocateObjRefPtrsInLargeTable(nRequested, ppLazyAllocate);
2320 OBJECTREF* AllocateStaticFieldObjRefPtrsCrossDomain(int nRequested, OBJECTREF** ppLazyAllocate = NULL)
2322 WRAPPER_NO_CONTRACT;
2324 return AllocateObjRefPtrsInLargeTable(nRequested, ppLazyAllocate, TRUE);
2326 #endif // DACCESS_COMPILE
2328 void EnumStaticGCRefs(promote_func* fn, ScanContext* sc);
2330 DomainLocalBlock *GetDomainLocalBlock()
2332 LIMITED_METHOD_DAC_CONTRACT;
2334 return &m_sDomainLocalBlock;
2337 static SIZE_T GetOffsetOfModuleSlotsPointer()
2339 WRAPPER_NO_CONTRACT;
2341 return offsetof(AppDomain,m_sDomainLocalBlock) + DomainLocalBlock::GetOffsetOfModuleSlotsPointer();
2344 void SetupSharedStatics();
2346 //****************************************************************************************
2348 // Create a quick lookup for classes loaded into this domain based on their GUID.
2350 void InsertClassForCLSID(MethodTable* pMT, BOOL fForceInsert = FALSE);
2351 void InsertClassForCLSID(MethodTable* pMT, GUID *pGuid);
2353 #ifdef FEATURE_COMINTEROP
2355 void CacheTypeByNameWorker(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE flags, BOOL bReplaceExisting = FALSE);
2356 TypeHandle LookupTypeByNameWorker(const SString &ssClassName, UINT *pvCacheVersion, BYTE *pbFlags);
2358 // Used by COM Interop for mapping WinRT runtime class names to real types.
2359 void CacheTypeByName(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE flags, BOOL bReplaceExisting = FALSE);
2360 TypeHandle LookupTypeByName(const SString &ssClassName, UINT *pvCacheVersion, BYTE *pbFlags);
2361 PTR_MethodTable LookupTypeByGuid(const GUID & guid);
2363 #ifndef DACCESS_COMPILE
2364 inline BOOL CanCacheWinRTTypeByGuid(TypeHandle typeHandle)
2374 // Only allow caching guid/types maps for types loaded during
2375 // "normal" domain operation
2376 if (IsCompilationDomain() || (m_Stage < STAGE_OPEN))
2379 MethodTable *pMT = typeHandle.GetMethodTable();
2382 // Don't cache mscorlib-internal declarations of WinRT types.
2383 if (pMT->GetModule()->IsSystem() && pMT->IsProjectedFromWinRT())
2386 // Don't cache redirected WinRT types.
2387 if (WinRTTypeNameConverter::IsRedirectedWinRTSourceType(pMT))
2393 #endif // !DACCESS_COMPILE
2395 void CacheWinRTTypeByGuid(TypeHandle typeHandle);
2396 void GetCachedWinRTTypes(SArray<PTR_MethodTable> * pTypes, SArray<GUID> * pGuids, UINT minEpoch, UINT * pCurEpoch);
2398 // Used by COM Interop for caching WinRT factory objects.
2399 void CacheWinRTFactoryObject(MethodTable *pClassMT, OBJECTREF *refFactory, LPVOID lpCtxCookie);
2400 OBJECTREF LookupWinRTFactoryObject(MethodTable *pClassMT, LPVOID lpCtxCookie);
2401 void RemoveWinRTFactoryObjects(LPVOID pCtxCookie);
2403 MethodTable *LoadCOMClass(GUID clsid, BOOL bLoadRecord = FALSE, BOOL* pfAssemblyInReg = NULL);
2404 OBJECTREF GetMissingObject(); // DispatchInfo will call function to retrieve the Missing.Value object.
2405 #endif // FEATURE_COMINTEROP
2407 #ifndef DACCESS_COMPILE
2408 MethodTable* LookupClass(REFIID iid)
2410 WRAPPER_NO_CONTRACT;
2412 MethodTable *pMT = (MethodTable*) m_clsidHash.LookupValue((UPTR) GetKeyFromGUID(&iid), (LPVOID)&iid);
2413 return (pMT == (MethodTable*) INVALIDENTRY
2417 #endif // DACCESS_COMPILE
2419 //<TODO>@todo get a better key</TODO>
2420 ULONG GetKeyFromGUID(const GUID *pguid)
2422 LIMITED_METHOD_CONTRACT;
2424 return *(ULONG *) pguid;
2427 #ifdef FEATURE_COMINTEROP
2428 RCWCache *GetRCWCache()
2430 WRAPPER_NO_CONTRACT;
2434 // By separating the cache creation from the common lookup, we
2435 // can keep the (x86) EH prolog/epilog off the path.
2436 return CreateRCWCache();
2439 RCWCache *CreateRCWCache();
2441 RCWCache *GetRCWCacheNoCreate()
2443 LIMITED_METHOD_CONTRACT;
2447 RCWRefCache *GetRCWRefCache();
2449 MethodTable* GetLicenseInteropHelperMethodTable();
2450 #endif // FEATURE_COMINTEROP
2452 //****************************************************************************************
2453 // Get the proxy for this app domain
2457 LIMITED_METHOD_CONTRACT;
2463 TPIndex GetTPIndex()
2465 LIMITED_METHOD_CONTRACT;
2469 IUnknown *CreateFusionContext();
2471 void SetIgnoreUnhandledExceptions()
2473 LIMITED_METHOD_CONTRACT;
2475 m_dwFlags |= IGNORE_UNHANDLED_EXCEPTIONS;
2478 BOOL IgnoreUnhandledExceptions()
2480 LIMITED_METHOD_CONTRACT;
2482 return (m_dwFlags & IGNORE_UNHANDLED_EXCEPTIONS);
2485 void SetCompilationDomain()
2487 LIMITED_METHOD_CONTRACT;
2489 m_dwFlags |= COMPILATION_DOMAIN;
2492 BOOL IsCompilationDomain();
2494 PTR_CompilationDomain ToCompilationDomain()
2496 LIMITED_METHOD_CONTRACT;
2498 _ASSERTE(IsCompilationDomain());
2499 return dac_cast<PTR_CompilationDomain>(this);
2502 static void ExceptionUnwind(Frame *pFrame);
2505 void TrackADThreadEnter(Thread *pThread, Frame *pFrame);
2506 void TrackADThreadExit(Thread *pThread, Frame *pFrame);
2507 void DumpADThreadTrack();
2510 #ifndef DACCESS_COMPILE
2511 void ThreadEnter(Thread *pThread, Frame *pFrame)
2513 STATIC_CONTRACT_NOTHROW;
2514 STATIC_CONTRACT_GC_NOTRIGGER;
2517 if (LoggingOn(LF_APPDOMAIN, LL_INFO100))
2518 TrackADThreadEnter(pThread, pFrame);
2522 InterlockedIncrement((LONG*)&m_dwThreadEnterCount);
2523 LOG((LF_APPDOMAIN, LL_INFO1000, "AppDomain::ThreadEnter %p to [%d] (%8.8x) %S count %d\n",
2524 pThread,GetId().m_dwId, this,
2525 GetFriendlyNameForLogging(),GetThreadEnterCount()));
2526 #if _DEBUG_AD_UNLOAD
2527 printf("AppDomain::ThreadEnter %p to [%d] (%8.8x) %S count %d\n",
2528 pThread, GetId().m_dwId, this,
2529 GetFriendlyNameForLogging(), GetThreadEnterCount());
2534 void ThreadExit(Thread *pThread, Frame *pFrame)
2536 STATIC_CONTRACT_NOTHROW;
2537 STATIC_CONTRACT_GC_NOTRIGGER;
2540 if (LoggingOn(LF_APPDOMAIN, LL_INFO100)) {
2541 TrackADThreadExit(pThread, pFrame);
2547 result = InterlockedDecrement((LONG*)&m_dwThreadEnterCount);
2548 _ASSERTE(result >= 0);
2549 LOG((LF_APPDOMAIN, LL_INFO1000, "AppDomain::ThreadExit from [%d] (%8.8x) %S count %d\n",
2550 this, GetId().m_dwId,
2551 GetFriendlyNameForLogging(), GetThreadEnterCount()));
2553 printf("AppDomain::ThreadExit %x from [%d] (%8.8x) %S count %d\n",
2554 pThread->GetThreadId(), this, GetId().m_dwId,
2555 GetFriendlyNameForLogging(), GetThreadEnterCount());
2559 #endif // DACCESS_COMPILE
2561 ULONG GetThreadEnterCount()
2563 LIMITED_METHOD_CONTRACT;
2564 return m_dwThreadEnterCount;
2567 BOOL OnlyOneThreadLeft()
2569 LIMITED_METHOD_CONTRACT;
2570 return m_dwThreadEnterCount==1 || m_dwThreadsStillInAppDomain ==1;
2573 static void RefTakerAcquire(AppDomain* pDomain)
2575 WRAPPER_NO_CONTRACT;
2580 FastInterlockIncrement(&pDomain->m_dwRefTakers);
2584 static void RefTakerRelease(AppDomain* pDomain)
2586 WRAPPER_NO_CONTRACT;
2590 _ASSERTE(pDomain->m_dwRefTakers);
2591 FastInterlockDecrement(&pDomain->m_dwRefTakers);
2598 BOOL IsHeldByIterator()
2600 LIMITED_METHOD_CONTRACT;
2601 return m_dwIterHolders>0;
2604 BOOL IsHeldByRefTaker()
2606 LIMITED_METHOD_CONTRACT;
2607 return m_dwRefTakers>0;
2610 void IteratorRelease()
2612 LIMITED_METHOD_CONTRACT;
2613 _ASSERTE(m_dwIterHolders);
2614 FastInterlockDecrement(&m_dwIterHolders);
2618 void IteratorAcquire()
2620 LIMITED_METHOD_CONTRACT;
2621 FastInterlockIncrement(&m_dwIterHolders);
2627 LIMITED_METHOD_DAC_CONTRACT;
2629 return m_Stage >= STAGE_ACTIVE;
2631 // Range for normal execution of code in the appdomain, currently used for
2632 // appdomain resource monitoring since we don't care to update resource usage
2633 // unless it's in these stages (as fields of AppDomain may not be valid if it's
2634 // not within these stages)
2637 LIMITED_METHOD_DAC_CONTRACT;
2639 return m_Stage >= STAGE_ACTIVE && m_Stage <= STAGE_OPEN;
2643 LIMITED_METHOD_DAC_CONTRACT;
2645 #ifdef DACCESS_COMPILE
2646 // We want to see all appdomains in SOS, even the about to be destructed ones.
2647 // There is no risk of races under DAC, so we will pretend to be unconditionally valid.
2650 return m_Stage > STAGE_CREATING;
2655 BOOL IsBeingCreated()
2657 LIMITED_METHOD_CONTRACT;
2659 return m_dwCreationHolders > 0;
2662 void IncCreationCount()
2664 LIMITED_METHOD_CONTRACT;
2666 FastInterlockIncrement(&m_dwCreationHolders);
2667 _ASSERTE(m_dwCreationHolders > 0);
2670 void DecCreationCount()
2672 LIMITED_METHOD_CONTRACT;
2674 FastInterlockDecrement(&m_dwCreationHolders);
2675 _ASSERTE(m_dwCreationHolders > -1);
2678 BOOL IsRunningIn(Thread* pThread);
2680 BOOL NotReadyForManagedCode()
2682 LIMITED_METHOD_CONTRACT;
2684 return m_Stage < STAGE_READYFORMANAGEDCODE;
2687 static void RaiseExitProcessEvent();
2688 Assembly* RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName);
2689 DomainAssembly* RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef);
2690 Assembly* RaiseAssemblyResolveEvent(AssemblySpec *pSpec);
2693 CrstExplicitInit m_ReflectionCrst;
2694 CrstExplicitInit m_RefClassFactCrst;
2697 EEClassFactoryInfoHashTable *m_pRefClassFactHash; // Hash table that maps a class factory info to a COM comp.
2698 #ifdef FEATURE_COMINTEROP
2699 DispIDCache *m_pRefDispIDCache;
2700 OBJECTHANDLE m_hndMissing; //Handle points to Missing.Value Object which is used for [Optional] arg scenario during IDispatch CCW Call
2702 MethodTable* m_rpCLRTypes[WinMDAdapter::RedirectedTypeIndex_Count];
2704 MethodTable* LoadRedirectedType(WinMDAdapter::RedirectedTypeIndex index, WinMDAdapter::FrameworkAssemblyIndex assembly);
2705 #endif // FEATURE_COMINTEROP
2709 CrstBase *GetRefClassFactCrst()
2711 LIMITED_METHOD_CONTRACT;
2713 return &m_RefClassFactCrst;
2716 #ifndef DACCESS_COMPILE
2717 EEClassFactoryInfoHashTable* GetClassFactHash()
2719 STATIC_CONTRACT_THROWS;
2720 STATIC_CONTRACT_GC_TRIGGERS;
2721 STATIC_CONTRACT_FAULT;
2723 if (m_pRefClassFactHash != NULL) {
2724 return m_pRefClassFactHash;
2727 return SetupClassFactHash();
2729 #endif // DACCESS_COMPILE
2731 #ifdef FEATURE_COMINTEROP
2732 DispIDCache* GetRefDispIDCache()
2734 STATIC_CONTRACT_THROWS;
2735 STATIC_CONTRACT_GC_TRIGGERS;
2736 STATIC_CONTRACT_FAULT;
2738 if (m_pRefDispIDCache != NULL) {
2739 return m_pRefDispIDCache;
2742 return SetupRefDispIDCache();
2744 #endif // FEATURE_COMINTEROP
2746 PTR_LoaderHeap GetStubHeap();
2747 PTR_LoaderHeap GetLowFrequencyHeap();
2748 PTR_LoaderHeap GetHighFrequencyHeap();
2750 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2751 #define ARM_ETW_ALLOC_THRESHOLD (4 * 1024 * 1024)
2752 // cache line size in ULONGLONG - 128 bytes which are 16 ULONGLONG's
2753 #define ARM_CACHE_LINE_SIZE_ULL 16
2755 inline ULONGLONG GetAllocBytes()
2757 LIMITED_METHOD_CONTRACT;
2758 ULONGLONG ullTotalAllocBytes = 0;
2760 // Ensure that m_pullAllocBytes is non-null to avoid an AV in a race between GC and AD unload.
2761 // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullAllocBytes, causing the AD unload.
2762 if(NULL != m_pullAllocBytes)
2764 for (DWORD i = 0; i < m_dwNumHeaps; i++)
2766 ullTotalAllocBytes += m_pullAllocBytes[i * ARM_CACHE_LINE_SIZE_ULL];
2769 return ullTotalAllocBytes;
2772 void RecordAllocBytes(size_t allocatedBytes, DWORD dwHeapNumber)
2774 LIMITED_METHOD_CONTRACT;
2775 _ASSERTE(dwHeapNumber < m_dwNumHeaps);
2777 // Ensure that m_pullAllocBytes is non-null to avoid an AV in a race between GC and AD unload.
2778 // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullAllocBytes, causing the AD unload.
2779 if(NULL != m_pullAllocBytes)
2781 m_pullAllocBytes[dwHeapNumber * ARM_CACHE_LINE_SIZE_ULL] += allocatedBytes;
2784 ULONGLONG ullTotalAllocBytes = GetAllocBytes();
2786 if ((ullTotalAllocBytes - m_ullLastEtwAllocBytes) >= ARM_ETW_ALLOC_THRESHOLD)
2788 m_ullLastEtwAllocBytes = ullTotalAllocBytes;
2789 FireEtwAppDomainMemAllocated((ULONGLONG)this, ullTotalAllocBytes, GetClrInstanceId());
2793 inline ULONGLONG GetSurvivedBytes()
2795 LIMITED_METHOD_CONTRACT;
2796 ULONGLONG ullTotalSurvivedBytes = 0;
2798 // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
2799 // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
2800 if(NULL != m_pullSurvivedBytes)
2802 for (DWORD i = 0; i < m_dwNumHeaps; i++)
2804 ullTotalSurvivedBytes += m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL];
2807 return ullTotalSurvivedBytes;
2810 void RecordSurvivedBytes(size_t promotedBytes, DWORD dwHeapNumber)
2812 WRAPPER_NO_CONTRACT;
2813 _ASSERTE(dwHeapNumber < m_dwNumHeaps);
2815 // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
2816 // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
2817 if(NULL != m_pullSurvivedBytes)
2819 m_pullSurvivedBytes[dwHeapNumber * ARM_CACHE_LINE_SIZE_ULL] += promotedBytes;
2823 inline void ResetSurvivedBytes()
2825 LIMITED_METHOD_CONTRACT;
2827 // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
2828 // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
2829 if(NULL != m_pullSurvivedBytes)
2831 for (DWORD i = 0; i < m_dwNumHeaps; i++)
2833 m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
2838 // Return the total processor time (user and kernel) used by threads executing in this AppDomain so far.
2839 // The result is in 100ns units.
2840 ULONGLONG QueryProcessorUsage();
2842 // Add to the current count of processor time used by threads within this AppDomain. This API is called by
2843 // threads transitioning between AppDomains.
2844 void UpdateProcessorUsage(ULONGLONG ullAdditionalUsage);
2845 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2848 size_t EstimateSize();
2849 EEClassFactoryInfoHashTable* SetupClassFactHash();
2850 #ifdef FEATURE_COMINTEROP
2851 DispIDCache* SetupRefDispIDCache();
2852 #endif // FEATURE_COMINTEROP
2855 BOOL PostBindResolveAssembly(AssemblySpec *pPrePolicySpec,
2856 AssemblySpec *pPostPolicySpec,
2857 HRESULT hrBindResult,
2858 AssemblySpec **ppFailedSpec);
2860 #ifdef FEATURE_COMINTEROP
2862 void ReleaseRCWs(LPVOID pCtxCookie);
2866 #endif // FEATURE_COMINTEROP
2869 void RaiseLoadingAssemblyEvent(DomainAssembly* pAssembly);
2871 friend class DomainAssembly;
2874 BOOL RaiseUnhandledExceptionEvent(OBJECTREF *pThrowable, BOOL isTerminating);
2878 STAGE_READYFORMANAGEDCODE,
2881 // Don't delete the following *_DONOTUSE members and in case a new member needs to be added,
2882 // add it at the end. The reason is that debugger stuff has its own copy of this enum and
2883 // it can use the members that are marked as *_DONOTUSE here when debugging older version
2885 STAGE_UNLOAD_REQUESTED_DONOTUSE,
2886 STAGE_EXITING_DONOTUSE,
2887 STAGE_EXITED_DONOTUSE,
2888 STAGE_FINALIZING_DONOTUSE,
2889 STAGE_FINALIZED_DONOTUSE,
2890 STAGE_HANDLETABLE_NOACCESS_DONOTUSE,
2891 STAGE_CLEARED_DONOTUSE,
2892 STAGE_COLLECTED_DONOTUSE,
2893 STAGE_CLOSED_DONOTUSE
2895 void SetStage(Stage stage)
2904 STRESS_LOG2(LF_APPDOMAIN, LL_INFO100,"Updating AD stage, ADID=%d, stage=%d\n",GetId().m_dwId,stage);
2905 TESTHOOKCALL(AppDomainStageChanged(GetId().m_dwId,m_Stage,stage));
2906 Stage lastStage=m_Stage;
2907 while (lastStage !=stage)
2908 lastStage = (Stage)FastInterlockCompareExchange((LONG*)&m_Stage,stage,lastStage);
2910 void UnwindThreads();
2911 // Return TRUE if EE is stopped
2912 // Return FALSE if more work is needed
2913 BOOL StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread);
2915 // List of unloaded LoaderAllocators, protected by code:GetLoaderAllocatorReferencesLock (for now)
2916 LoaderAllocator * m_pDelayedLoaderAllocatorUnloadList;
2920 // Register the loader allocator for deletion in code:ShutdownFreeLoaderAllocators.
2921 void RegisterLoaderAllocatorForDeletion(LoaderAllocator * pLoaderAllocator);
2924 void SetGCRefPoint(int gccounter)
2926 LIMITED_METHOD_CONTRACT;
2927 GetLoaderAllocator()->SetGCRefPoint(gccounter);
2931 LIMITED_METHOD_CONTRACT;
2932 return GetLoaderAllocator()->GetGCRefPoint();
2935 static USHORT GetOffsetOfId()
2937 LIMITED_METHOD_CONTRACT;
2938 size_t ofs = offsetof(class AppDomain, m_dwId);
2939 _ASSERTE(FitsInI2(ofs));
2944 void AddMemoryPressure();
2945 void RemoveMemoryPressure();
2947 void UnlinkClass(MethodTable *pMT);
2949 Assembly *GetRootAssembly()
2951 LIMITED_METHOD_CONTRACT;
2952 return m_pRootAssembly;
2955 #ifndef DACCESS_COMPILE
2956 void SetRootAssembly(Assembly *pAssembly)
2958 LIMITED_METHOD_CONTRACT;
2959 m_pRootAssembly = pAssembly;
2964 // The one and only AppDomain
2965 SPTR_DECL(AppDomain, m_pTheAppDomain);
2967 SString m_friendlyName;
2968 PTR_Assembly m_pRootAssembly;
2970 // General purpose flags.
2973 // When an application domain is created the ref count is artifically incremented
2974 // by one. For it to hit zero an explicit close must have happened.
2975 LONG m_cRef; // Ref count.
2977 // Hash table that maps a clsid to a type
2978 PtrHashMap m_clsidHash;
2980 #ifdef FEATURE_COMINTEROP
2981 // Hash table that maps WinRT class names to MethodTables.
2982 PTR_NameToTypeMapTable m_pNameToTypeMap;
2983 UINT m_vNameToTypeMapVersion;
2985 UINT m_nEpoch; // incremented each time m_pNameToTypeMap is enumerated
2987 // Hash table that remembers the last cached WinRT factory object per type per appdomain.
2988 WinRTFactoryCache *m_pWinRTFactoryCache;
2990 // this cache stores the RCWs in this domain
2991 RCWCache *m_pRCWCache;
2993 // this cache stores the RCW -> CCW references in this domain
2994 RCWRefCache *m_pRCWRefCache;
2996 // The method table used for LicenseInteropHelper
2997 MethodTable* m_pLicenseInteropHelperMT;
2998 #endif // FEATURE_COMINTEROP
3000 // The index of this app domain among existing app domains (starting from 1)
3003 // The thread-pool index of this app domain among existing app domains (starting from 1)
3006 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3007 ULONGLONG* m_pullAllocBytes;
3008 ULONGLONG* m_pullSurvivedBytes;
3010 ULONGLONG m_ullLastEtwAllocBytes;
3011 // Total processor time (user and kernel) utilized by threads running in this AppDomain so far. May not
3012 // account for threads currently executing in the AppDomain until a call to QueryProcessorUsage() is
3014 Volatile<ULONGLONG> m_ullTotalProcessorUsage;
3015 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3018 struct ThreadTrackInfo;
3019 typedef CDynArray<ThreadTrackInfo *> ThreadTrackInfoList;
3020 ThreadTrackInfoList *m_pThreadTrackInfoList;
3021 DWORD m_TrackSpinLock;
3024 // The number of times we have entered this AD
3025 ULONG m_dwThreadEnterCount;
3026 // The number of threads that have entered this AD, for ADU only
3027 ULONG m_dwThreadsStillInAppDomain;
3029 Volatile<Stage> m_Stage;
3031 ArrayList m_failedAssemblies;
3034 Volatile<LONG> m_dwIterHolders;
3035 Volatile<LONG> m_dwRefTakers;
3036 Volatile<LONG> m_dwCreationHolders;
3040 // DAC iterator for failed assembly loads
3042 class FailedAssemblyIterator
3044 ArrayList::Iterator m_i;
3049 WRAPPER_NO_CONTRACT;
3052 FailedAssembly *GetFailedAssembly()
3054 WRAPPER_NO_CONTRACT;
3055 return dac_cast<PTR_FailedAssembly>(m_i.GetElement());
3059 WRAPPER_NO_CONTRACT;
3060 return m_i.GetIndex();
3064 friend class AppDomain;
3065 // Cannot have constructor so this iterator can be used inside a union
3066 static FailedAssemblyIterator Create(AppDomain *pDomain)
3068 WRAPPER_NO_CONTRACT;
3069 FailedAssemblyIterator i;
3071 i.m_i = pDomain->m_failedAssemblies.Iterate();
3075 friend class FailedAssemblyIterator;
3077 FailedAssemblyIterator IterateFailedAssembliesEx()
3079 WRAPPER_NO_CONTRACT;
3080 return FailedAssemblyIterator::Create(this);
3083 //---------------------------------------------------------
3084 // Stub caches for Method stubs
3085 //---------------------------------------------------------
3090 CONTEXT_INITIALIZED = 0x0001,
3091 LOAD_SYSTEM_ASSEMBLY_EVENT_SENT = 0x0040,
3092 COMPILATION_DOMAIN = 0x0400, // Are we ngenning?
3093 IGNORE_UNHANDLED_EXCEPTIONS = 0x10000, // AppDomain was created using the APPDOMAIN_IGNORE_UNHANDLED_EXCEPTIONS flag
3096 AssemblySpecBindingCache m_AssemblyCache;
3097 DomainAssemblyCache m_UnmanagedCache;
3098 size_t m_MemoryPressure;
3100 ArrayList m_NativeDllSearchDirectories;
3101 BOOL m_ReversePInvokeCanEnter;
3102 bool m_ForceTrivialWaitOperations;
3106 #ifdef FEATURE_TYPEEQUIVALENCE
3108 VolatilePtr<TypeEquivalenceHashTable> m_pTypeEquivalenceTable;
3109 CrstExplicitInit m_TypeEquivalenceCrst;
3111 TypeEquivalenceHashTable * GetTypeEquivalenceCache();
3116 #ifdef DACCESS_COMPILE
3118 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
3122 #ifdef FEATURE_MULTICOREJIT
3125 MulticoreJitManager m_MulticoreJitManager;
3128 MulticoreJitManager & GetMulticoreJitManager()
3130 LIMITED_METHOD_CONTRACT;
3132 return m_MulticoreJitManager;
3137 #if defined(FEATURE_TIERED_COMPILATION)
3140 TieredCompilationManager * GetTieredCompilationManager()
3142 LIMITED_METHOD_CONTRACT;
3143 return &m_tieredCompilationManager;
3147 TieredCompilationManager m_tieredCompilationManager;
3151 #ifdef FEATURE_COMINTEROP
3155 #endif //FEATURE_COMINTEROP
3159 class ComInterfaceReleaseList
3161 SArray<IUnknown *> m_objects;
3163 ~ComInterfaceReleaseList()
3165 WRAPPER_NO_CONTRACT;
3167 for (COUNT_T i = 0; i < m_objects.GetCount(); i++)
3169 IUnknown *pItf = *(m_objects.GetElements() + i);
3170 if (pItf != nullptr)
3175 // Append to the list of object to free. Only use under the AppDomain "LockHolder(pAppDomain)"
3176 void Append(IUnknown *pInterfaceToRelease)
3178 WRAPPER_NO_CONTRACT;
3179 m_objects.Append(pInterfaceToRelease);
3181 } AppDomainInterfaceReleaseList;
3184 //-----------------------------------------------------------
3185 // Static ICLRPrivAssembly -> DomainAssembly mapping functions.
3186 // This map does not maintain a reference count to either key or value.
3187 // PEFile maintains a reference count on the ICLRPrivAssembly through its code:PEFile::m_pHostAssembly field.
3188 // It is removed from this hash table by code:DomainAssembly::~DomainAssembly.
3189 struct HostAssemblyHashTraits : public DefaultSHashTraits<PTR_DomainAssembly>
3192 typedef PTR_ICLRPrivAssembly key_t;
3194 static key_t GetKey(element_t const & elem)
3196 STATIC_CONTRACT_WRAPPER;
3197 return elem->GetFile()->GetHostAssembly();
3200 static BOOL Equals(key_t key1, key_t key2)
3202 LIMITED_METHOD_CONTRACT;
3203 return dac_cast<TADDR>(key1) == dac_cast<TADDR>(key2);
3206 static count_t Hash(key_t key)
3208 STATIC_CONTRACT_LIMITED_METHOD;
3209 //return reinterpret_cast<count_t>(dac_cast<TADDR>(key));
3210 return (count_t)(dac_cast<TADDR>(key));
3213 static element_t Null() { return NULL; }
3214 static element_t Deleted() { return (element_t)(TADDR)-1; }
3215 static bool IsNull(const element_t & e) { return e == NULL; }
3216 static bool IsDeleted(const element_t & e) { return dac_cast<TADDR>(e) == (TADDR)-1; }
3219 struct OriginalFileHostAssemblyHashTraits : public HostAssemblyHashTraits
3222 static key_t GetKey(element_t const & elem)
3224 STATIC_CONTRACT_WRAPPER;
3225 return elem->GetOriginalFile()->GetHostAssembly();
3229 typedef SHash<HostAssemblyHashTraits> HostAssemblyMap;
3230 typedef SHash<OriginalFileHostAssemblyHashTraits> OriginalFileHostAssemblyMap;
3231 HostAssemblyMap m_hostAssemblyMap;
3232 OriginalFileHostAssemblyMap m_hostAssemblyMapForOrigFile;
3233 CrstExplicitInit m_crstHostAssemblyMap;
3234 // Lock to serialize all Add operations (in addition to the "read-lock" above)
3235 CrstExplicitInit m_crstHostAssemblyMapAdd;
3238 // Returns DomainAssembly.
3239 PTR_DomainAssembly FindAssembly(PTR_ICLRPrivAssembly pHostAssembly);
3241 #ifndef DACCESS_COMPILE
3243 friend void DomainAssembly::Allocate();
3244 friend DomainAssembly::~DomainAssembly();
3246 // Called from DomainAssembly::Begin.
3247 void PublishHostedAssembly(
3248 DomainAssembly* pAssembly);
3250 // Called from DomainAssembly::UpdatePEFile.
3251 void UpdatePublishHostedAssembly(
3252 DomainAssembly* pAssembly,
3255 // Called from DomainAssembly::~DomainAssembly
3256 void UnPublishHostedAssembly(
3257 DomainAssembly* pAssembly);
3258 #endif // DACCESS_COMPILE
3260 #ifdef FEATURE_PREJIT
3261 friend void DomainFile::InsertIntoDomainFileWithNativeImageList();
3262 Volatile<DomainFile *> m_pDomainFileWithNativeImageList;
3264 DomainFile *GetDomainFilesWithNativeImagesList()
3266 LIMITED_METHOD_CONTRACT;
3267 return m_pDomainFileWithNativeImageList;
3270 }; // class AppDomain
3273 // This holder is to be used to take a reference to make sure AppDomain* is still valid
3274 // Please do not use if you are aleady ADU-safe
3275 typedef Wrapper<AppDomain*,AppDomain::RefTakerAcquire,AppDomain::RefTakerRelease,NULL> AppDomainRefTaker;
3277 // Just a ref holder
3278 typedef ReleaseHolder<AppDomain> AppDomainRefHolder;
3280 typedef VPTR(class SystemDomain) PTR_SystemDomain;
3282 class SystemDomain : public BaseDomain
3284 friend class AppDomainNative;
3285 friend class AppDomainIterator;
3286 friend class UnsafeAppDomainIterator;
3287 friend class ClrDataAccess;
3288 friend Frame *Thread::IsRunningIn(AppDomain* pDomain, int *count);
3290 VPTR_VTABLE_CLASS(SystemDomain, BaseDomain)
3291 VPTR_UNIQUE(VPTR_UNIQUE_SystemDomain)
3292 static AppDomain *GetAppDomainAtId(ADID indx);
3295 static PTR_LoaderAllocator GetGlobalLoaderAllocator();
3296 static AppDomain* GetAppDomainFromId(ADID indx,DWORD ADValidityKind)
3306 if (indx.m_dwId==DefaultADID)
3307 pRetVal= SystemDomain::System()->DefaultDomain();
3309 pRetVal= GetAppDomainAtId(indx);
3311 // Only call CheckADValidity in DEBUG builds for non-NULL return values
3312 if (pRetVal != NULL)
3313 CheckADValidity(pRetVal, ADValidityKind);
3317 //****************************************************************************************
3319 // To be run during the initial start up of the EE. This must be
3320 // performed prior to any class operations.
3321 static void Attach();
3323 //****************************************************************************************
3325 // To be run during shutdown. This must be done after all operations
3326 // that require the use of system classes (i.e., exceptions).
3327 // DetachBegin stops all domains, while DetachEnd deallocates domain resources.
3328 static void DetachBegin();
3330 //****************************************************************************************
3332 // To be run during shutdown. This must be done after all operations
3333 // that require the use of system classes (i.e., exceptions).
3334 // DetachBegin stops release resources held by systemdomain and the default domain.
3335 static void DetachEnd();
3337 //****************************************************************************************
3339 // Initializes and shutdowns the single instance of the SystemDomain
3341 #ifndef DACCESS_COMPILE
3342 void *operator new(size_t size, void *pInPlace);
3343 void operator delete(void *pMem);
3348 static void LazyInitGlobalStringLiteralMap();
3350 //****************************************************************************************
3352 // Load the base system classes, these classes are required before
3353 // any other classes are loaded
3354 void LoadBaseSystemClasses();
3356 AppDomain* DefaultDomain()
3358 LIMITED_METHOD_DAC_CONTRACT;
3360 return AppDomain::GetCurrentDomain();
3363 // Notification when an assembly is loaded into the system domain
3364 void OnAssemblyLoad(Assembly *assem);
3366 //****************************************************************************************
3368 // Global Static to get the one and only system domain
3369 static SystemDomain * System()
3371 LIMITED_METHOD_DAC_CONTRACT;
3373 return m_pSystemDomain;
3376 static PEAssembly* SystemFile()
3378 WRAPPER_NO_CONTRACT;
3380 _ASSERTE(m_pSystemDomain);
3381 return System()->m_pSystemFile;
3384 static Assembly* SystemAssembly()
3386 WRAPPER_NO_CONTRACT;
3388 return System()->m_pSystemAssembly;
3391 static Module* SystemModule()
3393 WRAPPER_NO_CONTRACT;
3395 return SystemAssembly()->GetManifestModule();
3398 static BOOL IsSystemLoaded()
3400 WRAPPER_NO_CONTRACT;
3402 return System()->m_pSystemAssembly != NULL;
3405 #ifndef DACCESS_COMPILE
3406 static GlobalStringLiteralMap *GetGlobalStringLiteralMap()
3408 WRAPPER_NO_CONTRACT;
3410 if (m_pGlobalStringLiteralMap == NULL)
3412 SystemDomain::LazyInitGlobalStringLiteralMap();
3414 _ASSERTE(m_pGlobalStringLiteralMap);
3415 return m_pGlobalStringLiteralMap;
3417 static GlobalStringLiteralMap *GetGlobalStringLiteralMapNoCreate()
3419 LIMITED_METHOD_CONTRACT;
3421 _ASSERTE(m_pGlobalStringLiteralMap);
3422 return m_pGlobalStringLiteralMap;
3424 #endif // DACCESS_COMPILE
3426 #if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3427 static Thread::ApartmentState GetEntryPointThreadAptState(IMDInternalImport* pScope, mdMethodDef mdMethod);
3428 static void SetThreadAptState(Thread::ApartmentState state);
3431 //****************************************************************************************
3433 // Use an already exising & inited Application Domain (e.g. a subclass).
3434 static void LoadDomain(AppDomain *pDomain);
3436 //****************************************************************************************
3437 // Methods used to get the callers module and hence assembly and app domain.
3438 __declspec(deprecated("This method is deprecated, use the version that takes a StackCrawlMark instead"))
3439 static Module* GetCallersModule(int skip);
3440 static MethodDesc* GetCallersMethod(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
3441 static MethodTable* GetCallersType(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
3442 static Module* GetCallersModule(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
3443 static Assembly* GetCallersAssembly(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
3445 static bool IsReflectionInvocationMethod(MethodDesc* pMeth);
3447 #ifndef DACCESS_COMPILE
3448 //****************************************************************************************
3449 // Returns the domain associated with the current context. (this can only be a child domain)
3450 static inline AppDomain * GetCurrentDomain()
3452 WRAPPER_NO_CONTRACT;
3453 return ::GetAppDomain();
3455 #endif //!DACCESS_COMPILE
3457 #ifdef DEBUGGING_SUPPORTED
3458 //****************************************************************************************
3459 // Debugger/Publisher helper function to indicate creation of new app domain to debugger
3460 // and publishing it in the IPC block
3461 static void PublishAppDomainAndInformDebugger (AppDomain *pDomain);
3462 #endif // DEBUGGING_SUPPORTED
3464 //****************************************************************************************
3465 // Helper function to remove a domain from the system
3466 BOOL RemoveDomain(AppDomain* pDomain); // Does not decrement the reference
3468 #ifdef PROFILING_SUPPORTED
3469 //****************************************************************************************
3470 // Tell profiler about system created domains which are created before the profiler is
3471 // actually activated.
3472 static void NotifyProfilerStartup();
3474 //****************************************************************************************
3475 // Tell profiler at shutdown that system created domains are going away. They are not
3476 // torn down using the normal sequence.
3477 static HRESULT NotifyProfilerShutdown();
3478 #endif // PROFILING_SUPPORTED
3480 //****************************************************************************************
3481 // return the dev path
3483 #ifndef DACCESS_COMPILE
3484 void IncrementNumAppDomains ()
3486 LIMITED_METHOD_CONTRACT;
3491 void DecrementNumAppDomains ()
3493 LIMITED_METHOD_CONTRACT;
3498 ULONG GetNumAppDomains ()
3500 LIMITED_METHOD_CONTRACT;
3502 return s_dNumAppDomains;
3504 #endif // DACCESS_COMPILE
3507 // AppDomains currently have both an index and an ID. The
3508 // index is "densely" assigned; indices are reused as domains
3509 // are unloaded. The Id's on the other hand, are not reclaimed
3510 // so may be sparse.
3512 // Another important difference - it's OK to call GetAppDomainAtId for
3513 // an unloaded domain (it will return NULL), while GetAppDomainAtIndex
3514 // will assert if the domain is unloaded.
3517 // I'm not really happy with this situation, but
3518 // (a) we need an ID for a domain which will last the process lifetime for the
3520 // (b) we need a dense ID, for the handle table index.
3521 // So for now, I'm leaving both, but hopefully in the future we can come up
3522 // with something better.
3525 static ADIndex GetNewAppDomainIndex(AppDomain * pAppDomain);
3526 static void ReleaseAppDomainIndex(ADIndex indx);
3527 static PTR_AppDomain GetAppDomainAtIndex(ADIndex indx);
3528 static PTR_AppDomain TestGetAppDomainAtIndex(ADIndex indx);
3529 static DWORD GetCurrentAppDomainMaxIndex()
3531 WRAPPER_NO_CONTRACT;
3533 ArrayListStatic* list = (ArrayListStatic *)&m_appDomainIndexList;
3534 PREFIX_ASSUME(list!=NULL);
3535 return list->GetCount();
3538 static ADID GetNewAppDomainId(AppDomain *pAppDomain);
3539 static void ReleaseAppDomainId(ADID indx);
3541 #ifndef DACCESS_COMPILE
3542 static ADID GetCurrentAppDomainMaxId() { ADID id; id.m_dwId=m_appDomainIdList.GetCount(); return id;}
3543 #endif // DACCESS_COMPILE
3546 #ifndef DACCESS_COMPILE
3547 DWORD RequireAppDomainCleanup()
3549 LIMITED_METHOD_CONTRACT;
3550 return m_pDelayedUnloadListOfLoaderAllocators != 0;
3553 void AddToDelayedUnloadList(LoaderAllocator * pAllocator)
3563 CrstHolder lh(&m_DelayedUnloadCrst);
3564 pAllocator->m_pLoaderAllocatorDestroyNext=m_pDelayedUnloadListOfLoaderAllocators;
3565 m_pDelayedUnloadListOfLoaderAllocators=pAllocator;
3567 int iGCRefPoint=GCHeapUtilities::GetGCHeap()->CollectionCount(GCHeapUtilities::GetGCHeap()->GetMaxGeneration());
3568 if (GCHeapUtilities::IsGCInProgress())
3570 pAllocator->SetGCRefPoint(iGCRefPoint);
3573 void ProcessDelayedUnloadLoaderAllocators();
3575 static void EnumAllStaticGCRefs(promote_func* fn, ScanContext* sc);
3577 #endif // DACCESS_COMPILE
3579 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3580 // The *AD* methods are what we got from tracing through EE roots.
3581 // RecordTotalSurvivedBytes is the total promoted from a GC.
3582 static void ResetADSurvivedBytes();
3583 static ULONGLONG GetADSurvivedBytes();
3584 static void RecordTotalSurvivedBytes(size_t totalSurvivedBytes);
3585 static ULONGLONG GetTotalSurvivedBytes()
3587 LIMITED_METHOD_CONTRACT;
3588 return m_totalSurvivedBytes;
3590 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3592 //****************************************************************************************
3593 // Routines to deal with the base library (currently mscorlib.dll)
3594 LPCWSTR BaseLibrary()
3596 WRAPPER_NO_CONTRACT;
3598 return m_BaseLibrary;
3601 #ifndef DACCESS_COMPILE
3602 BOOL IsBaseLibrary(SString &path)
3604 WRAPPER_NO_CONTRACT;
3606 // See if it is the installation path to mscorlib
3607 if (path.EqualsCaseInsensitive(m_BaseLibrary, PEImage::GetFileSystemLocale()))
3610 // Or, it might be the GAC location of mscorlib
3611 if (System()->SystemAssembly() != NULL
3612 && path.EqualsCaseInsensitive(System()->SystemAssembly()->GetManifestFile()->GetPath(),
3613 PEImage::GetFileSystemLocale()))
3619 BOOL IsBaseLibrarySatellite(SString &path)
3621 WRAPPER_NO_CONTRACT;
3623 // See if it is the installation path to mscorlib.resources
3624 SString s(SString::Ascii,g_psBaseLibrarySatelliteAssemblyName);
3625 if (path.EqualsCaseInsensitive(s, PEImage::GetFileSystemLocale()))
3628 // workaround! Must implement some code to do this string comparison for
3629 // mscorlib.resources in a culture-specific directory in the GAC.
3632 // Or, it might be the GAC location of mscorlib.resources
3633 if (System()->SystemAssembly() != NULL
3634 && path.EqualsCaseInsensitive(System()->SystemAssembly()->GetManifestFile()->GetPath(),
3635 PEImage::GetFileSystemLocale()))
3641 #endif // DACCESS_COMPILE
3643 // Return the system directory
3644 LPCWSTR SystemDirectory()
3646 WRAPPER_NO_CONTRACT;
3648 return m_SystemDirectory;
3653 //****************************************************************************************
3654 // Helper function to create the single COM domain
3655 void CreateDefaultDomain();
3657 //****************************************************************************************
3658 // Helper function to add a domain to the global list
3659 void AddDomain(AppDomain* pDomain);
3661 void CreatePreallocatedExceptions();
3663 void PreallocateSpecialObjects();
3665 //****************************************************************************************
3667 static StackWalkAction CallersMethodCallback(CrawlFrame* pCrawlFrame, VOID* pClientData);
3668 static StackWalkAction CallersMethodCallbackWithStackMark(CrawlFrame* pCrawlFrame, VOID* pClientData);
3670 #ifndef DACCESS_COMPILE
3671 // This class is not to be created through normal allocation.
3674 STANDARD_VM_CONTRACT;
3676 m_pDelayedUnloadListOfLoaderAllocators=NULL;
3678 m_GlobalAllocator.Init(this);
3682 PTR_PEAssembly m_pSystemFile; // Single assembly (here for quicker reference);
3683 PTR_Assembly m_pSystemAssembly; // Single assembly (here for quicker reference);
3685 GlobalLoaderAllocator m_GlobalAllocator;
3688 InlineSString<100> m_BaseLibrary;
3690 InlineSString<100> m_SystemDirectory;
3692 // <TODO>@TODO: CTS, we can keep the com modules in a single assembly or in different assemblies.
3693 // We are currently using different assemblies but this is potentitially to slow...</TODO>
3695 // Global domain that every one uses
3696 SPTR_DECL(SystemDomain, m_pSystemDomain);
3698 LoaderAllocator * m_pDelayedUnloadListOfLoaderAllocators;
3700 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3701 // This is what gets promoted for the whole GC heap.
3702 static size_t m_totalSurvivedBytes;
3703 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3705 SVAL_DECL(ArrayListStatic, m_appDomainIndexList);
3706 #ifndef DACCESS_COMPILE
3707 static CrstStatic m_DelayedUnloadCrst;
3708 static CrstStatic m_SystemDomainCrst;
3711 static ArrayListStatic m_appDomainIdList;
3713 static GlobalStringLiteralMap *m_pGlobalStringLiteralMap;
3715 static ULONG s_dNumAppDomains; // Maintain a count of children app domains.
3717 static DWORD m_dwLowestFreeIndex;
3718 #endif // DACCESS_COMPILE
3722 // These flags let the correct native image of mscorlib to be loaded.
3723 // This is important for hardbinding to it
3725 SVAL_DECL(BOOL, s_fForceDebug);
3726 SVAL_DECL(BOOL, s_fForceProfiling);
3727 SVAL_DECL(BOOL, s_fForceInstrument);
3730 static void SetCompilationOverrides(BOOL fForceDebug,
3731 BOOL fForceProfiling,
3732 BOOL fForceInstrument);
3734 static void GetCompilationOverrides(BOOL * fForceDebug,
3735 BOOL * fForceProfiling,
3736 BOOL * fForceInstrument);
3738 //****************************************************************************************
3741 #ifndef DACCESS_COMPILE
3743 inline static BOOL IsUnderDomainLock() { LIMITED_METHOD_CONTRACT; return m_SystemDomainCrst.OwnedByCurrentThread();};
3746 // This lock controls adding and removing domains from the system domain
3747 class LockHolder : public CrstHolder
3751 : CrstHolder(&m_SystemDomainCrst)
3753 WRAPPER_NO_CONTRACT;
3756 #endif // DACCESS_COMPILE
3759 DWORD GetTotalNumSizedRefHandles();
3761 #ifdef DACCESS_COMPILE
3763 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
3767 }; // class SystemDomain
3771 // an UnsafeAppDomainIterator is used to iterate over all existing domains
3773 // The iteration is guaranteed to include all domains that exist at the
3774 // start & end of the iteration. This iterator is considered unsafe because it does not
3775 // reference count the various appdomains, and can only be used when the runtime is stopped,
3776 // or external synchronization is used. (and therefore no other thread may cause the appdomain list to change.)
3778 class UnsafeAppDomainIterator
3780 friend class SystemDomain;
3782 UnsafeAppDomainIterator(BOOL bOnlyActive)
3784 m_bOnlyActive = bOnlyActive;
3789 LIMITED_METHOD_CONTRACT;
3790 SystemDomain* sysDomain = SystemDomain::System();
3793 ArrayListStatic* list = &sysDomain->m_appDomainIndexList;
3794 PREFIX_ASSUME(list != NULL);
3795 m_i = list->Iterate();
3807 WRAPPER_NO_CONTRACT;
3811 m_pCurrent = dac_cast<PTR_AppDomain>(m_i.GetElement());
3812 if (m_pCurrent != NULL &&
3814 m_pCurrent->IsActive() : m_pCurrent->IsValid()))
3824 AppDomain * GetDomain()
3826 LIMITED_METHOD_DAC_CONTRACT;
3833 ArrayList::Iterator m_i;
3834 AppDomain * m_pCurrent;
3836 }; // class UnsafeAppDomainIterator
3839 // an AppDomainIterator is used to iterate over all existing domains.
3841 // The iteration is guaranteed to include all domains that exist at the
3842 // start & end of the iteration. Any domains added or deleted during
3843 // iteration may or may not be included. The iterator also guarantees
3844 // that the current iterated appdomain (GetDomain()) will not be deleted.
3847 class AppDomainIterator : public UnsafeAppDomainIterator
3849 friend class SystemDomain;
3852 AppDomainIterator(BOOL bOnlyActive) : UnsafeAppDomainIterator(bOnlyActive)
3854 WRAPPER_NO_CONTRACT;
3858 ~AppDomainIterator()
3860 WRAPPER_NO_CONTRACT;
3862 #ifndef DACCESS_COMPILE
3863 if (GetDomain() != NULL)
3866 GetDomain()->IteratorRelease();
3868 GetDomain()->Release();
3875 WRAPPER_NO_CONTRACT;
3877 #ifndef DACCESS_COMPILE
3878 if (GetDomain() != NULL)
3881 GetDomain()->IteratorRelease();
3883 GetDomain()->Release();
3886 SystemDomain::LockHolder lh;
3889 if (UnsafeAppDomainIterator::Next())
3891 #ifndef DACCESS_COMPILE
3892 GetDomain()->AddRef();
3894 GetDomain()->IteratorAcquire();
3902 }; // class AppDomainIterator
3904 #include "comreflectioncache.inl"
3906 #define INVALID_APPDOMAIN_ID ((DWORD)-1)
3907 #define CURRENT_APPDOMAIN_ID ((ADID)(DWORD)0)