summaryrefslogtreecommitdiff
path: root/src/vm/appdomain.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/appdomain.hpp')
-rw-r--r--src/vm/appdomain.hpp5291
1 files changed, 5291 insertions, 0 deletions
diff --git a/src/vm/appdomain.hpp b/src/vm/appdomain.hpp
new file mode 100644
index 0000000000..97e8438329
--- /dev/null
+++ b/src/vm/appdomain.hpp
@@ -0,0 +1,5291 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Header: AppDomain.cpp
+**
+
+**
+** Purpose: Implements AppDomain (loader domain) architecture
+**
+**
+===========================================================*/
+#ifndef _APPDOMAIN_H
+#define _APPDOMAIN_H
+
+#include "eventtrace.h"
+#include "assembly.hpp"
+#include "clsload.hpp"
+#include "eehash.h"
+#ifdef FEATURE_FUSION
+#include "fusion.h"
+#endif
+#include "arraylist.h"
+#include "comreflectioncache.hpp"
+#include "comutilnative.h"
+#include "domainfile.h"
+#include "objectlist.h"
+#include "fptrstubs.h"
+#include "ilstubcache.h"
+#include "testhookmgr.h"
+#ifdef FEATURE_VERSIONING
+#include "../binder/inc/applicationcontext.hpp"
+#endif // FEATURE_VERSIONING
+#include "rejit.h"
+
+#ifdef FEATURE_MULTICOREJIT
+#include "multicorejit.h"
+#endif
+
+#ifdef FEATURE_COMINTEROP
+#include "clrprivbinderwinrt.h"
+#ifndef FEATURE_CORECLR
+#include "clrprivbinderreflectiononlywinrt.h"
+#include "clrprivtypecachereflectiononlywinrt.h"
+#endif
+#include "..\md\winmd\inc\adapter.h"
+#include "winrttypenameconverter.h"
+#endif // FEATURE_COMINTEROP
+
+#include "appxutil.h"
+
+class BaseDomain;
+class SystemDomain;
+class SharedDomain;
+class AppDomain;
+class CompilationDomain;
+class AppDomainEnum;
+class AssemblySink;
+class EEMarshalingData;
+class Context;
+class GlobalStringLiteralMap;
+class StringLiteralMap;
+struct SecurityContext;
+class MngStdInterfacesInfo;
+class DomainModule;
+class DomainAssembly;
+struct InteropMethodTableData;
+class LoadLevelLimiter;
+class UMEntryThunkCache;
+class TypeEquivalenceHashTable;
+class IApplicationSecurityDescriptor;
+class StringArrayList;
+
+typedef VPTR(IApplicationSecurityDescriptor) PTR_IApplicationSecurityDescriptor;
+
+extern INT64 g_PauseTime; // Total time in millisecond the CLR has been paused
+
+#ifdef FEATURE_COMINTEROP
+class ComCallWrapperCache;
+struct SimpleComCallWrapper;
+
+class RCWRefCache;
+
+// This enum is used to specify whether user want COM or remoting
+enum COMorRemotingFlag {
+ COMorRemoting_NotInitialized = 0,
+ COMorRemoting_COM = 1, // COM will be used both cross-domain and cross-runtime
+ COMorRemoting_Remoting = 2, // Remoting will be used cross-domain; cross-runtime will use Remoting only if it looks like it's expected (default)
+ COMorRemoting_LegacyMode = 3 // Remoting will be used both cross-domain and cross-runtime
+};
+
+#endif // FEATURE_COMINTEROP
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4200) // Disable zero-sized array warning
+#endif
+
+
+GPTR_DECL(IdDispenser, g_pModuleIndexDispenser);
+
+// This enum is aligned to System.ExceptionCatcherType.
+enum ExceptionCatcher {
+ ExceptionCatcher_ManagedCode = 0,
+ ExceptionCatcher_AppDomainTransition = 1,
+ ExceptionCatcher_COMInterop = 2,
+};
+
+// We would like *ALLOCATECLASS_FLAG to AV (in order to catch errors), so don't change it
+struct ClassInitFlags {
+ enum
+ {
+ INITIALIZED_FLAG_BIT = 0,
+ INITIALIZED_FLAG = 1<<INITIALIZED_FLAG_BIT,
+ ERROR_FLAG_BIT = 1,
+ ERROR_FLAG = 1<<ERROR_FLAG_BIT,
+ ALLOCATECLASS_FLAG_BIT = 2, // Bit to avoid racing for InstantiateStaticHandles
+ ALLOCATECLASS_FLAG = 1<<ALLOCATECLASS_FLAG_BIT,
+ COLLECTIBLE_FLAG_BIT = 3,
+ COLLECTIBLE_FLAG = 1<<COLLECTIBLE_FLAG_BIT
+ };
+};
+
+struct DomainLocalModule
+{
+ friend class ClrDataAccess;
+ friend class CheckAsmOffsets;
+ friend struct ThreadLocalModule;
+
+// 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
+// It is critically important that no GC is allowed to occur before this pointer is used.
+#define GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pGCStatics) \
+ {\
+ DomainLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast<DomainLocalModule::PTR_DynamicClassInfo>(dynamicClassInfoParam);\
+ DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast<DomainLocalModule::PTR_DynamicEntry>((DomainLocalModule::DynamicEntry*)dynamicClassInfo->m_pDynamicEntry.Load()); \
+ if ((dynamicClassInfo->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \
+ {\
+ PTRARRAYREF objArray;\
+ objArray = (PTRARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \
+ (dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hGCStatics);\
+ *(pGCStatics) = dac_cast<PTR_BYTE>(PTR_READ(PTR_TO_TADDR(OBJECTREFToObject( objArray )) + offsetof(PtrArray, m_Array), objArray->GetNumComponents() * sizeof(void*))) ;\
+ }\
+ else\
+ {\
+ *(pGCStatics) = (dac_cast<DomainLocalModule::PTR_NormalDynamicEntry>(pDynamicEntry))->GetGCStaticsBasePointer();\
+ }\
+ }\
+
+#define GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pNonGCStatics) \
+ {\
+ DomainLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast<DomainLocalModule::PTR_DynamicClassInfo>(dynamicClassInfoParam);\
+ DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast<DomainLocalModule::PTR_DynamicEntry>((DomainLocalModule::DynamicEntry*)(dynamicClassInfo)->m_pDynamicEntry.Load()); \
+ if (((dynamicClassInfo)->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \
+ {\
+ if ((dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hNonGCStatics != 0) \
+ { \
+ U1ARRAYREF objArray;\
+ objArray = (U1ARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \
+ (dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hNonGCStatics);\
+ *(pNonGCStatics) = dac_cast<PTR_BYTE>(PTR_READ( \
+ PTR_TO_TADDR(OBJECTREFToObject( objArray )) + sizeof(ArrayBase) - DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob(), \
+ objArray->GetNumComponents() * (DWORD)objArray->GetComponentSize() + DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob())); \
+ } else (*pNonGCStatics) = NULL; \
+ }\
+ else\
+ {\
+ *(pNonGCStatics) = dac_cast<DomainLocalModule::PTR_NormalDynamicEntry>(pDynamicEntry)->GetNonGCStaticsBasePointer();\
+ }\
+ }\
+
+ struct DynamicEntry
+ {
+ static DWORD GetOffsetOfDataBlob();
+ };
+ typedef DPTR(DynamicEntry) PTR_DynamicEntry;
+
+ struct CollectibleDynamicEntry : public DynamicEntry
+ {
+ LOADERHANDLE m_hGCStatics;
+ LOADERHANDLE m_hNonGCStatics;
+ };
+ typedef DPTR(CollectibleDynamicEntry) PTR_CollectibleDynamicEntry;
+
+ struct NormalDynamicEntry : public DynamicEntry
+ {
+ PTR_OBJECTREF m_pGCStatics;
+#ifdef FEATURE_64BIT_ALIGNMENT
+ // Padding to make m_pDataBlob aligned at MAX_PRIMITIVE_FIELD_SIZE
+ // code:MethodTableBuilder::PlaceRegularStaticFields assumes that the start of the data blob is aligned
+ SIZE_T m_padding;
+#endif
+ BYTE m_pDataBlob[0];
+
+ inline PTR_BYTE GetGCStaticsBasePointer()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ return dac_cast<PTR_BYTE>(m_pGCStatics);
+ }
+ inline PTR_BYTE GetNonGCStaticsBasePointer()
+ {
+ LIMITED_METHOD_CONTRACT
+ SUPPORTS_DAC;
+ return dac_cast<PTR_BYTE>(this);
+ }
+ };
+ typedef DPTR(NormalDynamicEntry) PTR_NormalDynamicEntry;
+
+ struct DynamicClassInfo
+ {
+ VolatilePtr<DynamicEntry, PTR_DynamicEntry> m_pDynamicEntry;
+ Volatile<DWORD> m_dwFlags;
+ };
+ typedef DPTR(DynamicClassInfo) PTR_DynamicClassInfo;
+
+ inline UMEntryThunk * GetADThunkTable()
+ {
+ LIMITED_METHOD_CONTRACT
+ return m_pADThunkTable;
+ }
+
+ inline void SetADThunkTable(UMEntryThunk* pADThunkTable)
+ {
+ LIMITED_METHOD_CONTRACT
+ InterlockedCompareExchangeT(m_pADThunkTable.GetPointer(), pADThunkTable, NULL);
+ }
+
+ // Note the difference between:
+ //
+ // GetPrecomputedNonGCStaticsBasePointer() and
+ // GetPrecomputedStaticsClassData()
+ //
+ // GetPrecomputedNonGCStaticsBasePointer returns the pointer that should be added to field offsets to retrieve statics
+ // GetPrecomputedStaticsClassData returns a pointer to the first byte of the precomputed statics block
+ inline TADDR GetPrecomputedNonGCStaticsBasePointer()
+ {
+ LIMITED_METHOD_CONTRACT
+ return dac_cast<TADDR>(this);
+ }
+
+ inline PTR_BYTE GetPrecomputedStaticsClassData()
+ {
+ LIMITED_METHOD_CONTRACT
+ return dac_cast<PTR_BYTE>(this) + offsetof(DomainLocalModule, m_pDataBlob);
+ }
+
+ static SIZE_T GetOffsetOfDataBlob() { return offsetof(DomainLocalModule, m_pDataBlob); }
+ static SIZE_T GetOffsetOfGCStaticPointer() { return offsetof(DomainLocalModule, m_pGCStatics); }
+
+ inline DomainFile* GetDomainFile()
+ {
+ LIMITED_METHOD_CONTRACT
+ SUPPORTS_DAC;
+ return m_pDomainFile;
+ }
+
+#ifndef DACCESS_COMPILE
+ inline void SetDomainFile(DomainFile* pDomainFile)
+ {
+ LIMITED_METHOD_CONTRACT
+ m_pDomainFile = pDomainFile;
+ }
+#endif
+
+ inline PTR_OBJECTREF GetPrecomputedGCStaticsBasePointer()
+ {
+ LIMITED_METHOD_CONTRACT
+ return m_pGCStatics;
+ }
+
+ inline PTR_OBJECTREF * GetPrecomputedGCStaticsBasePointerAddress()
+ {
+ LIMITED_METHOD_CONTRACT
+ return &m_pGCStatics;
+ }
+
+ // Returns bytes so we can add offsets
+ inline PTR_BYTE GetGCStaticsBasePointer(MethodTable * pMT)
+ {
+ WRAPPER_NO_CONTRACT
+ SUPPORTS_DAC;
+
+ if (pMT->IsDynamicStatics())
+ {
+ _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
+ return GetDynamicEntryGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator());
+ }
+ else
+ {
+ return dac_cast<PTR_BYTE>(m_pGCStatics);
+ }
+ }
+
+ inline PTR_BYTE GetNonGCStaticsBasePointer(MethodTable * pMT)
+ {
+ WRAPPER_NO_CONTRACT
+ SUPPORTS_DAC;
+
+ if (pMT->IsDynamicStatics())
+ {
+ _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
+ return GetDynamicEntryNonGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator());
+ }
+ else
+ {
+ return dac_cast<PTR_BYTE>(this);
+ }
+ }
+
+ inline DynamicClassInfo* GetDynamicClassInfo(DWORD n)
+ {
+ LIMITED_METHOD_CONTRACT
+ SUPPORTS_DAC;
+ _ASSERTE(m_pDynamicClassTable.Load() && m_aDynamicEntries > n);
+ dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[n].m_pDynamicEntry.Load());
+
+ return &m_pDynamicClassTable[n];
+ }
+
+ // These helpers can now return null, as the debugger may do queries on a type
+ // before the calls to PopulateClass happen
+ inline PTR_BYTE GetDynamicEntryGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ MODE_COOPERATIVE;
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+
+ if (n >= m_aDynamicEntries)
+ {
+ return NULL;
+ }
+
+ DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n);
+ if (!pClassInfo->m_pDynamicEntry)
+ {
+ return NULL;
+ }
+
+ PTR_BYTE retval = NULL;
+
+ GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval);
+
+ return retval;
+ }
+
+ inline PTR_BYTE GetDynamicEntryNonGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ MODE_COOPERATIVE;
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+
+ if (n >= m_aDynamicEntries)
+ {
+ return NULL;
+ }
+
+ DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n);
+ if (!pClassInfo->m_pDynamicEntry)
+ {
+ return NULL;
+ }
+
+ PTR_BYTE retval = NULL;
+
+ GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval);
+
+ return retval;
+ }
+
+ FORCEINLINE PTR_DynamicClassInfo GetDynamicClassInfoIfInitialized(DWORD n)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ // m_aDynamicEntries is set last, it needs to be checked first
+ if (n >= m_aDynamicEntries)
+ {
+ return NULL;
+ }
+
+ _ASSERTE(m_pDynamicClassTable.Load() != NULL);
+ PTR_DynamicClassInfo pDynamicClassInfo = (PTR_DynamicClassInfo)(m_pDynamicClassTable.Load() + n);
+
+ // INITIALIZED_FLAG is set last, it needs to be checked first
+ if ((pDynamicClassInfo->m_dwFlags & ClassInitFlags::INITIALIZED_FLAG) == 0)
+ {
+ return NULL;
+ }
+
+ PREFIX_ASSUME(pDynamicClassInfo != NULL);
+ return pDynamicClassInfo;
+ }
+
+ // iClassIndex is slightly expensive to compute, so if we already know
+ // it, we can use this helper
+ inline BOOL IsClassInitialized(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
+ {
+ WRAPPER_NO_CONTRACT;
+ return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::INITIALIZED_FLAG) != 0;
+ }
+
+ inline BOOL IsPrecomputedClassInitialized(DWORD classID)
+ {
+ return GetPrecomputedStaticsClassData()[classID] & ClassInitFlags::INITIALIZED_FLAG;
+ }
+
+ inline BOOL IsClassAllocated(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
+ {
+ WRAPPER_NO_CONTRACT;
+ return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ALLOCATECLASS_FLAG) != 0;
+ }
+
+ BOOL IsClassInitError(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
+ {
+ WRAPPER_NO_CONTRACT;
+ return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ERROR_FLAG) != 0;
+ }
+
+ void SetClassInitialized(MethodTable* pMT);
+ void SetClassInitError(MethodTable* pMT);
+
+ void EnsureDynamicClassIndex(DWORD dwID);
+
+ void AllocateDynamicClass(MethodTable *pMT);
+
+ void PopulateClass(MethodTable *pMT);
+
+#ifdef DACCESS_COMPILE
+ void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
+#endif
+
+ static DWORD OffsetOfDataBlob()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return offsetof(DomainLocalModule, m_pDataBlob);
+ }
+
+ FORCEINLINE MethodTable * GetMethodTableFromClassDomainID(DWORD dwClassDomainID)
+ {
+ DWORD rid = (DWORD)(dwClassDomainID) + 1;
+ TypeHandle th = GetDomainFile()->GetModule()->LookupTypeDef(TokenFromRid(rid, mdtTypeDef));
+ _ASSERTE(!th.IsNull());
+ MethodTable * pMT = th.AsMethodTable();
+ PREFIX_ASSUME(pMT != NULL);
+ return pMT;
+ }
+
+private:
+ friend void EmitFastGetSharedStaticBase(CPUSTUBLINKER *psl, CodeLabel *init, bool bCCtorCheck);
+
+ void SetClassFlags(MethodTable* pMT, DWORD dwFlags);
+ DWORD GetClassFlags(MethodTable* pMT, DWORD iClassIndex);
+
+ PTR_DomainFile m_pDomainFile;
+ VolatilePtr<DynamicClassInfo, PTR_DynamicClassInfo> m_pDynamicClassTable; // used for generics and reflection.emit in memory
+ Volatile<SIZE_T> m_aDynamicEntries; // number of entries in dynamic table
+ VolatilePtr<UMEntryThunk> m_pADThunkTable;
+ PTR_OBJECTREF m_pGCStatics; // Handle to GC statics of the module
+
+ // In addition to storing the ModuleIndex in the Module class, we also
+ // keep a copy of the ModuleIndex in the DomainLocalModule class. This
+ // allows the thread static JIT helpers to quickly convert a pointer to
+ // a DomainLocalModule into a ModuleIndex.
+ ModuleIndex m_ModuleIndex;
+
+ // Note that the static offset calculation in code:Module::BuildStaticsOffsets takes the offset m_pDataBlob
+ // into consideration for alignment so we do not need any padding to ensure that the start of the data blob is aligned
+
+ BYTE m_pDataBlob[0]; // First byte of the statics blob
+
+ // Layout of m_pDataBlob is:
+ // ClassInit bytes (hold flags for cctor run, cctor error, etc)
+ // Non GC Statics
+
+public:
+
+ // The Module class need to be able to initialized ModuleIndex,
+ // so for now I will make it a friend..
+ friend class Module;
+
+ FORCEINLINE ModuleIndex GetModuleIndex()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return m_ModuleIndex;
+ }
+
+}; // struct DomainLocalModule
+
+
+typedef DPTR(class DomainLocalBlock) PTR_DomainLocalBlock;
+class DomainLocalBlock
+{
+ friend class ClrDataAccess;
+ friend class CheckAsmOffsets;
+
+private:
+ PTR_AppDomain m_pDomain;
+ DPTR(PTR_DomainLocalModule) m_pModuleSlots;
+ SIZE_T m_aModuleIndices; // Module entries the shared block has allocated
+
+public: // used by code generators
+ static SIZE_T GetOffsetOfModuleSlotsPointer() { return offsetof(DomainLocalBlock, m_pModuleSlots);}
+
+public:
+
+#ifndef DACCESS_COMPILE
+ DomainLocalBlock()
+ : m_pDomain(NULL), m_pModuleSlots(NULL), m_aModuleIndices(0) {}
+
+ void EnsureModuleIndex(ModuleIndex index);
+
+ void Init(AppDomain *pDomain) { LIMITED_METHOD_CONTRACT; m_pDomain = pDomain; }
+#endif
+
+ void SetModuleSlot(ModuleIndex index, PTR_DomainLocalModule pLocalModule);
+
+ FORCEINLINE PTR_DomainLocalModule GetModuleSlot(ModuleIndex index)
+ {
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+ _ASSERTE(index.m_dwIndex < m_aModuleIndices);
+ return m_pModuleSlots[index.m_dwIndex];
+ }
+
+ inline PTR_DomainLocalModule GetModuleSlot(MethodTable* pMT)
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetModuleSlot(pMT->GetModuleForStatics()->GetModuleIndex());
+ }
+
+ DomainFile* TryGetDomainFile(ModuleIndex index)
+ {
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+
+ // the publishing of m_aModuleIndices and m_pModuleSlots is dependent
+ // on the order of accesses; we must ensure that we read from m_aModuleIndices
+ // before m_pModuleSlots.
+ if (index.m_dwIndex < m_aModuleIndices)
+ {
+ MemoryBarrier();
+ if (m_pModuleSlots[index.m_dwIndex])
+ {
+ return m_pModuleSlots[index.m_dwIndex]->GetDomainFile();
+ }
+ }
+
+ return NULL;
+ }
+
+ DomainFile* GetDomainFile(SIZE_T ModuleID)
+ {
+ WRAPPER_NO_CONTRACT;
+ ModuleIndex index = Module::IDToIndex(ModuleID);
+ _ASSERTE(index.m_dwIndex < m_aModuleIndices);
+ return m_pModuleSlots[index.m_dwIndex]->GetDomainFile();
+ }
+
+#ifndef DACCESS_COMPILE
+ void SetDomainFile(ModuleIndex index, DomainFile* pDomainFile)
+ {
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(index.m_dwIndex < m_aModuleIndices);
+ m_pModuleSlots[index.m_dwIndex]->SetDomainFile(pDomainFile);
+ }
+#endif
+
+#ifdef DACCESS_COMPILE
+ void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
+#endif
+
+
+private:
+
+ //
+ // Low level routines to get & set class entries
+ //
+
+};
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+
+// The large heap handle bucket class is used to contain handles allocated
+// from an array contained in the large heap.
+class LargeHeapHandleBucket
+{
+public:
+ // Constructor and desctructor.
+ LargeHeapHandleBucket(LargeHeapHandleBucket *pNext, DWORD Size, BaseDomain *pDomain, BOOL bCrossAD = FALSE);
+ ~LargeHeapHandleBucket();
+
+ // This returns the next bucket.
+ LargeHeapHandleBucket *GetNext()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_pNext;
+ }
+
+ // This returns the number of remaining handle slots.
+ DWORD GetNumRemainingHandles()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_ArraySize - m_CurrentPos;
+ }
+
+ void ConsumeRemaining()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_CurrentPos = m_ArraySize;
+ }
+
+ OBJECTREF *TryAllocateEmbeddedFreeHandle();
+
+ // Allocate handles from the bucket.
+ OBJECTREF* AllocateHandles(DWORD nRequested);
+ OBJECTREF* CurrentPos()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pArrayDataPtr + m_CurrentPos;
+ }
+
+private:
+ LargeHeapHandleBucket *m_pNext;
+ int m_ArraySize;
+ int m_CurrentPos;
+ int m_CurrentEmbeddedFreePos;
+ OBJECTHANDLE m_hndHandleArray;
+ OBJECTREF *m_pArrayDataPtr;
+};
+
+
+
+// The large heap handle table is used to allocate handles that are pointers
+// to objects stored in an array in the large object heap.
+class LargeHeapHandleTable
+{
+public:
+ // Constructor and desctructor.
+ LargeHeapHandleTable(BaseDomain *pDomain, DWORD InitialBucketSize);
+ ~LargeHeapHandleTable();
+
+ // Allocate handles from the large heap handle table.
+ OBJECTREF* AllocateHandles(DWORD nRequested, BOOL bCrossAD = FALSE);
+
+ // Release object handles allocated using AllocateHandles().
+ void ReleaseHandles(OBJECTREF *pObjRef, DWORD nReleased);
+
+private:
+ // The buckets of object handles.
+ LargeHeapHandleBucket *m_pHead;
+
+ // We need to know the containing domain so we know where to allocate handles
+ BaseDomain *m_pDomain;
+
+ // The size of the LargeHeapHandleBuckets.
+ DWORD m_NextBucketSize;
+
+ // for finding and re-using embedded free items in the list
+ LargeHeapHandleBucket *m_pFreeSearchHint;
+ DWORD m_cEmbeddedFree;
+
+#ifdef _DEBUG
+
+ // these functions are present to enforce that there is a locking mechanism in place
+ // for each LargeHeapHandleTable even though the code itself does not do the locking
+ // you must tell the table which lock you intend to use and it will verify that it has
+ // in fact been taken before performing any operations
+
+public:
+ void RegisterCrstDebug(CrstBase *pCrst)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ // this function must be called exactly once
+ _ASSERTE(pCrst != NULL);
+ _ASSERTE(m_pCrstDebug == NULL);
+ m_pCrstDebug = pCrst;
+ }
+
+private:
+ // we will assert that this Crst is held before using the object
+ CrstBase *m_pCrstDebug;
+
+#endif
+
+};
+
+class LargeHeapHandleBlockHolder;
+void LargeHeapHandleBlockHolder__StaticFree(LargeHeapHandleBlockHolder*);
+
+
+class LargeHeapHandleBlockHolder:public Holder<LargeHeapHandleBlockHolder*,DoNothing,LargeHeapHandleBlockHolder__StaticFree>
+
+{
+ LargeHeapHandleTable* m_pTable;
+ DWORD m_Count;
+ OBJECTREF* m_Data;
+public:
+ FORCEINLINE LargeHeapHandleBlockHolder(LargeHeapHandleTable* pOwner, DWORD nCount)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_Data = pOwner->AllocateHandles(nCount);
+ m_Count=nCount;
+ m_pTable=pOwner;
+ };
+
+ FORCEINLINE void FreeData()
+ {
+ WRAPPER_NO_CONTRACT;
+ for (DWORD i=0;i< m_Count;i++)
+ ClearObjectReference(m_Data+i);
+ m_pTable->ReleaseHandles(m_Data, m_Count);
+ };
+ FORCEINLINE OBJECTREF* operator[] (DWORD idx)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(idx<m_Count);
+ return &(m_Data[idx]);
+ }
+};
+
+FORCEINLINE void LargeHeapHandleBlockHolder__StaticFree(LargeHeapHandleBlockHolder* pHolder)
+{
+ WRAPPER_NO_CONTRACT;
+ pHolder->FreeData();
+};
+
+
+
+
+
+// The large heap handle bucket class is used to contain handles allocated
+// from an array contained in the large heap.
+class ThreadStaticHandleBucket
+{
+public:
+ // Constructor and desctructor.
+ ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain);
+ ~ThreadStaticHandleBucket();
+
+ // This returns the next bucket.
+ ThreadStaticHandleBucket *GetNext()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_pNext;
+ }
+
+ // Allocate handles from the bucket.
+ OBJECTHANDLE GetHandles();
+
+private:
+ ThreadStaticHandleBucket *m_pNext;
+ int m_ArraySize;
+ OBJECTHANDLE m_hndHandleArray;
+};
+
+
+// The large heap handle table is used to allocate handles that are pointers
+// to objects stored in an array in the large object heap.
+class ThreadStaticHandleTable
+{
+public:
+ // Constructor and desctructor.
+ ThreadStaticHandleTable(BaseDomain *pDomain);
+ ~ThreadStaticHandleTable();
+
+ // Allocate handles from the large heap handle table.
+ OBJECTHANDLE AllocateHandles(DWORD nRequested);
+
+private:
+ // The buckets of object handles.
+ ThreadStaticHandleBucket *m_pHead;
+
+ // We need to know the containing domain so we know where to allocate handles
+ BaseDomain *m_pDomain;
+};
+
+
+
+
+//--------------------------------------------------------------------------------------
+// Base class for domains. It provides an abstract way of finding the first assembly and
+// for creating assemblies in the the domain. The system domain only has one assembly, it
+// contains the classes that are logically shared between domains. All other domains can
+// have multiple assemblies. Iteration is done be getting the first assembly and then
+// calling the Next() method on the assembly.
+//
+// The system domain should be as small as possible, it includes object, exceptions, etc.
+// which are the basic classes required to load other assemblies. All other classes
+// should be loaded into the domain. Of coarse there is a trade off between loading the
+// same classes multiple times, requiring all domains to load certain assemblies (working
+// set) and being able to specify specific versions.
+//
+
+#define LOW_FREQUENCY_HEAP_RESERVE_SIZE (3 * PAGE_SIZE)
+#define LOW_FREQUENCY_HEAP_COMMIT_SIZE (1 * PAGE_SIZE)
+
+#define HIGH_FREQUENCY_HEAP_RESERVE_SIZE (10 * PAGE_SIZE)
+#define HIGH_FREQUENCY_HEAP_COMMIT_SIZE (1 * PAGE_SIZE)
+
+#define STUB_HEAP_RESERVE_SIZE (3 * PAGE_SIZE)
+#define STUB_HEAP_COMMIT_SIZE (1 * PAGE_SIZE)
+
+// --------------------------------------------------------------------------------
+// PE File List lock - for creating list locks on PE files
+// --------------------------------------------------------------------------------
+
+class PEFileListLock : public ListLock
+{
+public:
+#ifndef DACCESS_COMPILE
+ ListLockEntry *FindFileLock(PEFile *pFile)
+ {
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_FORBID_FAULT;
+
+ PRECONDITION(HasLock());
+
+ ListLockEntry *pEntry;
+
+ for (pEntry = m_pHead;
+ pEntry != NULL;
+ pEntry = pEntry->m_pNext)
+ {
+ if (((PEFile *)pEntry->m_pData)->Equals(pFile))
+ {
+ return pEntry;
+ }
+ }
+
+ return NULL;
+ }
+#endif // DACCESS_COMPILE
+
+ DEBUG_NOINLINE static void HolderEnter(PEFileListLock *pThis) PUB
+ {
+ WRAPPER_NO_CONTRACT;
+ ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
+
+ pThis->Enter();
+ }
+
+ DEBUG_NOINLINE static void HolderLeave(PEFileListLock *pThis) PUB
+ {
+ WRAPPER_NO_CONTRACT;
+ ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
+
+ pThis->Leave();
+ }
+
+ typedef Wrapper<PEFileListLock*, PEFileListLock::HolderEnter, PEFileListLock::HolderLeave> Holder;
+};
+
+typedef PEFileListLock::Holder PEFileListLockHolder;
+
+// Loading infrastructure:
+//
+// a DomainFile is a file being loaded. Files are loaded in layers to enable loading in the
+// presence of dependency loops.
+//
+// FileLoadLevel describes the various levels available. These are implemented slightly
+// differently for assemblies and modules, but the basic structure is the same.
+//
+// LoadLock and FileLoadLock form the ListLock data structures for files. The FileLoadLock
+// is specialized in that it allows taking a lock at a particular level. Basicall any
+// thread may obtain the lock at a level at which the file has previously been loaded to, but
+// only one thread may obtain the lock at its current level.
+//
+// The PendingLoadQueue is a per thread data structure which serves two purposes. First, it
+// holds a "load limit" which automatically restricts the level of recursive loads to be
+// one less than the current load which is preceding. This, together with the AppDomain
+// LoadLock level behavior, will prevent any deadlocks from occuring due to circular
+// dependencies. (Note that it is important that the loading logic understands this restriction,
+// and any given level of loading must deal with the fact that any recursive loads will be partially
+// unfulfilled in a specific way.)
+//
+// The second function is to queue up any unfulfilled load requests for the thread. These
+// are then delivered immediately after the current load request is dealt with.
+
+class FileLoadLock : public ListLockEntry
+{
+private:
+ FileLoadLevel m_level;
+ DomainFile *m_pDomainFile;
+ HRESULT m_cachedHR;
+ ADID m_AppDomainId;
+
+public:
+ static FileLoadLock *Create(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile);
+
+ ~FileLoadLock();
+ DomainFile *GetDomainFile();
+ ADID GetAppDomainId();
+ FileLoadLevel GetLoadLevel();
+
+ // CanAcquire will return FALSE if Acquire will definitely not take the lock due
+ // to levels or deadlock.
+ // (Note that there is a race exiting from the function, where Acquire may end
+ // up not taking the lock anyway if another thread did work in the meantime.)
+ BOOL CanAcquire(FileLoadLevel targetLevel);
+
+ // Acquire will return FALSE and not take the lock if the file
+ // has already been loaded to the target level. Otherwise,
+ // it will return TRUE and take the lock.
+ //
+ // Note that the taker must release the lock via IncrementLoadLevel.
+ BOOL Acquire(FileLoadLevel targetLevel);
+
+ // CompleteLoadLevel can be called after Acquire returns true
+ // returns TRUE if it updated load level, FALSE if the level was set already
+ BOOL CompleteLoadLevel(FileLoadLevel level, BOOL success);
+
+ void SetError(Exception *ex);
+
+ void AddRef();
+ UINT32 Release() DAC_EMPTY_RET(0);
+
+private:
+
+ FileLoadLock(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile);
+
+ static void HolderLeave(FileLoadLock *pThis);
+
+public:
+ typedef Wrapper<FileLoadLock *, DoNothing, FileLoadLock::HolderLeave> Holder;
+
+};
+
+typedef FileLoadLock::Holder FileLoadLockHolder;
+
+#ifndef DACCESS_COMPILE
+ typedef ReleaseHolder<FileLoadLock> FileLoadLockRefHolder;
+#endif // DACCESS_COMPILE
+
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning (disable: 4324) //sometimes 64bit compilers complain about alignment
+#endif
+class LoadLevelLimiter
+{
+ FileLoadLevel m_currentLevel;
+ LoadLevelLimiter* m_previousLimit;
+ BOOL m_bActive;
+
+public:
+
+ LoadLevelLimiter()
+ : m_currentLevel(FILE_ACTIVE),
+ m_previousLimit(NULL),
+ m_bActive(FALSE)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+
+ void Activate()
+ {
+ WRAPPER_NO_CONTRACT;
+ m_previousLimit=GetThread()->GetLoadLevelLimiter();
+ if(m_previousLimit)
+ m_currentLevel=m_previousLimit->GetLoadLevel();
+ GetThread()->SetLoadLevelLimiter(this);
+ m_bActive=TRUE;
+ }
+
+ void Deactivate()
+ {
+ WRAPPER_NO_CONTRACT;
+ if (m_bActive)
+ {
+ GetThread()->SetLoadLevelLimiter(m_previousLimit);
+ m_bActive=FALSE;
+ }
+ }
+
+ ~LoadLevelLimiter()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ // PendingLoadQueues are allocated on the stack during a load, and
+ // shared with all nested loads on the same thread.
+
+ // Make sure the thread pointer gets reset after the
+ // top level queue goes out of scope.
+ if(m_bActive)
+ {
+ Deactivate();
+ }
+ }
+
+ FileLoadLevel GetLoadLevel()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_currentLevel;
+ }
+
+ void SetLoadLevel(FileLoadLevel level)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_currentLevel = level;
+ }
+};
+#ifdef _MSC_VER
+#pragma warning (pop) //4324
+#endif
+
+#define OVERRIDE_LOAD_LEVEL_LIMIT(newLimit) \
+ LoadLevelLimiter __newLimit; \
+ __newLimit.Activate(); \
+ __newLimit.SetLoadLevel(newLimit);
+
+// A BaseDomain much basic information in a code:AppDomain including
+//
+// * code:#AppdomainHeaps - Heaps for any data structures that will be freed on appdomain unload
+//
+class BaseDomain
+{
+ friend class Assembly;
+ friend class AssemblySpec;
+ friend class AppDomain;
+ friend class AppDomainNative;
+
+ VPTR_BASE_VTABLE_CLASS(BaseDomain)
+ VPTR_UNIQUE(VPTR_UNIQUE_BaseDomain)
+
+protected:
+ // These 2 variables are only used on the AppDomain, but by placing them here
+ // we reduce the cost of keeping the asmconstants file up to date.
+
+ // The creation sequence number of this app domain (starting from 1)
+ // This ID is generated by the code:SystemDomain::GetNewAppDomainId routine
+ // The ID are recycled.
+ //
+ // see also code:ADID
+ ADID m_dwId;
+
+ DomainLocalBlock m_sDomainLocalBlock;
+
+public:
+
+ class AssemblyIterator;
+ friend class AssemblyIterator;
+
+ // Static initialization.
+ static void Attach();
+
+ //****************************************************************************************
+ //
+ // Initialization/shutdown routines for every instance of an BaseDomain.
+
+ BaseDomain();
+ virtual ~BaseDomain() {}
+ void Init();
+ void Stop();
+ void Terminate();
+
+ // ID to uniquely identify this AppDomain - used by the AppDomain publishing
+ // service (to publish the list of all appdomains present in the process),
+ // which in turn is used by, for eg., the debugger (to decide which App-
+ // Domain(s) to attach to).
+ // This is also used by Remoting for routing cross-appDomain calls.
+ ADID GetId (void)
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ return m_dwId;
+ }
+
+ virtual BOOL IsAppDomain() { LIMITED_METHOD_DAC_CONTRACT; return FALSE; }
+ virtual BOOL IsSharedDomain() { LIMITED_METHOD_DAC_CONTRACT; return FALSE; }
+
+ inline BOOL IsDefaultDomain(); // defined later in this file
+ virtual PTR_LoaderAllocator GetLoaderAllocator() = 0;
+ virtual PTR_AppDomain AsAppDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ _ASSERTE(!"Not an AppDomain");
+ return NULL;
+ }
+
+
+ // If one domain is the SharedDomain and one is an AppDomain then
+ // return the AppDomain, i.e. return the domain with the shorter lifetime
+ // of the two given domains.
+ static PTR_BaseDomain ComputeBaseDomain(
+ BaseDomain *pGenericDefinitionDomain, // the domain that owns the generic type or method
+ Instantiation classInst, // the type arguments to the type (if any)
+ Instantiation methodInst = Instantiation()); // the type arguments to the method (if any)
+
+ static PTR_BaseDomain ComputeBaseDomain(TypeKey * pTypeKey);
+
+#ifdef FEATURE_COMINTEROP
+ //****************************************************************************************
+ //
+ // This will look up interop data for a method table
+ //
+
+#ifndef DACCESS_COMPILE
+ // Returns the data pointer if present, NULL otherwise
+ InteropMethodTableData *LookupComInteropData(MethodTable *pMT)
+ {
+ // Take the lock
+ CrstHolder holder(&m_InteropDataCrst);
+
+ // Lookup
+ InteropMethodTableData *pData = (InteropMethodTableData*) m_interopDataHash.LookupValue((UPTR) pMT, (LPVOID) NULL);
+
+ // Not there...
+ if (pData == (InteropMethodTableData*) INVALIDENTRY)
+ return NULL;
+
+ // Found it
+ return pData;
+ }
+
+ // Returns TRUE if successfully inserted, FALSE if this would be a duplicate entry
+ BOOL InsertComInteropData(MethodTable* pMT, InteropMethodTableData *pData)
+ {
+ // We don't keep track of this kind of information for interfaces
+ _ASSERTE(!pMT->IsInterface());
+
+ // Take the lock
+ CrstHolder holder(&m_InteropDataCrst);
+
+ // Check to see that it's not already in there
+ InteropMethodTableData *pDupData = (InteropMethodTableData*) m_interopDataHash.LookupValue((UPTR) pMT, (LPVOID) NULL);
+ if (pDupData != (InteropMethodTableData*) INVALIDENTRY)
+ return FALSE;
+
+ // Not in there, so insert
+ m_interopDataHash.InsertValue((UPTR) pMT, (LPVOID) pData);
+
+ // Success
+ return TRUE;
+ }
+#endif // DACCESS_COMPILE
+#endif // FEATURE_COMINTEROP
+
+ void SetDisableInterfaceCache()
+ {
+ m_fDisableInterfaceCache = TRUE;
+ }
+ BOOL GetDisableInterfaceCache()
+ {
+ return m_fDisableInterfaceCache;
+ }
+
+#ifdef FEATURE_COMINTEROP
+ MngStdInterfacesInfo * GetMngStdInterfacesInfo()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_pMngStdInterfacesInfo;
+ }
+
+ PTR_CLRPrivBinderWinRT GetWinRtBinder()
+ {
+ return m_pWinRtBinder;
+ }
+#endif // FEATURE_COMINTEROP
+
+ //****************************************************************************************
+ // This method returns marshaling data that the EE uses that is stored on a per app domain
+ // basis.
+ EEMarshalingData *GetMarshalingData();
+
+ // Deletes marshaling data at shutdown (which contains cached factories that needs to be released)
+ void DeleteMarshalingData();
+
+#ifdef _DEBUG
+ BOOL OwnDomainLocalBlockLock()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ return m_DomainLocalBlockCrst.OwnedByCurrentThread();
+ }
+#endif
+
+ //****************************************************************************************
+ // Get the class init lock. The method is limited to friends because inappropriate use
+ // will cause deadlocks in the system
+ ListLock* GetClassInitLock()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return &m_ClassInitLock;
+ }
+
+ ListLock* GetJitLock()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return &m_JITLock;
+ }
+
+ ListLock* GetILStubGenLock()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return &m_ILStubGenLock;
+ }
+
+ STRINGREF *IsStringInterned(STRINGREF *pString);
+ STRINGREF *GetOrInternString(STRINGREF *pString);
+
+ virtual BOOL CanUnload() { LIMITED_METHOD_CONTRACT; return FALSE; } // can never unload BaseDomain
+
+ // Returns an array of OBJECTREF* that can be used to store domain specific data.
+ // Statics and reflection info (Types, MemberInfo,..) are stored this way
+ // If ppLazyAllocate != 0, allocation will only take place if *ppLazyAllocate != 0 (and the allocation
+ // will be properly serialized)
+ OBJECTREF *AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate = NULL, BOOL bCrossAD = FALSE);
+
+#ifdef FEATURE_PREJIT
+ // Ensures that the file for logging profile data is open (we only open it once)
+ // return false on failure
+ static BOOL EnsureNGenLogFileOpen();
+#endif
+
+ //****************************************************************************************
+ // Handles
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) // needs GetCurrentThreadHomeHeapNumber
+ OBJECTHANDLE CreateTypedHandle(OBJECTREF object, int type)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ::CreateTypedHandle(m_hHandleTableBucket->pTable[GetCurrentThreadHomeHeapNumber()], object, type);
+ }
+
+ OBJECTHANDLE CreateHandle(OBJECTREF object)
+ {
+ WRAPPER_NO_CONTRACT;
+ CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL)
+ return ::CreateHandle(m_hHandleTableBucket->pTable[GetCurrentThreadHomeHeapNumber()], object);
+ }
+
+ OBJECTHANDLE CreateWeakHandle(OBJECTREF object)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ::CreateWeakHandle(m_hHandleTableBucket->pTable[GetCurrentThreadHomeHeapNumber()], object);
+ }
+
+ OBJECTHANDLE CreateShortWeakHandle(OBJECTREF object)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ::CreateShortWeakHandle(m_hHandleTableBucket->pTable[GetCurrentThreadHomeHeapNumber()], object);
+ }
+
+ OBJECTHANDLE CreateLongWeakHandle(OBJECTREF object)
+ {
+ WRAPPER_NO_CONTRACT;
+ CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL)
+ return ::CreateLongWeakHandle(m_hHandleTableBucket->pTable[GetCurrentThreadHomeHeapNumber()], object);
+ }
+
+ OBJECTHANDLE CreateStrongHandle(OBJECTREF object)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ::CreateStrongHandle(m_hHandleTableBucket->pTable[GetCurrentThreadHomeHeapNumber()], object);
+ }
+
+ OBJECTHANDLE CreatePinningHandle(OBJECTREF object)
+ {
+ WRAPPER_NO_CONTRACT;
+#if CHECK_APP_DOMAIN_LEAKS
+ if(IsAppDomain())
+ object->TryAssignAppDomain((AppDomain*)this,TRUE);
+#endif
+ return ::CreatePinningHandle(m_hHandleTableBucket->pTable[GetCurrentThreadHomeHeapNumber()], object);
+ }
+
+ OBJECTHANDLE CreateSizedRefHandle(OBJECTREF object)
+ {
+ WRAPPER_NO_CONTRACT;
+ OBJECTHANDLE h = ::CreateSizedRefHandle(
+ m_hHandleTableBucket->pTable[GCHeap::IsServerHeap() ? (m_dwSizedRefHandles % m_iNumberOfProcessors) : GetCurrentThreadHomeHeapNumber()],
+ object);
+ InterlockedIncrement((LONG*)&m_dwSizedRefHandles);
+ return h;
+ }
+
+#ifdef FEATURE_COMINTEROP
+ OBJECTHANDLE CreateRefcountedHandle(OBJECTREF object)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ::CreateRefcountedHandle(m_hHandleTableBucket->pTable[GetCurrentThreadHomeHeapNumber()], object);
+ }
+
+ OBJECTHANDLE CreateWinRTWeakHandle(OBJECTREF object, IWeakReference* pWinRTWeakReference)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ return ::CreateWinRTWeakHandle(m_hHandleTableBucket->pTable[GetCurrentThreadHomeHeapNumber()], object, pWinRTWeakReference);
+ }
+#endif // FEATURE_COMINTEROP
+
+ OBJECTHANDLE CreateVariableHandle(OBJECTREF object, UINT type)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ::CreateVariableHandle(m_hHandleTableBucket->pTable[GetCurrentThreadHomeHeapNumber()], object, type);
+ }
+
+ OBJECTHANDLE CreateDependentHandle(OBJECTREF primary, OBJECTREF secondary)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ::CreateDependentHandle(m_hHandleTableBucket->pTable[GetCurrentThreadHomeHeapNumber()], primary, secondary);
+ }
+#endif // DACCESS_COMPILE && !CROSSGEN_COMPILE
+
+ BOOL ContainsOBJECTHANDLE(OBJECTHANDLE handle);
+
+#ifdef FEATURE_FUSION
+ IApplicationContext *GetFusionContext() {LIMITED_METHOD_CONTRACT; return m_pFusionContext; }
+#else
+ IUnknown *GetFusionContext() {LIMITED_METHOD_CONTRACT; return m_pFusionContext; }
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+ CLRPrivBinderCoreCLR *GetTPABinderContext() {LIMITED_METHOD_CONTRACT; return m_pTPABinderContext; }
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+
+#endif
+
+ CrstExplicitInit * GetLoaderAllocatorReferencesLock()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return &m_crstLoaderAllocatorReferences;
+ }
+
+protected:
+
+ //****************************************************************************************
+ // Helper method to initialize the large heap handle table.
+ void InitLargeHeapHandleTable();
+
+ //****************************************************************************************
+ // Adds an assembly to the domain.
+ void AddAssemblyNoLock(Assembly* assem);
+
+ //****************************************************************************************
+ //
+ // Hash table that maps a MethodTable to COM Interop compatibility data.
+ PtrHashMap m_interopDataHash;
+
+ // Critical sections & locks
+ PEFileListLock m_FileLoadLock; // Protects the list of assemblies in the domain
+ CrstExplicitInit m_DomainCrst; // General Protection for the Domain
+ CrstExplicitInit m_DomainCacheCrst; // Protects the Assembly and Unmanaged caches
+ CrstExplicitInit m_DomainLocalBlockCrst;
+ CrstExplicitInit m_InteropDataCrst; // Used for COM Interop compatiblilty
+ // Used to protect the reference lists in the collectible loader allocators attached to this appdomain
+ CrstExplicitInit m_crstLoaderAllocatorReferences;
+ CrstExplicitInit m_WinRTFactoryCacheCrst; // For WinRT factory cache
+
+ //#AssemblyListLock
+ // Used to protect the assembly list. Taken also by GC or debugger thread, therefore we have to avoid
+ // triggering GC while holding this lock (by switching the thread to GC_NOTRIGGER while it is held).
+ CrstExplicitInit m_crstAssemblyList;
+ BOOL m_fDisableInterfaceCache; // RCW COM interface cache
+ ListLock m_ClassInitLock;
+ ListLock m_JITLock;
+ ListLock m_ILStubGenLock;
+
+ // Fusion context, used for adding assemblies to the is domain. It defines
+ // fusion properties for finding assemblyies such as SharedBinPath,
+ // PrivateBinPath, Application Directory, etc.
+#ifdef FEATURE_FUSION
+ IApplicationContext* m_pFusionContext; // Binding context for the domain
+#else
+ IUnknown *m_pFusionContext; // Current binding context for the domain
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+ CLRPrivBinderCoreCLR *m_pTPABinderContext; // Reference to the binding context that holds TPA list details
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+
+#endif
+
+ HandleTableBucket *m_hHandleTableBucket;
+
+ // The large heap handle table.
+ LargeHeapHandleTable *m_pLargeHeapHandleTable;
+
+ // The large heap handle table critical section.
+ CrstExplicitInit m_LargeHeapHandleTableCrst;
+
+ EEMarshalingData *m_pMarshalingData;
+
+#ifdef FEATURE_COMINTEROP
+ // Information regarding the managed standard interfaces.
+ MngStdInterfacesInfo *m_pMngStdInterfacesInfo;
+
+ // WinRT binder (only in classic = non-AppX; AppX has the WinRT binder inside code:CLRPrivBinderAppX)
+ PTR_CLRPrivBinderWinRT m_pWinRtBinder;
+#endif // FEATURE_COMINTEROP
+
+ // Number of allocated slots for context local statics of this domain
+ DWORD m_dwContextStatics;
+
+ // Protects allocation of slot IDs for thread and context statics
+ static CrstStatic m_SpecialStaticsCrst;
+
+public:
+ // Lazily allocate offset for context static
+ DWORD AllocateContextStaticsOffset(DWORD* pOffsetSlot);
+
+public:
+ // Only call this routine when you can guarantee there are no
+ // loads in progress.
+ void ClearFusionContext();
+
+public:
+
+ //****************************************************************************************
+ // Synchronization holders.
+
+ class LockHolder : public CrstHolder
+ {
+ public:
+ LockHolder(BaseDomain *pD)
+ : CrstHolder(&pD->m_DomainCrst)
+ {
+ WRAPPER_NO_CONTRACT;
+ }
+ };
+ friend class LockHolder;
+
+ class CacheLockHolder : public CrstHolder
+ {
+ public:
+ CacheLockHolder(BaseDomain *pD)
+ : CrstHolder(&pD->m_DomainCacheCrst)
+ {
+ WRAPPER_NO_CONTRACT;
+ }
+ };
+ friend class CacheLockHolder;
+
+ class DomainLocalBlockLockHolder : public CrstHolder
+ {
+ public:
+ DomainLocalBlockLockHolder(BaseDomain *pD)
+ : CrstHolder(&pD->m_DomainLocalBlockCrst)
+ {
+ WRAPPER_NO_CONTRACT;
+ }
+ };
+ friend class DomainLocalBlockLockHolder;
+
+ class LoadLockHolder : public PEFileListLockHolder
+ {
+ public:
+ LoadLockHolder(BaseDomain *pD, BOOL Take = TRUE)
+ : PEFileListLockHolder(&pD->m_FileLoadLock, Take)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ CAN_TAKE_LOCK;
+ }
+ CONTRACTL_END;
+ }
+ };
+ friend class LoadLockHolder;
+ class WinRTFactoryCacheLockHolder : public CrstHolder
+ {
+ public:
+ WinRTFactoryCacheLockHolder(BaseDomain *pD)
+ : CrstHolder(&pD->m_WinRTFactoryCacheCrst)
+ {
+ WRAPPER_NO_CONTRACT;
+ }
+ };
+ friend class WinRTFactoryCacheLockHolder;
+
+public:
+ void InitVSD();
+ RangeList *GetCollectibleVSDRanges() { return &m_collVSDRanges; }
+
+private:
+ TypeIDMap m_typeIDMap;
+ // Range list for collectible types. Maps VSD PCODEs back to the VirtualCallStubManager they belong to
+ LockedRangeList m_collVSDRanges;
+
+public:
+ UINT32 GetTypeID(PTR_MethodTable pMT);
+ UINT32 LookupTypeID(PTR_MethodTable pMT);
+ PTR_MethodTable LookupType(UINT32 id);
+
+private:
+ // I have yet to figure out an efficent way to get the number of handles
+ // of a particular type that's currently used by the process without
+ // spending more time looking at the handle table code. We know that
+ // our only customer (asp.net) in Dev10 is not going to create many of
+ // these handles so I am taking a shortcut for now and keep the sizedref
+ // handle count on the AD itself.
+ DWORD m_dwSizedRefHandles;
+
+ static int m_iNumberOfProcessors;
+
+public:
+ // Called by DestroySizedRefHandle
+ void DecNumSizedRefHandles()
+ {
+ WRAPPER_NO_CONTRACT;
+ LONG result;
+ result = InterlockedDecrement((LONG*)&m_dwSizedRefHandles);
+ _ASSERTE(result >= 0);
+ }
+
+ DWORD GetNumSizedRefHandles()
+ {
+ return m_dwSizedRefHandles;
+ }
+
+ // Profiler rejit
+private:
+ ReJitManager m_reJitMgr;
+
+public:
+ ReJitManager * GetReJitManager() { return &m_reJitMgr; }
+
+#ifdef DACCESS_COMPILE
+public:
+ virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
+ bool enumThis);
+#endif
+
+}; // class BaseDomain
+
+enum
+{
+ ATTACH_ASSEMBLY_LOAD = 0x1,
+ ATTACH_MODULE_LOAD = 0x2,
+ ATTACH_CLASS_LOAD = 0x4,
+
+ ATTACH_ALL = 0x7
+};
+
+class ADUnloadSink
+{
+
+protected:
+ ~ADUnloadSink();
+ CLREvent m_UnloadCompleteEvent;
+ HRESULT m_UnloadResult;
+ Volatile<LONG> m_cRef;
+public:
+ ADUnloadSink();
+ void ReportUnloadResult (HRESULT hr, OBJECTREF* pException);
+ void WaitUnloadCompletion();
+ HRESULT GetUnloadResult() {LIMITED_METHOD_CONTRACT; return m_UnloadResult;};
+ void Reset();
+ ULONG AddRef();
+ ULONG Release();
+};
+
+
+FORCEINLINE void ADUnloadSink__Release(ADUnloadSink* pADSink)
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (pADSink)
+ pADSink->Release();
+}
+
+typedef Wrapper <ADUnloadSink*,DoNothing,ADUnloadSink__Release,NULL> ADUnloadSinkHolder;
+
+// This filters the output of IterateAssemblies. This ought to be declared more locally
+// but it would result in really verbose callsites.
+//
+// Assemblies can be categorized by their load status (loaded, loading, or loaded just
+// enough that they would be made available to profilers)
+// Independently, they can also be categorized as execution or introspection.
+//
+// An assembly will be included in the results of IterateAssemblies only if
+// the appropriate bit is set for *both* characterizations.
+//
+// The flags can be combined so if you want all loaded assemblies, you must specify:
+//
+/// kIncludeLoaded|kIncludeExecution|kIncludeIntrospection
+
+enum AssemblyIterationFlags
+{
+ // load status flags
+ kIncludeLoaded = 0x00000001, // include assemblies that are already loaded
+ // (m_level >= code:FILE_LOAD_DELIVER_EVENTS)
+ kIncludeLoading = 0x00000002, // include assemblies that are still in the process of loading
+ // (all m_level values)
+ kIncludeAvailableToProfilers
+ = 0x00000020, // include assemblies available to profilers
+ // See comment at code:DomainFile::IsAvailableToProfilers
+
+ // Execution / introspection flags
+ kIncludeExecution = 0x00000004, // include assemblies that are loaded for execution only
+ kIncludeIntrospection = 0x00000008, // include assemblies that are loaded for introspection only
+
+ kIncludeFailedToLoad = 0x00000010, // include assemblies that failed to load
+
+ // Collectible assemblies flags
+ kExcludeCollectible = 0x00000040, // Exclude all collectible assemblies
+ kIncludeCollected = 0x00000080,
+ // Include assemblies which were collected and cannot be referenced anymore. Such assemblies are not
+ // AddRef-ed. Any manipulation with them should be protected by code:GetAssemblyListLock.
+ // Should be used only by code:LoaderAllocator::GCLoaderAllocators.
+
+}; // enum AssemblyIterationFlags
+
+//---------------------------------------------------------------------------------------
+//
+// Base class for holder code:CollectibleAssemblyHolder (see code:HolderBase).
+// Manages AddRef/Release for collectible assemblies. It is no-op for 'normal' non-collectible assemblies.
+//
+// Each type of type parameter needs 2 methods implemented:
+// code:CollectibleAssemblyHolderBase::GetLoaderAllocator
+// code:CollectibleAssemblyHolderBase::IsCollectible
+//
+template<typename _Type>
+class CollectibleAssemblyHolderBase
+{
+protected:
+ _Type m_value;
+public:
+ CollectibleAssemblyHolderBase(const _Type & value = NULL)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_value = value;
+ }
+ void DoAcquire()
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // We don't need to keep the assembly alive in DAC - see code:#CAH_DAC
+#ifndef DACCESS_COMPILE
+ if (this->IsCollectible(m_value))
+ {
+ LoaderAllocator * pLoaderAllocator = GetLoaderAllocator(m_value);
+ pLoaderAllocator->AddReference();
+ }
+#endif //!DACCESS_COMPILE
+ }
+ void DoRelease()
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+#ifndef DACCESS_COMPILE
+ if (this->IsCollectible(m_value))
+ {
+ LoaderAllocator * pLoaderAllocator = GetLoaderAllocator(m_value);
+ pLoaderAllocator->Release();
+ }
+#endif //!DACCESS_COMPILE
+ }
+
+private:
+ LoaderAllocator * GetLoaderAllocator(DomainAssembly * pDomainAssembly)
+ {
+ WRAPPER_NO_CONTRACT;
+ return pDomainAssembly->GetLoaderAllocator();
+ }
+ BOOL IsCollectible(DomainAssembly * pDomainAssembly)
+ {
+ WRAPPER_NO_CONTRACT;
+ return pDomainAssembly->IsCollectible();
+ }
+ LoaderAllocator * GetLoaderAllocator(Assembly * pAssembly)
+ {
+ WRAPPER_NO_CONTRACT;
+ return pAssembly->GetLoaderAllocator();
+ }
+ BOOL IsCollectible(Assembly * pAssembly)
+ {
+ WRAPPER_NO_CONTRACT;
+ return pAssembly->IsCollectible();
+ }
+}; // class CollectibleAssemblyHolderBase<>
+
+//---------------------------------------------------------------------------------------
+//
+// Holder of assembly reference which keeps collectible assembly alive while the holder is valid.
+//
+// Collectible assembly can be collected at any point when GC happens. Almost instantly all native data
+// structures of the assembly (e.g. code:DomainAssembly, code:Assembly) could be deallocated.
+// Therefore any usage of (collectible) assembly data structures from native world, has to prevent the
+// deallocation by increasing ref-count on the assembly / associated loader allocator.
+//
+// #CAH_DAC
+// In DAC we don't AddRef/Release as the assembly doesn't have to be kept alive: The process is stopped when
+// DAC is used and therefore the assembly cannot just disappear.
+//
+template<typename _Type>
+class CollectibleAssemblyHolder : public BaseWrapper<_Type, CollectibleAssemblyHolderBase<_Type> >
+{
+public:
+ FORCEINLINE
+ CollectibleAssemblyHolder(const _Type & value = NULL, BOOL fTake = TRUE)
+ : BaseWrapper<_Type, CollectibleAssemblyHolderBase<_Type> >(value, fTake)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ }
+
+ FORCEINLINE
+ CollectibleAssemblyHolder &
+ operator=(const _Type & value)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ BaseWrapper<_Type, CollectibleAssemblyHolderBase<_Type> >::operator=(value);
+ return *this;
+ }
+
+ // Operator & is overloaded in parent, therefore we have to get to 'this' pointer explicitly.
+ FORCEINLINE
+ CollectibleAssemblyHolder<_Type> *
+ This()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return this;
+ }
+}; // class CollectibleAssemblyHolder<>
+
+//---------------------------------------------------------------------------------------
+//
+#ifdef FEATURE_LOADER_OPTIMIZATION
+class SharedAssemblyLocator
+{
+public:
+ enum
+ {
+ DOMAINASSEMBLY = 1,
+ PEASSEMBLY = 2,
+ PEASSEMBLYEXACT = 3
+ };
+ DWORD GetType() {LIMITED_METHOD_CONTRACT; return m_type;};
+#ifndef DACCESS_COMPILE
+ DomainAssembly* GetDomainAssembly() {LIMITED_METHOD_CONTRACT; _ASSERTE(m_type==DOMAINASSEMBLY); return (DomainAssembly*)m_value;};
+ PEAssembly* GetPEAssembly() {LIMITED_METHOD_CONTRACT; _ASSERTE(m_type==PEASSEMBLY||m_type==PEASSEMBLYEXACT); return (PEAssembly*)m_value;};
+ SharedAssemblyLocator(DomainAssembly* pAssembly)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_type=DOMAINASSEMBLY;
+ m_value=pAssembly;
+ }
+ SharedAssemblyLocator(PEAssembly* pFile, DWORD type = PEASSEMBLY)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_type = type;
+ m_value = pFile;
+ }
+#endif // DACCESS_COMPILE
+
+ DWORD Hash();
+protected:
+ DWORD m_type;
+ LPVOID m_value;
+#if FEATURE_VERSIONING
+ ULONG m_uIdentityHash;
+#endif
+};
+#endif // FEATURE_LOADER_OPTIMIZATION
+
+//
+// Stores binding information about failed assembly loads for DAC
+//
+struct FailedAssembly {
+ SString displayName;
+ SString location;
+#ifdef FEATURE_FUSION
+ LOADCTX_TYPE context;
+#endif
+ HRESULT error;
+
+ void Initialize(AssemblySpec *pSpec, Exception *ex)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ displayName.SetASCII(pSpec->GetName());
+ location.Set(pSpec->GetCodeBase());
+ error = ex->GetHR();
+
+ //
+ // Determine the binding context assembly would have been in.
+ // If the parent has been set, use its binding context.
+ // If the parent hasn't been set but the code base has, use LoadFrom.
+ // Otherwise, use the default.
+ //
+#ifdef FEATURE_FUSION
+ context = pSpec->GetParentIAssembly() ? pSpec->GetParentIAssembly()->GetFusionLoadContext() : LOADCTX_TYPE_LOADFROM;
+#endif // FEATURE_FUSION
+ }
+};
+
+#ifdef FEATURE_COMINTEROP
+
+// Cache used by COM Interop
+struct NameToTypeMapEntry
+{
+ // Host space representation of the key
+ struct Key
+ {
+ LPCWSTR m_wzName; // The type name or registry string representation of the GUID "{<guid>}"
+ SIZE_T m_cchName; // wcslen(m_wzName) for faster hashtable lookup
+ };
+ struct DacKey
+ {
+ PTR_CWSTR m_wzName; // The type name or registry string representation of the GUID "{<guid>}"
+ SIZE_T m_cchName; // wcslen(m_wzName) for faster hashtable lookup
+ } m_key;
+ TypeHandle m_typeHandle; // Using TypeHandle instead of MethodTable* to avoid losing information when sharing method tables.
+ UINT m_nEpoch; // tracks creation Epoch. This is incremented each time an external reader enumerate the cache
+ BYTE m_bFlags;
+};
+
+typedef DPTR(NameToTypeMapEntry) PTR_NameToTypeMapEntry;
+
+class NameToTypeMapTraits : public NoRemoveSHashTraits< DefaultSHashTraits<NameToTypeMapEntry> >
+{
+public:
+ typedef NameToTypeMapEntry::Key key_t;
+
+ static const NameToTypeMapEntry Null() { NameToTypeMapEntry e; e.m_key.m_wzName = NULL; e.m_key.m_cchName = 0; return e; }
+ static bool IsNull(const NameToTypeMapEntry &e) { return e.m_key.m_wzName == NULL; }
+ static const key_t GetKey(const NameToTypeMapEntry &e)
+ {
+ key_t key;
+ key.m_wzName = (LPCWSTR)(e.m_key.m_wzName); // this cast brings the string over to the host, in a DAC build
+ key.m_cchName = e.m_key.m_cchName;
+
+ return key;
+ }
+ static count_t Hash(const key_t &key) { WRAPPER_NO_CONTRACT; return HashStringN(key.m_wzName, key.m_cchName); }
+
+ static BOOL Equals(const key_t &lhs, const key_t &rhs)
+ {
+ WRAPPER_NO_CONTRACT;
+ return (lhs.m_cchName == rhs.m_cchName) && memcmp(lhs.m_wzName, rhs.m_wzName, lhs.m_cchName * sizeof(WCHAR)) == 0;
+ }
+
+ void OnDestructPerEntryCleanupAction(const NameToTypeMapEntry& e)
+ {
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(e.m_key.m_cchName == wcslen(e.m_key.m_wzName));
+#ifndef DACCESS_COMPILE
+ delete [] e.m_key.m_wzName;
+#endif // DACCESS_COMPILE
+ }
+ static const bool s_DestructPerEntryCleanupAction = true;
+};
+
+typedef SHash<NameToTypeMapTraits> NameToTypeMapTable;
+
+typedef DPTR(NameToTypeMapTable) PTR_NameToTypeMapTable;
+
+struct WinRTFactoryCacheEntry
+{
+ typedef MethodTable *Key;
+ Key key; // Type as KEY
+
+ CtxEntry *m_pCtxEntry; // Context entry - used to verify whether the cache is a match
+ OBJECTHANDLE m_ohFactoryObject; // Handle to factory object
+};
+
+class WinRTFactoryCacheTraits : public DefaultSHashTraits<WinRTFactoryCacheEntry>
+{
+public:
+ typedef WinRTFactoryCacheEntry::Key key_t;
+ static const WinRTFactoryCacheEntry Null() { WinRTFactoryCacheEntry e; e.key = NULL; return e; }
+ static bool IsNull(const WinRTFactoryCacheEntry &e) { return e.key == NULL; }
+ static const WinRTFactoryCacheEntry::Key GetKey(const WinRTFactoryCacheEntry& e) { return e.key; }
+ static count_t Hash(WinRTFactoryCacheEntry::Key key) { return (count_t)((size_t)key); }
+ static BOOL Equals(WinRTFactoryCacheEntry::Key lhs, WinRTFactoryCacheEntry::Key rhs)
+ { return lhs == rhs; }
+ static const WinRTFactoryCacheEntry Deleted() { WinRTFactoryCacheEntry e; e.key = (MethodTable *)-1; return e; }
+ static bool IsDeleted(const WinRTFactoryCacheEntry &e) { return e.key == (MethodTable *)-1; }
+
+ static void OnDestructPerEntryCleanupAction(const WinRTFactoryCacheEntry& e);
+ static const bool s_DestructPerEntryCleanupAction = true;
+};
+
+typedef SHash<WinRTFactoryCacheTraits> WinRTFactoryCache;
+
+#endif // FEATURE_COMINTEROP
+
+class AppDomainIterator;
+
+const DWORD DefaultADID = 1;
+
+template <class AppDomainType> class AppDomainCreationHolder;
+
+// An Appdomain is the managed equivalent of a process. It is an isolation unit (conceptually you don't
+// have pointers directly from one appdomain to another, but rather go through remoting proxies). It is
+// also a unit of unloading.
+//
+// Threads are always running in the context of a particular AppDomain. See
+// file:threads.h#RuntimeThreadLocals for more details.
+//
+// see code:BaseDomain for much of the meat of a AppDomain (heaps locks, etc)
+// * code:AppDomain.m_Assemblies - is a list of code:Assembly in the appdomain
+//
+class AppDomain : public BaseDomain
+{
+ friend class ADUnloadSink;
+ friend class SystemDomain;
+ friend class AssemblySink;
+ friend class AppDomainNative;
+ friend class AssemblyNative;
+ friend class AssemblySpec;
+ friend class ClassLoader;
+ friend class ThreadNative;
+ friend class RCWCache;
+ friend class ClrDataAccess;
+ friend class CheckAsmOffsets;
+ friend class AppDomainFromIDHolder;
+
+ VPTR_VTABLE_CLASS(AppDomain, BaseDomain)
+
+public:
+#ifndef DACCESS_COMPILE
+ AppDomain();
+ virtual ~AppDomain();
+#endif
+ static void DoADUnloadWork();
+ DomainAssembly* FindDomainAssembly(Assembly*);
+ void EnterContext(Thread* pThread, Context* pCtx,ContextTransitionFrame *pFrame);
+
+#ifndef DACCESS_COMPILE
+ //-----------------------------------------------------------------------------------------------------------------
+ // Convenience wrapper for ::GetAppDomain to provide better encapsulation.
+ static AppDomain * GetCurrentDomain()
+ { return ::GetAppDomain(); }
+#endif //!DACCESS_COMPILE
+
+ //-----------------------------------------------------------------------------------------------------------------
+ // Initializes an AppDomain. (this functions is not called from the SystemDomain)
+ void Init();
+
+ // creates only unamaged part
+ static void CreateUnmanagedObject(AppDomainCreationHolder<AppDomain>& result);
+ inline void SetAppDomainManagerInfo(LPCWSTR szAssemblyName, LPCWSTR szTypeName, EInitializeNewDomainFlags dwInitializeDomainFlags);
+ inline BOOL HasAppDomainManagerInfo();
+ inline LPCWSTR GetAppDomainManagerAsm();
+ inline LPCWSTR GetAppDomainManagerType();
+ inline EInitializeNewDomainFlags GetAppDomainManagerInitializeNewDomainFlags();
+
+#ifndef FEATURE_CORECLR
+ inline BOOL AppDomainManagerSetFromConfig();
+ Assembly *GetAppDomainManagerEntryAssembly();
+ void ComputeTargetFrameworkName();
+#endif // FEATURE_CORECLR
+
+#if defined(FEATURE_CORECLR) && defined(FEATURE_COMINTEROP)
+ HRESULT SetWinrtApplicationContext(SString &appLocalWinMD);
+#endif // FEATURE_CORECLR && FEATURE_COMINTEROP
+
+ BOOL CanReversePInvokeEnter();
+ void SetReversePInvokeCannotEnter();
+ bool MustForceTrivialWaitOperations();
+ void SetForceTrivialWaitOperations();
+
+ //****************************************************************************************
+ //
+ // Stop deletes all the assemblies but does not remove other resources like
+ // the critical sections
+ void Stop();
+
+ // Gets rid of resources
+ void Terminate();
+
+#ifdef FEATURE_PREJIT
+ //assembly cleanup that requires suspended runtime
+ void DeleteNativeCodeRanges();
+#endif
+
+ // final assembly cleanup
+ void ShutdownAssemblies();
+ void ShutdownFreeLoaderAllocators(BOOL bFromManagedCode);
+
+ void ReleaseDomainBoundInfo();
+ void ReleaseFiles();
+
+
+ // Remove the Appdomain for the system and cleans up. This call should not be
+ // called from shut down code.
+ void CloseDomain();
+
+ virtual BOOL IsAppDomain() { LIMITED_METHOD_DAC_CONTRACT; return TRUE; }
+ virtual PTR_AppDomain AsAppDomain() { LIMITED_METHOD_CONTRACT; return dac_cast<PTR_AppDomain>(this); }
+
+#ifndef FEATURE_CORECLR
+ void InitializeSorting(OBJECTREF* ppAppdomainSetup);
+ void InitializeHashing(OBJECTREF* ppAppdomainSetup);
+#endif
+
+ OBJECTREF DoSetup(OBJECTREF* setupInfo);
+
+ OBJECTREF GetExposedObject();
+ OBJECTREF GetRawExposedObject() {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+ if (m_ExposedObject) {
+ return ObjectFromHandle(m_ExposedObject);
+ }
+ else {
+ return NULL;
+ }
+ }
+
+ OBJECTHANDLE GetRawExposedObjectHandleForDebugger() { LIMITED_METHOD_DAC_CONTRACT; return m_ExposedObject; }
+
+#ifdef FEATURE_COMINTEROP
+ HRESULT GetComIPForExposedObject(IUnknown **pComIP);
+
+ MethodTable *GetRedirectedType(WinMDAdapter::RedirectedTypeIndex index);
+#endif // FEATURE_COMINTEROP
+
+
+ //****************************************************************************************
+
+protected:
+ // Multi-thread safe access to the list of assemblies
+ class DomainAssemblyList
+ {
+ private:
+ ArrayList m_array;
+#ifdef _DEBUG
+ AppDomain * dbg_m_pAppDomain;
+ public:
+ void Debug_SetAppDomain(AppDomain * pAppDomain)
+ {
+ dbg_m_pAppDomain = pAppDomain;
+ }
+#endif //_DEBUG
+ public:
+ bool IsEmpty()
+ {
+ CONTRACTL {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ } CONTRACTL_END;
+
+ // This function can be reliably called without taking the lock, because the first assembly
+ // added to the arraylist is non-collectible, and the ArrayList itself allows lockless read access
+ return (m_array.GetCount() == 0);
+ }
+ void Clear(AppDomain * pAppDomain)
+ {
+ CONTRACTL {
+ NOTHROW;
+ WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
+ MODE_ANY;
+ } CONTRACTL_END;
+
+ _ASSERTE(dbg_m_pAppDomain == pAppDomain);
+
+ CrstHolder ch(pAppDomain->GetAssemblyListLock());
+ m_array.Clear();
+ }
+
+ DWORD GetCount(AppDomain * pAppDomain)
+ {
+ CONTRACTL {
+ NOTHROW;
+ WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
+ MODE_ANY;
+ } CONTRACTL_END;
+
+ _ASSERTE(dbg_m_pAppDomain == pAppDomain);
+
+ CrstHolder ch(pAppDomain->GetAssemblyListLock());
+ return GetCount_Unlocked();
+ }
+ DWORD GetCount_Unlocked()
+ {
+ CONTRACTL {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ } CONTRACTL_END;
+
+#ifndef DACCESS_COMPILE
+ _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
+#endif
+ // code:Append_Unlock guarantees that we do not have more than MAXDWORD items
+ return m_array.GetCount();
+ }
+
+ void Get(AppDomain * pAppDomain, DWORD index, CollectibleAssemblyHolder<DomainAssembly *> * pAssemblyHolder)
+ {
+ CONTRACTL {
+ NOTHROW;
+ WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
+ MODE_ANY;
+ } CONTRACTL_END;
+
+ _ASSERTE(dbg_m_pAppDomain == pAppDomain);
+
+ CrstHolder ch(pAppDomain->GetAssemblyListLock());
+ Get_Unlocked(index, pAssemblyHolder);
+ }
+ void Get_Unlocked(DWORD index, CollectibleAssemblyHolder<DomainAssembly *> * pAssemblyHolder)
+ {
+ CONTRACTL {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ } CONTRACTL_END;
+
+ _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
+ *pAssemblyHolder = dac_cast<PTR_DomainAssembly>(m_array.Get(index));
+ }
+ // Doesn't lock the assembly list (caller has to hold the lock already).
+ // Doesn't AddRef the returned assembly (if collectible).
+ DomainAssembly * Get_UnlockedNoReference(DWORD index)
+ {
+ CONTRACTL {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SUPPORTS_DAC;
+ } CONTRACTL_END;
+
+#ifndef DACCESS_COMPILE
+ _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
+#endif
+ return dac_cast<PTR_DomainAssembly>(m_array.Get(index));
+ }
+
+#ifndef DACCESS_COMPILE
+ void Set(AppDomain * pAppDomain, DWORD index, DomainAssembly * pAssembly)
+ {
+ CONTRACTL {
+ NOTHROW;
+ WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
+ MODE_ANY;
+ } CONTRACTL_END;
+
+ _ASSERTE(dbg_m_pAppDomain == pAppDomain);
+
+ CrstHolder ch(pAppDomain->GetAssemblyListLock());
+ return Set_Unlocked(index, pAssembly);
+ }
+ void Set_Unlocked(DWORD index, DomainAssembly * pAssembly)
+ {
+ CONTRACTL {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ } CONTRACTL_END;
+
+ _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
+ m_array.Set(index, pAssembly);
+ }
+
+ HRESULT Append_Unlocked(DomainAssembly * pAssembly)
+ {
+ CONTRACTL {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ } CONTRACTL_END;
+
+ _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
+ return m_array.Append(pAssembly);
+ }
+#else //DACCESS_COMPILE
+ void
+ EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+ {
+ SUPPORTS_DAC;
+
+ m_array.EnumMemoryRegions(flags);
+ }
+#endif // DACCESS_COMPILE
+
+ // Should be used only by code:AssemblyIterator::Create
+ ArrayList::Iterator GetArrayListIterator()
+ {
+ return m_array.Iterate();
+ }
+ }; // class DomainAssemblyList
+
+ // Conceptually a list of code:Assembly structures, protected by lock code:GetAssemblyListLock
+ DomainAssemblyList m_Assemblies;
+
+public:
+ // Note that this lock switches thread into GC_NOTRIGGER region as GC can take it too.
+ CrstExplicitInit * GetAssemblyListLock()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return &m_crstAssemblyList;
+ }
+
+public:
+ class AssemblyIterator
+ {
+ // AppDomain context with the assembly list
+ AppDomain * m_pAppDomain;
+ ArrayList::Iterator m_Iterator;
+ AssemblyIterationFlags m_assemblyIterationFlags;
+
+ public:
+ BOOL Next(CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder);
+ // Note: Does not lock the assembly list, but AddRefs collectible assemblies.
+ BOOL Next_Unlocked(CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder);
+#ifndef DACCESS_COMPILE
+ private:
+ // Can be called only from AppDomain shutdown code:AppDomain::ShutdownAssemblies.
+ // Note: Does not lock the assembly list and does not AddRefs collectible assemblies.
+ BOOL Next_UnsafeNoAddRef(DomainAssembly ** ppDomainAssembly);
+#endif
+
+ private:
+ inline DWORD GetIndex()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_Iterator.GetIndex();
+ }
+
+ private:
+ friend class AppDomain;
+ // Cannot have constructor so this iterator can be used inside a union
+ static AssemblyIterator Create(AppDomain * pAppDomain, AssemblyIterationFlags assemblyIterationFlags)
+ {
+ LIMITED_METHOD_CONTRACT;
+ AssemblyIterator i;
+
+ i.m_pAppDomain = pAppDomain;
+ i.m_Iterator = pAppDomain->m_Assemblies.GetArrayListIterator();
+ i.m_assemblyIterationFlags = assemblyIterationFlags;
+ return i;
+ }
+ }; // class AssemblyIterator
+
+ AssemblyIterator IterateAssembliesEx(AssemblyIterationFlags assemblyIterationFlags)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return AssemblyIterator::Create(this, assemblyIterationFlags);
+ }
+
+#ifdef FEATURE_CORECLR
+private:
+ struct NativeImageDependenciesEntry
+ {
+ BaseAssemblySpec m_AssemblySpec;
+ GUID m_guidMVID;
+ };
+
+ class NativeImageDependenciesTraits : public NoRemoveSHashTraits<DefaultSHashTraits<NativeImageDependenciesEntry *> >
+ {
+ public:
+ typedef BaseAssemblySpec *key_t;
+ static key_t GetKey(NativeImageDependenciesEntry * e) { return &(e->m_AssemblySpec); }
+
+ static count_t Hash(key_t k)
+ {
+ return k->Hash();
+ }
+
+ static BOOL Equals(key_t lhs, key_t rhs)
+ {
+ return lhs->CompareEx(rhs);
+ }
+ };
+
+ SHash<NativeImageDependenciesTraits> m_NativeImageDependencies;
+
+public:
+ void CheckForMismatchedNativeImages(AssemblySpec * pSpec, const GUID * pGuid);
+
+public:
+ class PathIterator
+ {
+ friend class AppDomain;
+
+ ArrayList::Iterator m_i;
+
+ public:
+ BOOL Next()
+ {
+ WRAPPER_NO_CONTRACT;
+ return m_i.Next();
+ }
+
+ SString* GetPath()
+ {
+ WRAPPER_NO_CONTRACT;
+ return dac_cast<PTR_SString>(m_i.GetElement());
+ }
+ };
+ BOOL BindingByManifestFile();
+
+ PathIterator IterateNativeDllSearchDirectories();
+ void SetNativeDllSearchDirectories(LPCWSTR paths);
+ BOOL HasNativeDllSearchDirectories();
+ void ShutdownNativeDllSearchDirectories();
+#endif // FEATURE_CORECLR
+
+public:
+ SIZE_T GetAssemblyCount()
+ {
+ WRAPPER_NO_CONTRACT;
+ return m_Assemblies.GetCount(this);
+ }
+
+ CHECK CheckCanLoadTypes(Assembly *pAssembly);
+ CHECK CheckCanExecuteManagedCode(MethodDesc* pMD);
+ CHECK CheckLoading(DomainFile *pFile, FileLoadLevel level);
+
+ FileLoadLevel GetDomainFileLoadLevel(DomainFile *pFile);
+ BOOL IsLoading(DomainFile *pFile, FileLoadLevel level);
+ static FileLoadLevel GetThreadFileLoadLevel();
+
+ void LoadDomainFile(DomainFile *pFile,
+ FileLoadLevel targetLevel);
+
+ enum FindAssemblyOptions
+ {
+ FindAssemblyOptions_None = 0x0,
+ FindAssemblyOptions_IncludeFailedToLoad = 0x1
+ };
+
+ DomainAssembly * FindAssembly(PEAssembly * pFile, FindAssemblyOptions options = FindAssemblyOptions_None) DAC_EMPTY_RET(NULL);
+
+#ifdef FEATURE_MIXEDMODE
+ // Finds only loaded modules, elevates level if needed
+ Module* GetIJWModule(HMODULE hMod) DAC_EMPTY_RET(NULL);
+ // Finds loading modules
+ DomainFile* FindIJWDomainFile(HMODULE hMod, const SString &path) DAC_EMPTY_RET(NULL);
+#endif // FEATURE_MIXEDMODE
+
+ Assembly *LoadAssembly(AssemblySpec* pIdentity,
+ PEAssembly *pFile,
+ FileLoadLevel targetLevel,
+ AssemblyLoadSecurity *pLoadSecurity = NULL);
+
+ // this function does not provide caching, you must use LoadDomainAssembly
+ // unless the call is guaranteed to succeed or you don't need the caching
+ // (e.g. if you will FailFast or tear down the AppDomain anyway)
+ // The main point that you should not bypass caching if you might try to load the same file again,
+ // resulting in multiple DomainAssembly objects that share the same PEAssembly for ngen image
+ //which is violating our internal assumptions
+ DomainAssembly *LoadDomainAssemblyInternal( AssemblySpec* pIdentity,
+ PEAssembly *pFile,
+ FileLoadLevel targetLevel,
+ AssemblyLoadSecurity *pLoadSecurity = NULL);
+
+ DomainAssembly *LoadDomainAssembly( AssemblySpec* pIdentity,
+ PEAssembly *pFile,
+ FileLoadLevel targetLevel,
+ AssemblyLoadSecurity *pLoadSecurity = NULL);
+
+#ifdef FEATURE_MULTIMODULE_ASSEMBLIES
+ DomainModule *LoadDomainModule(DomainAssembly *pAssembly,
+ PEModule *pFile,
+ FileLoadLevel targetLevel);
+#endif
+
+ CHECK CheckValidModule(Module *pModule);
+#ifdef FEATURE_LOADER_OPTIMIZATION
+ DomainFile *LoadDomainNeutralModuleDependency(Module *pModule, FileLoadLevel targetLevel);
+#endif
+
+#ifdef FEATURE_FUSION
+ PEAssembly *BindExplicitAssembly(HMODULE hMod, BOOL bindable);
+ Assembly *LoadExplicitAssembly(HMODULE hMod, BOOL bindable);
+ void GetFileFromFusion(IAssembly *pIAssembly, LPCWSTR wszModuleName,
+ SString &path);
+#endif
+ // private:
+ void LoadSystemAssemblies();
+
+ DomainFile *LoadDomainFile(FileLoadLock *pLock,
+ FileLoadLevel targetLevel);
+
+ void TryIncrementalLoad(DomainFile *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder);
+
+ Assembly *LoadAssemblyHelper(LPCWSTR wszAssembly,
+ LPCWSTR wszCodeBase);
+
+#ifndef DACCESS_COMPILE // needs AssemblySpec
+ //****************************************************************************************
+ // Returns and Inserts assemblies into a lookup cache based on the binding information
+ // in the AssemblySpec. There can be many AssemblySpecs to a single assembly.
+ DomainAssembly* FindCachedAssembly(AssemblySpec* pSpec, BOOL fThrow=TRUE)
+ {
+ WRAPPER_NO_CONTRACT;
+ return m_AssemblyCache.LookupAssembly(pSpec, fThrow);
+ }
+
+ PEAssembly* FindCachedFile(AssemblySpec* pSpec, BOOL fThrow = TRUE);
+ BOOL IsCached(AssemblySpec *pSpec);
+#endif // DACCESS_COMPILE
+ void CacheStringsForDAC();
+
+ BOOL AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAllowFailure = FALSE);
+ BOOL AddAssemblyToCache(AssemblySpec* pSpec, DomainAssembly *pAssembly);
+ BOOL AddExceptionToCache(AssemblySpec* pSpec, Exception *ex);
+ void AddUnmanagedImageToCache(LPCWSTR libraryName, HMODULE hMod);
+ HMODULE FindUnmanagedImageInCache(LPCWSTR libraryName);
+ //****************************************************************************************
+ //
+ // Adds an assembly to the domain.
+ void AddAssembly(DomainAssembly * assem);
+ void RemoveAssembly_Unlocked(DomainAssembly * pAsm);
+
+ BOOL ContainsAssembly(Assembly * assem);
+
+#ifdef FEATURE_LOADER_OPTIMIZATION
+ enum SharePolicy
+ {
+ // Attributes to control when to use domain neutral assemblies
+ SHARE_POLICY_UNSPECIFIED, // Use the current default policy (LoaderOptimization.NotSpecified)
+ SHARE_POLICY_NEVER, // Do not share anything, except the system assembly (LoaderOptimization.SingleDomain)
+ SHARE_POLICY_ALWAYS, // Share everything possible (LoaderOptimization.MultiDomain)
+ SHARE_POLICY_GAC, // Share only GAC-bound assemblies (LoaderOptimization.MultiDomainHost)
+
+ SHARE_POLICY_COUNT,
+ SHARE_POLICY_MASK = 0x3,
+
+ // NOTE that previously defined was a bit 0x40 which might be set on this value
+ // in custom attributes.
+ SHARE_POLICY_DEFAULT = SHARE_POLICY_NEVER,
+ };
+
+ void SetSharePolicy(SharePolicy policy);
+ SharePolicy GetSharePolicy();
+ BOOL ReduceSharePolicyFromAlways();
+
+ //****************************************************************************************
+ // Determines if the image is to be loaded into the shared assembly or an individual
+ // appdomains.
+#ifndef FEATURE_CORECLR
+ BOOL ApplySharePolicy(DomainAssembly *pFile);
+ BOOL ApplySharePolicyFlag(DomainAssembly *pFile);
+#endif
+#endif // FEATURE_LOADER_OPTIMIZATION
+
+ BOOL HasSetSecurityPolicy();
+
+ FORCEINLINE IApplicationSecurityDescriptor* GetSecurityDescriptor()
+ {
+ LIMITED_METHOD_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ return static_cast<IApplicationSecurityDescriptor*>(m_pSecDesc);
+ }
+
+ void CreateSecurityDescriptor();
+
+ //****************************************************************************************
+ //
+ // Reference count. When an appdomain is first created the reference is bump
+ // to one when it is added to the list of domains (see SystemDomain). An explicit
+ // Removal from the list is necessary before it will be deleted.
+ ULONG AddRef(void);
+ ULONG Release(void) DAC_EMPTY_RET(0);
+
+ //****************************************************************************************
+ LPCWSTR GetFriendlyName(BOOL fDebuggerCares = TRUE);
+ LPCWSTR GetFriendlyNameForDebugger();
+ LPCWSTR GetFriendlyNameForLogging();
+#ifdef DACCESS_COMPILE
+ PVOID GetFriendlyNameNoSet(bool* isUtf8);
+#endif
+ void SetFriendlyName(LPCWSTR pwzFriendlyName, BOOL fDebuggerCares = TRUE);
+ void ResetFriendlyName(BOOL fDebuggerCares = TRUE);
+
+ //****************************************************************************************
+
+ // This can be used to override the binding behavior of the appdomain. It
+ // is overridden in the compilation domain. It is important that all
+ // static binding goes through this path.
+ virtual PEAssembly * BindAssemblySpec(
+ AssemblySpec *pSpec,
+ BOOL fThrowOnFileNotFound,
+ BOOL fRaisePrebindEvents,
+ StackCrawlMark *pCallerStackMark = NULL,
+ AssemblyLoadSecurity *pLoadSecurity = NULL,
+ BOOL fUseHostBinderIfAvailable = TRUE) DAC_EMPTY_RET(NULL);
+
+ HRESULT BindAssemblySpecForHostedBinder(
+ AssemblySpec * pSpec,
+ IAssemblyName * pAssemblyName,
+ ICLRPrivBinder * pBinder,
+ PEAssembly ** ppAssembly) DAC_EMPTY_RET(E_FAIL);
+
+ HRESULT BindHostedPrivAssembly(
+ PEAssembly * pParentPEAssembly,
+ ICLRPrivAssembly * pPrivAssembly,
+ IAssemblyName * pAssemblyName,
+ PEAssembly ** ppAssembly,
+ BOOL fIsIntrospectionOnly = FALSE) DAC_EMPTY_RET(S_OK);
+
+#ifdef FEATURE_REFLECTION_ONLY_LOAD
+ virtual DomainAssembly *BindAssemblySpecForIntrospectionDependencies(AssemblySpec *pSpec) DAC_EMPTY_RET(NULL);
+#endif
+
+ PEAssembly *TryResolveAssembly(AssemblySpec *pSpec, BOOL fPreBind);
+
+ // Store a successful binding into the cache. This will keep the file from
+ // being physically unmapped, as well as shortcutting future attempts to bind
+ // the same spec throught the Cached entry point.
+ //
+ // Right now we only cache assembly binds for "probing" type
+ // binding situations, basically when loading domain neutral assemblies or
+ // zap files.
+ //
+ // <TODO>@todo: We may want to be more aggressive about this if
+ // there are other situations where we are repeatedly binding the
+ // same assembly specs, though.</TODO>
+ //
+ // Returns TRUE if stored
+ // FALSE if it's a duplicate (caller should clean up args)
+ BOOL StoreBindAssemblySpecResult(AssemblySpec *pSpec,
+ PEAssembly *pFile,
+ BOOL clone = TRUE);
+
+ BOOL StoreBindAssemblySpecError(AssemblySpec *pSpec,
+ HRESULT hr,
+ OBJECTREF *pThrowable,
+ BOOL clone = TRUE);
+
+ //****************************************************************************************
+ //
+#ifdef FEATURE_FUSION
+ static BOOL SetContextProperty(IApplicationContext* pFusionContext,
+ LPCWSTR pProperty,
+ OBJECTREF* obj);
+#endif
+ //****************************************************************************************
+ //
+ // Uses the first assembly to add an application base to the Context. This is done
+ // in a lazy fashion so executables do not take the perf hit unless the load other
+ // assemblies
+#ifdef FEATURE_FUSION
+ LPWSTR GetDynamicDir();
+#endif
+#ifndef DACCESS_COMPILE
+ void OnAssemblyLoad(Assembly *assem);
+ void OnAssemblyLoadUnlocked(Assembly *assem);
+ static BOOL OnUnhandledException(OBJECTREF *pThrowable, BOOL isTerminating = TRUE);
+
+#endif
+
+ // True iff a debugger is attached to the process (same as CORDebuggerAttached)
+ BOOL IsDebuggerAttached (void);
+
+#ifdef DEBUGGING_SUPPORTED
+ // Notify debugger of all assemblies, modules, and possibly classes in this AppDomain
+ BOOL NotifyDebuggerLoad(int flags, BOOL attaching);
+
+ // Send unload notifications to the debugger for all assemblies, modules and classes in this AppDomain
+ void NotifyDebuggerUnload();
+#endif // DEBUGGING_SUPPORTED
+
+ void SetSystemAssemblyLoadEventSent (BOOL fFlag);
+ BOOL WasSystemAssemblyLoadEventSent (void);
+
+#ifndef DACCESS_COMPILE
+ OBJECTREF* AllocateStaticFieldObjRefPtrs(int nRequested, OBJECTREF** ppLazyAllocate = NULL)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ return AllocateObjRefPtrsInLargeTable(nRequested, ppLazyAllocate);
+ }
+
+ OBJECTREF* AllocateStaticFieldObjRefPtrsCrossDomain(int nRequested, OBJECTREF** ppLazyAllocate = NULL)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ return AllocateObjRefPtrsInLargeTable(nRequested, ppLazyAllocate, TRUE);
+ }
+#endif // DACCESS_COMPILE
+
+ void EnumStaticGCRefs(promote_func* fn, ScanContext* sc);
+
+ DomainLocalBlock *GetDomainLocalBlock()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return &m_sDomainLocalBlock;
+ }
+
+ static SIZE_T GetOffsetOfModuleSlotsPointer()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ return offsetof(AppDomain,m_sDomainLocalBlock) + DomainLocalBlock::GetOffsetOfModuleSlotsPointer();
+ }
+
+ void SetupSharedStatics();
+
+ ADUnloadSink* PrepareForWaitUnloadCompletion();
+
+ //****************************************************************************************
+ //
+ // Create a quick lookup for classes loaded into this domain based on their GUID.
+ //
+ void InsertClassForCLSID(MethodTable* pMT, BOOL fForceInsert = FALSE);
+ void InsertClassForCLSID(MethodTable* pMT, GUID *pGuid);
+
+#ifdef FEATURE_COMINTEROP
+private:
+ void CacheTypeByNameWorker(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE flags, BOOL bReplaceExisting = FALSE);
+ TypeHandle LookupTypeByNameWorker(const SString &ssClassName, UINT *pvCacheVersion, BYTE *pbFlags);
+public:
+ // Used by COM Interop for mapping WinRT runtime class names to real types.
+ void CacheTypeByName(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE flags, BOOL bReplaceExisting = FALSE);
+ TypeHandle LookupTypeByName(const SString &ssClassName, UINT *pvCacheVersion, BYTE *pbFlags);
+ PTR_MethodTable LookupTypeByGuid(const GUID & guid);
+
+#ifndef DACCESS_COMPILE
+ inline BOOL CanCacheWinRTTypeByGuid(TypeHandle typeHandle)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Only allow caching guid/types maps for types loaded during
+ // "normal" domain operation
+ if (IsCompilationDomain() || (m_Stage < STAGE_OPEN))
+ return FALSE;
+
+ MethodTable *pMT = typeHandle.GetMethodTable();
+ if (pMT != NULL)
+ {
+ // Don't cache mscorlib-internal declarations of WinRT types.
+ if (pMT->GetModule()->IsSystem() && pMT->IsProjectedFromWinRT())
+ return FALSE;
+
+ // Don't cache redirected WinRT types.
+ if (WinRTTypeNameConverter::IsRedirectedWinRTSourceType(pMT))
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+#endif // !DACCESS_COMPILE
+
+ void CacheWinRTTypeByGuid(TypeHandle typeHandle);
+ void GetCachedWinRTTypes(SArray<PTR_MethodTable> * pTypes, SArray<GUID> * pGuids, UINT minEpoch, UINT * pCurEpoch);
+
+ // Used by COM Interop for caching WinRT factory objects.
+ void CacheWinRTFactoryObject(MethodTable *pClassMT, OBJECTREF *refFactory, LPVOID lpCtxCookie);
+ OBJECTREF LookupWinRTFactoryObject(MethodTable *pClassMT, LPVOID lpCtxCookie);
+ void RemoveWinRTFactoryObjects(LPVOID pCtxCookie);
+
+ MethodTable *LoadCOMClass(GUID clsid, BOOL bLoadRecord = FALSE, BOOL* pfAssemblyInReg = NULL);
+ COMorRemotingFlag GetComOrRemotingFlag();
+ BOOL GetPreferComInsteadOfManagedRemoting();
+ OBJECTREF GetMissingObject(); // DispatchInfo will call function to retrieve the Missing.Value object.
+#endif // FEATURE_COMINTEROP
+
+#ifndef DACCESS_COMPILE
+ MethodTable* LookupClass(REFIID iid)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ MethodTable *pMT = (MethodTable*) m_clsidHash.LookupValue((UPTR) GetKeyFromGUID(&iid), (LPVOID)&iid);
+ return (pMT == (MethodTable*) INVALIDENTRY
+ ? NULL
+ : pMT);
+ }
+#endif // DACCESS_COMPILE
+
+ //<TODO>@todo get a better key</TODO>
+ ULONG GetKeyFromGUID(const GUID *pguid)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return *(ULONG *) pguid;
+ }
+
+#ifdef FEATURE_COMINTEROP
+ ComCallWrapperCache* GetComCallWrapperCache();
+ RCWCache *GetRCWCache()
+ {
+ WRAPPER_NO_CONTRACT;
+ if (m_pRCWCache)
+ return m_pRCWCache;
+
+ // By separating the cache creation from the common lookup, we
+ // can keep the (x86) EH prolog/epilog off the path.
+ return CreateRCWCache();
+ }
+private:
+ RCWCache *CreateRCWCache();
+public:
+ RCWCache *GetRCWCacheNoCreate()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pRCWCache;
+ }
+
+ RCWRefCache *GetRCWRefCache();
+
+ void ResetComCallWrapperCache()
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pComCallWrapperCache = NULL;
+ }
+
+ MethodTable* GetLicenseInteropHelperMethodTable();
+#endif // FEATURE_COMINTEROP
+
+ //****************************************************************************************
+ // Get the proxy for this app domain
+#ifdef FEATURE_REMOTING
+ OBJECTREF GetAppDomainProxy();
+#endif
+
+ ADIndex GetIndex()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+
+ return m_dwIndex;
+ }
+
+ TPIndex GetTPIndex()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_tpIndex;
+ }
+
+ void InitializeDomainContext(BOOL allowRedirects, LPCWSTR pwszPath, LPCWSTR pwszConfig);
+
+#ifdef FEATURE_FUSION
+ IApplicationContext *CreateFusionContext();
+ void SetupLoaderOptimization(DWORD optimization);
+#endif
+#ifdef FEATURE_VERSIONING
+ IUnknown *CreateFusionContext();
+#endif // FEATURE_VERSIONING
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+ void OverrideDefaultContextBinder(IUnknown *pOverrideBinder)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(pOverrideBinder != NULL);
+ pOverrideBinder->AddRef();
+ m_pFusionContext->Release();
+ m_pFusionContext = pOverrideBinder;
+ }
+
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+
+#ifdef FEATURE_PREJIT
+ CorCompileConfigFlags GetNativeConfigFlags();
+#endif // FEATURE_PREJIT
+
+ //****************************************************************************************
+ // Create a domain context rooted at the fileName. The directory containing the file name
+ // is the application base and the configuration file is the fileName appended with
+ // .config. If no name is passed in then no domain is created.
+ static AppDomain* CreateDomainContext(LPCWSTR fileName);
+
+ // Sets up the current domain's fusion context based on the given exe file name
+ // (app base & config file)
+ void SetupExecutableFusionContext(LPCWSTR exePath);
+
+ //****************************************************************************************
+ // Manage a pool of asyncrhonous objects used to fetch assemblies. When a sink is released
+ // it places itself back on the pool list. Only one object is kept in the pool.
+#ifdef FEATURE_FUSION
+ AssemblySink* AllocateAssemblySink(AssemblySpec* pSpec);
+#endif
+ void SetIsUserCreatedDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_dwFlags |= USER_CREATED_DOMAIN;
+ }
+
+ BOOL IsUserCreatedDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return (m_dwFlags & USER_CREATED_DOMAIN);
+ }
+
+ void SetIgnoreUnhandledExceptions()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_dwFlags |= IGNORE_UNHANDLED_EXCEPTIONS;
+ }
+
+ BOOL IgnoreUnhandledExceptions()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return (m_dwFlags & IGNORE_UNHANDLED_EXCEPTIONS);
+ }
+
+ void SetPassiveDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_dwFlags |= PASSIVE_DOMAIN;
+ }
+
+ BOOL IsPassiveDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return (m_dwFlags & PASSIVE_DOMAIN);
+ }
+
+ void SetVerificationDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_dwFlags |= VERIFICATION_DOMAIN;
+ }
+
+ BOOL IsVerificationDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return (m_dwFlags & VERIFICATION_DOMAIN);
+ }
+
+ void SetIllegalVerificationDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_dwFlags |= ILLEGAL_VERIFICATION_DOMAIN;
+ }
+
+ BOOL IsIllegalVerificationDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return (m_dwFlags & ILLEGAL_VERIFICATION_DOMAIN);
+ }
+
+ void SetCompilationDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_dwFlags |= (PASSIVE_DOMAIN|COMPILATION_DOMAIN);
+ }
+
+ BOOL IsCompilationDomain();
+
+ PTR_CompilationDomain ToCompilationDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(IsCompilationDomain());
+ return dac_cast<PTR_CompilationDomain>(this);
+ }
+
+ void SetCanUnload()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_dwFlags |= APP_DOMAIN_CAN_BE_UNLOADED;
+ }
+
+ BOOL CanUnload()
+ {
+ LIMITED_METHOD_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ return m_dwFlags & APP_DOMAIN_CAN_BE_UNLOADED;
+ }
+
+ void SetRemotingConfigured()
+ {
+ LIMITED_METHOD_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ FastInterlockOr((ULONG*)&m_dwFlags, REMOTING_CONFIGURED_FOR_DOMAIN);
+ }
+
+ BOOL IsRemotingConfigured()
+ {
+ LIMITED_METHOD_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ return m_dwFlags & REMOTING_CONFIGURED_FOR_DOMAIN;
+ }
+
+ void SetOrphanedLocks()
+ {
+ LIMITED_METHOD_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ FastInterlockOr((ULONG*)&m_dwFlags, ORPHANED_LOCKS);
+ }
+
+ BOOL HasOrphanedLocks()
+ {
+ LIMITED_METHOD_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ return m_dwFlags & ORPHANED_LOCKS;
+ }
+
+ // This function is used to relax asserts in the lock accounting.
+ // It returns true if we are fine with hosed lock accounting in this domain.
+ BOOL OkToIgnoreOrphanedLocks()
+ {
+ WRAPPER_NO_CONTRACT;
+ return HasOrphanedLocks() && m_Stage >= STAGE_UNLOAD_REQUESTED;
+ }
+
+ static void ExceptionUnwind(Frame *pFrame);
+
+#ifdef _DEBUG
+ void TrackADThreadEnter(Thread *pThread, Frame *pFrame);
+ void TrackADThreadExit(Thread *pThread, Frame *pFrame);
+ void DumpADThreadTrack();
+#endif
+
+#ifndef DACCESS_COMPILE
+ void ThreadEnter(Thread *pThread, Frame *pFrame)
+ {
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+
+#ifdef _DEBUG
+ if (LoggingOn(LF_APPDOMAIN, LL_INFO100))
+ TrackADThreadEnter(pThread, pFrame);
+ else
+#endif
+ {
+ InterlockedIncrement((LONG*)&m_dwThreadEnterCount);
+ LOG((LF_APPDOMAIN, LL_INFO1000, "AppDomain::ThreadEnter %p to [%d] (%8.8x) %S count %d\n",
+ pThread,GetId().m_dwId, this,
+ GetFriendlyNameForLogging(),GetThreadEnterCount()));
+#if _DEBUG_AD_UNLOAD
+ printf("AppDomain::ThreadEnter %p to [%d] (%8.8x) %S count %d\n",
+ pThread, GetId().m_dwId, this,
+ GetFriendlyNameForLogging(), GetThreadEnterCount());
+#endif
+ }
+ }
+
+ void ThreadExit(Thread *pThread, Frame *pFrame)
+ {
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+
+#ifdef _DEBUG
+ if (LoggingOn(LF_APPDOMAIN, LL_INFO100)) {
+ TrackADThreadExit(pThread, pFrame);
+ }
+ else
+#endif
+ {
+ LONG result;
+ result = InterlockedDecrement((LONG*)&m_dwThreadEnterCount);
+ _ASSERTE(result >= 0);
+ LOG((LF_APPDOMAIN, LL_INFO1000, "AppDomain::ThreadExit from [%d] (%8.8x) %S count %d\n",
+ this, GetId().m_dwId,
+ GetFriendlyNameForLogging(), GetThreadEnterCount()));
+#if _DEBUG_ADUNLOAD
+ printf("AppDomain::ThreadExit %x from [%d] (%8.8x) %S count %d\n",
+ pThread->GetThreadId(), this, GetId().m_dwId,
+ GetFriendlyNameForLogging(), GetThreadEnterCount());
+#endif
+ }
+ }
+#endif // DACCESS_COMPILE
+
+ ULONG GetThreadEnterCount()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_dwThreadEnterCount;
+ }
+
+ BOOL OnlyOneThreadLeft()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_dwThreadEnterCount==1 || m_dwThreadsStillInAppDomain ==1;
+ }
+
+ Context *GetDefaultContext()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pDefaultContext;
+ }
+
+ BOOL CanLoadCode()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_Stage >= STAGE_READYFORMANAGEDCODE && m_Stage < STAGE_CLOSED;
+ }
+
+ void SetAnonymouslyHostedDynamicMethodsAssembly(DomainAssembly * pDomainAssembly)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(pDomainAssembly != NULL);
+ _ASSERTE(m_anonymouslyHostedDynamicMethodsAssembly == NULL);
+ m_anonymouslyHostedDynamicMethodsAssembly = pDomainAssembly;
+ }
+
+ DomainAssembly * GetAnonymouslyHostedDynamicMethodsAssembly()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_anonymouslyHostedDynamicMethodsAssembly;
+ }
+
+ BOOL HasUnloadStarted()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_Stage>=STAGE_EXITED;
+ }
+ static void RefTakerAcquire(AppDomain* pDomain)
+ {
+ WRAPPER_NO_CONTRACT;
+ if(!pDomain)
+ return;
+ pDomain->AddRef();
+#ifdef _DEBUG
+ FastInterlockIncrement(&pDomain->m_dwRefTakers);
+#endif
+ }
+
+ static void RefTakerRelease(AppDomain* pDomain)
+ {
+ WRAPPER_NO_CONTRACT;
+ if(!pDomain)
+ return;
+#ifdef _DEBUG
+ _ASSERTE(pDomain->m_dwRefTakers);
+ FastInterlockDecrement(&pDomain->m_dwRefTakers);
+#endif
+ pDomain->Release();
+ }
+
+#ifdef _DEBUG
+
+ BOOL IsHeldByIterator()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_dwIterHolders>0;
+ }
+
+ BOOL IsHeldByRefTaker()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_dwRefTakers>0;
+ }
+
+ void IteratorRelease()
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(m_dwIterHolders);
+ FastInterlockDecrement(&m_dwIterHolders);
+ }
+
+
+ void IteratorAcquire()
+ {
+ LIMITED_METHOD_CONTRACT;
+ FastInterlockIncrement(&m_dwIterHolders);
+ }
+
+#endif
+ BOOL IsActive()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return m_Stage >= STAGE_ACTIVE && m_Stage < STAGE_CLOSED;
+ }
+ // Range for normal execution of code in the appdomain, currently used for
+ // appdomain resource monitoring since we don't care to update resource usage
+ // unless it's in these stages (as fields of AppDomain may not be valid if it's
+ // not within these stages)
+ BOOL IsUserActive()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return m_Stage >= STAGE_ACTIVE && m_Stage <= STAGE_OPEN;
+ }
+ BOOL IsValid()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+#ifdef DACCESS_COMPILE
+ // We want to see all appdomains in SOS, even the about to be destructed ones.
+ // There is no risk of races under DAC, so we will pretend to be unconditionally valid.
+ return TRUE;
+#else
+ return m_Stage > STAGE_CREATING && m_Stage < STAGE_CLOSED;
+#endif
+ }
+
+#ifdef _DEBUG
+ BOOL IsBeingCreated()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_dwCreationHolders > 0;
+ }
+
+ void IncCreationCount()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ FastInterlockIncrement(&m_dwCreationHolders);
+ _ASSERTE(m_dwCreationHolders > 0);
+ }
+
+ void DecCreationCount()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ FastInterlockDecrement(&m_dwCreationHolders);
+ _ASSERTE(m_dwCreationHolders > -1);
+ }
+#endif
+ BOOL IsRunningIn(Thread* pThread);
+
+ BOOL IsUnloading()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+
+ return m_Stage > STAGE_UNLOAD_REQUESTED;
+ }
+
+ BOOL NotReadyForManagedCode()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_Stage < STAGE_READYFORMANAGEDCODE;
+ }
+
+ void SetFinalized()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetStage(STAGE_FINALIZED);
+ }
+
+ BOOL IsFinalizing()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_Stage >= STAGE_FINALIZING;
+ }
+
+ BOOL IsFinalized()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_Stage >= STAGE_FINALIZED;
+ }
+
+ BOOL NoAccessToHandleTable()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+
+ return m_Stage >= STAGE_HANDLETABLE_NOACCESS;
+ }
+
+ // Checks whether the given thread can enter the app domain
+ BOOL CanThreadEnter(Thread *pThread);
+
+ // Following two are needed for the Holder
+ static void SetUnloadInProgress(AppDomain *pThis) PUB;
+ static void SetUnloadComplete(AppDomain *pThis) PUB;
+ // Predicates for GC asserts
+ BOOL ShouldHaveFinalization()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return ((DWORD) m_Stage) < STAGE_COLLECTED;
+ }
+ BOOL ShouldHaveCode()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return ((DWORD) m_Stage) < STAGE_COLLECTED;
+ }
+ BOOL ShouldHaveRoots()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return ((DWORD) m_Stage) < STAGE_CLEARED;
+ }
+ BOOL ShouldHaveInstances()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return ((DWORD) m_Stage) < STAGE_COLLECTED;
+ }
+
+
+ static void RaiseExitProcessEvent();
+ Assembly* RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName);
+ DomainAssembly* RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef);
+ Assembly* RaiseAssemblyResolveEvent(AssemblySpec *pSpec, BOOL fIntrospection, BOOL fPreBind);
+
+private:
+ CrstExplicitInit m_ReflectionCrst;
+ CrstExplicitInit m_RefClassFactCrst;
+
+
+ EEClassFactoryInfoHashTable *m_pRefClassFactHash; // Hash table that maps a class factory info to a COM comp.
+#ifdef FEATURE_COMINTEROP
+ DispIDCache *m_pRefDispIDCache;
+ COMorRemotingFlag m_COMorRemotingFlag;
+ OBJECTHANDLE m_hndMissing; //Handle points to Missing.Value Object which is used for [Optional] arg scenario during IDispatch CCW Call
+
+ MethodTable* m_rpCLRTypes[WinMDAdapter::RedirectedTypeIndex_Count];
+
+ MethodTable* LoadRedirectedType(WinMDAdapter::RedirectedTypeIndex index, WinMDAdapter::FrameworkAssemblyIndex assembly);
+#endif // FEATURE_COMINTEROP
+
+public:
+
+ CrstBase *GetRefClassFactCrst()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return &m_RefClassFactCrst;
+ }
+
+#ifndef DACCESS_COMPILE
+ EEClassFactoryInfoHashTable* GetClassFactHash()
+ {
+ STATIC_CONTRACT_THROWS;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_FAULT;
+
+ if (m_pRefClassFactHash != NULL) {
+ return m_pRefClassFactHash;
+ }
+
+ return SetupClassFactHash();
+ }
+#endif // DACCESS_COMPILE
+
+#ifdef FEATURE_COMINTEROP
+ DispIDCache* GetRefDispIDCache()
+ {
+ STATIC_CONTRACT_THROWS;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_FAULT;
+
+ if (m_pRefDispIDCache != NULL) {
+ return m_pRefDispIDCache;
+ }
+
+ return SetupRefDispIDCache();
+ }
+#endif // FEATURE_COMINTEROP
+
+ PTR_LoaderHeap GetStubHeap();
+ PTR_LoaderHeap GetLowFrequencyHeap();
+ PTR_LoaderHeap GetHighFrequencyHeap();
+ virtual PTR_LoaderAllocator GetLoaderAllocator();
+
+#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
+ #define ARM_ETW_ALLOC_THRESHOLD (4 * 1024 * 1024)
+ // cache line size in ULONGLONG - 128 bytes which are 16 ULONGLONG's
+ #define ARM_CACHE_LINE_SIZE_ULL 16
+
+ inline ULONGLONG GetAllocBytes()
+ {
+ LIMITED_METHOD_CONTRACT;
+ ULONGLONG ullTotalAllocBytes = 0;
+
+ // Ensure that m_pullAllocBytes is non-null to avoid an AV in a race between GC and AD unload.
+ // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullAllocBytes, causing the AD unload.
+ if(NULL != m_pullAllocBytes)
+ {
+ for (DWORD i = 0; i < m_dwNumHeaps; i++)
+ {
+ ullTotalAllocBytes += m_pullAllocBytes[i * ARM_CACHE_LINE_SIZE_ULL];
+ }
+ }
+ return ullTotalAllocBytes;
+ }
+
+ void RecordAllocBytes(size_t allocatedBytes, DWORD dwHeapNumber)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(dwHeapNumber < m_dwNumHeaps);
+
+ // Ensure that m_pullAllocBytes is non-null to avoid an AV in a race between GC and AD unload.
+ // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullAllocBytes, causing the AD unload.
+ if(NULL != m_pullAllocBytes)
+ {
+ m_pullAllocBytes[dwHeapNumber * ARM_CACHE_LINE_SIZE_ULL] += allocatedBytes;
+ }
+
+ ULONGLONG ullTotalAllocBytes = GetAllocBytes();
+
+ if ((ullTotalAllocBytes - m_ullLastEtwAllocBytes) >= ARM_ETW_ALLOC_THRESHOLD)
+ {
+ m_ullLastEtwAllocBytes = ullTotalAllocBytes;
+ FireEtwAppDomainMemAllocated((ULONGLONG)this, ullTotalAllocBytes, GetClrInstanceId());
+ }
+ }
+
+ inline ULONGLONG GetSurvivedBytes()
+ {
+ LIMITED_METHOD_CONTRACT;
+ ULONGLONG ullTotalSurvivedBytes = 0;
+
+ // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
+ // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
+ if(NULL != m_pullSurvivedBytes)
+ {
+ for (DWORD i = 0; i < m_dwNumHeaps; i++)
+ {
+ ullTotalSurvivedBytes += m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL];
+ }
+ }
+ return ullTotalSurvivedBytes;
+ }
+
+ void RecordSurvivedBytes(size_t promotedBytes, DWORD dwHeapNumber)
+ {
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(dwHeapNumber < m_dwNumHeaps);
+
+ // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
+ // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
+ if(NULL != m_pullSurvivedBytes)
+ {
+ m_pullSurvivedBytes[dwHeapNumber * ARM_CACHE_LINE_SIZE_ULL] += promotedBytes;
+ }
+ }
+
+ inline void ResetSurvivedBytes()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
+ // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
+ if(NULL != m_pullSurvivedBytes)
+ {
+ for (DWORD i = 0; i < m_dwNumHeaps; i++)
+ {
+ m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
+ }
+ }
+ }
+
+ // Return the total processor time (user and kernel) used by threads executing in this AppDomain so far.
+ // The result is in 100ns units.
+ ULONGLONG QueryProcessorUsage();
+
+ // Add to the current count of processor time used by threads within this AppDomain. This API is called by
+ // threads transitioning between AppDomains.
+ void UpdateProcessorUsage(ULONGLONG ullAdditionalUsage);
+#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
+
+private:
+ static void RaiseOneExitProcessEvent_Wrapper(AppDomainIterator* pi);
+ static void RaiseOneExitProcessEvent();
+ size_t EstimateSize();
+ EEClassFactoryInfoHashTable* SetupClassFactHash();
+#ifdef FEATURE_COMINTEROP
+ DispIDCache* SetupRefDispIDCache();
+ COMorRemotingFlag GetPreferComInsteadOfManagedRemotingFromConfigFile();
+#endif // FEATURE_COMINTEROP
+
+ void InitializeDefaultDomainManager ();
+
+#ifdef FEATURE_CLICKONCE
+ void InitializeDefaultClickOnceDomain();
+#endif // FEATURE_CLICKONCE
+
+ void InitializeDefaultDomainSecurity();
+public:
+#ifdef FEATURE_CLICKONCE
+ BOOL IsClickOnceAppDomain();
+#endif // FEATURE_CLICKONCE
+
+protected:
+ BOOL PostBindResolveAssembly(AssemblySpec *pPrePolicySpec,
+ AssemblySpec *pPostPolicySpec,
+ HRESULT hrBindResult,
+ AssemblySpec **ppFailedSpec);
+
+#ifdef FEATURE_COMINTEROP
+public:
+ void ReleaseRCWs(LPVOID pCtxCookie);
+ void DetachRCWs();
+
+protected:
+#endif // FEATURE_COMINTEROP
+
+ LPWSTR m_pwDynamicDir;
+
+private:
+ void RaiseLoadingAssemblyEvent(DomainAssembly* pAssembly);
+
+ friend class DomainAssembly;
+
+public:
+ static void ProcessUnloadDomainEventOnFinalizeThread();
+ static BOOL HasWorkForFinalizerThread()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return s_pAppDomainToRaiseUnloadEvent != NULL;
+ }
+
+private:
+ static AppDomain* s_pAppDomainToRaiseUnloadEvent;
+ static BOOL s_fProcessUnloadDomainEvent;
+
+ void RaiseUnloadDomainEvent();
+ static void RaiseUnloadDomainEvent_Wrapper(LPVOID /* AppDomain * */);
+
+ BOOL RaiseUnhandledExceptionEvent(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating);
+ BOOL HasUnhandledExceptionEventHandler();
+ BOOL RaiseUnhandledExceptionEventNoThrow(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating);
+
+ struct RaiseUnhandled_Args
+ {
+ AppDomain *pExceptionDomain;
+ AppDomain *pTargetDomain;
+ OBJECTREF *pSender;
+ OBJECTREF *pThrowable;
+ BOOL isTerminating;
+ BOOL *pResult;
+ };
+ #ifndef FEATURE_CORECLR
+ static void RaiseUnhandledExceptionEvent_Wrapper(LPVOID /* RaiseUnhandled_Args * */);
+ #endif
+
+
+ static void AllowThreadEntrance(AppDomain *pApp);
+ static void RestrictThreadEntrance(AppDomain *pApp);
+
+ typedef Holder<AppDomain*,DoNothing<AppDomain*>,AppDomain::AllowThreadEntrance,NULL> RestrictEnterHolder;
+
+ enum Stage {
+ STAGE_CREATING,
+ STAGE_READYFORMANAGEDCODE,
+ STAGE_ACTIVE,
+ STAGE_OPEN,
+ STAGE_UNLOAD_REQUESTED,
+ STAGE_EXITING,
+ STAGE_EXITED,
+ STAGE_FINALIZING,
+ STAGE_FINALIZED,
+ STAGE_HANDLETABLE_NOACCESS,
+ STAGE_CLEARED,
+ STAGE_COLLECTED,
+ STAGE_CLOSED
+ };
+ void SetStage(Stage stage)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ STRESS_LOG2(LF_APPDOMAIN, LL_INFO100,"Updating AD stage, ADID=%d, stage=%d\n",GetId().m_dwId,stage);
+ TESTHOOKCALL(AppDomainStageChanged(GetId().m_dwId,m_Stage,stage));
+ Stage lastStage=m_Stage;
+ while (lastStage !=stage)
+ lastStage = (Stage)FastInterlockCompareExchange((LONG*)&m_Stage,stage,lastStage);
+ };
+ void Exit(BOOL fRunFinalizers, BOOL fAsyncExit);
+ void Close();
+ void ClearGCRoots();
+ void ClearGCHandles();
+ void HandleAsyncPinHandles();
+ void UnwindThreads();
+ // Return TRUE if EE is stopped
+ // Return FALSE if more work is needed
+ BOOL StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread);
+
+ // Use Rude Abort to unload the domain.
+ BOOL m_fRudeUnload;
+
+ Thread *m_pUnloadRequestThread;
+ ADUnloadSink* m_ADUnloadSink;
+ BOOL m_bForceGCOnUnload;
+ BOOL m_bUnloadingFromUnloadEvent;
+ AppDomainLoaderAllocator m_LoaderAllocator;
+
+ // List of unloaded LoaderAllocators, protected by code:GetLoaderAllocatorReferencesLock (for now)
+ LoaderAllocator * m_pDelayedLoaderAllocatorUnloadList;
+
+public:
+
+ // Register the loader allocator for deletion in code:ShutdownFreeLoaderAllocators.
+ void RegisterLoaderAllocatorForDeletion(LoaderAllocator * pLoaderAllocator);
+
+ AppDomain * m_pNextInDelayedUnloadList;
+
+ void SetForceGCOnUnload(BOOL bSet)
+ {
+ m_bForceGCOnUnload=bSet;
+ }
+
+ void SetUnloadingFromUnloadEvent()
+ {
+ m_bUnloadingFromUnloadEvent=TRUE;
+ }
+
+ BOOL IsUnloadingFromUnloadEvent()
+ {
+ return m_bUnloadingFromUnloadEvent;
+ }
+
+ void SetRudeUnload()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_fRudeUnload = TRUE;
+ }
+
+ BOOL IsRudeUnload()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_fRudeUnload;
+ }
+
+ ADUnloadSink* GetADUnloadSink();
+ ADUnloadSink* GetADUnloadSinkForUnload();
+ void SetUnloadRequestThread(Thread *pThread)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_pUnloadRequestThread = pThread;
+ }
+
+ Thread *GetUnloadRequestThread()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_pUnloadRequestThread;
+ }
+
+public:
+ void SetGCRefPoint(int gccounter)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_LoaderAllocator.SetGCRefPoint(gccounter);
+ }
+ int GetGCRefPoint()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_LoaderAllocator.GetGCRefPoint();
+ }
+
+ static USHORT GetOffsetOfId()
+ {
+ LIMITED_METHOD_CONTRACT;
+ size_t ofs = offsetof(class AppDomain, m_dwId);
+ _ASSERTE(FitsInI2(ofs));
+ return (USHORT)ofs;
+ }
+
+
+ void AddMemoryPressure();
+ void RemoveMemoryPressure();
+ void Unload(BOOL fForceUnload);
+ static HRESULT UnloadById(ADID Id, BOOL fSync, BOOL fExceptionsPassThrough=FALSE);
+ static HRESULT UnloadWait(ADID Id, ADUnloadSink* pSink);
+#ifdef FEATURE_TESTHOOKS
+ static HRESULT UnloadWaitNoCatch(ADID Id, ADUnloadSink* pSink);
+#endif
+ static void ResetUnloadRequestThread(ADID Id);
+
+ void UnlinkClass(MethodTable *pMT);
+
+ typedef Holder<AppDomain *, AppDomain::SetUnloadInProgress, AppDomain::SetUnloadComplete> UnloadHolder;
+ Assembly *GetRootAssembly()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pRootAssembly;
+ }
+
+#ifndef DACCESS_COMPILE
+ void SetRootAssembly(Assembly *pAssembly)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pRootAssembly = pAssembly;
+ }
+#endif
+
+private:
+ SString m_friendlyName;
+ PTR_Assembly m_pRootAssembly;
+
+ // General purpose flags.
+ DWORD m_dwFlags;
+
+ // When an application domain is created the ref count is artifically incremented
+ // by one. For it to hit zero an explicit close must have happened.
+ LONG m_cRef; // Ref count.
+
+ PTR_IApplicationSecurityDescriptor m_pSecDesc; // Application Security Descriptor
+
+ OBJECTHANDLE m_ExposedObject;
+
+#ifdef FEATURE_LOADER_OPTIMIZATION
+ // Indicates where assemblies will be loaded for
+ // this domain. By default all assemblies are loaded into the domain.
+ // There are two additional settings, all
+ // assemblies can be loaded into the shared domain or assemblies
+ // that are strong named are loaded into the shared area.
+ SharePolicy m_SharePolicy;
+#endif
+
+ IUnknown *m_pComIPForExposedObject;
+
+ // Hash table that maps a clsid to a type
+ PtrHashMap m_clsidHash;
+
+#ifdef FEATURE_COMINTEROP
+ // Hash table that maps WinRT class names to MethodTables.
+ PTR_NameToTypeMapTable m_pNameToTypeMap;
+ UINT m_vNameToTypeMapVersion;
+
+ UINT m_nEpoch; // incremented each time m_pNameToTypeMap is enumerated
+
+ // Hash table that remembers the last cached WinRT factory object per type per appdomain.
+ WinRTFactoryCache *m_pWinRTFactoryCache;
+
+ // The wrapper cache for this domain - it has its own CCacheLineAllocator on a per domain basis
+ // to allow the domain to go away and eventually kill the memory when all refs are gone
+ ComCallWrapperCache *m_pComCallWrapperCache;
+
+ // this cache stores the RCWs in this domain
+ RCWCache *m_pRCWCache;
+
+ // this cache stores the RCW -> CCW references in this domain
+ RCWRefCache *m_pRCWRefCache;
+
+ // The method table used for LicenseInteropHelper
+ MethodTable* m_pLicenseInteropHelperMT;
+#endif // FEATURE_COMINTEROP
+
+ AssemblySink* m_pAsyncPool; // asynchronous retrival object pool (only one is kept)
+
+ // The index of this app domain among existing app domains (starting from 1)
+ ADIndex m_dwIndex;
+
+ // The thread-pool index of this app domain among existing app domains (starting from 1)
+ TPIndex m_tpIndex;
+
+#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
+ ULONGLONG* m_pullAllocBytes;
+ ULONGLONG* m_pullSurvivedBytes;
+ DWORD m_dwNumHeaps;
+ ULONGLONG m_ullLastEtwAllocBytes;
+ // Total processor time (user and kernel) utilized by threads running in this AppDomain so far. May not
+ // account for threads currently executing in the AppDomain until a call to QueryProcessorUsage() is
+ // made.
+ Volatile<ULONGLONG> m_ullTotalProcessorUsage;
+#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
+
+#ifdef _DEBUG
+ struct ThreadTrackInfo;
+ typedef CDynArray<ThreadTrackInfo *> ThreadTrackInfoList;
+ ThreadTrackInfoList *m_pThreadTrackInfoList;
+ DWORD m_TrackSpinLock;
+#endif
+
+
+ // IL stub cache with fabricated MethodTable parented by a random module in this AD.
+ ILStubCache m_ILStubCache;
+
+ // U->M thunks created in this domain and not associated with a delegate.
+ // The cache is keyed by MethodDesc pointers.
+ UMEntryThunkCache *m_pUMEntryThunkCache;
+
+ // The number of times we have entered this AD
+ ULONG m_dwThreadEnterCount;
+ // The number of threads that have entered this AD, for ADU only
+ ULONG m_dwThreadsStillInAppDomain;
+
+ Volatile<Stage> m_Stage;
+
+ // The default context for this domain
+ Context *m_pDefaultContext;
+
+ SString m_applicationBase;
+ SString m_privateBinPaths;
+ SString m_configFile;
+
+ ArrayList m_failedAssemblies;
+
+ DomainAssembly * m_anonymouslyHostedDynamicMethodsAssembly;
+
+#ifdef _DEBUG
+ Volatile<LONG> m_dwIterHolders;
+ Volatile<LONG> m_dwRefTakers;
+ Volatile<LONG> m_dwCreationHolders;
+#endif
+
+ //
+ // DAC iterator for failed assembly loads
+ //
+ class FailedAssemblyIterator
+ {
+ ArrayList::Iterator m_i;
+
+ public:
+ BOOL Next()
+ {
+ WRAPPER_NO_CONTRACT;
+ return m_i.Next();
+ }
+ FailedAssembly *GetFailedAssembly()
+ {
+ WRAPPER_NO_CONTRACT;
+ return dac_cast<PTR_FailedAssembly>(m_i.GetElement());
+ }
+ SIZE_T GetIndex()
+ {
+ WRAPPER_NO_CONTRACT;
+ return m_i.GetIndex();
+ }
+
+ private:
+ friend class AppDomain;
+ // Cannot have constructor so this iterator can be used inside a union
+ static FailedAssemblyIterator Create(AppDomain *pDomain)
+ {
+ WRAPPER_NO_CONTRACT;
+ FailedAssemblyIterator i;
+
+ i.m_i = pDomain->m_failedAssemblies.Iterate();
+ return i;
+ }
+ };
+ friend class FailedAssemblyIterator;
+
+ FailedAssemblyIterator IterateFailedAssembliesEx()
+ {
+ WRAPPER_NO_CONTRACT;
+ return FailedAssemblyIterator::Create(this);
+ }
+
+ //---------------------------------------------------------
+ // Stub caches for Method stubs
+ //---------------------------------------------------------
+
+#ifdef FEATURE_FUSION
+ void TurnOnBindingRedirects();
+#endif
+public:
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+private:
+ Volatile<BOOL> m_fIsBindingModelLocked;
+public:
+ BOOL IsHostAssemblyResolverInUse();
+ BOOL IsBindingModelLocked();
+ BOOL LockBindingModel();
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+
+ UMEntryThunkCache *GetUMEntryThunkCache();
+
+ ILStubCache* GetILStubCache()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return &m_ILStubCache;
+ }
+
+ static AppDomain* GetDomain(ILStubCache* pILStubCache)
+ {
+ return CONTAINING_RECORD(pILStubCache, AppDomain, m_ILStubCache);
+ }
+
+ enum {
+ CONTEXT_INITIALIZED = 0x0001,
+ USER_CREATED_DOMAIN = 0x0002, // created by call to AppDomain.CreateDomain
+ ALLOCATEDCOM = 0x0008,
+ LOAD_SYSTEM_ASSEMBLY_EVENT_SENT = 0x0040,
+ REMOTING_CONFIGURED_FOR_DOMAIN = 0x0100,
+ COMPILATION_DOMAIN = 0x0400, // Are we ngenning?
+ APP_DOMAIN_CAN_BE_UNLOADED = 0x0800, // if need extra bits, can derive this at runtime
+ ORPHANED_LOCKS = 0x1000, // Orphaned locks exist in this appdomain.
+ PASSIVE_DOMAIN = 0x2000, // Can we execute code in this AppDomain
+ VERIFICATION_DOMAIN = 0x4000, // This is a verification domain
+ ILLEGAL_VERIFICATION_DOMAIN = 0x8000, // This can't be a verification domain
+ IGNORE_UNHANDLED_EXCEPTIONS = 0x10000, // AppDomain was created using the APPDOMAIN_IGNORE_UNHANDLED_EXCEPTIONS flag
+ ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP = 0x20000, // AppDomain was created using the APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP flag
+#ifdef FEATURE_CORECLR
+ ENABLE_SKIP_PLAT_CHECKS = 0x200000, // Skip various assembly checks (like platform check)
+ ENABLE_ASSEMBLY_LOADFILE = 0x400000, // Allow Assembly.LoadFile in CoreCLR
+ DISABLE_TRANSPARENCY_ENFORCEMENT= 0x800000, // Disable enforcement of security transparency rules
+#endif
+ };
+
+ SecurityContext *m_pSecContext;
+
+ AssemblySpecBindingCache m_AssemblyCache;
+ DomainAssemblyCache m_UnmanagedCache;
+ size_t m_MemoryPressure;
+
+ SString m_AppDomainManagerAssembly;
+ SString m_AppDomainManagerType;
+ BOOL m_fAppDomainManagerSetInConfig;
+ EInitializeNewDomainFlags m_dwAppDomainManagerInitializeDomainFlags;
+
+#ifdef FEATURE_CORECLR
+ ArrayList m_NativeDllSearchDirectories;
+#endif
+ BOOL m_ReversePInvokeCanEnter;
+ bool m_ForceTrivialWaitOperations;
+ // Section to support AD unload due to escalation
+public:
+ static void CreateADUnloadWorker();
+
+ static void CreateADUnloadStartEvent();
+
+ static DWORD WINAPI ADUnloadThreadStart(void *args);
+
+ // Default is safe unload with test hook
+ void EnableADUnloadWorker();
+
+ // If called to handle stack overflow, we can not set event, since the thread has limit stack.
+ void EnableADUnloadWorker(EEPolicy::AppDomainUnloadTypes type, BOOL fHasStack = TRUE);
+
+ static void EnableADUnloadWorkerForThreadAbort();
+ static void EnableADUnloadWorkerForFinalizer();
+ static void EnableADUnloadWorkerForCollectedADCleanup();
+
+ BOOL IsUnloadRequested()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return (m_Stage == STAGE_UNLOAD_REQUESTED);
+ }
+
+#ifdef FEATURE_CORECLR
+ BOOL IsImageFromTrustedPath(PEImage* pImage);
+ BOOL IsImageFullyTrusted(PEImage* pImage);
+#endif
+
+#ifdef FEATURE_TYPEEQUIVALENCE
+private:
+ VolatilePtr<TypeEquivalenceHashTable> m_pTypeEquivalenceTable;
+ CrstExplicitInit m_TypeEquivalenceCrst;
+public:
+ TypeEquivalenceHashTable * GetTypeEquivalenceCache();
+#endif
+
+ private:
+ static void ADUnloadWorkerHelper(AppDomain *pDomain);
+ static CLREvent * g_pUnloadStartEvent;
+
+#ifdef DACCESS_COMPILE
+public:
+ virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
+ bool enumThis);
+#endif
+
+#ifdef FEATURE_MULTICOREJIT
+
+private:
+ MulticoreJitManager m_MulticoreJitManager;
+
+public:
+ MulticoreJitManager & GetMulticoreJitManager()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_MulticoreJitManager;
+ }
+
+#endif
+
+#ifdef FEATURE_COMINTEROP
+
+private:
+#ifdef FEATURE_REFLECTION_ONLY_LOAD
+ // ReflectionOnly WinRT binder and its TypeCache (only in classic = non-AppX; the scenario is not supported in AppX)
+ CLRPrivBinderReflectionOnlyWinRT * m_pReflectionOnlyWinRtBinder;
+ CLRPrivTypeCacheReflectionOnlyWinRT * m_pReflectionOnlyWinRtTypeCache;
+#endif // FEATURE_REFLECTION_ONLY_LOAD
+
+#endif //FEATURE_COMINTEROP
+
+public:
+#ifndef FEATURE_CORECLR
+ BOOL m_bUseOsSorting;
+ DWORD m_sortVersion;
+ COMNlsCustomSortLibrary *m_pCustomSortLibrary;
+#if _DEBUG
+ BOOL m_bSortingInitialized;
+#endif // _DEBUG
+ COMNlsHashProvider *m_pNlsHashProvider;
+#endif // !FEATURE_CORECLR
+
+private:
+ // This is the root-level default load context root binder. If null, then
+ // the Fusion binder is used; otherwise this binder is used.
+ ReleaseHolder<ICLRPrivBinder> m_pLoadContextHostBinder;
+
+ // -------------------------
+ // IMPORTANT!
+ // The shared and designer context binders are ONLY to be used in tool
+ // scenarios. There are known issues where use of these binders will
+ // cause application crashes, and interesting behaviors.
+ // -------------------------
+
+ // This is the default designer shared context root binder.
+ // This is used as the parent binder for ImmersiveDesignerContextBinders
+ ReleaseHolder<ICLRPrivBinder> m_pSharedContextHostBinder;
+
+ // This is the current context root binder.
+ // Normally, this variable is immutable for appdomain lifetime, but in designer scenarios
+ // it may be replaced by designer context binders
+ Volatile<ICLRPrivBinder *> m_pCurrentContextHostBinder;
+
+public:
+ // Returns the current hosted binder, or null if none available.
+ inline
+ ICLRPrivBinder * GetCurrentLoadContextHostBinder() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pCurrentContextHostBinder;
+ }
+
+ // Returns the shared context binder, or null if none available.
+ inline
+ ICLRPrivBinder * GetSharedContextHostBinder() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pSharedContextHostBinder;
+ }
+
+ // Returns the load context binder, or null if none available.
+ inline
+ ICLRPrivBinder * GetLoadContextHostBinder() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pLoadContextHostBinder;
+ }
+
+#ifndef DACCESS_COMPILE
+
+ // This is only called from the ImmersiveDesignerContext code
+ // It is protected with a managed monitor lock
+ inline
+ void SetSharedContextHostBinder(ICLRPrivBinder * pBinder)
+ {
+ LIMITED_METHOD_CONTRACT;
+ pBinder->AddRef();
+ m_pSharedContextHostBinder = pBinder;
+ }
+
+ // This is called from CorHost2's implementation of ICLRPrivRuntime::CreateAppDomain.
+ // Should only be called during AppDomain creation.
+ inline
+ void SetLoadContextHostBinder(ICLRPrivBinder * pBinder)
+ {
+ LIMITED_METHOD_CONTRACT;
+ pBinder->AddRef();
+ m_pLoadContextHostBinder = m_pCurrentContextHostBinder = pBinder;
+ }
+
+ inline
+ void SetCurrentContextHostBinder(ICLRPrivBinder * pBinder)
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ }
+ CONTRACTL_END;
+
+ LockHolder lh(this);
+
+#ifdef FEATURE_COMINTEROP
+ if (m_pNameToTypeMap != nullptr)
+ {
+ delete m_pNameToTypeMap;
+ m_pNameToTypeMap = nullptr;
+ }
+
+ m_vNameToTypeMapVersion++;
+#endif
+
+ m_pCurrentContextHostBinder = pBinder;
+ }
+
+#endif // DACCESS_COMPILE
+
+ // Indicates that a hosted binder is present.
+ inline
+ bool HasLoadContextHostBinder()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pLoadContextHostBinder != nullptr;
+ }
+
+ class ComInterfaceReleaseList
+ {
+ SArray<IUnknown *> m_objects;
+ public:
+ ~ComInterfaceReleaseList()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ for (COUNT_T i = 0; i < m_objects.GetCount(); i++)
+ {
+ IUnknown *pItf = *(m_objects.GetElements() + i);
+ if (pItf != nullptr)
+ pItf->Release();
+ }
+ }
+
+ // Append to the list of object to free. Only use under the AppDomain "LockHolder(pAppDomain)"
+ void Append(IUnknown *pInterfaceToRelease)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_objects.Append(pInterfaceToRelease);
+ }
+ } AppDomainInterfaceReleaseList;
+
+private:
+ //-----------------------------------------------------------
+ // Static ICLRPrivAssembly -> DomainAssembly mapping functions.
+ // This map does not maintain a reference count to either key or value.
+ // PEFile maintains a reference count on the ICLRPrivAssembly through its code:PEFile::m_pHostAssembly field.
+ // It is removed from this hash table by code:DomainAssembly::~DomainAssembly.
+ struct HostAssemblyHashTraits : public DefaultSHashTraits<PTR_DomainAssembly>
+ {
+ public:
+ typedef PTR_ICLRPrivAssembly key_t;
+
+ static key_t GetKey(element_t const & elem)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ return elem->GetFile()->GetHostAssembly();
+ }
+
+ static BOOL Equals(key_t key1, key_t key2)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return dac_cast<TADDR>(key1) == dac_cast<TADDR>(key2);
+ }
+
+ static count_t Hash(key_t key)
+ {
+ STATIC_CONTRACT_LIMITED_METHOD;
+ //return reinterpret_cast<count_t>(dac_cast<TADDR>(key));
+ return (count_t)(dac_cast<TADDR>(key));
+ }
+
+ static const element_t Null() { return NULL; }
+ static const element_t Deleted() { return (element_t)(TADDR)-1; }
+ static bool IsNull(const element_t & e) { return e == NULL; }
+ static bool IsDeleted(const element_t & e) { return dac_cast<TADDR>(e) == (TADDR)-1; }
+ };
+
+ struct OriginalFileHostAssemblyHashTraits : public HostAssemblyHashTraits
+ {
+ public:
+ static key_t GetKey(element_t const & elem)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ return elem->GetOriginalFile()->GetHostAssembly();
+ }
+ };
+
+ typedef SHash<HostAssemblyHashTraits> HostAssemblyMap;
+ typedef SHash<OriginalFileHostAssemblyHashTraits> OriginalFileHostAssemblyMap;
+ HostAssemblyMap m_hostAssemblyMap;
+ OriginalFileHostAssemblyMap m_hostAssemblyMapForOrigFile;
+ CrstExplicitInit m_crstHostAssemblyMap;
+ // Lock to serialize all Add operations (in addition to the "read-lock" above)
+ CrstExplicitInit m_crstHostAssemblyMapAdd;
+
+public:
+ // Returns DomainAssembly.
+ PTR_DomainAssembly FindAssembly(PTR_ICLRPrivAssembly pHostAssembly);
+
+#ifndef DACCESS_COMPILE
+private:
+ friend void DomainAssembly::Allocate();
+ friend DomainAssembly::~DomainAssembly();
+
+ // Called from DomainAssembly::Begin.
+ void PublishHostedAssembly(
+ DomainAssembly* pAssembly);
+
+ // Called from DomainAssembly::UpdatePEFile.
+ void UpdatePublishHostedAssembly(
+ DomainAssembly* pAssembly,
+ PTR_PEFile pFile);
+
+ // Called from DomainAssembly::~DomainAssembly
+ void UnPublishHostedAssembly(
+ DomainAssembly* pAssembly);
+#endif // DACCESS_COMPILE
+
+#ifdef FEATURE_PREJIT
+ friend void DomainFile::InsertIntoDomainFileWithNativeImageList();
+ Volatile<DomainFile *> m_pDomainFileWithNativeImageList;
+public:
+ DomainFile *GetDomainFilesWithNativeImagesList()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pDomainFileWithNativeImageList;
+ }
+#endif
+}; // class AppDomain
+
+
+// This holder is to be used to take a reference to make sure AppDomain* is still valid
+// Please do not use if you are aleady ADU-safe
+typedef Wrapper<AppDomain*,AppDomain::RefTakerAcquire,AppDomain::RefTakerRelease,NULL> AppDomainRefTaker;
+
+// Just a ref holder
+typedef ReleaseHolder<AppDomain> AppDomainRefHolder;
+
+// This class provides a way to access AppDomain by ID
+// without risking the appdomain getting invalid in the process
+class AppDomainFromIDHolder
+{
+public:
+ enum SyncType
+ {
+ SyncType_GC, // Prevents AD from being unloaded by forbidding GC for the lifetime of the object
+ SyncType_ADLock // Prevents AD from being unloaded by requiring ownership of DomainLock for the lifetime of the object
+ };
+protected:
+ AppDomain* m_pDomain;
+#ifdef _DEBUG
+ BOOL m_bAcquired;
+ BOOL m_bChecked;
+ SyncType m_type;
+#endif
+public:
+ DEBUG_NOINLINE AppDomainFromIDHolder(ADID adId, BOOL bUnsafePoint, SyncType synctype=SyncType_GC);
+ DEBUG_NOINLINE AppDomainFromIDHolder(SyncType synctype=SyncType_GC);
+ DEBUG_NOINLINE ~AppDomainFromIDHolder();
+
+ void* GetAddress() { return m_pDomain; } // Used to get an identfier for ETW
+ void Assign(ADID adId, BOOL bUnsafePoint);
+ void ThrowIfUnloaded();
+ void Release();
+ BOOL IsUnloaded()
+ {
+ LIMITED_METHOD_CONTRACT;
+#ifdef _DEBUG
+ m_bChecked=TRUE;
+ if (m_pDomain==NULL)
+ {
+ // no need to enforce anything
+ Release();
+ }
+#endif
+ return m_pDomain==NULL;
+ };
+ AppDomain* operator->();
+}; // class AppDomainFromIDHolder
+
+
+
+typedef VPTR(class SystemDomain) PTR_SystemDomain;
+
+class SystemDomain : public BaseDomain
+{
+ friend class AppDomainNative;
+ friend class AppDomainIterator;
+ friend class UnsafeAppDomainIterator;
+ friend class ClrDataAccess;
+ friend class AppDomainFromIDHolder;
+ friend Frame *Thread::IsRunningIn(AppDomain* pDomain, int *count);
+
+ VPTR_VTABLE_CLASS(SystemDomain, BaseDomain)
+ VPTR_UNIQUE(VPTR_UNIQUE_SystemDomain)
+ static AppDomain *GetAppDomainAtId(ADID indx);
+
+public:
+ static PTR_LoaderAllocator GetGlobalLoaderAllocator();
+ virtual PTR_LoaderAllocator GetLoaderAllocator() { WRAPPER_NO_CONTRACT; return GetGlobalLoaderAllocator(); }
+ static AppDomain* GetAppDomainFromId(ADID indx,DWORD ADValidityKind)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+ AppDomain* pRetVal;
+ if (indx.m_dwId==DefaultADID)
+ pRetVal= SystemDomain::System()->DefaultDomain();
+ else
+ pRetVal= GetAppDomainAtId(indx);
+#ifdef _DEBUG
+ // Only call CheckADValidity in DEBUG builds for non-NULL return values
+ if (pRetVal != NULL)
+ CheckADValidity(pRetVal, ADValidityKind);
+#endif
+ return pRetVal;
+ }
+ //****************************************************************************************
+ //
+ // To be run during the initial start up of the EE. This must be
+ // performed prior to any class operations.
+ static void Attach();
+
+ //****************************************************************************************
+ //
+ // To be run during shutdown. This must be done after all operations
+ // that require the use of system classes (i.e., exceptions).
+ // DetachBegin stops all domains, while DetachEnd deallocates domain resources.
+ static void DetachBegin();
+
+ //****************************************************************************************
+ //
+ // To be run during shutdown. This must be done after all operations
+ // that require the use of system classes (i.e., exceptions).
+ // DetachBegin stops release resources held by systemdomain and the default domain.
+ static void DetachEnd();
+
+ //****************************************************************************************
+ //
+ // Initializes and shutdowns the single instance of the SystemDomain
+ // in the EE
+#ifndef DACCESS_COMPILE
+ void *operator new(size_t size, void *pInPlace);
+ void operator delete(void *pMem);
+#endif
+ void Init();
+ void Stop();
+ void Terminate();
+ static void LazyInitGlobalStringLiteralMap();
+
+ //****************************************************************************************
+ //
+ // Load the base system classes, these classes are required before
+ // any other classes are loaded
+ void LoadBaseSystemClasses();
+
+ AppDomain* DefaultDomain()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return m_pDefaultDomain;
+ }
+
+ // Notification when an assembly is loaded into the system domain
+ void OnAssemblyLoad(Assembly *assem);
+
+ //****************************************************************************************
+ //
+ // Global Static to get the one and only system domain
+ static SystemDomain * System()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return m_pSystemDomain;
+ }
+
+ static PEAssembly* SystemFile()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ _ASSERTE(m_pSystemDomain);
+ return System()->m_pSystemFile;
+ }
+
+ static Assembly* SystemAssembly()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ return System()->m_pSystemAssembly;
+ }
+
+ static Module* SystemModule()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ return SystemAssembly()->GetManifestModule();
+ }
+
+ static BOOL IsSystemLoaded()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ return System()->m_pSystemAssembly != NULL;
+ }
+
+#ifndef DACCESS_COMPILE
+ static GlobalStringLiteralMap *GetGlobalStringLiteralMap()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ if (m_pGlobalStringLiteralMap == NULL)
+ {
+ SystemDomain::LazyInitGlobalStringLiteralMap();
+ }
+ _ASSERTE(m_pGlobalStringLiteralMap);
+ return m_pGlobalStringLiteralMap;
+ }
+ static GlobalStringLiteralMap *GetGlobalStringLiteralMapNoCreate()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(m_pGlobalStringLiteralMap);
+ return m_pGlobalStringLiteralMap;
+ }
+#endif // DACCESS_COMPILE
+
+#ifndef FEATURE_CORECLR
+ static void ExecuteMainMethod(HMODULE hMod, __in_opt LPWSTR path = NULL);
+#endif
+ static void ActivateApplication(int *pReturnValue);
+
+ static void InitializeDefaultDomain(BOOL allowRedirects, ICLRPrivBinder * pBinder = NULL);
+ static void SetupDefaultDomain();
+ static HRESULT SetupDefaultDomainNoThrow();
+
+#if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
+ static Thread::ApartmentState GetEntryPointThreadAptState(IMDInternalImport* pScope, mdMethodDef mdMethod);
+ static void SetThreadAptState(IMDInternalImport* pScope, Thread::ApartmentState state);
+#endif
+ static BOOL SetGlobalSharePolicyUsingAttribute(IMDInternalImport* pScope, mdMethodDef mdMethod);
+
+#ifdef FEATURE_MIXEDMODE
+ static HRESULT RunDllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved);
+#endif // FEATURE_MIXEDMODE
+
+ //****************************************************************************************
+ //
+ // Use an already exising & inited Application Domain (e.g. a subclass).
+ static void LoadDomain(AppDomain *pDomain);
+
+#ifndef DACCESS_COMPILE
+ static void MakeUnloadable(AppDomain* pApp)
+ {
+ WRAPPER_NO_CONTRACT;
+ System()->AddDomain(pApp);
+ pApp->SetCanUnload();
+ }
+#endif // DACCESS_COMPILE
+
+ //****************************************************************************************
+ // Methods used to get the callers module and hence assembly and app domain.
+ __declspec(deprecated("This method is deprecated, use the version that takes a StackCrawlMark instead"))
+ static Module* GetCallersModule(int skip);
+ static MethodDesc* GetCallersMethod(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
+ static MethodTable* GetCallersType(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
+ static Module* GetCallersModule(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
+ static Assembly* GetCallersAssembly(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
+
+ static bool IsReflectionInvocationMethod(MethodDesc* pMeth);
+
+#ifndef DACCESS_COMPILE
+ //****************************************************************************************
+ // Returns the domain associated with the current context. (this can only be a child domain)
+ static inline AppDomain * GetCurrentDomain()
+ {
+ WRAPPER_NO_CONTRACT;
+ return ::GetAppDomain();
+ }
+#endif //!DACCESS_COMPILE
+
+#ifdef DEBUGGING_SUPPORTED
+ //****************************************************************************************
+ // Debugger/Publisher helper function to indicate creation of new app domain to debugger
+ // and publishing it in the IPC block
+ static void PublishAppDomainAndInformDebugger (AppDomain *pDomain);
+#endif // DEBUGGING_SUPPORTED
+
+ //****************************************************************************************
+ // Helper function to remove a domain from the system
+ BOOL RemoveDomain(AppDomain* pDomain); // Does not decrement the reference
+
+#ifdef PROFILING_SUPPORTED
+ //****************************************************************************************
+ // Tell profiler about system created domains which are created before the profiler is
+ // actually activated.
+ static void NotifyProfilerStartup();
+
+ //****************************************************************************************
+ // Tell profiler at shutdown that system created domains are going away. They are not
+ // torn down using the normal sequence.
+ static HRESULT NotifyProfilerShutdown();
+#endif // PROFILING_SUPPORTED
+
+ //****************************************************************************************
+ // return the dev path
+#ifdef FEATURE_FUSION
+ void GetDevpathW(__out_ecount_opt(1) LPWSTR* pPath, DWORD* pSize);
+#endif
+
+#ifndef DACCESS_COMPILE
+ void IncrementNumAppDomains ()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ s_dNumAppDomains++;
+ }
+
+ void DecrementNumAppDomains ()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ s_dNumAppDomains--;
+ }
+
+ ULONG GetNumAppDomains ()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return s_dNumAppDomains;
+ }
+#endif // DACCESS_COMPILE
+
+ //
+ // AppDomains currently have both an index and an ID. The
+ // index is "densely" assigned; indices are reused as domains
+ // are unloaded. The Id's on the other hand, are not reclaimed
+ // so may be sparse.
+ //
+ // Another important difference - it's OK to call GetAppDomainAtId for
+ // an unloaded domain (it will return NULL), while GetAppDomainAtIndex
+ // will assert if the domain is unloaded.
+ //<TODO>
+ // @todo:
+ // I'm not really happy with this situation, but
+ // (a) we need an ID for a domain which will last the process lifetime for the
+ // remoting code.
+ // (b) we need a dense ID, for the handle table index.
+ // So for now, I'm leaving both, but hopefully in the future we can come up
+ // with something better.
+ //</TODO>
+
+ static ADIndex GetNewAppDomainIndex(AppDomain * pAppDomain);
+ static void ReleaseAppDomainIndex(ADIndex indx);
+ static PTR_AppDomain GetAppDomainAtIndex(ADIndex indx);
+ static PTR_AppDomain TestGetAppDomainAtIndex(ADIndex indx);
+ static DWORD GetCurrentAppDomainMaxIndex()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ ArrayListStatic* list = (ArrayListStatic *)&m_appDomainIndexList;
+ PREFIX_ASSUME(list!=NULL);
+ return list->GetCount();
+ }
+
+ static ADID GetNewAppDomainId(AppDomain *pAppDomain);
+ static void ReleaseAppDomainId(ADID indx);
+
+#ifndef DACCESS_COMPILE
+ static ADID GetCurrentAppDomainMaxId() { ADID id; id.m_dwId=m_appDomainIdList.GetCount(); return id;}
+#endif // DACCESS_COMPILE
+
+
+#ifndef DACCESS_COMPILE
+ DWORD RequireAppDomainCleanup()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pDelayedUnloadList != 0 || m_pDelayedUnloadListOfLoaderAllocators != 0;
+ }
+
+ void AddToDelayedUnloadList(AppDomain* pDomain, BOOL bAsync)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+ m_UnloadIsAsync = bAsync;
+
+ CrstHolder lh(&m_DelayedUnloadCrst);
+ pDomain->m_pNextInDelayedUnloadList=m_pDelayedUnloadList;
+ m_pDelayedUnloadList=pDomain;
+ if (m_UnloadIsAsync)
+ {
+ pDomain->AddRef();
+ int iGCRefPoint=GCHeap::GetGCHeap()->CollectionCount(GCHeap::GetGCHeap()->GetMaxGeneration());
+ if (GCHeap::GetGCHeap()->IsGCInProgress())
+ iGCRefPoint++;
+ pDomain->SetGCRefPoint(iGCRefPoint);
+ }
+ }
+
+ void AddToDelayedUnloadList(LoaderAllocator * pAllocator)
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ CrstHolder lh(&m_DelayedUnloadCrst);
+ pAllocator->m_pLoaderAllocatorDestroyNext=m_pDelayedUnloadListOfLoaderAllocators;
+ m_pDelayedUnloadListOfLoaderAllocators=pAllocator;
+
+ int iGCRefPoint=GCHeap::GetGCHeap()->CollectionCount(GCHeap::GetGCHeap()->GetMaxGeneration());
+ if (GCHeap::GetGCHeap()->IsGCInProgress())
+ iGCRefPoint++;
+ pAllocator->SetGCRefPoint(iGCRefPoint);
+ }
+
+ void ClearCollectedDomains();
+ void ProcessClearingDomains();
+ void ProcessDelayedUnloadDomains();
+
+ static void SetUnloadInProgress(AppDomain *pDomain)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ _ASSERTE(m_pAppDomainBeingUnloaded == NULL);
+ m_pAppDomainBeingUnloaded = pDomain;
+ m_dwIndexOfAppDomainBeingUnloaded = pDomain->GetIndex();
+ }
+
+ static void SetUnloadDomainCleared()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ // about to delete, so clear this pointer so nobody uses it
+ m_pAppDomainBeingUnloaded = NULL;
+ }
+ static void SetUnloadComplete()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ // should have already cleared the AppDomain* prior to delete
+ // either we succesfully unloaded and cleared or we failed and restored the ID
+ _ASSERTE(m_pAppDomainBeingUnloaded == NULL && m_dwIndexOfAppDomainBeingUnloaded.m_dwIndex != 0
+ || m_pAppDomainBeingUnloaded && SystemDomain::GetAppDomainAtId(m_pAppDomainBeingUnloaded->GetId()) != NULL);
+ m_pAppDomainBeingUnloaded = NULL;
+ m_pAppDomainUnloadingThread = NULL;
+ }
+
+ static AppDomain *AppDomainBeingUnloaded()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pAppDomainBeingUnloaded;
+ }
+
+ static ADIndex IndexOfAppDomainBeingUnloaded()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_dwIndexOfAppDomainBeingUnloaded;
+ }
+
+ static void SetUnloadRequestingThread(Thread *pRequestingThread)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pAppDomainUnloadRequestingThread = pRequestingThread;
+ }
+
+ static Thread *GetUnloadRequestingThread()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pAppDomainUnloadRequestingThread;
+ }
+
+ static void SetUnloadingThread(Thread *pUnloadingThread)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pAppDomainUnloadingThread = pUnloadingThread;
+ }
+
+ static Thread *GetUnloadingThread()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pAppDomainUnloadingThread;
+ }
+
+ static void EnumAllStaticGCRefs(promote_func* fn, ScanContext* sc);
+
+#endif // DACCESS_COMPILE
+
+#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
+ // The *AD* methods are what we got from tracing through EE roots.
+ // RecordTotalSurvivedBytes is the total promoted from a GC.
+ static void ResetADSurvivedBytes();
+ static ULONGLONG GetADSurvivedBytes();
+ static void RecordTotalSurvivedBytes(size_t totalSurvivedBytes);
+ static ULONGLONG GetTotalSurvivedBytes()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_totalSurvivedBytes;
+ }
+#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
+
+ //****************************************************************************************
+ // Routines to deal with the base library (currently mscorlib.dll)
+ LPCWSTR BaseLibrary()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ return m_BaseLibrary;
+ }
+
+#ifndef DACCESS_COMPILE
+ BOOL IsBaseLibrary(SString &path)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ // See if it is the installation path to mscorlib
+ if (path.EqualsCaseInsensitive(m_BaseLibrary, PEImage::GetFileSystemLocale()))
+ return TRUE;
+
+ // Or, it might be the GAC location of mscorlib
+ if (System()->SystemAssembly() != NULL
+ && path.EqualsCaseInsensitive(System()->SystemAssembly()->GetManifestFile()->GetPath(),
+ PEImage::GetFileSystemLocale()))
+ return TRUE;
+
+ return FALSE;
+ }
+
+ BOOL IsBaseLibrarySatellite(SString &path)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ // See if it is the installation path to mscorlib.resources
+ SString s(SString::Ascii,g_psBaseLibrarySatelliteAssemblyName);
+ if (path.EqualsCaseInsensitive(s, PEImage::GetFileSystemLocale()))
+ return TRUE;
+
+ // workaround! Must implement some code to do this string comparison for
+ // mscorlib.resources in a culture-specific directory in the GAC.
+
+ /*
+ // Or, it might be the GAC location of mscorlib.resources
+ if (System()->SystemAssembly() != NULL
+ && path.EqualsCaseInsensitive(System()->SystemAssembly()->GetManifestFile()->GetPath(),
+ PEImage::GetFileSystemLocale()))
+ return TRUE;
+ */
+
+ return FALSE;
+ }
+#endif // DACCESS_COMPILE
+
+ // Return the system directory
+ LPCWSTR SystemDirectory()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ return m_SystemDirectory;
+ }
+
+private:
+
+ //****************************************************************************************
+ // Helper function to create the single COM domain
+ void CreateDefaultDomain();
+
+ //****************************************************************************************
+ // Helper function to add a domain to the global list
+ void AddDomain(AppDomain* pDomain);
+
+ void CreatePreallocatedExceptions();
+
+ void PreallocateSpecialObjects();
+
+ //****************************************************************************************
+ //
+ static StackWalkAction CallersMethodCallback(CrawlFrame* pCrawlFrame, VOID* pClientData);
+ static StackWalkAction CallersMethodCallbackWithStackMark(CrawlFrame* pCrawlFrame, VOID* pClientData);
+
+#ifndef DACCESS_COMPILE
+ // This class is not to be created through normal allocation.
+ SystemDomain()
+ {
+ STANDARD_VM_CONTRACT;
+
+ m_pDefaultDomain = NULL;
+ m_pDelayedUnloadList=NULL;
+ m_pDelayedUnloadListOfLoaderAllocators=NULL;
+ m_UnloadIsAsync = FALSE;
+
+ m_GlobalAllocator.Init(this);
+ }
+#endif
+
+ PTR_PEAssembly m_pSystemFile; // Single assembly (here for quicker reference);
+ PTR_Assembly m_pSystemAssembly; // Single assembly (here for quicker reference);
+ PTR_AppDomain m_pDefaultDomain; // Default domain for COM+ classes exposed through IClassFactory.
+
+ GlobalLoaderAllocator m_GlobalAllocator;
+
+
+ InlineSString<100> m_BaseLibrary;
+
+#ifdef FEATURE_VERSIONING
+
+ InlineSString<100> m_SystemDirectory;
+
+#else
+
+ LPCWSTR m_SystemDirectory;
+
+#endif
+
+ LPWSTR m_pwDevpath;
+ DWORD m_dwDevpath;
+ BOOL m_fDevpath; // have we searched the environment
+
+ // <TODO>@TODO: CTS, we can keep the com modules in a single assembly or in different assemblies.
+ // We are currently using different assemblies but this is potentitially to slow...</TODO>
+
+ // Global domain that every one uses
+ SPTR_DECL(SystemDomain, m_pSystemDomain);
+
+ AppDomain* m_pDelayedUnloadList;
+ BOOL m_UnloadIsAsync;
+
+ LoaderAllocator * m_pDelayedUnloadListOfLoaderAllocators;
+
+#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
+ // This is what gets promoted for the whole GC heap.
+ static size_t m_totalSurvivedBytes;
+#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
+
+ SVAL_DECL(ArrayListStatic, m_appDomainIndexList);
+#ifndef DACCESS_COMPILE
+ static CrstStatic m_DelayedUnloadCrst;
+ static CrstStatic m_SystemDomainCrst;
+
+
+ static ArrayListStatic m_appDomainIdList;
+
+ // only one ad can be unloaded at a time
+ static AppDomain* m_pAppDomainBeingUnloaded;
+ // need this so can determine AD being unloaded after it has been deleted
+ static ADIndex m_dwIndexOfAppDomainBeingUnloaded;
+
+ // if had to spin off a separate thread to do the unload, this is the original thread.
+ // allows us to delay aborting it until it's the last one so that it can receive
+ // notification of an unload failure
+ static Thread *m_pAppDomainUnloadRequestingThread;
+
+ // this is the thread doing the actual unload. He's allowed to enter the domain
+ // even if have started unloading.
+ static Thread *m_pAppDomainUnloadingThread;
+
+ static GlobalStringLiteralMap *m_pGlobalStringLiteralMap;
+
+ static ULONG s_dNumAppDomains; // Maintain a count of children app domains.
+
+ static DWORD m_dwLowestFreeIndex;
+#endif // DACCESS_COMPILE
+
+protected:
+
+ // These flags let the correct native image of mscorlib to be loaded.
+ // This is important for hardbinding to it
+
+ SVAL_DECL(BOOL, s_fForceDebug);
+ SVAL_DECL(BOOL, s_fForceProfiling);
+ SVAL_DECL(BOOL, s_fForceInstrument);
+
+public:
+ static void SetCompilationOverrides(BOOL fForceDebug,
+ BOOL fForceProfiling,
+ BOOL fForceInstrument);
+
+ static void GetCompilationOverrides(BOOL * fForceDebug,
+ BOOL * fForceProfiling,
+ BOOL * fForceInstrument);
+public:
+ //****************************************************************************************
+ //
+
+#ifndef DACCESS_COMPILE
+#ifdef _DEBUG
+inline static BOOL IsUnderDomainLock() { LIMITED_METHOD_CONTRACT; return m_SystemDomainCrst.OwnedByCurrentThread();};
+#endif
+
+ // This lock controls adding and removing domains from the system domain
+ class LockHolder : public CrstHolder
+ {
+ public:
+ LockHolder()
+ : CrstHolder(&m_SystemDomainCrst)
+ {
+ WRAPPER_NO_CONTRACT;
+ }
+ };
+#endif // DACCESS_COMPILE
+
+public:
+ DWORD GetTotalNumSizedRefHandles();
+
+#ifdef DACCESS_COMPILE
+public:
+ virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
+ bool enumThis);
+#endif
+
+}; // class SystemDomain
+
+
+//
+// an UnsafeAppDomainIterator is used to iterate over all existing domains
+//
+// The iteration is guaranteed to include all domains that exist at the
+// start & end of the iteration. This iterator is considered unsafe because it does not
+// reference count the various appdomains, and can only be used when the runtime is stopped,
+// or external synchronization is used. (and therefore no other thread may cause the appdomain list to change.)
+//
+class UnsafeAppDomainIterator
+{
+ friend class SystemDomain;
+public:
+ UnsafeAppDomainIterator(BOOL bOnlyActive)
+ {
+ m_bOnlyActive = bOnlyActive;
+ }
+
+ void Init()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SystemDomain* sysDomain = SystemDomain::System();
+ if (sysDomain)
+ {
+ ArrayListStatic* list = &sysDomain->m_appDomainIndexList;
+ PREFIX_ASSUME(list != NULL);
+ m_i = list->Iterate();
+ }
+ else
+ {
+ m_i.SetEmpty();
+ }
+
+ m_pCurrent = NULL;
+ }
+
+ BOOL Next()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ while (m_i.Next())
+ {
+ m_pCurrent = dac_cast<PTR_AppDomain>(m_i.GetElement());
+ if (m_pCurrent != NULL &&
+ (m_bOnlyActive ?
+ m_pCurrent->IsActive() : m_pCurrent->IsValid()))
+ {
+ return TRUE;
+ }
+ }
+
+ m_pCurrent = NULL;
+ return FALSE;
+ }
+
+ AppDomain * GetDomain()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return m_pCurrent;
+ }
+
+ private:
+
+ ArrayList::Iterator m_i;
+ AppDomain * m_pCurrent;
+ BOOL m_bOnlyActive;
+}; // class UnsafeAppDomainIterator
+
+//
+// an AppDomainIterator is used to iterate over all existing domains.
+//
+// The iteration is guaranteed to include all domains that exist at the
+// start & end of the iteration. Any domains added or deleted during
+// iteration may or may not be included. The iterator also guarantees
+// that the current iterated appdomain (GetDomain()) will not be deleted.
+//
+
+class AppDomainIterator : public UnsafeAppDomainIterator
+{
+ friend class SystemDomain;
+
+ public:
+ AppDomainIterator(BOOL bOnlyActive) : UnsafeAppDomainIterator(bOnlyActive)
+ {
+ WRAPPER_NO_CONTRACT;
+ Init();
+ }
+
+ ~AppDomainIterator()
+ {
+ WRAPPER_NO_CONTRACT;
+
+#ifndef DACCESS_COMPILE
+ if (GetDomain() != NULL)
+ {
+#ifdef _DEBUG
+ GetDomain()->IteratorRelease();
+#endif
+ GetDomain()->Release();
+ }
+#endif
+ }
+
+ BOOL Next()
+ {
+ WRAPPER_NO_CONTRACT;
+
+#ifndef DACCESS_COMPILE
+ if (GetDomain() != NULL)
+ {
+#ifdef _DEBUG
+ GetDomain()->IteratorRelease();
+#endif
+ GetDomain()->Release();
+ }
+
+ SystemDomain::LockHolder lh;
+#endif
+
+ if (UnsafeAppDomainIterator::Next())
+ {
+#ifndef DACCESS_COMPILE
+ GetDomain()->AddRef();
+#ifdef _DEBUG
+ GetDomain()->IteratorAcquire();
+#endif
+#endif
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+}; // class AppDomainIterator
+
+typedef VPTR(class SharedDomain) PTR_SharedDomain;
+
+class SharedDomain : public BaseDomain
+{
+ VPTR_VTABLE_CLASS_AND_CTOR(SharedDomain, BaseDomain)
+
+public:
+
+ static void Attach();
+ static void Detach();
+
+ virtual BOOL IsSharedDomain() { LIMITED_METHOD_DAC_CONTRACT; return TRUE; }
+ virtual PTR_LoaderAllocator GetLoaderAllocator() { WRAPPER_NO_CONTRACT; return SystemDomain::GetGlobalLoaderAllocator(); }
+
+ virtual PTR_AppDomain AsAppDomain()
+ {
+ LIMITED_METHOD_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ _ASSERTE(!"Not an AppDomain");
+ return NULL;
+ }
+
+ static SharedDomain * GetDomain();
+
+ void Init();
+ void Terminate();
+
+ // This will also set the tenured bit if and only if the add was successful,
+ // and will make sure that the bit appears atomically set to all readers that
+ // might be accessing the hash on another thread.
+ MethodTable * FindIndexClass(SIZE_T index);
+
+#ifdef FEATURE_LOADER_OPTIMIZATION
+ void AddShareableAssembly(Assembly * pAssembly);
+
+ class SharedAssemblyIterator
+ {
+ PtrHashMap::PtrIterator i;
+ Assembly * m_pAssembly;
+
+ public:
+ SharedAssemblyIterator() :
+ i(GetDomain() ? GetDomain()->m_assemblyMap.firstBucket() : NULL)
+ { LIMITED_METHOD_DAC_CONTRACT; }
+
+ BOOL Next()
+ {
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+
+ if (i.end())
+ return FALSE;
+
+ m_pAssembly = PTR_Assembly(dac_cast<TADDR>(i.GetValue()));
+ ++i;
+ return TRUE;
+ }
+
+ Assembly * GetAssembly()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return m_pAssembly;
+ }
+
+ private:
+ friend class SharedDomain;
+ };
+
+ Assembly * FindShareableAssembly(SharedAssemblyLocator * pLocator);
+ SIZE_T GetShareableAssemblyCount();
+#endif //FEATURE_LOADER_OPTIMIZATION
+
+private:
+ friend class SharedAssemblyIterator;
+ friend class SharedFileLockHolder;
+ friend class ClrDataAccess;
+
+#ifndef DACCESS_COMPILE
+ void *operator new(size_t size, void *pInPlace);
+ void operator delete(void *pMem);
+#endif
+
+ SPTR_DECL(SharedDomain, m_pSharedDomain);
+
+#ifdef FEATURE_LOADER_OPTIMIZATION
+ PEFileListLock m_FileCreateLock;
+ SIZE_T m_nextClassIndex;
+ PtrHashMap m_assemblyMap;
+#endif
+
+public:
+#ifdef DACCESS_COMPILE
+ virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
+ bool enumThis);
+#endif
+
+#ifdef FEATURE_LOADER_OPTIMIZATION
+ // Hash map comparison function`
+ static BOOL CompareSharedAssembly(UPTR u1, UPTR u2);
+#endif
+};
+
+#ifdef FEATURE_LOADER_OPTIMIZATION
+class SharedFileLockHolderBase : protected HolderBase<PEFile *>
+{
+ protected:
+ PEFileListLock *m_pLock;
+ ListLockEntry *m_pLockElement;
+
+ SharedFileLockHolderBase(PEFile *value)
+ : HolderBase<PEFile *>(value)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_pLock = NULL;
+ m_pLockElement = NULL;
+ }
+
+#ifndef DACCESS_COMPILE
+ void DoAcquire()
+ {
+ STATIC_CONTRACT_THROWS;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_FAULT;
+
+ PEFileListLockHolder lockHolder(m_pLock);
+
+ m_pLockElement = m_pLock->FindFileLock(m_value);
+ if (m_pLockElement == NULL)
+ {
+ m_pLockElement = new ListLockEntry(m_pLock, m_value);
+ m_pLock->AddElement(m_pLockElement);
+ }
+ else
+ m_pLockElement->AddRef();
+
+ lockHolder.Release();
+
+ m_pLockElement->Enter();
+ }
+
+ void DoRelease()
+ {
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_FORBID_FAULT;
+
+ m_pLockElement->Leave();
+ m_pLockElement->Release();
+ m_pLockElement = NULL;
+ }
+#endif // DACCESS_COMPILE
+};
+
+class SharedFileLockHolder : public BaseHolder<PEFile *, SharedFileLockHolderBase>
+{
+ public:
+ DEBUG_NOINLINE SharedFileLockHolder(SharedDomain *pDomain, PEFile *pFile, BOOL Take = TRUE)
+ : BaseHolder<PEFile *, SharedFileLockHolderBase>(pFile, FALSE)
+ {
+ STATIC_CONTRACT_THROWS;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_FAULT;
+ ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
+
+ m_pLock = &pDomain->m_FileCreateLock;
+ if (Take)
+ Acquire();
+ }
+};
+#endif // FEATURE_LOADER_OPTIMIZATION
+
+inline BOOL BaseDomain::IsDefaultDomain()
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+ return (SystemDomain::System()->DefaultDomain() == this);
+}
+
+#include "comreflectioncache.inl"
+
+#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+// holds an extra reference so needs special Extract() and should not have SuppressRelease()
+// Holders/Wrappers have nonvirtual methods so cannot use them as the base class
+template <class AppDomainType>
+class AppDomainCreationHolder
+{
+private:
+ // disable the copy ctor
+ AppDomainCreationHolder(const AppDomainCreationHolder<AppDomainType>&) {}
+
+protected:
+ AppDomainType* m_pDomain;
+ BOOL m_bAcquired;
+ void ReleaseAppDomainDuringCreation()
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ WRAPPER(GC_TRIGGERS);
+ PRECONDITION(m_bAcquired);
+ PRECONDITION(CheckPointer(m_pDomain));
+ }
+ CONTRACTL_END;
+
+ if (m_pDomain->NotReadyForManagedCode())
+ {
+ m_pDomain->Release();
+ }
+ else
+ {
+ STRESS_LOG2 (LF_APPDOMAIN, LL_INFO100, "Unload domain during creation [%d] %p\n", m_pDomain->GetId().m_dwId, m_pDomain);
+ SystemDomain::MakeUnloadable(m_pDomain);
+#ifdef _DEBUG
+ DWORD hostTestADUnload = g_pConfig->GetHostTestADUnload();
+ m_pDomain->EnableADUnloadWorker(hostTestADUnload != 2?EEPolicy::ADU_Safe:EEPolicy::ADU_Rude);
+#else
+ m_pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
+#endif
+ }
+ };
+
+public:
+ AppDomainCreationHolder()
+ {
+ m_pDomain=NULL;
+ m_bAcquired=FALSE;
+ };
+ ~AppDomainCreationHolder()
+ {
+ if (m_bAcquired)
+ {
+ Release();
+ }
+ };
+ void Assign(AppDomainType* pDomain)
+ {
+ if(m_bAcquired)
+ Release();
+ m_pDomain=pDomain;
+ if(m_pDomain)
+ {
+ AppDomain::RefTakerAcquire(m_pDomain);
+#ifdef _DEBUG
+ m_pDomain->IncCreationCount();
+#endif // _DEBUG
+ }
+ m_bAcquired=TRUE;
+ };
+
+ void Release()
+ {
+ _ASSERTE(m_bAcquired);
+ if(m_pDomain)
+ {
+#ifdef _DEBUG
+ m_pDomain->DecCreationCount();
+#endif // _DEBUG
+ if(!m_pDomain->IsDefaultDomain())
+ ReleaseAppDomainDuringCreation();
+ AppDomain::RefTakerRelease(m_pDomain);
+ };
+ m_bAcquired=FALSE;
+ };
+
+ AppDomainType* Extract()
+ {
+ _ASSERTE(m_bAcquired);
+ if(m_pDomain)
+ {
+#ifdef _DEBUG
+ m_pDomain->DecCreationCount();
+#endif // _DEBUG
+ AppDomain::RefTakerRelease(m_pDomain);
+ }
+ m_bAcquired=FALSE;
+ return m_pDomain;
+ };
+
+ AppDomainType* operator ->()
+ {
+ _ASSERTE(m_bAcquired);
+ return m_pDomain;
+ }
+
+ operator AppDomainType*()
+ {
+ _ASSERTE(m_bAcquired);
+ return m_pDomain;
+ }
+
+ void DoneCreating()
+ {
+ Extract();
+ }
+};
+#endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE
+
+#endif