1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*============================================================
6**
7** Header: AppDomain.cpp
8**
9
10**
11** Purpose: Implements AppDomain (loader domain) architecture
12**
13**
14===========================================================*/
15#ifndef _APPDOMAIN_H
16#define _APPDOMAIN_H
17
18#include "eventtrace.h"
19#include "assembly.hpp"
20#include "clsload.hpp"
21#include "eehash.h"
22#include "arraylist.h"
23#include "comreflectioncache.hpp"
24#include "comutilnative.h"
25#include "domainfile.h"
26#include "objectlist.h"
27#include "fptrstubs.h"
28#include "testhookmgr.h"
29#include "gcheaputilities.h"
30#include "gchandleutilities.h"
31#include "../binder/inc/applicationcontext.hpp"
32#include "rejit.h"
33
34#ifdef FEATURE_MULTICOREJIT
35#include "multicorejit.h"
36#endif
37
38#ifdef FEATURE_COMINTEROP
39#include "clrprivbinderwinrt.h"
40#include "..\md\winmd\inc\adapter.h"
41#include "winrttypenameconverter.h"
42#endif // FEATURE_COMINTEROP
43
44#include "appxutil.h"
45
46#ifdef FEATURE_TIERED_COMPILATION
47#include "tieredcompilation.h"
48#include "callcounter.h"
49#endif
50
51#include "codeversion.h"
52
53class BaseDomain;
54class SystemDomain;
55class AppDomain;
56class CompilationDomain;
57class AppDomainEnum;
58class AssemblySink;
59class EEMarshalingData;
60class GlobalStringLiteralMap;
61class StringLiteralMap;
62class MngStdInterfacesInfo;
63class DomainModule;
64class DomainAssembly;
65struct InteropMethodTableData;
66class LoadLevelLimiter;
67class TypeEquivalenceHashTable;
68class StringArrayList;
69
70extern INT64 g_PauseTime; // Total time in millisecond the CLR has been paused
71
72#ifdef FEATURE_COMINTEROP
73class ComCallWrapperCache;
74struct SimpleComCallWrapper;
75class RCWRefCache;
76#endif // FEATURE_COMINTEROP
77
78#ifdef _MSC_VER
79#pragma warning(push)
80#pragma warning(disable : 4200) // Disable zero-sized array warning
81#endif
82
83
84GPTR_DECL(IdDispenser, g_pModuleIndexDispenser);
85
86// This enum is aligned to System.ExceptionCatcherType.
87enum ExceptionCatcher {
88 ExceptionCatcher_ManagedCode = 0,
89 ExceptionCatcher_AppDomainTransition = 1,
90 ExceptionCatcher_COMInterop = 2,
91};
92
93// We would like *ALLOCATECLASS_FLAG to AV (in order to catch errors), so don't change it
94struct ClassInitFlags {
95 enum
96 {
97 INITIALIZED_FLAG_BIT = 0,
98 INITIALIZED_FLAG = 1<<INITIALIZED_FLAG_BIT,
99 ERROR_FLAG_BIT = 1,
100 ERROR_FLAG = 1<<ERROR_FLAG_BIT,
101 ALLOCATECLASS_FLAG_BIT = 2, // Bit to avoid racing for InstantiateStaticHandles
102 ALLOCATECLASS_FLAG = 1<<ALLOCATECLASS_FLAG_BIT,
103 COLLECTIBLE_FLAG_BIT = 3,
104 COLLECTIBLE_FLAG = 1<<COLLECTIBLE_FLAG_BIT
105 };
106};
107
108struct DomainLocalModule
109{
110 friend class ClrDataAccess;
111 friend class CheckAsmOffsets;
112 friend struct ThreadLocalModule;
113
114// 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
115// It is critically important that no GC is allowed to occur before this pointer is used.
116#define GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pGCStatics) \
117 {\
118 DomainLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast<DomainLocalModule::PTR_DynamicClassInfo>(dynamicClassInfoParam);\
119 DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast<DomainLocalModule::PTR_DynamicEntry>((DomainLocalModule::DynamicEntry*)dynamicClassInfo->m_pDynamicEntry.Load()); \
120 if ((dynamicClassInfo->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \
121 {\
122 PTRARRAYREF objArray;\
123 objArray = (PTRARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \
124 (dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hGCStatics);\
125 *(pGCStatics) = dac_cast<PTR_BYTE>(PTR_READ(PTR_TO_TADDR(OBJECTREFToObject( objArray )) + offsetof(PtrArray, m_Array), objArray->GetNumComponents() * sizeof(void*))) ;\
126 }\
127 else\
128 {\
129 *(pGCStatics) = (dac_cast<DomainLocalModule::PTR_NormalDynamicEntry>(pDynamicEntry))->GetGCStaticsBasePointer();\
130 }\
131 }\
132
133#define GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pNonGCStatics) \
134 {\
135 DomainLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast<DomainLocalModule::PTR_DynamicClassInfo>(dynamicClassInfoParam);\
136 DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast<DomainLocalModule::PTR_DynamicEntry>((DomainLocalModule::DynamicEntry*)(dynamicClassInfo)->m_pDynamicEntry.Load()); \
137 if (((dynamicClassInfo)->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \
138 {\
139 if ((dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hNonGCStatics != 0) \
140 { \
141 U1ARRAYREF objArray;\
142 objArray = (U1ARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \
143 (dac_cast<DomainLocalModule::PTR_CollectibleDynamicEntry>(pDynamicEntry))->m_hNonGCStatics);\
144 *(pNonGCStatics) = dac_cast<PTR_BYTE>(PTR_READ( \
145 PTR_TO_TADDR(OBJECTREFToObject( objArray )) + sizeof(ArrayBase) - DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob(), \
146 objArray->GetNumComponents() * (DWORD)objArray->GetComponentSize() + DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob())); \
147 } else (*pNonGCStatics) = NULL; \
148 }\
149 else\
150 {\
151 *(pNonGCStatics) = dac_cast<DomainLocalModule::PTR_NormalDynamicEntry>(pDynamicEntry)->GetNonGCStaticsBasePointer();\
152 }\
153 }\
154
155 struct DynamicEntry
156 {
157 static DWORD GetOffsetOfDataBlob();
158 };
159 typedef DPTR(DynamicEntry) PTR_DynamicEntry;
160
161 struct CollectibleDynamicEntry : public DynamicEntry
162 {
163 LOADERHANDLE m_hGCStatics;
164 LOADERHANDLE m_hNonGCStatics;
165 };
166 typedef DPTR(CollectibleDynamicEntry) PTR_CollectibleDynamicEntry;
167
168 struct NormalDynamicEntry : public DynamicEntry
169 {
170 PTR_OBJECTREF m_pGCStatics;
171#ifdef FEATURE_64BIT_ALIGNMENT
172 // Padding to make m_pDataBlob aligned at MAX_PRIMITIVE_FIELD_SIZE
173 // code:MethodTableBuilder::PlaceRegularStaticFields assumes that the start of the data blob is aligned
174 SIZE_T m_padding;
175#endif
176 BYTE m_pDataBlob[0];
177
178 inline PTR_BYTE GetGCStaticsBasePointer()
179 {
180 LIMITED_METHOD_CONTRACT;
181 SUPPORTS_DAC;
182 return dac_cast<PTR_BYTE>(m_pGCStatics);
183 }
184 inline PTR_BYTE GetNonGCStaticsBasePointer()
185 {
186 LIMITED_METHOD_CONTRACT
187 SUPPORTS_DAC;
188 return dac_cast<PTR_BYTE>(this);
189 }
190 };
191 typedef DPTR(NormalDynamicEntry) PTR_NormalDynamicEntry;
192
193 struct DynamicClassInfo
194 {
195 VolatilePtr<DynamicEntry, PTR_DynamicEntry> m_pDynamicEntry;
196 Volatile<DWORD> m_dwFlags;
197 };
198 typedef DPTR(DynamicClassInfo) PTR_DynamicClassInfo;
199
200 inline UMEntryThunk * GetADThunkTable()
201 {
202 LIMITED_METHOD_CONTRACT
203 return m_pADThunkTable;
204 }
205
206 inline void SetADThunkTable(UMEntryThunk* pADThunkTable)
207 {
208 LIMITED_METHOD_CONTRACT
209 InterlockedCompareExchangeT(m_pADThunkTable.GetPointer(), pADThunkTable, NULL);
210 }
211
212 // Note the difference between:
213 //
214 // GetPrecomputedNonGCStaticsBasePointer() and
215 // GetPrecomputedStaticsClassData()
216 //
217 // GetPrecomputedNonGCStaticsBasePointer returns the pointer that should be added to field offsets to retrieve statics
218 // GetPrecomputedStaticsClassData returns a pointer to the first byte of the precomputed statics block
219 inline TADDR GetPrecomputedNonGCStaticsBasePointer()
220 {
221 LIMITED_METHOD_CONTRACT
222 return dac_cast<TADDR>(this);
223 }
224
225 inline PTR_BYTE GetPrecomputedStaticsClassData()
226 {
227 LIMITED_METHOD_CONTRACT
228 return dac_cast<PTR_BYTE>(this) + offsetof(DomainLocalModule, m_pDataBlob);
229 }
230
231 static SIZE_T GetOffsetOfDataBlob() { return offsetof(DomainLocalModule, m_pDataBlob); }
232 static SIZE_T GetOffsetOfGCStaticPointer() { return offsetof(DomainLocalModule, m_pGCStatics); }
233
234 inline DomainFile* GetDomainFile()
235 {
236 LIMITED_METHOD_CONTRACT
237 SUPPORTS_DAC;
238 return m_pDomainFile;
239 }
240
241#ifndef DACCESS_COMPILE
242 inline void SetDomainFile(DomainFile* pDomainFile)
243 {
244 LIMITED_METHOD_CONTRACT
245 m_pDomainFile = pDomainFile;
246 }
247#endif
248
249 inline PTR_OBJECTREF GetPrecomputedGCStaticsBasePointer()
250 {
251 LIMITED_METHOD_CONTRACT
252 return m_pGCStatics;
253 }
254
255 inline PTR_OBJECTREF * GetPrecomputedGCStaticsBasePointerAddress()
256 {
257 LIMITED_METHOD_CONTRACT
258 return &m_pGCStatics;
259 }
260
261 // Returns bytes so we can add offsets
262 inline PTR_BYTE GetGCStaticsBasePointer(MethodTable * pMT)
263 {
264 WRAPPER_NO_CONTRACT
265 SUPPORTS_DAC;
266
267 if (pMT->IsDynamicStatics())
268 {
269 _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
270 return GetDynamicEntryGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator());
271 }
272 else
273 {
274 return dac_cast<PTR_BYTE>(m_pGCStatics);
275 }
276 }
277
278 inline PTR_BYTE GetNonGCStaticsBasePointer(MethodTable * pMT)
279 {
280 WRAPPER_NO_CONTRACT
281 SUPPORTS_DAC;
282
283 if (pMT->IsDynamicStatics())
284 {
285 _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
286 return GetDynamicEntryNonGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator());
287 }
288 else
289 {
290 return dac_cast<PTR_BYTE>(this);
291 }
292 }
293
294 inline DynamicClassInfo* GetDynamicClassInfo(DWORD n)
295 {
296 LIMITED_METHOD_CONTRACT
297 SUPPORTS_DAC;
298 _ASSERTE(m_pDynamicClassTable.Load() && m_aDynamicEntries > n);
299 dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[n].m_pDynamicEntry.Load());
300
301 return &m_pDynamicClassTable[n];
302 }
303
304 // These helpers can now return null, as the debugger may do queries on a type
305 // before the calls to PopulateClass happen
306 inline PTR_BYTE GetDynamicEntryGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator)
307 {
308 CONTRACTL
309 {
310 NOTHROW;
311 GC_NOTRIGGER;
312 SO_TOLERANT;
313 MODE_COOPERATIVE;
314 SUPPORTS_DAC;
315 }
316 CONTRACTL_END;
317
318
319 if (n >= m_aDynamicEntries)
320 {
321 return NULL;
322 }
323
324 DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n);
325 if (!pClassInfo->m_pDynamicEntry)
326 {
327 return NULL;
328 }
329
330 PTR_BYTE retval = NULL;
331
332 GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval);
333
334 return retval;
335 }
336
337 inline PTR_BYTE GetDynamicEntryNonGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator)
338 {
339 CONTRACTL
340 {
341 NOTHROW;
342 GC_NOTRIGGER;
343 SO_TOLERANT;
344 MODE_COOPERATIVE;
345 SUPPORTS_DAC;
346 }
347 CONTRACTL_END;
348
349
350 if (n >= m_aDynamicEntries)
351 {
352 return NULL;
353 }
354
355 DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n);
356 if (!pClassInfo->m_pDynamicEntry)
357 {
358 return NULL;
359 }
360
361 PTR_BYTE retval = NULL;
362
363 GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval);
364
365 return retval;
366 }
367
368 FORCEINLINE PTR_DynamicClassInfo GetDynamicClassInfoIfInitialized(DWORD n)
369 {
370 WRAPPER_NO_CONTRACT;
371
372 // m_aDynamicEntries is set last, it needs to be checked first
373 if (n >= m_aDynamicEntries)
374 {
375 return NULL;
376 }
377
378 _ASSERTE(m_pDynamicClassTable.Load() != NULL);
379 PTR_DynamicClassInfo pDynamicClassInfo = (PTR_DynamicClassInfo)(m_pDynamicClassTable.Load() + n);
380
381 // INITIALIZED_FLAG is set last, it needs to be checked first
382 if ((pDynamicClassInfo->m_dwFlags & ClassInitFlags::INITIALIZED_FLAG) == 0)
383 {
384 return NULL;
385 }
386
387 PREFIX_ASSUME(pDynamicClassInfo != NULL);
388 return pDynamicClassInfo;
389 }
390
391 // iClassIndex is slightly expensive to compute, so if we already know
392 // it, we can use this helper
393 inline BOOL IsClassInitialized(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
394 {
395 WRAPPER_NO_CONTRACT;
396 return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::INITIALIZED_FLAG) != 0;
397 }
398
399 inline BOOL IsPrecomputedClassInitialized(DWORD classID)
400 {
401 return GetPrecomputedStaticsClassData()[classID] & ClassInitFlags::INITIALIZED_FLAG;
402 }
403
404 inline BOOL IsClassAllocated(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
405 {
406 WRAPPER_NO_CONTRACT;
407 return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ALLOCATECLASS_FLAG) != 0;
408 }
409
410 BOOL IsClassInitError(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1)
411 {
412 WRAPPER_NO_CONTRACT;
413 return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ERROR_FLAG) != 0;
414 }
415
416 void SetClassInitialized(MethodTable* pMT);
417 void SetClassInitError(MethodTable* pMT);
418
419 void EnsureDynamicClassIndex(DWORD dwID);
420
421 void AllocateDynamicClass(MethodTable *pMT);
422
423 void PopulateClass(MethodTable *pMT);
424
425#ifdef DACCESS_COMPILE
426 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
427#endif
428
429 static DWORD OffsetOfDataBlob()
430 {
431 LIMITED_METHOD_CONTRACT;
432 return offsetof(DomainLocalModule, m_pDataBlob);
433 }
434
435 FORCEINLINE MethodTable * GetMethodTableFromClassDomainID(DWORD dwClassDomainID)
436 {
437 DWORD rid = (DWORD)(dwClassDomainID) + 1;
438 TypeHandle th = GetDomainFile()->GetModule()->LookupTypeDef(TokenFromRid(rid, mdtTypeDef));
439 _ASSERTE(!th.IsNull());
440 MethodTable * pMT = th.AsMethodTable();
441 PREFIX_ASSUME(pMT != NULL);
442 return pMT;
443 }
444
445private:
446 friend void EmitFastGetSharedStaticBase(CPUSTUBLINKER *psl, CodeLabel *init, bool bCCtorCheck);
447
448 void SetClassFlags(MethodTable* pMT, DWORD dwFlags);
449 DWORD GetClassFlags(MethodTable* pMT, DWORD iClassIndex);
450
451 PTR_DomainFile m_pDomainFile;
452 VolatilePtr<DynamicClassInfo, PTR_DynamicClassInfo> m_pDynamicClassTable; // used for generics and reflection.emit in memory
453 Volatile<SIZE_T> m_aDynamicEntries; // number of entries in dynamic table
454 VolatilePtr<UMEntryThunk> m_pADThunkTable;
455 PTR_OBJECTREF m_pGCStatics; // Handle to GC statics of the module
456
457 // In addition to storing the ModuleIndex in the Module class, we also
458 // keep a copy of the ModuleIndex in the DomainLocalModule class. This
459 // allows the thread static JIT helpers to quickly convert a pointer to
460 // a DomainLocalModule into a ModuleIndex.
461 ModuleIndex m_ModuleIndex;
462
463 // Note that the static offset calculation in code:Module::BuildStaticsOffsets takes the offset m_pDataBlob
464 // into consideration for alignment so we do not need any padding to ensure that the start of the data blob is aligned
465
466 BYTE m_pDataBlob[0]; // First byte of the statics blob
467
468 // Layout of m_pDataBlob is:
469 // ClassInit bytes (hold flags for cctor run, cctor error, etc)
470 // Non GC Statics
471
472public:
473
474 // The Module class need to be able to initialized ModuleIndex,
475 // so for now I will make it a friend..
476 friend class Module;
477
478 FORCEINLINE ModuleIndex GetModuleIndex()
479 {
480 LIMITED_METHOD_DAC_CONTRACT;
481 return m_ModuleIndex;
482 }
483
484}; // struct DomainLocalModule
485
486#define OFFSETOF__DomainLocalModule__m_pDataBlob_ (6 * TARGET_POINTER_SIZE)
487#ifdef FEATURE_64BIT_ALIGNMENT
488#define OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob (TARGET_POINTER_SIZE /* m_pGCStatics */ + TARGET_POINTER_SIZE /* m_padding */)
489#else
490#define OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob TARGET_POINTER_SIZE /* m_pGCStatics */
491#endif
492
493typedef DPTR(class DomainLocalBlock) PTR_DomainLocalBlock;
494class DomainLocalBlock
495{
496 friend class ClrDataAccess;
497 friend class CheckAsmOffsets;
498
499private:
500 PTR_AppDomain m_pDomain;
501 DPTR(PTR_DomainLocalModule) m_pModuleSlots;
502 SIZE_T m_aModuleIndices; // Module entries the shared block has allocated
503
504public: // used by code generators
505 static SIZE_T GetOffsetOfModuleSlotsPointer() { return offsetof(DomainLocalBlock, m_pModuleSlots);}
506
507public:
508
509#ifndef DACCESS_COMPILE
510 DomainLocalBlock()
511 : m_pDomain(NULL), m_pModuleSlots(NULL), m_aModuleIndices(0) {}
512
513 void EnsureModuleIndex(ModuleIndex index);
514
515 void Init(AppDomain *pDomain) { LIMITED_METHOD_CONTRACT; m_pDomain = pDomain; }
516#endif
517
518 void SetModuleSlot(ModuleIndex index, PTR_DomainLocalModule pLocalModule);
519
520 FORCEINLINE PTR_DomainLocalModule GetModuleSlot(ModuleIndex index)
521 {
522 WRAPPER_NO_CONTRACT;
523 SUPPORTS_DAC;
524 _ASSERTE(index.m_dwIndex < m_aModuleIndices);
525 return m_pModuleSlots[index.m_dwIndex];
526 }
527
528 inline PTR_DomainLocalModule GetModuleSlot(MethodTable* pMT)
529 {
530 WRAPPER_NO_CONTRACT;
531 return GetModuleSlot(pMT->GetModuleForStatics()->GetModuleIndex());
532 }
533
534 DomainFile* TryGetDomainFile(ModuleIndex index)
535 {
536 WRAPPER_NO_CONTRACT;
537 SUPPORTS_DAC;
538
539 // the publishing of m_aModuleIndices and m_pModuleSlots is dependent
540 // on the order of accesses; we must ensure that we read from m_aModuleIndices
541 // before m_pModuleSlots.
542 if (index.m_dwIndex < m_aModuleIndices)
543 {
544 MemoryBarrier();
545 if (m_pModuleSlots[index.m_dwIndex])
546 {
547 return m_pModuleSlots[index.m_dwIndex]->GetDomainFile();
548 }
549 }
550
551 return NULL;
552 }
553
554 DomainFile* GetDomainFile(SIZE_T ModuleID)
555 {
556 WRAPPER_NO_CONTRACT;
557 ModuleIndex index = Module::IDToIndex(ModuleID);
558 _ASSERTE(index.m_dwIndex < m_aModuleIndices);
559 return m_pModuleSlots[index.m_dwIndex]->GetDomainFile();
560 }
561
562#ifndef DACCESS_COMPILE
563 void SetDomainFile(ModuleIndex index, DomainFile* pDomainFile)
564 {
565 WRAPPER_NO_CONTRACT;
566 _ASSERTE(index.m_dwIndex < m_aModuleIndices);
567 m_pModuleSlots[index.m_dwIndex]->SetDomainFile(pDomainFile);
568 }
569#endif
570
571#ifdef DACCESS_COMPILE
572 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
573#endif
574
575
576private:
577
578 //
579 // Low level routines to get & set class entries
580 //
581
582};
583
584#ifdef _MSC_VER
585#pragma warning(pop)
586#endif
587
588
589// The large heap handle bucket class is used to contain handles allocated
590// from an array contained in the large heap.
591class LargeHeapHandleBucket
592{
593public:
594 // Constructor and desctructor.
595 LargeHeapHandleBucket(LargeHeapHandleBucket *pNext, DWORD Size, BaseDomain *pDomain, BOOL bCrossAD = FALSE);
596 ~LargeHeapHandleBucket();
597
598 // This returns the next bucket.
599 LargeHeapHandleBucket *GetNext()
600 {
601 LIMITED_METHOD_CONTRACT;
602
603 return m_pNext;
604 }
605
606 // This returns the number of remaining handle slots.
607 DWORD GetNumRemainingHandles()
608 {
609 LIMITED_METHOD_CONTRACT;
610
611 return m_ArraySize - m_CurrentPos;
612 }
613
614 void ConsumeRemaining()
615 {
616 LIMITED_METHOD_CONTRACT;
617
618 m_CurrentPos = m_ArraySize;
619 }
620
621 OBJECTREF *TryAllocateEmbeddedFreeHandle();
622
623 // Allocate handles from the bucket.
624 OBJECTREF* AllocateHandles(DWORD nRequested);
625 OBJECTREF* CurrentPos()
626 {
627 LIMITED_METHOD_CONTRACT;
628 return m_pArrayDataPtr + m_CurrentPos;
629 }
630
631private:
632 LargeHeapHandleBucket *m_pNext;
633 int m_ArraySize;
634 int m_CurrentPos;
635 int m_CurrentEmbeddedFreePos;
636 OBJECTHANDLE m_hndHandleArray;
637 OBJECTREF *m_pArrayDataPtr;
638};
639
640
641
642// The large heap handle table is used to allocate handles that are pointers
643// to objects stored in an array in the large object heap.
644class LargeHeapHandleTable
645{
646public:
647 // Constructor and desctructor.
648 LargeHeapHandleTable(BaseDomain *pDomain, DWORD InitialBucketSize);
649 ~LargeHeapHandleTable();
650
651 // Allocate handles from the large heap handle table.
652 OBJECTREF* AllocateHandles(DWORD nRequested, BOOL bCrossAD = FALSE);
653
654 // Release object handles allocated using AllocateHandles().
655 void ReleaseHandles(OBJECTREF *pObjRef, DWORD nReleased);
656
657private:
658 // The buckets of object handles.
659 LargeHeapHandleBucket *m_pHead;
660
661 // We need to know the containing domain so we know where to allocate handles
662 BaseDomain *m_pDomain;
663
664 // The size of the LargeHeapHandleBuckets.
665 DWORD m_NextBucketSize;
666
667 // for finding and re-using embedded free items in the list
668 LargeHeapHandleBucket *m_pFreeSearchHint;
669 DWORD m_cEmbeddedFree;
670
671#ifdef _DEBUG
672
673 // these functions are present to enforce that there is a locking mechanism in place
674 // for each LargeHeapHandleTable even though the code itself does not do the locking
675 // you must tell the table which lock you intend to use and it will verify that it has
676 // in fact been taken before performing any operations
677
678public:
679 void RegisterCrstDebug(CrstBase *pCrst)
680 {
681 LIMITED_METHOD_CONTRACT;
682
683 // this function must be called exactly once
684 _ASSERTE(pCrst != NULL);
685 _ASSERTE(m_pCrstDebug == NULL);
686 m_pCrstDebug = pCrst;
687 }
688
689private:
690 // we will assert that this Crst is held before using the object
691 CrstBase *m_pCrstDebug;
692
693#endif
694
695};
696
697class LargeHeapHandleBlockHolder;
698void LargeHeapHandleBlockHolder__StaticFree(LargeHeapHandleBlockHolder*);
699
700
701class LargeHeapHandleBlockHolder:public Holder<LargeHeapHandleBlockHolder*,DoNothing,LargeHeapHandleBlockHolder__StaticFree>
702
703{
704 LargeHeapHandleTable* m_pTable;
705 DWORD m_Count;
706 OBJECTREF* m_Data;
707public:
708 FORCEINLINE LargeHeapHandleBlockHolder(LargeHeapHandleTable* pOwner, DWORD nCount)
709 {
710 WRAPPER_NO_CONTRACT;
711 m_Data = pOwner->AllocateHandles(nCount);
712 m_Count=nCount;
713 m_pTable=pOwner;
714 };
715
716 FORCEINLINE void FreeData()
717 {
718 WRAPPER_NO_CONTRACT;
719 for (DWORD i=0;i< m_Count;i++)
720 ClearObjectReference(m_Data+i);
721 m_pTable->ReleaseHandles(m_Data, m_Count);
722 };
723 FORCEINLINE OBJECTREF* operator[] (DWORD idx)
724 {
725 LIMITED_METHOD_CONTRACT;
726 _ASSERTE(idx<m_Count);
727 return &(m_Data[idx]);
728 }
729};
730
731FORCEINLINE void LargeHeapHandleBlockHolder__StaticFree(LargeHeapHandleBlockHolder* pHolder)
732{
733 WRAPPER_NO_CONTRACT;
734 pHolder->FreeData();
735};
736
737
738
739
740
741// The large heap handle bucket class is used to contain handles allocated
742// from an array contained in the large heap.
743class ThreadStaticHandleBucket
744{
745public:
746 // Constructor and desctructor.
747 ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain);
748 ~ThreadStaticHandleBucket();
749
750 // This returns the next bucket.
751 ThreadStaticHandleBucket *GetNext()
752 {
753 LIMITED_METHOD_CONTRACT;
754
755 return m_pNext;
756 }
757
758 // Allocate handles from the bucket.
759 OBJECTHANDLE GetHandles();
760
761private:
762 ThreadStaticHandleBucket *m_pNext;
763 int m_ArraySize;
764 OBJECTHANDLE m_hndHandleArray;
765};
766
767
768// The large heap handle table is used to allocate handles that are pointers
769// to objects stored in an array in the large object heap.
770class ThreadStaticHandleTable
771{
772public:
773 // Constructor and desctructor.
774 ThreadStaticHandleTable(BaseDomain *pDomain);
775 ~ThreadStaticHandleTable();
776
777 // Allocate handles from the large heap handle table.
778 OBJECTHANDLE AllocateHandles(DWORD nRequested);
779
780private:
781 // The buckets of object handles.
782 ThreadStaticHandleBucket *m_pHead;
783
784 // We need to know the containing domain so we know where to allocate handles
785 BaseDomain *m_pDomain;
786};
787
788
789
790
791//--------------------------------------------------------------------------------------
792// Base class for domains. It provides an abstract way of finding the first assembly and
793// for creating assemblies in the the domain. The system domain only has one assembly, it
794// contains the classes that are logically shared between domains. All other domains can
795// have multiple assemblies. Iteration is done be getting the first assembly and then
796// calling the Next() method on the assembly.
797//
798// The system domain should be as small as possible, it includes object, exceptions, etc.
799// which are the basic classes required to load other assemblies. All other classes
800// should be loaded into the domain. Of coarse there is a trade off between loading the
801// same classes multiple times, requiring all domains to load certain assemblies (working
802// set) and being able to specify specific versions.
803//
804
805#define LOW_FREQUENCY_HEAP_RESERVE_SIZE (3 * GetOsPageSize())
806#define LOW_FREQUENCY_HEAP_COMMIT_SIZE (1 * GetOsPageSize())
807
808#define HIGH_FREQUENCY_HEAP_RESERVE_SIZE (10 * GetOsPageSize())
809#define HIGH_FREQUENCY_HEAP_COMMIT_SIZE (1 * GetOsPageSize())
810
811#define STUB_HEAP_RESERVE_SIZE (3 * GetOsPageSize())
812#define STUB_HEAP_COMMIT_SIZE (1 * GetOsPageSize())
813
814// --------------------------------------------------------------------------------
815// PE File List lock - for creating list locks on PE files
816// --------------------------------------------------------------------------------
817
818class PEFileListLock : public ListLock
819{
820public:
821#ifndef DACCESS_COMPILE
822 ListLockEntry *FindFileLock(PEFile *pFile)
823 {
824 STATIC_CONTRACT_NOTHROW;
825 STATIC_CONTRACT_GC_NOTRIGGER;
826 STATIC_CONTRACT_FORBID_FAULT;
827
828 PRECONDITION(HasLock());
829
830 ListLockEntry *pEntry;
831
832 for (pEntry = m_pHead;
833 pEntry != NULL;
834 pEntry = pEntry->m_pNext)
835 {
836 if (((PEFile *)pEntry->m_data)->Equals(pFile))
837 {
838 return pEntry;
839 }
840 }
841
842 return NULL;
843 }
844#endif // DACCESS_COMPILE
845
846 DEBUG_NOINLINE static void HolderEnter(PEFileListLock *pThis) PUB
847 {
848 WRAPPER_NO_CONTRACT;
849 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
850
851 pThis->Enter();
852 }
853
854 DEBUG_NOINLINE static void HolderLeave(PEFileListLock *pThis) PUB
855 {
856 WRAPPER_NO_CONTRACT;
857 ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
858
859 pThis->Leave();
860 }
861
862 typedef Wrapper<PEFileListLock*, PEFileListLock::HolderEnter, PEFileListLock::HolderLeave> Holder;
863};
864
865typedef PEFileListLock::Holder PEFileListLockHolder;
866
867// Loading infrastructure:
868//
869// a DomainFile is a file being loaded. Files are loaded in layers to enable loading in the
870// presence of dependency loops.
871//
872// FileLoadLevel describes the various levels available. These are implemented slightly
873// differently for assemblies and modules, but the basic structure is the same.
874//
875// LoadLock and FileLoadLock form the ListLock data structures for files. The FileLoadLock
876// is specialized in that it allows taking a lock at a particular level. Basicall any
877// thread may obtain the lock at a level at which the file has previously been loaded to, but
878// only one thread may obtain the lock at its current level.
879//
880// The PendingLoadQueue is a per thread data structure which serves two purposes. First, it
881// holds a "load limit" which automatically restricts the level of recursive loads to be
882// one less than the current load which is preceding. This, together with the AppDomain
883// LoadLock level behavior, will prevent any deadlocks from occuring due to circular
884// dependencies. (Note that it is important that the loading logic understands this restriction,
885// and any given level of loading must deal with the fact that any recursive loads will be partially
886// unfulfilled in a specific way.)
887//
888// The second function is to queue up any unfulfilled load requests for the thread. These
889// are then delivered immediately after the current load request is dealt with.
890
891class FileLoadLock : public ListLockEntry
892{
893private:
894 FileLoadLevel m_level;
895 DomainFile *m_pDomainFile;
896 HRESULT m_cachedHR;
897 ADID m_AppDomainId;
898
899public:
900 static FileLoadLock *Create(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile);
901
902 ~FileLoadLock();
903 DomainFile *GetDomainFile();
904 ADID GetAppDomainId();
905 FileLoadLevel GetLoadLevel();
906
907 // CanAcquire will return FALSE if Acquire will definitely not take the lock due
908 // to levels or deadlock.
909 // (Note that there is a race exiting from the function, where Acquire may end
910 // up not taking the lock anyway if another thread did work in the meantime.)
911 BOOL CanAcquire(FileLoadLevel targetLevel);
912
913 // Acquire will return FALSE and not take the lock if the file
914 // has already been loaded to the target level. Otherwise,
915 // it will return TRUE and take the lock.
916 //
917 // Note that the taker must release the lock via IncrementLoadLevel.
918 BOOL Acquire(FileLoadLevel targetLevel);
919
920 // CompleteLoadLevel can be called after Acquire returns true
921 // returns TRUE if it updated load level, FALSE if the level was set already
922 BOOL CompleteLoadLevel(FileLoadLevel level, BOOL success);
923
924 void SetError(Exception *ex);
925
926 void AddRef();
927 UINT32 Release() DAC_EMPTY_RET(0);
928
929private:
930
931 FileLoadLock(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile);
932
933 static void HolderLeave(FileLoadLock *pThis);
934
935public:
936 typedef Wrapper<FileLoadLock *, DoNothing, FileLoadLock::HolderLeave> Holder;
937
938};
939
940typedef FileLoadLock::Holder FileLoadLockHolder;
941
942#ifndef DACCESS_COMPILE
943 typedef ReleaseHolder<FileLoadLock> FileLoadLockRefHolder;
944#endif // DACCESS_COMPILE
945
946 typedef ListLockBase<NativeCodeVersion> JitListLock;
947 typedef ListLockEntryBase<NativeCodeVersion> JitListLockEntry;
948
949
950#ifdef _MSC_VER
951#pragma warning(push)
952#pragma warning (disable: 4324) //sometimes 64bit compilers complain about alignment
953#endif
954class LoadLevelLimiter
955{
956 FileLoadLevel m_currentLevel;
957 LoadLevelLimiter* m_previousLimit;
958 BOOL m_bActive;
959
960public:
961
962 LoadLevelLimiter()
963 : m_currentLevel(FILE_ACTIVE),
964 m_previousLimit(NULL),
965 m_bActive(FALSE)
966 {
967 LIMITED_METHOD_CONTRACT;
968 }
969
970 void Activate()
971 {
972 WRAPPER_NO_CONTRACT;
973 m_previousLimit=GetThread()->GetLoadLevelLimiter();
974 if(m_previousLimit)
975 m_currentLevel=m_previousLimit->GetLoadLevel();
976 GetThread()->SetLoadLevelLimiter(this);
977 m_bActive=TRUE;
978 }
979
980 void Deactivate()
981 {
982 WRAPPER_NO_CONTRACT;
983 if (m_bActive)
984 {
985 GetThread()->SetLoadLevelLimiter(m_previousLimit);
986 m_bActive=FALSE;
987 }
988 }
989
990 ~LoadLevelLimiter()
991 {
992 WRAPPER_NO_CONTRACT;
993
994 // PendingLoadQueues are allocated on the stack during a load, and
995 // shared with all nested loads on the same thread.
996
997 // Make sure the thread pointer gets reset after the
998 // top level queue goes out of scope.
999 if(m_bActive)
1000 {
1001 Deactivate();
1002 }
1003 }
1004
1005 FileLoadLevel GetLoadLevel()
1006 {
1007 LIMITED_METHOD_CONTRACT;
1008 return m_currentLevel;
1009 }
1010
1011 void SetLoadLevel(FileLoadLevel level)
1012 {
1013 LIMITED_METHOD_CONTRACT;
1014 m_currentLevel = level;
1015 }
1016};
1017#ifdef _MSC_VER
1018#pragma warning (pop) //4324
1019#endif
1020
1021#define OVERRIDE_LOAD_LEVEL_LIMIT(newLimit) \
1022 LoadLevelLimiter __newLimit; \
1023 __newLimit.Activate(); \
1024 __newLimit.SetLoadLevel(newLimit);
1025
1026// A BaseDomain much basic information in a code:AppDomain including
1027//
1028// * code:#AppdomainHeaps - Heaps for any data structures that will be freed on appdomain unload
1029//
1030class BaseDomain
1031{
1032 friend class Assembly;
1033 friend class AssemblySpec;
1034 friend class AppDomain;
1035 friend class AppDomainNative;
1036
1037 VPTR_BASE_VTABLE_CLASS(BaseDomain)
1038 VPTR_UNIQUE(VPTR_UNIQUE_BaseDomain)
1039
1040protected:
1041 // These 2 variables are only used on the AppDomain, but by placing them here
1042 // we reduce the cost of keeping the asmconstants file up to date.
1043
1044 // The creation sequence number of this app domain (starting from 1)
1045 // This ID is generated by the code:SystemDomain::GetNewAppDomainId routine
1046 // The ID are recycled.
1047 //
1048 // see also code:ADID
1049 ADID m_dwId;
1050
1051 DomainLocalBlock m_sDomainLocalBlock;
1052
1053public:
1054
1055 class AssemblyIterator;
1056 friend class AssemblyIterator;
1057
1058 // Static initialization.
1059 static void Attach();
1060
1061 //****************************************************************************************
1062 //
1063 // Initialization/shutdown routines for every instance of an BaseDomain.
1064
1065 BaseDomain();
1066 virtual ~BaseDomain() {}
1067 void Init();
1068 void Stop();
1069 void Terminate();
1070
1071 // ID to uniquely identify this AppDomain - used by the AppDomain publishing
1072 // service (to publish the list of all appdomains present in the process),
1073 // which in turn is used by, for eg., the debugger (to decide which App-
1074 // Domain(s) to attach to).
1075 // This is also used by Remoting for routing cross-appDomain calls.
1076 ADID GetId (void)
1077 {
1078 LIMITED_METHOD_DAC_CONTRACT;
1079 STATIC_CONTRACT_SO_TOLERANT;
1080 return m_dwId;
1081 }
1082
1083 virtual BOOL IsAppDomain() { LIMITED_METHOD_DAC_CONTRACT; return FALSE; }
1084
1085 BOOL IsSharedDomain() { LIMITED_METHOD_DAC_CONTRACT; return FALSE; }
1086 BOOL IsDefaultDomain() { LIMITED_METHOD_DAC_CONTRACT; return TRUE; }
1087
1088 PTR_LoaderAllocator GetLoaderAllocator();
1089 virtual PTR_AppDomain AsAppDomain()
1090 {
1091 LIMITED_METHOD_CONTRACT;
1092 STATIC_CONTRACT_SO_TOLERANT;
1093 _ASSERTE(!"Not an AppDomain");
1094 return NULL;
1095 }
1096
1097#ifdef FEATURE_COMINTEROP
1098 //****************************************************************************************
1099 //
1100 // This will look up interop data for a method table
1101 //
1102
1103#endif // FEATURE_COMINTEROP
1104
1105 void SetDisableInterfaceCache()
1106 {
1107 m_fDisableInterfaceCache = TRUE;
1108 }
1109 BOOL GetDisableInterfaceCache()
1110 {
1111 return m_fDisableInterfaceCache;
1112 }
1113
1114#ifdef FEATURE_COMINTEROP
1115 MngStdInterfacesInfo * GetMngStdInterfacesInfo()
1116 {
1117 LIMITED_METHOD_CONTRACT;
1118
1119 return m_pMngStdInterfacesInfo;
1120 }
1121
1122 PTR_CLRPrivBinderWinRT GetWinRtBinder()
1123 {
1124 return m_pWinRtBinder;
1125 }
1126#endif // FEATURE_COMINTEROP
1127
1128 //****************************************************************************************
1129 // This method returns marshaling data that the EE uses that is stored on a per app domain
1130 // basis.
1131 EEMarshalingData *GetMarshalingData();
1132
1133 // Deletes marshaling data at shutdown (which contains cached factories that needs to be released)
1134 void DeleteMarshalingData();
1135
1136#ifdef _DEBUG
1137 BOOL OwnDomainLocalBlockLock()
1138 {
1139 WRAPPER_NO_CONTRACT;
1140
1141 return m_DomainLocalBlockCrst.OwnedByCurrentThread();
1142 }
1143#endif
1144
1145 //****************************************************************************************
1146 // Get the class init lock. The method is limited to friends because inappropriate use
1147 // will cause deadlocks in the system
1148 ListLock* GetClassInitLock()
1149 {
1150 LIMITED_METHOD_CONTRACT;
1151
1152 return &m_ClassInitLock;
1153 }
1154
1155 JitListLock* GetJitLock()
1156 {
1157 LIMITED_METHOD_CONTRACT;
1158 return &m_JITLock;
1159 }
1160
1161 ListLock* GetILStubGenLock()
1162 {
1163 LIMITED_METHOD_CONTRACT;
1164 return &m_ILStubGenLock;
1165 }
1166
1167 STRINGREF *IsStringInterned(STRINGREF *pString);
1168 STRINGREF *GetOrInternString(STRINGREF *pString);
1169
1170 // Returns an array of OBJECTREF* that can be used to store domain specific data.
1171 // Statics and reflection info (Types, MemberInfo,..) are stored this way
1172 // If ppLazyAllocate != 0, allocation will only take place if *ppLazyAllocate != 0 (and the allocation
1173 // will be properly serialized)
1174 OBJECTREF *AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate = NULL, BOOL bCrossAD = FALSE);
1175
1176#ifdef FEATURE_PREJIT
1177 // Ensures that the file for logging profile data is open (we only open it once)
1178 // return false on failure
1179 static BOOL EnsureNGenLogFileOpen();
1180#endif
1181
1182 //****************************************************************************************
1183 // Handles
1184
1185#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1186 OBJECTHANDLE CreateTypedHandle(OBJECTREF object, HandleType type)
1187 {
1188 WRAPPER_NO_CONTRACT;
1189 return ::CreateHandleCommon(m_handleStore, object, type);
1190 }
1191
1192 OBJECTHANDLE CreateHandle(OBJECTREF object)
1193 {
1194 WRAPPER_NO_CONTRACT;
1195 CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL)
1196 return ::CreateHandle(m_handleStore, object);
1197 }
1198
1199 OBJECTHANDLE CreateWeakHandle(OBJECTREF object)
1200 {
1201 WRAPPER_NO_CONTRACT;
1202 return ::CreateWeakHandle(m_handleStore, object);
1203 }
1204
1205 OBJECTHANDLE CreateShortWeakHandle(OBJECTREF object)
1206 {
1207 WRAPPER_NO_CONTRACT;
1208 return ::CreateShortWeakHandle(m_handleStore, object);
1209 }
1210
1211 OBJECTHANDLE CreateLongWeakHandle(OBJECTREF object)
1212 {
1213 WRAPPER_NO_CONTRACT;
1214 CONDITIONAL_CONTRACT_VIOLATION(ModeViolation, object == NULL)
1215 return ::CreateLongWeakHandle(m_handleStore, object);
1216 }
1217
1218 OBJECTHANDLE CreateStrongHandle(OBJECTREF object)
1219 {
1220 WRAPPER_NO_CONTRACT;
1221 return ::CreateStrongHandle(m_handleStore, object);
1222 }
1223
1224 OBJECTHANDLE CreatePinningHandle(OBJECTREF object)
1225 {
1226 WRAPPER_NO_CONTRACT;
1227 return ::CreatePinningHandle(m_handleStore, object);
1228 }
1229
1230 OBJECTHANDLE CreateSizedRefHandle(OBJECTREF object)
1231 {
1232 WRAPPER_NO_CONTRACT;
1233 OBJECTHANDLE h;
1234 if (GCHeapUtilities::IsServerHeap())
1235 {
1236 h = ::CreateSizedRefHandle(m_handleStore, object, m_dwSizedRefHandles % m_iNumberOfProcessors);
1237 }
1238 else
1239 {
1240 h = ::CreateSizedRefHandle(m_handleStore, object);
1241 }
1242
1243 InterlockedIncrement((LONG*)&m_dwSizedRefHandles);
1244 return h;
1245 }
1246
1247#ifdef FEATURE_COMINTEROP
1248 OBJECTHANDLE CreateRefcountedHandle(OBJECTREF object)
1249 {
1250 WRAPPER_NO_CONTRACT;
1251 return ::CreateRefcountedHandle(m_handleStore, object);
1252 }
1253
1254 OBJECTHANDLE CreateWinRTWeakHandle(OBJECTREF object, IWeakReference* pWinRTWeakReference)
1255 {
1256 WRAPPER_NO_CONTRACT;
1257 return ::CreateWinRTWeakHandle(m_handleStore, object, pWinRTWeakReference);
1258 }
1259#endif // FEATURE_COMINTEROP
1260
1261 OBJECTHANDLE CreateVariableHandle(OBJECTREF object, UINT type)
1262 {
1263 WRAPPER_NO_CONTRACT;
1264 return ::CreateVariableHandle(m_handleStore, object, type);
1265 }
1266
1267 OBJECTHANDLE CreateDependentHandle(OBJECTREF primary, OBJECTREF secondary)
1268 {
1269 WRAPPER_NO_CONTRACT;
1270 return ::CreateDependentHandle(m_handleStore, primary, secondary);
1271 }
1272
1273#endif // DACCESS_COMPILE && !CROSSGEN_COMPILE
1274
1275 IUnknown *GetFusionContext() {LIMITED_METHOD_CONTRACT; return m_pFusionContext; }
1276
1277 CLRPrivBinderCoreCLR *GetTPABinderContext() {LIMITED_METHOD_CONTRACT; return m_pTPABinderContext; }
1278
1279
1280 CrstExplicitInit * GetLoaderAllocatorReferencesLock()
1281 {
1282 LIMITED_METHOD_CONTRACT;
1283 return &m_crstLoaderAllocatorReferences;
1284 }
1285
1286protected:
1287
1288 //****************************************************************************************
1289 // Helper method to initialize the large heap handle table.
1290 void InitLargeHeapHandleTable();
1291
1292 //****************************************************************************************
1293 // Adds an assembly to the domain.
1294 void AddAssemblyNoLock(Assembly* assem);
1295
1296 //****************************************************************************************
1297 //
1298 // Hash table that maps a MethodTable to COM Interop compatibility data.
1299 PtrHashMap m_interopDataHash;
1300
1301 // Critical sections & locks
1302 PEFileListLock m_FileLoadLock; // Protects the list of assemblies in the domain
1303 CrstExplicitInit m_DomainCrst; // General Protection for the Domain
1304 CrstExplicitInit m_DomainCacheCrst; // Protects the Assembly and Unmanaged caches
1305 CrstExplicitInit m_DomainLocalBlockCrst;
1306 CrstExplicitInit m_InteropDataCrst; // Used for COM Interop compatiblilty
1307 // Used to protect the reference lists in the collectible loader allocators attached to this appdomain
1308 CrstExplicitInit m_crstLoaderAllocatorReferences;
1309 CrstExplicitInit m_WinRTFactoryCacheCrst; // For WinRT factory cache
1310
1311 //#AssemblyListLock
1312 // Used to protect the assembly list. Taken also by GC or debugger thread, therefore we have to avoid
1313 // triggering GC while holding this lock (by switching the thread to GC_NOTRIGGER while it is held).
1314 CrstExplicitInit m_crstAssemblyList;
1315 BOOL m_fDisableInterfaceCache; // RCW COM interface cache
1316 ListLock m_ClassInitLock;
1317 JitListLock m_JITLock;
1318 ListLock m_ILStubGenLock;
1319
1320 // Fusion context, used for adding assemblies to the is domain. It defines
1321 // fusion properties for finding assemblyies such as SharedBinPath,
1322 // PrivateBinPath, Application Directory, etc.
1323 IUnknown *m_pFusionContext; // Current binding context for the domain
1324
1325 CLRPrivBinderCoreCLR *m_pTPABinderContext; // Reference to the binding context that holds TPA list details
1326
1327 IGCHandleStore* m_handleStore;
1328
1329 // The large heap handle table.
1330 LargeHeapHandleTable *m_pLargeHeapHandleTable;
1331
1332 // The large heap handle table critical section.
1333 CrstExplicitInit m_LargeHeapHandleTableCrst;
1334
1335 EEMarshalingData *m_pMarshalingData;
1336
1337#ifdef FEATURE_COMINTEROP
1338 // Information regarding the managed standard interfaces.
1339 MngStdInterfacesInfo *m_pMngStdInterfacesInfo;
1340
1341 // WinRT binder
1342 PTR_CLRPrivBinderWinRT m_pWinRtBinder;
1343#endif // FEATURE_COMINTEROP
1344
1345 // Protects allocation of slot IDs for thread statics
1346 static CrstStatic m_SpecialStaticsCrst;
1347
1348public:
1349 // Only call this routine when you can guarantee there are no
1350 // loads in progress.
1351 void ClearFusionContext();
1352
1353 //****************************************************************************************
1354 // Synchronization holders.
1355
1356 class LockHolder : public CrstHolder
1357 {
1358 public:
1359 LockHolder(BaseDomain *pD)
1360 : CrstHolder(&pD->m_DomainCrst)
1361 {
1362 WRAPPER_NO_CONTRACT;
1363 }
1364 };
1365 friend class LockHolder;
1366
1367 class CacheLockHolder : public CrstHolder
1368 {
1369 public:
1370 CacheLockHolder(BaseDomain *pD)
1371 : CrstHolder(&pD->m_DomainCacheCrst)
1372 {
1373 WRAPPER_NO_CONTRACT;
1374 }
1375 };
1376 friend class CacheLockHolder;
1377
1378 class DomainLocalBlockLockHolder : public CrstHolder
1379 {
1380 public:
1381 DomainLocalBlockLockHolder(BaseDomain *pD)
1382 : CrstHolder(&pD->m_DomainLocalBlockCrst)
1383 {
1384 WRAPPER_NO_CONTRACT;
1385 }
1386 };
1387 friend class DomainLocalBlockLockHolder;
1388
1389 class LoadLockHolder : public PEFileListLockHolder
1390 {
1391 public:
1392 LoadLockHolder(BaseDomain *pD, BOOL Take = TRUE)
1393 : PEFileListLockHolder(&pD->m_FileLoadLock, Take)
1394 {
1395 CONTRACTL
1396 {
1397 NOTHROW;
1398 GC_NOTRIGGER;
1399 MODE_ANY;
1400 CAN_TAKE_LOCK;
1401 }
1402 CONTRACTL_END;
1403 }
1404 };
1405 friend class LoadLockHolder;
1406 class WinRTFactoryCacheLockHolder : public CrstHolder
1407 {
1408 public:
1409 WinRTFactoryCacheLockHolder(BaseDomain *pD)
1410 : CrstHolder(&pD->m_WinRTFactoryCacheCrst)
1411 {
1412 WRAPPER_NO_CONTRACT;
1413 }
1414 };
1415 friend class WinRTFactoryCacheLockHolder;
1416
1417public:
1418 void InitVSD();
1419 RangeList *GetCollectibleVSDRanges() { return &m_collVSDRanges; }
1420
1421private:
1422 TypeIDMap m_typeIDMap;
1423 // Range list for collectible types. Maps VSD PCODEs back to the VirtualCallStubManager they belong to
1424 LockedRangeList m_collVSDRanges;
1425
1426public:
1427 UINT32 GetTypeID(PTR_MethodTable pMT);
1428 UINT32 LookupTypeID(PTR_MethodTable pMT);
1429 PTR_MethodTable LookupType(UINT32 id);
1430
1431private:
1432 // I have yet to figure out an efficent way to get the number of handles
1433 // of a particular type that's currently used by the process without
1434 // spending more time looking at the handle table code. We know that
1435 // our only customer (asp.net) in Dev10 is not going to create many of
1436 // these handles so I am taking a shortcut for now and keep the sizedref
1437 // handle count on the AD itself.
1438 DWORD m_dwSizedRefHandles;
1439
1440 static int m_iNumberOfProcessors;
1441
1442public:
1443 // Called by DestroySizedRefHandle
1444 void DecNumSizedRefHandles()
1445 {
1446 WRAPPER_NO_CONTRACT;
1447 LONG result;
1448 result = InterlockedDecrement((LONG*)&m_dwSizedRefHandles);
1449 _ASSERTE(result >= 0);
1450 }
1451
1452 DWORD GetNumSizedRefHandles()
1453 {
1454 return m_dwSizedRefHandles;
1455 }
1456
1457#ifdef FEATURE_CODE_VERSIONING
1458private:
1459 CodeVersionManager m_codeVersionManager;
1460
1461public:
1462 CodeVersionManager* GetCodeVersionManager() { return &m_codeVersionManager; }
1463#endif //FEATURE_CODE_VERSIONING
1464
1465#ifdef FEATURE_TIERED_COMPILATION
1466private:
1467 CallCounter m_callCounter;
1468
1469public:
1470 CallCounter* GetCallCounter() { return &m_callCounter; }
1471#endif
1472
1473#ifdef DACCESS_COMPILE
1474public:
1475 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
1476 bool enumThis);
1477#endif
1478
1479}; // class BaseDomain
1480
1481enum
1482{
1483 ATTACH_ASSEMBLY_LOAD = 0x1,
1484 ATTACH_MODULE_LOAD = 0x2,
1485 ATTACH_CLASS_LOAD = 0x4,
1486
1487 ATTACH_ALL = 0x7
1488};
1489
1490// This filters the output of IterateAssemblies. This ought to be declared more locally
1491// but it would result in really verbose callsites.
1492//
1493// Assemblies can be categorized by their load status (loaded, loading, or loaded just
1494// enough that they would be made available to profilers)
1495// Independently, they can also be categorized as execution or introspection.
1496//
1497// An assembly will be included in the results of IterateAssemblies only if
1498// the appropriate bit is set for *both* characterizations.
1499//
1500// The flags can be combined so if you want all loaded assemblies, you must specify:
1501//
1502/// kIncludeLoaded|kIncludeExecution
1503
1504enum AssemblyIterationFlags
1505{
1506 // load status flags
1507 kIncludeLoaded = 0x00000001, // include assemblies that are already loaded
1508 // (m_level >= code:FILE_LOAD_DELIVER_EVENTS)
1509 kIncludeLoading = 0x00000002, // include assemblies that are still in the process of loading
1510 // (all m_level values)
1511 kIncludeAvailableToProfilers
1512 = 0x00000020, // include assemblies available to profilers
1513 // See comment at code:DomainFile::IsAvailableToProfilers
1514
1515 // Execution / introspection flags
1516 kIncludeExecution = 0x00000004, // include assemblies that are loaded for execution only
1517
1518 kIncludeFailedToLoad = 0x00000010, // include assemblies that failed to load
1519
1520 // Collectible assemblies flags
1521 kExcludeCollectible = 0x00000040, // Exclude all collectible assemblies
1522 kIncludeCollected = 0x00000080,
1523 // Include assemblies which were collected and cannot be referenced anymore. Such assemblies are not
1524 // AddRef-ed. Any manipulation with them should be protected by code:GetAssemblyListLock.
1525 // Should be used only by code:LoaderAllocator::GCLoaderAllocators.
1526
1527}; // enum AssemblyIterationFlags
1528
1529//---------------------------------------------------------------------------------------
1530//
1531// Base class for holder code:CollectibleAssemblyHolder (see code:HolderBase).
1532// Manages AddRef/Release for collectible assemblies. It is no-op for 'normal' non-collectible assemblies.
1533//
1534// Each type of type parameter needs 2 methods implemented:
1535// code:CollectibleAssemblyHolderBase::GetLoaderAllocator
1536// code:CollectibleAssemblyHolderBase::IsCollectible
1537//
1538template<typename _Type>
1539class CollectibleAssemblyHolderBase
1540{
1541protected:
1542 _Type m_value;
1543public:
1544 CollectibleAssemblyHolderBase(const _Type & value = NULL)
1545 {
1546 LIMITED_METHOD_CONTRACT;
1547 m_value = value;
1548 }
1549 void DoAcquire()
1550 {
1551 CONTRACTL
1552 {
1553 NOTHROW;
1554 GC_NOTRIGGER;
1555 MODE_ANY;
1556 }
1557 CONTRACTL_END;
1558
1559 // We don't need to keep the assembly alive in DAC - see code:#CAH_DAC
1560#ifndef DACCESS_COMPILE
1561 if (this->IsCollectible(m_value))
1562 {
1563 LoaderAllocator * pLoaderAllocator = GetLoaderAllocator(m_value);
1564 pLoaderAllocator->AddReference();
1565 }
1566#endif //!DACCESS_COMPILE
1567 }
1568 void DoRelease()
1569 {
1570 CONTRACTL
1571 {
1572 NOTHROW;
1573 GC_NOTRIGGER;
1574 MODE_ANY;
1575 }
1576 CONTRACTL_END;
1577
1578#ifndef DACCESS_COMPILE
1579 if (this->IsCollectible(m_value))
1580 {
1581 LoaderAllocator * pLoaderAllocator = GetLoaderAllocator(m_value);
1582 pLoaderAllocator->Release();
1583 }
1584#endif //!DACCESS_COMPILE
1585 }
1586
1587private:
1588 LoaderAllocator * GetLoaderAllocator(DomainAssembly * pDomainAssembly)
1589 {
1590 WRAPPER_NO_CONTRACT;
1591 return pDomainAssembly->GetLoaderAllocator();
1592 }
1593 BOOL IsCollectible(DomainAssembly * pDomainAssembly)
1594 {
1595 WRAPPER_NO_CONTRACT;
1596 return pDomainAssembly->IsCollectible();
1597 }
1598 LoaderAllocator * GetLoaderAllocator(Assembly * pAssembly)
1599 {
1600 WRAPPER_NO_CONTRACT;
1601 return pAssembly->GetLoaderAllocator();
1602 }
1603 BOOL IsCollectible(Assembly * pAssembly)
1604 {
1605 WRAPPER_NO_CONTRACT;
1606 return pAssembly->IsCollectible();
1607 }
1608}; // class CollectibleAssemblyHolderBase<>
1609
1610//---------------------------------------------------------------------------------------
1611//
1612// Holder of assembly reference which keeps collectible assembly alive while the holder is valid.
1613//
1614// Collectible assembly can be collected at any point when GC happens. Almost instantly all native data
1615// structures of the assembly (e.g. code:DomainAssembly, code:Assembly) could be deallocated.
1616// Therefore any usage of (collectible) assembly data structures from native world, has to prevent the
1617// deallocation by increasing ref-count on the assembly / associated loader allocator.
1618//
1619// #CAH_DAC
1620// In DAC we don't AddRef/Release as the assembly doesn't have to be kept alive: The process is stopped when
1621// DAC is used and therefore the assembly cannot just disappear.
1622//
1623template<typename _Type>
1624class CollectibleAssemblyHolder : public BaseWrapper<_Type, CollectibleAssemblyHolderBase<_Type> >
1625{
1626public:
1627 FORCEINLINE
1628 CollectibleAssemblyHolder(const _Type & value = NULL, BOOL fTake = TRUE)
1629 : BaseWrapper<_Type, CollectibleAssemblyHolderBase<_Type> >(value, fTake)
1630 {
1631 STATIC_CONTRACT_WRAPPER;
1632 }
1633
1634 FORCEINLINE
1635 CollectibleAssemblyHolder &
1636 operator=(const _Type & value)
1637 {
1638 STATIC_CONTRACT_WRAPPER;
1639 BaseWrapper<_Type, CollectibleAssemblyHolderBase<_Type> >::operator=(value);
1640 return *this;
1641 }
1642
1643 // Operator & is overloaded in parent, therefore we have to get to 'this' pointer explicitly.
1644 FORCEINLINE
1645 CollectibleAssemblyHolder<_Type> *
1646 This()
1647 {
1648 LIMITED_METHOD_CONTRACT;
1649 return this;
1650 }
1651}; // class CollectibleAssemblyHolder<>
1652
1653//---------------------------------------------------------------------------------------
1654//
1655// Stores binding information about failed assembly loads for DAC
1656//
1657struct FailedAssembly {
1658 SString displayName;
1659 SString location;
1660 HRESULT error;
1661
1662 void Initialize(AssemblySpec *pSpec, Exception *ex)
1663 {
1664 CONTRACTL
1665 {
1666 THROWS;
1667 GC_TRIGGERS;
1668 MODE_ANY;
1669 }
1670 CONTRACTL_END;
1671
1672 displayName.SetASCII(pSpec->GetName());
1673 location.Set(pSpec->GetCodeBase());
1674 error = ex->GetHR();
1675
1676 //
1677 // Determine the binding context assembly would have been in.
1678 // If the parent has been set, use its binding context.
1679 // If the parent hasn't been set but the code base has, use LoadFrom.
1680 // Otherwise, use the default.
1681 //
1682 }
1683};
1684
1685#ifdef FEATURE_COMINTEROP
1686
1687// Cache used by COM Interop
1688struct NameToTypeMapEntry
1689{
1690 // Host space representation of the key
1691 struct Key
1692 {
1693 LPCWSTR m_wzName; // The type name or registry string representation of the GUID "{<guid>}"
1694 SIZE_T m_cchName; // wcslen(m_wzName) for faster hashtable lookup
1695 };
1696 struct DacKey
1697 {
1698 PTR_CWSTR m_wzName; // The type name or registry string representation of the GUID "{<guid>}"
1699 SIZE_T m_cchName; // wcslen(m_wzName) for faster hashtable lookup
1700 } m_key;
1701 TypeHandle m_typeHandle; // Using TypeHandle instead of MethodTable* to avoid losing information when sharing method tables.
1702 UINT m_nEpoch; // tracks creation Epoch. This is incremented each time an external reader enumerate the cache
1703 BYTE m_bFlags;
1704};
1705
1706typedef DPTR(NameToTypeMapEntry) PTR_NameToTypeMapEntry;
1707
1708class NameToTypeMapTraits : public NoRemoveSHashTraits< DefaultSHashTraits<NameToTypeMapEntry> >
1709{
1710public:
1711 typedef NameToTypeMapEntry::Key key_t;
1712
1713 static const NameToTypeMapEntry Null() { NameToTypeMapEntry e; e.m_key.m_wzName = NULL; e.m_key.m_cchName = 0; return e; }
1714 static bool IsNull(const NameToTypeMapEntry &e) { return e.m_key.m_wzName == NULL; }
1715 static const key_t GetKey(const NameToTypeMapEntry &e)
1716 {
1717 key_t key;
1718 key.m_wzName = (LPCWSTR)(e.m_key.m_wzName); // this cast brings the string over to the host, in a DAC build
1719 key.m_cchName = e.m_key.m_cchName;
1720
1721 return key;
1722 }
1723 static count_t Hash(const key_t &key) { WRAPPER_NO_CONTRACT; return HashStringN(key.m_wzName, key.m_cchName); }
1724
1725 static BOOL Equals(const key_t &lhs, const key_t &rhs)
1726 {
1727 WRAPPER_NO_CONTRACT;
1728 return (lhs.m_cchName == rhs.m_cchName) && memcmp(lhs.m_wzName, rhs.m_wzName, lhs.m_cchName * sizeof(WCHAR)) == 0;
1729 }
1730
1731 void OnDestructPerEntryCleanupAction(const NameToTypeMapEntry& e)
1732 {
1733 WRAPPER_NO_CONTRACT;
1734 _ASSERTE(e.m_key.m_cchName == wcslen(e.m_key.m_wzName));
1735#ifndef DACCESS_COMPILE
1736 delete [] e.m_key.m_wzName;
1737#endif // DACCESS_COMPILE
1738 }
1739 static const bool s_DestructPerEntryCleanupAction = true;
1740};
1741
1742typedef SHash<NameToTypeMapTraits> NameToTypeMapTable;
1743
1744typedef DPTR(NameToTypeMapTable) PTR_NameToTypeMapTable;
1745
1746struct WinRTFactoryCacheEntry
1747{
1748 typedef MethodTable *Key;
1749 Key key; // Type as KEY
1750
1751 CtxEntry *m_pCtxEntry; // Context entry - used to verify whether the cache is a match
1752 OBJECTHANDLE m_ohFactoryObject; // Handle to factory object
1753};
1754
1755class WinRTFactoryCacheTraits : public DefaultSHashTraits<WinRTFactoryCacheEntry>
1756{
1757public:
1758 typedef WinRTFactoryCacheEntry::Key key_t;
1759 static const WinRTFactoryCacheEntry Null() { WinRTFactoryCacheEntry e; e.key = NULL; return e; }
1760 static bool IsNull(const WinRTFactoryCacheEntry &e) { return e.key == NULL; }
1761 static const WinRTFactoryCacheEntry::Key GetKey(const WinRTFactoryCacheEntry& e) { return e.key; }
1762 static count_t Hash(WinRTFactoryCacheEntry::Key key) { return (count_t)((size_t)key); }
1763 static BOOL Equals(WinRTFactoryCacheEntry::Key lhs, WinRTFactoryCacheEntry::Key rhs)
1764 { return lhs == rhs; }
1765 static const WinRTFactoryCacheEntry Deleted() { WinRTFactoryCacheEntry e; e.key = (MethodTable *)-1; return e; }
1766 static bool IsDeleted(const WinRTFactoryCacheEntry &e) { return e.key == (MethodTable *)-1; }
1767
1768 static void OnDestructPerEntryCleanupAction(const WinRTFactoryCacheEntry& e);
1769 static const bool s_DestructPerEntryCleanupAction = true;
1770};
1771
1772typedef SHash<WinRTFactoryCacheTraits> WinRTFactoryCache;
1773
1774#endif // FEATURE_COMINTEROP
1775
1776class AppDomainIterator;
1777
1778const DWORD DefaultADID = 1;
1779
1780// An Appdomain is the managed equivalent of a process. It is an isolation unit (conceptually you don't
1781// have pointers directly from one appdomain to another, but rather go through remoting proxies). It is
1782// also a unit of unloading.
1783//
1784// Threads are always running in the context of a particular AppDomain. See
1785// file:threads.h#RuntimeThreadLocals for more details.
1786//
1787// see code:BaseDomain for much of the meat of a AppDomain (heaps locks, etc)
1788// * code:AppDomain.m_Assemblies - is a list of code:Assembly in the appdomain
1789//
1790class AppDomain : public BaseDomain
1791{
1792 friend class SystemDomain;
1793 friend class AssemblySink;
1794 friend class AppDomainNative;
1795 friend class AssemblyNative;
1796 friend class AssemblySpec;
1797 friend class ClassLoader;
1798 friend class ThreadNative;
1799 friend class RCWCache;
1800 friend class ClrDataAccess;
1801 friend class CheckAsmOffsets;
1802
1803 VPTR_VTABLE_CLASS(AppDomain, BaseDomain)
1804
1805public:
1806#ifndef DACCESS_COMPILE
1807 AppDomain();
1808 virtual ~AppDomain();
1809 static void Create();
1810#endif
1811
1812 DomainAssembly* FindDomainAssembly(Assembly*);
1813
1814 //-----------------------------------------------------------------------------------------------------------------
1815 // Convenience wrapper for ::GetAppDomain to provide better encapsulation.
1816 static PTR_AppDomain GetCurrentDomain()
1817 { return m_pTheAppDomain; }
1818
1819 //-----------------------------------------------------------------------------------------------------------------
1820 // Initializes an AppDomain. (this functions is not called from the SystemDomain)
1821 void Init();
1822
1823#if defined(FEATURE_COMINTEROP)
1824 HRESULT SetWinrtApplicationContext(LPCWSTR pwzAppLocalWinMD);
1825#endif // FEATURE_COMINTEROP
1826
1827 bool MustForceTrivialWaitOperations();
1828 void SetForceTrivialWaitOperations();
1829
1830 //****************************************************************************************
1831 //
1832 // Stop deletes all the assemblies but does not remove other resources like
1833 // the critical sections
1834 void Stop();
1835
1836 // Gets rid of resources
1837 void Terminate();
1838
1839#ifdef FEATURE_PREJIT
1840 //assembly cleanup that requires suspended runtime
1841 void DeleteNativeCodeRanges();
1842#endif
1843
1844 // final assembly cleanup
1845 void ShutdownAssemblies();
1846 void ShutdownFreeLoaderAllocators(BOOL bFromManagedCode);
1847
1848 void ReleaseDomainBoundInfo();
1849 void ReleaseFiles();
1850
1851
1852 // Remove the Appdomain for the system and cleans up. This call should not be
1853 // called from shut down code.
1854 void CloseDomain();
1855
1856 virtual BOOL IsAppDomain() { LIMITED_METHOD_DAC_CONTRACT; return TRUE; }
1857 virtual PTR_AppDomain AsAppDomain() { LIMITED_METHOD_CONTRACT; return dac_cast<PTR_AppDomain>(this); }
1858
1859 OBJECTREF GetRawExposedObject() { LIMITED_METHOD_CONTRACT; return NULL; }
1860 OBJECTHANDLE GetRawExposedObjectHandleForDebugger() { LIMITED_METHOD_DAC_CONTRACT; return NULL; }
1861
1862#ifdef FEATURE_COMINTEROP
1863 MethodTable *GetRedirectedType(WinMDAdapter::RedirectedTypeIndex index);
1864#endif // FEATURE_COMINTEROP
1865
1866
1867 //****************************************************************************************
1868
1869protected:
1870 // Multi-thread safe access to the list of assemblies
1871 class DomainAssemblyList
1872 {
1873 private:
1874 ArrayList m_array;
1875#ifdef _DEBUG
1876 AppDomain * dbg_m_pAppDomain;
1877 public:
1878 void Debug_SetAppDomain(AppDomain * pAppDomain)
1879 {
1880 dbg_m_pAppDomain = pAppDomain;
1881 }
1882#endif //_DEBUG
1883 public:
1884 bool IsEmpty()
1885 {
1886 CONTRACTL {
1887 NOTHROW;
1888 GC_NOTRIGGER;
1889 MODE_ANY;
1890 } CONTRACTL_END;
1891
1892 // This function can be reliably called without taking the lock, because the first assembly
1893 // added to the arraylist is non-collectible, and the ArrayList itself allows lockless read access
1894 return (m_array.GetCount() == 0);
1895 }
1896 void Clear(AppDomain * pAppDomain)
1897 {
1898 CONTRACTL {
1899 NOTHROW;
1900 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
1901 MODE_ANY;
1902 } CONTRACTL_END;
1903
1904 _ASSERTE(dbg_m_pAppDomain == pAppDomain);
1905
1906 CrstHolder ch(pAppDomain->GetAssemblyListLock());
1907 m_array.Clear();
1908 }
1909
1910 DWORD GetCount(AppDomain * pAppDomain)
1911 {
1912 CONTRACTL {
1913 NOTHROW;
1914 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
1915 MODE_ANY;
1916 } CONTRACTL_END;
1917
1918 _ASSERTE(dbg_m_pAppDomain == pAppDomain);
1919
1920 CrstHolder ch(pAppDomain->GetAssemblyListLock());
1921 return GetCount_Unlocked();
1922 }
1923 DWORD GetCount_Unlocked()
1924 {
1925 CONTRACTL {
1926 NOTHROW;
1927 GC_NOTRIGGER;
1928 MODE_ANY;
1929 } CONTRACTL_END;
1930
1931#ifndef DACCESS_COMPILE
1932 _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
1933#endif
1934 // code:Append_Unlock guarantees that we do not have more than MAXDWORD items
1935 return m_array.GetCount();
1936 }
1937
1938 void Get(AppDomain * pAppDomain, DWORD index, CollectibleAssemblyHolder<DomainAssembly *> * pAssemblyHolder)
1939 {
1940 CONTRACTL {
1941 NOTHROW;
1942 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
1943 MODE_ANY;
1944 } CONTRACTL_END;
1945
1946 _ASSERTE(dbg_m_pAppDomain == pAppDomain);
1947
1948 CrstHolder ch(pAppDomain->GetAssemblyListLock());
1949 Get_Unlocked(index, pAssemblyHolder);
1950 }
1951 void Get_Unlocked(DWORD index, CollectibleAssemblyHolder<DomainAssembly *> * pAssemblyHolder)
1952 {
1953 CONTRACTL {
1954 NOTHROW;
1955 GC_NOTRIGGER;
1956 MODE_ANY;
1957 } CONTRACTL_END;
1958
1959 _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
1960 *pAssemblyHolder = dac_cast<PTR_DomainAssembly>(m_array.Get(index));
1961 }
1962 // Doesn't lock the assembly list (caller has to hold the lock already).
1963 // Doesn't AddRef the returned assembly (if collectible).
1964 DomainAssembly * Get_UnlockedNoReference(DWORD index)
1965 {
1966 CONTRACTL {
1967 NOTHROW;
1968 GC_NOTRIGGER;
1969 MODE_ANY;
1970 SUPPORTS_DAC;
1971 } CONTRACTL_END;
1972
1973#ifndef DACCESS_COMPILE
1974 _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
1975#endif
1976 return dac_cast<PTR_DomainAssembly>(m_array.Get(index));
1977 }
1978
1979#ifndef DACCESS_COMPILE
1980 void Set(AppDomain * pAppDomain, DWORD index, DomainAssembly * pAssembly)
1981 {
1982 CONTRACTL {
1983 NOTHROW;
1984 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
1985 MODE_ANY;
1986 } CONTRACTL_END;
1987
1988 _ASSERTE(dbg_m_pAppDomain == pAppDomain);
1989
1990 CrstHolder ch(pAppDomain->GetAssemblyListLock());
1991 return Set_Unlocked(index, pAssembly);
1992 }
1993 void Set_Unlocked(DWORD index, DomainAssembly * pAssembly)
1994 {
1995 CONTRACTL {
1996 NOTHROW;
1997 GC_NOTRIGGER;
1998 MODE_ANY;
1999 } CONTRACTL_END;
2000
2001 _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
2002 m_array.Set(index, pAssembly);
2003 }
2004
2005 HRESULT Append_Unlocked(DomainAssembly * pAssembly)
2006 {
2007 CONTRACTL {
2008 NOTHROW;
2009 GC_NOTRIGGER;
2010 MODE_ANY;
2011 } CONTRACTL_END;
2012
2013 _ASSERTE(dbg_m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
2014 return m_array.Append(pAssembly);
2015 }
2016#else //DACCESS_COMPILE
2017 void
2018 EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2019 {
2020 SUPPORTS_DAC;
2021
2022 m_array.EnumMemoryRegions(flags);
2023 }
2024#endif // DACCESS_COMPILE
2025
2026 // Should be used only by code:AssemblyIterator::Create
2027 ArrayList::Iterator GetArrayListIterator()
2028 {
2029 return m_array.Iterate();
2030 }
2031 }; // class DomainAssemblyList
2032
2033 // Conceptually a list of code:Assembly structures, protected by lock code:GetAssemblyListLock
2034 DomainAssemblyList m_Assemblies;
2035
2036public:
2037 // Note that this lock switches thread into GC_NOTRIGGER region as GC can take it too.
2038 CrstExplicitInit * GetAssemblyListLock()
2039 {
2040 LIMITED_METHOD_CONTRACT;
2041 return &m_crstAssemblyList;
2042 }
2043
2044public:
2045 class AssemblyIterator
2046 {
2047 // AppDomain context with the assembly list
2048 AppDomain * m_pAppDomain;
2049 ArrayList::Iterator m_Iterator;
2050 AssemblyIterationFlags m_assemblyIterationFlags;
2051
2052 public:
2053 BOOL Next(CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder);
2054 // Note: Does not lock the assembly list, but AddRefs collectible assemblies.
2055 BOOL Next_Unlocked(CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder);
2056#ifndef DACCESS_COMPILE
2057 private:
2058 // Can be called only from AppDomain shutdown code:AppDomain::ShutdownAssemblies.
2059 // Note: Does not lock the assembly list and does not AddRefs collectible assemblies.
2060 BOOL Next_UnsafeNoAddRef(DomainAssembly ** ppDomainAssembly);
2061#endif
2062
2063 private:
2064 inline DWORD GetIndex()
2065 {
2066 LIMITED_METHOD_CONTRACT;
2067 return m_Iterator.GetIndex();
2068 }
2069
2070 private:
2071 friend class AppDomain;
2072 // Cannot have constructor so this iterator can be used inside a union
2073 static AssemblyIterator Create(AppDomain * pAppDomain, AssemblyIterationFlags assemblyIterationFlags)
2074 {
2075 LIMITED_METHOD_CONTRACT;
2076 AssemblyIterator i;
2077
2078 i.m_pAppDomain = pAppDomain;
2079 i.m_Iterator = pAppDomain->m_Assemblies.GetArrayListIterator();
2080 i.m_assemblyIterationFlags = assemblyIterationFlags;
2081 return i;
2082 }
2083 }; // class AssemblyIterator
2084
2085 AssemblyIterator IterateAssembliesEx(AssemblyIterationFlags assemblyIterationFlags)
2086 {
2087 LIMITED_METHOD_CONTRACT;
2088 return AssemblyIterator::Create(this, assemblyIterationFlags);
2089 }
2090
2091private:
2092 struct NativeImageDependenciesEntry
2093 {
2094 BaseAssemblySpec m_AssemblySpec;
2095 GUID m_guidMVID;
2096 };
2097
2098 class NativeImageDependenciesTraits : public DeleteElementsOnDestructSHashTraits<DefaultSHashTraits<NativeImageDependenciesEntry *> >
2099 {
2100 public:
2101 typedef BaseAssemblySpec *key_t;
2102 static key_t GetKey(NativeImageDependenciesEntry * e) { return &(e->m_AssemblySpec); }
2103
2104 static count_t Hash(key_t k)
2105 {
2106 return k->Hash();
2107 }
2108
2109 static BOOL Equals(key_t lhs, key_t rhs)
2110 {
2111 return lhs->CompareEx(rhs);
2112 }
2113 };
2114
2115 SHash<NativeImageDependenciesTraits> m_NativeImageDependencies;
2116
2117public:
2118 void CheckForMismatchedNativeImages(AssemblySpec * pSpec, const GUID * pGuid);
2119 BOOL RemoveNativeImageDependency(AssemblySpec* pSpec);
2120
2121public:
2122 class PathIterator
2123 {
2124 friend class AppDomain;
2125
2126 ArrayList::Iterator m_i;
2127
2128 public:
2129 BOOL Next()
2130 {
2131 WRAPPER_NO_CONTRACT;
2132 return m_i.Next();
2133 }
2134
2135 SString* GetPath()
2136 {
2137 WRAPPER_NO_CONTRACT;
2138 return dac_cast<PTR_SString>(m_i.GetElement());
2139 }
2140 };
2141
2142 PathIterator IterateNativeDllSearchDirectories();
2143 void SetNativeDllSearchDirectories(LPCWSTR paths);
2144 BOOL HasNativeDllSearchDirectories();
2145 void ShutdownNativeDllSearchDirectories();
2146
2147public:
2148 SIZE_T GetAssemblyCount()
2149 {
2150 WRAPPER_NO_CONTRACT;
2151 return m_Assemblies.GetCount(this);
2152 }
2153
2154 CHECK CheckCanLoadTypes(Assembly *pAssembly);
2155 CHECK CheckCanExecuteManagedCode(MethodDesc* pMD);
2156 CHECK CheckLoading(DomainFile *pFile, FileLoadLevel level);
2157
2158 FileLoadLevel GetDomainFileLoadLevel(DomainFile *pFile);
2159 BOOL IsLoading(DomainFile *pFile, FileLoadLevel level);
2160 static FileLoadLevel GetThreadFileLoadLevel();
2161
2162 void LoadDomainFile(DomainFile *pFile,
2163 FileLoadLevel targetLevel);
2164
2165 enum FindAssemblyOptions
2166 {
2167 FindAssemblyOptions_None = 0x0,
2168 FindAssemblyOptions_IncludeFailedToLoad = 0x1
2169 };
2170
2171 DomainAssembly * FindAssembly(PEAssembly * pFile, FindAssemblyOptions options = FindAssemblyOptions_None) DAC_EMPTY_RET(NULL);
2172
2173
2174 Assembly *LoadAssembly(AssemblySpec* pIdentity,
2175 PEAssembly *pFile,
2176 FileLoadLevel targetLevel);
2177
2178 // this function does not provide caching, you must use LoadDomainAssembly
2179 // unless the call is guaranteed to succeed or you don't need the caching
2180 // (e.g. if you will FailFast or tear down the AppDomain anyway)
2181 // The main point that you should not bypass caching if you might try to load the same file again,
2182 // resulting in multiple DomainAssembly objects that share the same PEAssembly for ngen image
2183 //which is violating our internal assumptions
2184 DomainAssembly *LoadDomainAssemblyInternal( AssemblySpec* pIdentity,
2185 PEAssembly *pFile,
2186 FileLoadLevel targetLevel);
2187
2188 DomainAssembly *LoadDomainAssembly( AssemblySpec* pIdentity,
2189 PEAssembly *pFile,
2190 FileLoadLevel targetLevel);
2191
2192
2193 CHECK CheckValidModule(Module *pModule);
2194
2195 // private:
2196 void LoadSystemAssemblies();
2197
2198 DomainFile *LoadDomainFile(FileLoadLock *pLock,
2199 FileLoadLevel targetLevel);
2200
2201 void TryIncrementalLoad(DomainFile *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder);
2202
2203 Assembly *LoadAssemblyHelper(LPCWSTR wszAssembly,
2204 LPCWSTR wszCodeBase);
2205
2206#ifndef DACCESS_COMPILE // needs AssemblySpec
2207
2208 void GetCacheAssemblyList(SetSHash<PTR_DomainAssembly>& assemblyList);
2209
2210 //****************************************************************************************
2211 // Returns and Inserts assemblies into a lookup cache based on the binding information
2212 // in the AssemblySpec. There can be many AssemblySpecs to a single assembly.
2213 DomainAssembly* FindCachedAssembly(AssemblySpec* pSpec, BOOL fThrow=TRUE)
2214 {
2215 WRAPPER_NO_CONTRACT;
2216 return m_AssemblyCache.LookupAssembly(pSpec, fThrow);
2217 }
2218
2219 PEAssembly* FindCachedFile(AssemblySpec* pSpec, BOOL fThrow = TRUE);
2220 BOOL IsCached(AssemblySpec *pSpec);
2221#endif // DACCESS_COMPILE
2222 void CacheStringsForDAC();
2223
2224 BOOL AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAllowFailure = FALSE);
2225 BOOL RemoveFileFromCache(PEAssembly *pFile);
2226
2227 BOOL AddAssemblyToCache(AssemblySpec* pSpec, DomainAssembly *pAssembly);
2228 BOOL RemoveAssemblyFromCache(DomainAssembly* pAssembly);
2229
2230 BOOL AddExceptionToCache(AssemblySpec* pSpec, Exception *ex);
2231 void AddUnmanagedImageToCache(LPCWSTR libraryName, HMODULE hMod);
2232 HMODULE FindUnmanagedImageInCache(LPCWSTR libraryName);
2233 //****************************************************************************************
2234 //
2235 // Adds or removes an assembly to the domain.
2236 void AddAssembly(DomainAssembly * assem);
2237 void RemoveAssembly(DomainAssembly * pAsm);
2238
2239 BOOL ContainsAssembly(Assembly * assem);
2240
2241 //****************************************************************************************
2242 //
2243 // Reference count. When an appdomain is first created the reference is bump
2244 // to one when it is added to the list of domains (see SystemDomain). An explicit
2245 // Removal from the list is necessary before it will be deleted.
2246 ULONG AddRef(void);
2247 ULONG Release(void) DAC_EMPTY_RET(0);
2248
2249 //****************************************************************************************
2250 LPCWSTR GetFriendlyName(BOOL fDebuggerCares = TRUE);
2251 LPCWSTR GetFriendlyNameForDebugger();
2252 LPCWSTR GetFriendlyNameForLogging();
2253#ifdef DACCESS_COMPILE
2254 PVOID GetFriendlyNameNoSet(bool* isUtf8);
2255#endif
2256 void SetFriendlyName(LPCWSTR pwzFriendlyName, BOOL fDebuggerCares = TRUE);
2257
2258 //****************************************************************************************
2259
2260 // This can be used to override the binding behavior of the appdomain. It
2261 // is overridden in the compilation domain. It is important that all
2262 // static binding goes through this path.
2263 virtual PEAssembly * BindAssemblySpec(
2264 AssemblySpec *pSpec,
2265 BOOL fThrowOnFileNotFound,
2266 BOOL fUseHostBinderIfAvailable = TRUE) DAC_EMPTY_RET(NULL);
2267
2268 HRESULT BindAssemblySpecForHostedBinder(
2269 AssemblySpec * pSpec,
2270 IAssemblyName * pAssemblyName,
2271 ICLRPrivBinder * pBinder,
2272 PEAssembly ** ppAssembly) DAC_EMPTY_RET(E_FAIL);
2273
2274 HRESULT BindHostedPrivAssembly(
2275 PEAssembly * pParentPEAssembly,
2276 ICLRPrivAssembly * pPrivAssembly,
2277 IAssemblyName * pAssemblyName,
2278 PEAssembly ** ppAssembly) DAC_EMPTY_RET(S_OK);
2279
2280
2281 PEAssembly *TryResolveAssembly(AssemblySpec *pSpec);
2282
2283 // Store a successful binding into the cache. This will keep the file from
2284 // being physically unmapped, as well as shortcutting future attempts to bind
2285 // the same spec throught the Cached entry point.
2286 //
2287 // Right now we only cache assembly binds for "probing" type
2288 // binding situations, basically when loading domain neutral assemblies or
2289 // zap files.
2290 //
2291 // <TODO>@todo: We may want to be more aggressive about this if
2292 // there are other situations where we are repeatedly binding the
2293 // same assembly specs, though.</TODO>
2294 //
2295 // Returns TRUE if stored
2296 // FALSE if it's a duplicate (caller should clean up args)
2297 BOOL StoreBindAssemblySpecResult(AssemblySpec *pSpec,
2298 PEAssembly *pFile,
2299 BOOL clone = TRUE);
2300
2301 BOOL StoreBindAssemblySpecError(AssemblySpec *pSpec,
2302 HRESULT hr,
2303 OBJECTREF *pThrowable,
2304 BOOL clone = TRUE);
2305
2306 //****************************************************************************************
2307 //
2308 //****************************************************************************************
2309 //
2310 // Uses the first assembly to add an application base to the Context. This is done
2311 // in a lazy fashion so executables do not take the perf hit unless the load other
2312 // assemblies
2313#ifndef DACCESS_COMPILE
2314 void OnAssemblyLoad(Assembly *assem);
2315 void OnAssemblyLoadUnlocked(Assembly *assem);
2316 static BOOL OnUnhandledException(OBJECTREF *pThrowable, BOOL isTerminating = TRUE);
2317
2318#endif
2319
2320 // True iff a debugger is attached to the process (same as CORDebuggerAttached)
2321 BOOL IsDebuggerAttached (void);
2322
2323#ifdef DEBUGGING_SUPPORTED
2324 // Notify debugger of all assemblies, modules, and possibly classes in this AppDomain
2325 BOOL NotifyDebuggerLoad(int flags, BOOL attaching);
2326
2327 // Send unload notifications to the debugger for all assemblies, modules and classes in this AppDomain
2328 void NotifyDebuggerUnload();
2329#endif // DEBUGGING_SUPPORTED
2330
2331 void SetSystemAssemblyLoadEventSent (BOOL fFlag);
2332 BOOL WasSystemAssemblyLoadEventSent (void);
2333
2334#ifndef DACCESS_COMPILE
2335 OBJECTREF* AllocateStaticFieldObjRefPtrs(int nRequested, OBJECTREF** ppLazyAllocate = NULL)
2336 {
2337 WRAPPER_NO_CONTRACT;
2338
2339 return AllocateObjRefPtrsInLargeTable(nRequested, ppLazyAllocate);
2340 }
2341
2342 OBJECTREF* AllocateStaticFieldObjRefPtrsCrossDomain(int nRequested, OBJECTREF** ppLazyAllocate = NULL)
2343 {
2344 WRAPPER_NO_CONTRACT;
2345
2346 return AllocateObjRefPtrsInLargeTable(nRequested, ppLazyAllocate, TRUE);
2347 }
2348#endif // DACCESS_COMPILE
2349
2350 void EnumStaticGCRefs(promote_func* fn, ScanContext* sc);
2351
2352 DomainLocalBlock *GetDomainLocalBlock()
2353 {
2354 LIMITED_METHOD_DAC_CONTRACT;
2355
2356 return &m_sDomainLocalBlock;
2357 }
2358
2359 static SIZE_T GetOffsetOfModuleSlotsPointer()
2360 {
2361 WRAPPER_NO_CONTRACT;
2362
2363 return offsetof(AppDomain,m_sDomainLocalBlock) + DomainLocalBlock::GetOffsetOfModuleSlotsPointer();
2364 }
2365
2366 void SetupSharedStatics();
2367
2368 //****************************************************************************************
2369 //
2370 // Create a quick lookup for classes loaded into this domain based on their GUID.
2371 //
2372 void InsertClassForCLSID(MethodTable* pMT, BOOL fForceInsert = FALSE);
2373 void InsertClassForCLSID(MethodTable* pMT, GUID *pGuid);
2374
2375#ifdef FEATURE_COMINTEROP
2376private:
2377 void CacheTypeByNameWorker(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE flags, BOOL bReplaceExisting = FALSE);
2378 TypeHandle LookupTypeByNameWorker(const SString &ssClassName, UINT *pvCacheVersion, BYTE *pbFlags);
2379public:
2380 // Used by COM Interop for mapping WinRT runtime class names to real types.
2381 void CacheTypeByName(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE flags, BOOL bReplaceExisting = FALSE);
2382 TypeHandle LookupTypeByName(const SString &ssClassName, UINT *pvCacheVersion, BYTE *pbFlags);
2383 PTR_MethodTable LookupTypeByGuid(const GUID & guid);
2384
2385#ifndef DACCESS_COMPILE
2386 inline BOOL CanCacheWinRTTypeByGuid(TypeHandle typeHandle)
2387 {
2388 CONTRACTL
2389 {
2390 THROWS;
2391 GC_NOTRIGGER;
2392 MODE_ANY;
2393 }
2394 CONTRACTL_END;
2395
2396 // Only allow caching guid/types maps for types loaded during
2397 // "normal" domain operation
2398 if (IsCompilationDomain() || (m_Stage < STAGE_OPEN))
2399 return FALSE;
2400
2401 MethodTable *pMT = typeHandle.GetMethodTable();
2402 if (pMT != NULL)
2403 {
2404 // Don't cache mscorlib-internal declarations of WinRT types.
2405 if (pMT->GetModule()->IsSystem() && pMT->IsProjectedFromWinRT())
2406 return FALSE;
2407
2408 // Don't cache redirected WinRT types.
2409 if (WinRTTypeNameConverter::IsRedirectedWinRTSourceType(pMT))
2410 return FALSE;
2411 }
2412
2413 return TRUE;
2414 }
2415#endif // !DACCESS_COMPILE
2416
2417 void CacheWinRTTypeByGuid(TypeHandle typeHandle);
2418 void GetCachedWinRTTypes(SArray<PTR_MethodTable> * pTypes, SArray<GUID> * pGuids, UINT minEpoch, UINT * pCurEpoch);
2419
2420 // Used by COM Interop for caching WinRT factory objects.
2421 void CacheWinRTFactoryObject(MethodTable *pClassMT, OBJECTREF *refFactory, LPVOID lpCtxCookie);
2422 OBJECTREF LookupWinRTFactoryObject(MethodTable *pClassMT, LPVOID lpCtxCookie);
2423 void RemoveWinRTFactoryObjects(LPVOID pCtxCookie);
2424
2425 MethodTable *LoadCOMClass(GUID clsid, BOOL bLoadRecord = FALSE, BOOL* pfAssemblyInReg = NULL);
2426 OBJECTREF GetMissingObject(); // DispatchInfo will call function to retrieve the Missing.Value object.
2427#endif // FEATURE_COMINTEROP
2428
2429#ifndef DACCESS_COMPILE
2430 MethodTable* LookupClass(REFIID iid)
2431 {
2432 WRAPPER_NO_CONTRACT;
2433
2434 MethodTable *pMT = (MethodTable*) m_clsidHash.LookupValue((UPTR) GetKeyFromGUID(&iid), (LPVOID)&iid);
2435 return (pMT == (MethodTable*) INVALIDENTRY
2436 ? NULL
2437 : pMT);
2438 }
2439#endif // DACCESS_COMPILE
2440
2441 //<TODO>@todo get a better key</TODO>
2442 ULONG GetKeyFromGUID(const GUID *pguid)
2443 {
2444 LIMITED_METHOD_CONTRACT;
2445
2446 return *(ULONG *) pguid;
2447 }
2448
2449#ifdef FEATURE_COMINTEROP
2450 RCWCache *GetRCWCache()
2451 {
2452 WRAPPER_NO_CONTRACT;
2453 if (m_pRCWCache)
2454 return m_pRCWCache;
2455
2456 // By separating the cache creation from the common lookup, we
2457 // can keep the (x86) EH prolog/epilog off the path.
2458 return CreateRCWCache();
2459 }
2460private:
2461 RCWCache *CreateRCWCache();
2462public:
2463 RCWCache *GetRCWCacheNoCreate()
2464 {
2465 LIMITED_METHOD_CONTRACT;
2466 return m_pRCWCache;
2467 }
2468
2469 RCWRefCache *GetRCWRefCache();
2470
2471 MethodTable* GetLicenseInteropHelperMethodTable();
2472#endif // FEATURE_COMINTEROP
2473
2474 //****************************************************************************************
2475 // Get the proxy for this app domain
2476
2477 ADIndex GetIndex()
2478 {
2479 LIMITED_METHOD_CONTRACT;
2480 SUPPORTS_DAC;
2481
2482 return m_dwIndex;
2483 }
2484
2485 TPIndex GetTPIndex()
2486 {
2487 LIMITED_METHOD_CONTRACT;
2488 return m_tpIndex;
2489 }
2490
2491 IUnknown *CreateFusionContext();
2492
2493 void SetIgnoreUnhandledExceptions()
2494 {
2495 LIMITED_METHOD_CONTRACT;
2496
2497 m_dwFlags |= IGNORE_UNHANDLED_EXCEPTIONS;
2498 }
2499
2500 BOOL IgnoreUnhandledExceptions()
2501 {
2502 LIMITED_METHOD_CONTRACT;
2503
2504 return (m_dwFlags & IGNORE_UNHANDLED_EXCEPTIONS);
2505 }
2506
2507 void SetCompilationDomain()
2508 {
2509 LIMITED_METHOD_CONTRACT;
2510
2511 m_dwFlags |= COMPILATION_DOMAIN;
2512 }
2513
2514 BOOL IsCompilationDomain();
2515
2516 PTR_CompilationDomain ToCompilationDomain()
2517 {
2518 LIMITED_METHOD_CONTRACT;
2519
2520 _ASSERTE(IsCompilationDomain());
2521 return dac_cast<PTR_CompilationDomain>(this);
2522 }
2523
2524 static void ExceptionUnwind(Frame *pFrame);
2525
2526#ifdef _DEBUG
2527 void TrackADThreadEnter(Thread *pThread, Frame *pFrame);
2528 void TrackADThreadExit(Thread *pThread, Frame *pFrame);
2529 void DumpADThreadTrack();
2530#endif
2531
2532#ifndef DACCESS_COMPILE
2533 void ThreadEnter(Thread *pThread, Frame *pFrame)
2534 {
2535 STATIC_CONTRACT_NOTHROW;
2536 STATIC_CONTRACT_GC_NOTRIGGER;
2537
2538#ifdef _DEBUG
2539 if (LoggingOn(LF_APPDOMAIN, LL_INFO100))
2540 TrackADThreadEnter(pThread, pFrame);
2541 else
2542#endif
2543 {
2544 InterlockedIncrement((LONG*)&m_dwThreadEnterCount);
2545 LOG((LF_APPDOMAIN, LL_INFO1000, "AppDomain::ThreadEnter %p to [%d] (%8.8x) %S count %d\n",
2546 pThread,GetId().m_dwId, this,
2547 GetFriendlyNameForLogging(),GetThreadEnterCount()));
2548#if _DEBUG_AD_UNLOAD
2549 printf("AppDomain::ThreadEnter %p to [%d] (%8.8x) %S count %d\n",
2550 pThread, GetId().m_dwId, this,
2551 GetFriendlyNameForLogging(), GetThreadEnterCount());
2552#endif
2553 }
2554 }
2555
2556 void ThreadExit(Thread *pThread, Frame *pFrame)
2557 {
2558 STATIC_CONTRACT_NOTHROW;
2559 STATIC_CONTRACT_GC_NOTRIGGER;
2560
2561#ifdef _DEBUG
2562 if (LoggingOn(LF_APPDOMAIN, LL_INFO100)) {
2563 TrackADThreadExit(pThread, pFrame);
2564 }
2565 else
2566#endif
2567 {
2568 LONG result;
2569 result = InterlockedDecrement((LONG*)&m_dwThreadEnterCount);
2570 _ASSERTE(result >= 0);
2571 LOG((LF_APPDOMAIN, LL_INFO1000, "AppDomain::ThreadExit from [%d] (%8.8x) %S count %d\n",
2572 this, GetId().m_dwId,
2573 GetFriendlyNameForLogging(), GetThreadEnterCount()));
2574#if _DEBUG_ADUNLOAD
2575 printf("AppDomain::ThreadExit %x from [%d] (%8.8x) %S count %d\n",
2576 pThread->GetThreadId(), this, GetId().m_dwId,
2577 GetFriendlyNameForLogging(), GetThreadEnterCount());
2578#endif
2579 }
2580 }
2581#endif // DACCESS_COMPILE
2582
2583 ULONG GetThreadEnterCount()
2584 {
2585 LIMITED_METHOD_CONTRACT;
2586 return m_dwThreadEnterCount;
2587 }
2588
2589 BOOL OnlyOneThreadLeft()
2590 {
2591 LIMITED_METHOD_CONTRACT;
2592 return m_dwThreadEnterCount==1 || m_dwThreadsStillInAppDomain ==1;
2593 }
2594
2595 static void RefTakerAcquire(AppDomain* pDomain)
2596 {
2597 WRAPPER_NO_CONTRACT;
2598 if(!pDomain)
2599 return;
2600 pDomain->AddRef();
2601#ifdef _DEBUG
2602 FastInterlockIncrement(&pDomain->m_dwRefTakers);
2603#endif
2604 }
2605
2606 static void RefTakerRelease(AppDomain* pDomain)
2607 {
2608 WRAPPER_NO_CONTRACT;
2609 if(!pDomain)
2610 return;
2611#ifdef _DEBUG
2612 _ASSERTE(pDomain->m_dwRefTakers);
2613 FastInterlockDecrement(&pDomain->m_dwRefTakers);
2614#endif
2615 pDomain->Release();
2616 }
2617
2618#ifdef _DEBUG
2619
2620 BOOL IsHeldByIterator()
2621 {
2622 LIMITED_METHOD_CONTRACT;
2623 return m_dwIterHolders>0;
2624 }
2625
2626 BOOL IsHeldByRefTaker()
2627 {
2628 LIMITED_METHOD_CONTRACT;
2629 return m_dwRefTakers>0;
2630 }
2631
2632 void IteratorRelease()
2633 {
2634 LIMITED_METHOD_CONTRACT;
2635 _ASSERTE(m_dwIterHolders);
2636 FastInterlockDecrement(&m_dwIterHolders);
2637 }
2638
2639
2640 void IteratorAcquire()
2641 {
2642 LIMITED_METHOD_CONTRACT;
2643 FastInterlockIncrement(&m_dwIterHolders);
2644 }
2645
2646#endif
2647 BOOL IsActive()
2648 {
2649 LIMITED_METHOD_DAC_CONTRACT;
2650
2651 return m_Stage >= STAGE_ACTIVE;
2652 }
2653 // Range for normal execution of code in the appdomain, currently used for
2654 // appdomain resource monitoring since we don't care to update resource usage
2655 // unless it's in these stages (as fields of AppDomain may not be valid if it's
2656 // not within these stages)
2657 BOOL IsUserActive()
2658 {
2659 LIMITED_METHOD_DAC_CONTRACT;
2660
2661 return m_Stage >= STAGE_ACTIVE && m_Stage <= STAGE_OPEN;
2662 }
2663 BOOL IsValid()
2664 {
2665 LIMITED_METHOD_DAC_CONTRACT;
2666
2667#ifdef DACCESS_COMPILE
2668 // We want to see all appdomains in SOS, even the about to be destructed ones.
2669 // There is no risk of races under DAC, so we will pretend to be unconditionally valid.
2670 return TRUE;
2671#else
2672 return m_Stage > STAGE_CREATING;
2673#endif
2674 }
2675
2676#ifdef _DEBUG
2677 BOOL IsBeingCreated()
2678 {
2679 LIMITED_METHOD_CONTRACT;
2680
2681 return m_dwCreationHolders > 0;
2682 }
2683
2684 void IncCreationCount()
2685 {
2686 LIMITED_METHOD_CONTRACT;
2687
2688 FastInterlockIncrement(&m_dwCreationHolders);
2689 _ASSERTE(m_dwCreationHolders > 0);
2690 }
2691
2692 void DecCreationCount()
2693 {
2694 LIMITED_METHOD_CONTRACT;
2695
2696 FastInterlockDecrement(&m_dwCreationHolders);
2697 _ASSERTE(m_dwCreationHolders > -1);
2698 }
2699#endif
2700 BOOL IsRunningIn(Thread* pThread);
2701
2702 BOOL NotReadyForManagedCode()
2703 {
2704 LIMITED_METHOD_CONTRACT;
2705
2706 return m_Stage < STAGE_READYFORMANAGEDCODE;
2707 }
2708
2709 static void RaiseExitProcessEvent();
2710 Assembly* RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName);
2711 DomainAssembly* RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef);
2712 Assembly* RaiseAssemblyResolveEvent(AssemblySpec *pSpec);
2713
2714private:
2715 CrstExplicitInit m_ReflectionCrst;
2716 CrstExplicitInit m_RefClassFactCrst;
2717
2718
2719 EEClassFactoryInfoHashTable *m_pRefClassFactHash; // Hash table that maps a class factory info to a COM comp.
2720#ifdef FEATURE_COMINTEROP
2721 DispIDCache *m_pRefDispIDCache;
2722 OBJECTHANDLE m_hndMissing; //Handle points to Missing.Value Object which is used for [Optional] arg scenario during IDispatch CCW Call
2723
2724 MethodTable* m_rpCLRTypes[WinMDAdapter::RedirectedTypeIndex_Count];
2725
2726 MethodTable* LoadRedirectedType(WinMDAdapter::RedirectedTypeIndex index, WinMDAdapter::FrameworkAssemblyIndex assembly);
2727#endif // FEATURE_COMINTEROP
2728
2729public:
2730
2731 CrstBase *GetRefClassFactCrst()
2732 {
2733 LIMITED_METHOD_CONTRACT;
2734
2735 return &m_RefClassFactCrst;
2736 }
2737
2738#ifndef DACCESS_COMPILE
2739 EEClassFactoryInfoHashTable* GetClassFactHash()
2740 {
2741 STATIC_CONTRACT_THROWS;
2742 STATIC_CONTRACT_GC_TRIGGERS;
2743 STATIC_CONTRACT_FAULT;
2744
2745 if (m_pRefClassFactHash != NULL) {
2746 return m_pRefClassFactHash;
2747 }
2748
2749 return SetupClassFactHash();
2750 }
2751#endif // DACCESS_COMPILE
2752
2753#ifdef FEATURE_COMINTEROP
2754 DispIDCache* GetRefDispIDCache()
2755 {
2756 STATIC_CONTRACT_THROWS;
2757 STATIC_CONTRACT_GC_TRIGGERS;
2758 STATIC_CONTRACT_FAULT;
2759
2760 if (m_pRefDispIDCache != NULL) {
2761 return m_pRefDispIDCache;
2762 }
2763
2764 return SetupRefDispIDCache();
2765 }
2766#endif // FEATURE_COMINTEROP
2767
2768 PTR_LoaderHeap GetStubHeap();
2769 PTR_LoaderHeap GetLowFrequencyHeap();
2770 PTR_LoaderHeap GetHighFrequencyHeap();
2771
2772#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2773 #define ARM_ETW_ALLOC_THRESHOLD (4 * 1024 * 1024)
2774 // cache line size in ULONGLONG - 128 bytes which are 16 ULONGLONG's
2775 #define ARM_CACHE_LINE_SIZE_ULL 16
2776
2777 inline ULONGLONG GetAllocBytes()
2778 {
2779 LIMITED_METHOD_CONTRACT;
2780 ULONGLONG ullTotalAllocBytes = 0;
2781
2782 // Ensure that m_pullAllocBytes is non-null to avoid an AV in a race between GC and AD unload.
2783 // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullAllocBytes, causing the AD unload.
2784 if(NULL != m_pullAllocBytes)
2785 {
2786 for (DWORD i = 0; i < m_dwNumHeaps; i++)
2787 {
2788 ullTotalAllocBytes += m_pullAllocBytes[i * ARM_CACHE_LINE_SIZE_ULL];
2789 }
2790 }
2791 return ullTotalAllocBytes;
2792 }
2793
2794 void RecordAllocBytes(size_t allocatedBytes, DWORD dwHeapNumber)
2795 {
2796 LIMITED_METHOD_CONTRACT;
2797 _ASSERTE(dwHeapNumber < m_dwNumHeaps);
2798
2799 // Ensure that m_pullAllocBytes is non-null to avoid an AV in a race between GC and AD unload.
2800 // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullAllocBytes, causing the AD unload.
2801 if(NULL != m_pullAllocBytes)
2802 {
2803 m_pullAllocBytes[dwHeapNumber * ARM_CACHE_LINE_SIZE_ULL] += allocatedBytes;
2804 }
2805
2806 ULONGLONG ullTotalAllocBytes = GetAllocBytes();
2807
2808 if ((ullTotalAllocBytes - m_ullLastEtwAllocBytes) >= ARM_ETW_ALLOC_THRESHOLD)
2809 {
2810 m_ullLastEtwAllocBytes = ullTotalAllocBytes;
2811 FireEtwAppDomainMemAllocated((ULONGLONG)this, ullTotalAllocBytes, GetClrInstanceId());
2812 }
2813 }
2814
2815 inline ULONGLONG GetSurvivedBytes()
2816 {
2817 LIMITED_METHOD_CONTRACT;
2818 ULONGLONG ullTotalSurvivedBytes = 0;
2819
2820 // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
2821 // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
2822 if(NULL != m_pullSurvivedBytes)
2823 {
2824 for (DWORD i = 0; i < m_dwNumHeaps; i++)
2825 {
2826 ullTotalSurvivedBytes += m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL];
2827 }
2828 }
2829 return ullTotalSurvivedBytes;
2830 }
2831
2832 void RecordSurvivedBytes(size_t promotedBytes, DWORD dwHeapNumber)
2833 {
2834 WRAPPER_NO_CONTRACT;
2835 _ASSERTE(dwHeapNumber < m_dwNumHeaps);
2836
2837 // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
2838 // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
2839 if(NULL != m_pullSurvivedBytes)
2840 {
2841 m_pullSurvivedBytes[dwHeapNumber * ARM_CACHE_LINE_SIZE_ULL] += promotedBytes;
2842 }
2843 }
2844
2845 inline void ResetSurvivedBytes()
2846 {
2847 LIMITED_METHOD_CONTRACT;
2848
2849 // Ensure that m_pullSurvivedBytes is non-null to avoid an AV in a race between GC and AD unload.
2850 // A race can occur when a new appdomain is created, but an OOM is thrown when allocating for m_pullSurvivedBytes, causing the AD unload.
2851 if(NULL != m_pullSurvivedBytes)
2852 {
2853 for (DWORD i = 0; i < m_dwNumHeaps; i++)
2854 {
2855 m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
2856 }
2857 }
2858 }
2859
2860 // Return the total processor time (user and kernel) used by threads executing in this AppDomain so far.
2861 // The result is in 100ns units.
2862 ULONGLONG QueryProcessorUsage();
2863
2864 // Add to the current count of processor time used by threads within this AppDomain. This API is called by
2865 // threads transitioning between AppDomains.
2866 void UpdateProcessorUsage(ULONGLONG ullAdditionalUsage);
2867#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2868
2869private:
2870 size_t EstimateSize();
2871 EEClassFactoryInfoHashTable* SetupClassFactHash();
2872#ifdef FEATURE_COMINTEROP
2873 DispIDCache* SetupRefDispIDCache();
2874#endif // FEATURE_COMINTEROP
2875
2876protected:
2877 BOOL PostBindResolveAssembly(AssemblySpec *pPrePolicySpec,
2878 AssemblySpec *pPostPolicySpec,
2879 HRESULT hrBindResult,
2880 AssemblySpec **ppFailedSpec);
2881
2882#ifdef FEATURE_COMINTEROP
2883public:
2884 void ReleaseRCWs(LPVOID pCtxCookie);
2885 void DetachRCWs();
2886
2887protected:
2888#endif // FEATURE_COMINTEROP
2889
2890private:
2891 void RaiseLoadingAssemblyEvent(DomainAssembly* pAssembly);
2892
2893 friend class DomainAssembly;
2894
2895private:
2896 BOOL RaiseUnhandledExceptionEvent(OBJECTREF *pThrowable, BOOL isTerminating);
2897
2898 enum Stage {
2899 STAGE_CREATING,
2900 STAGE_READYFORMANAGEDCODE,
2901 STAGE_ACTIVE,
2902 STAGE_OPEN,
2903 // Don't delete the following *_DONOTUSE members and in case a new member needs to be added,
2904 // add it at the end. The reason is that debugger stuff has its own copy of this enum and
2905 // it can use the members that are marked as *_DONOTUSE here when debugging older version
2906 // of the runtime.
2907 STAGE_UNLOAD_REQUESTED_DONOTUSE,
2908 STAGE_EXITING_DONOTUSE,
2909 STAGE_EXITED_DONOTUSE,
2910 STAGE_FINALIZING_DONOTUSE,
2911 STAGE_FINALIZED_DONOTUSE,
2912 STAGE_HANDLETABLE_NOACCESS_DONOTUSE,
2913 STAGE_CLEARED_DONOTUSE,
2914 STAGE_COLLECTED_DONOTUSE,
2915 STAGE_CLOSED_DONOTUSE
2916 };
2917 void SetStage(Stage stage)
2918 {
2919 CONTRACTL
2920 {
2921 NOTHROW;
2922 GC_NOTRIGGER;
2923 SO_TOLERANT;
2924 MODE_ANY;
2925 }
2926 CONTRACTL_END;
2927 STRESS_LOG2(LF_APPDOMAIN, LL_INFO100,"Updating AD stage, ADID=%d, stage=%d\n",GetId().m_dwId,stage);
2928 TESTHOOKCALL(AppDomainStageChanged(GetId().m_dwId,m_Stage,stage));
2929 Stage lastStage=m_Stage;
2930 while (lastStage !=stage)
2931 lastStage = (Stage)FastInterlockCompareExchange((LONG*)&m_Stage,stage,lastStage);
2932 };
2933 void UnwindThreads();
2934 // Return TRUE if EE is stopped
2935 // Return FALSE if more work is needed
2936 BOOL StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread);
2937
2938 // List of unloaded LoaderAllocators, protected by code:GetLoaderAllocatorReferencesLock (for now)
2939 LoaderAllocator * m_pDelayedLoaderAllocatorUnloadList;
2940
2941public:
2942
2943 // Register the loader allocator for deletion in code:ShutdownFreeLoaderAllocators.
2944 void RegisterLoaderAllocatorForDeletion(LoaderAllocator * pLoaderAllocator);
2945
2946public:
2947 void SetGCRefPoint(int gccounter)
2948 {
2949 LIMITED_METHOD_CONTRACT;
2950 GetLoaderAllocator()->SetGCRefPoint(gccounter);
2951 }
2952 int GetGCRefPoint()
2953 {
2954 LIMITED_METHOD_CONTRACT;
2955 return GetLoaderAllocator()->GetGCRefPoint();
2956 }
2957
2958 static USHORT GetOffsetOfId()
2959 {
2960 LIMITED_METHOD_CONTRACT;
2961 size_t ofs = offsetof(class AppDomain, m_dwId);
2962 _ASSERTE(FitsInI2(ofs));
2963 return (USHORT)ofs;
2964 }
2965
2966
2967 void AddMemoryPressure();
2968 void RemoveMemoryPressure();
2969
2970 void UnlinkClass(MethodTable *pMT);
2971
2972 Assembly *GetRootAssembly()
2973 {
2974 LIMITED_METHOD_CONTRACT;
2975 return m_pRootAssembly;
2976 }
2977
2978#ifndef DACCESS_COMPILE
2979 void SetRootAssembly(Assembly *pAssembly)
2980 {
2981 LIMITED_METHOD_CONTRACT;
2982 m_pRootAssembly = pAssembly;
2983 }
2984#endif
2985
2986private:
2987 // The one and only AppDomain
2988 SPTR_DECL(AppDomain, m_pTheAppDomain);
2989
2990 SString m_friendlyName;
2991 PTR_Assembly m_pRootAssembly;
2992
2993 // General purpose flags.
2994 DWORD m_dwFlags;
2995
2996 // When an application domain is created the ref count is artifically incremented
2997 // by one. For it to hit zero an explicit close must have happened.
2998 LONG m_cRef; // Ref count.
2999
3000 // Hash table that maps a clsid to a type
3001 PtrHashMap m_clsidHash;
3002
3003#ifdef FEATURE_COMINTEROP
3004 // Hash table that maps WinRT class names to MethodTables.
3005 PTR_NameToTypeMapTable m_pNameToTypeMap;
3006 UINT m_vNameToTypeMapVersion;
3007
3008 UINT m_nEpoch; // incremented each time m_pNameToTypeMap is enumerated
3009
3010 // Hash table that remembers the last cached WinRT factory object per type per appdomain.
3011 WinRTFactoryCache *m_pWinRTFactoryCache;
3012
3013 // this cache stores the RCWs in this domain
3014 RCWCache *m_pRCWCache;
3015
3016 // this cache stores the RCW -> CCW references in this domain
3017 RCWRefCache *m_pRCWRefCache;
3018
3019 // The method table used for LicenseInteropHelper
3020 MethodTable* m_pLicenseInteropHelperMT;
3021#endif // FEATURE_COMINTEROP
3022
3023 // The index of this app domain among existing app domains (starting from 1)
3024 ADIndex m_dwIndex;
3025
3026 // The thread-pool index of this app domain among existing app domains (starting from 1)
3027 TPIndex m_tpIndex;
3028
3029#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3030 ULONGLONG* m_pullAllocBytes;
3031 ULONGLONG* m_pullSurvivedBytes;
3032 DWORD m_dwNumHeaps;
3033 ULONGLONG m_ullLastEtwAllocBytes;
3034 // Total processor time (user and kernel) utilized by threads running in this AppDomain so far. May not
3035 // account for threads currently executing in the AppDomain until a call to QueryProcessorUsage() is
3036 // made.
3037 Volatile<ULONGLONG> m_ullTotalProcessorUsage;
3038#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3039
3040#ifdef _DEBUG
3041 struct ThreadTrackInfo;
3042 typedef CDynArray<ThreadTrackInfo *> ThreadTrackInfoList;
3043 ThreadTrackInfoList *m_pThreadTrackInfoList;
3044 DWORD m_TrackSpinLock;
3045#endif
3046
3047 // The number of times we have entered this AD
3048 ULONG m_dwThreadEnterCount;
3049 // The number of threads that have entered this AD, for ADU only
3050 ULONG m_dwThreadsStillInAppDomain;
3051
3052 Volatile<Stage> m_Stage;
3053
3054 ArrayList m_failedAssemblies;
3055
3056#ifdef _DEBUG
3057 Volatile<LONG> m_dwIterHolders;
3058 Volatile<LONG> m_dwRefTakers;
3059 Volatile<LONG> m_dwCreationHolders;
3060#endif
3061
3062 //
3063 // DAC iterator for failed assembly loads
3064 //
3065 class FailedAssemblyIterator
3066 {
3067 ArrayList::Iterator m_i;
3068
3069 public:
3070 BOOL Next()
3071 {
3072 WRAPPER_NO_CONTRACT;
3073 return m_i.Next();
3074 }
3075 FailedAssembly *GetFailedAssembly()
3076 {
3077 WRAPPER_NO_CONTRACT;
3078 return dac_cast<PTR_FailedAssembly>(m_i.GetElement());
3079 }
3080 SIZE_T GetIndex()
3081 {
3082 WRAPPER_NO_CONTRACT;
3083 return m_i.GetIndex();
3084 }
3085
3086 private:
3087 friend class AppDomain;
3088 // Cannot have constructor so this iterator can be used inside a union
3089 static FailedAssemblyIterator Create(AppDomain *pDomain)
3090 {
3091 WRAPPER_NO_CONTRACT;
3092 FailedAssemblyIterator i;
3093
3094 i.m_i = pDomain->m_failedAssemblies.Iterate();
3095 return i;
3096 }
3097 };
3098 friend class FailedAssemblyIterator;
3099
3100 FailedAssemblyIterator IterateFailedAssembliesEx()
3101 {
3102 WRAPPER_NO_CONTRACT;
3103 return FailedAssemblyIterator::Create(this);
3104 }
3105
3106 //---------------------------------------------------------
3107 // Stub caches for Method stubs
3108 //---------------------------------------------------------
3109
3110public:
3111
3112 enum {
3113 CONTEXT_INITIALIZED = 0x0001,
3114 LOAD_SYSTEM_ASSEMBLY_EVENT_SENT = 0x0040,
3115 COMPILATION_DOMAIN = 0x0400, // Are we ngenning?
3116 IGNORE_UNHANDLED_EXCEPTIONS = 0x10000, // AppDomain was created using the APPDOMAIN_IGNORE_UNHANDLED_EXCEPTIONS flag
3117 };
3118
3119 AssemblySpecBindingCache m_AssemblyCache;
3120 DomainAssemblyCache m_UnmanagedCache;
3121 size_t m_MemoryPressure;
3122
3123 ArrayList m_NativeDllSearchDirectories;
3124 BOOL m_ReversePInvokeCanEnter;
3125 bool m_ForceTrivialWaitOperations;
3126
3127public:
3128
3129#ifdef FEATURE_TYPEEQUIVALENCE
3130private:
3131 VolatilePtr<TypeEquivalenceHashTable> m_pTypeEquivalenceTable;
3132 CrstExplicitInit m_TypeEquivalenceCrst;
3133public:
3134 TypeEquivalenceHashTable * GetTypeEquivalenceCache();
3135#endif
3136
3137 private:
3138
3139#ifdef DACCESS_COMPILE
3140public:
3141 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
3142 bool enumThis);
3143#endif
3144
3145#ifdef FEATURE_MULTICOREJIT
3146
3147private:
3148 MulticoreJitManager m_MulticoreJitManager;
3149
3150public:
3151 MulticoreJitManager & GetMulticoreJitManager()
3152 {
3153 LIMITED_METHOD_CONTRACT;
3154
3155 return m_MulticoreJitManager;
3156 }
3157
3158#endif
3159
3160#if defined(FEATURE_TIERED_COMPILATION)
3161
3162public:
3163 TieredCompilationManager * GetTieredCompilationManager()
3164 {
3165 LIMITED_METHOD_CONTRACT;
3166 return &m_tieredCompilationManager;
3167 }
3168
3169private:
3170 TieredCompilationManager m_tieredCompilationManager;
3171
3172#endif
3173
3174#ifdef FEATURE_COMINTEROP
3175
3176private:
3177
3178#endif //FEATURE_COMINTEROP
3179
3180public:
3181
3182 class ComInterfaceReleaseList
3183 {
3184 SArray<IUnknown *> m_objects;
3185 public:
3186 ~ComInterfaceReleaseList()
3187 {
3188 WRAPPER_NO_CONTRACT;
3189
3190 for (COUNT_T i = 0; i < m_objects.GetCount(); i++)
3191 {
3192 IUnknown *pItf = *(m_objects.GetElements() + i);
3193 if (pItf != nullptr)
3194 pItf->Release();
3195 }
3196 }
3197
3198 // Append to the list of object to free. Only use under the AppDomain "LockHolder(pAppDomain)"
3199 void Append(IUnknown *pInterfaceToRelease)
3200 {
3201 WRAPPER_NO_CONTRACT;
3202 m_objects.Append(pInterfaceToRelease);
3203 }
3204 } AppDomainInterfaceReleaseList;
3205
3206private:
3207 //-----------------------------------------------------------
3208 // Static ICLRPrivAssembly -> DomainAssembly mapping functions.
3209 // This map does not maintain a reference count to either key or value.
3210 // PEFile maintains a reference count on the ICLRPrivAssembly through its code:PEFile::m_pHostAssembly field.
3211 // It is removed from this hash table by code:DomainAssembly::~DomainAssembly.
3212 struct HostAssemblyHashTraits : public DefaultSHashTraits<PTR_DomainAssembly>
3213 {
3214 public:
3215 typedef PTR_ICLRPrivAssembly key_t;
3216
3217 static key_t GetKey(element_t const & elem)
3218 {
3219 STATIC_CONTRACT_WRAPPER;
3220 return elem->GetFile()->GetHostAssembly();
3221 }
3222
3223 static BOOL Equals(key_t key1, key_t key2)
3224 {
3225 LIMITED_METHOD_CONTRACT;
3226 return dac_cast<TADDR>(key1) == dac_cast<TADDR>(key2);
3227 }
3228
3229 static count_t Hash(key_t key)
3230 {
3231 STATIC_CONTRACT_LIMITED_METHOD;
3232 //return reinterpret_cast<count_t>(dac_cast<TADDR>(key));
3233 return (count_t)(dac_cast<TADDR>(key));
3234 }
3235
3236 static element_t Null() { return NULL; }
3237 static element_t Deleted() { return (element_t)(TADDR)-1; }
3238 static bool IsNull(const element_t & e) { return e == NULL; }
3239 static bool IsDeleted(const element_t & e) { return dac_cast<TADDR>(e) == (TADDR)-1; }
3240 };
3241
3242 struct OriginalFileHostAssemblyHashTraits : public HostAssemblyHashTraits
3243 {
3244 public:
3245 static key_t GetKey(element_t const & elem)
3246 {
3247 STATIC_CONTRACT_WRAPPER;
3248 return elem->GetOriginalFile()->GetHostAssembly();
3249 }
3250 };
3251
3252 typedef SHash<HostAssemblyHashTraits> HostAssemblyMap;
3253 typedef SHash<OriginalFileHostAssemblyHashTraits> OriginalFileHostAssemblyMap;
3254 HostAssemblyMap m_hostAssemblyMap;
3255 OriginalFileHostAssemblyMap m_hostAssemblyMapForOrigFile;
3256 CrstExplicitInit m_crstHostAssemblyMap;
3257 // Lock to serialize all Add operations (in addition to the "read-lock" above)
3258 CrstExplicitInit m_crstHostAssemblyMapAdd;
3259
3260public:
3261 // Returns DomainAssembly.
3262 PTR_DomainAssembly FindAssembly(PTR_ICLRPrivAssembly pHostAssembly);
3263
3264#ifndef DACCESS_COMPILE
3265private:
3266 friend void DomainAssembly::Allocate();
3267 friend DomainAssembly::~DomainAssembly();
3268
3269 // Called from DomainAssembly::Begin.
3270 void PublishHostedAssembly(
3271 DomainAssembly* pAssembly);
3272
3273 // Called from DomainAssembly::UpdatePEFile.
3274 void UpdatePublishHostedAssembly(
3275 DomainAssembly* pAssembly,
3276 PTR_PEFile pFile);
3277
3278 // Called from DomainAssembly::~DomainAssembly
3279 void UnPublishHostedAssembly(
3280 DomainAssembly* pAssembly);
3281#endif // DACCESS_COMPILE
3282
3283#ifdef FEATURE_PREJIT
3284 friend void DomainFile::InsertIntoDomainFileWithNativeImageList();
3285 Volatile<DomainFile *> m_pDomainFileWithNativeImageList;
3286public:
3287 DomainFile *GetDomainFilesWithNativeImagesList()
3288 {
3289 LIMITED_METHOD_CONTRACT;
3290 return m_pDomainFileWithNativeImageList;
3291 }
3292#endif
3293}; // class AppDomain
3294
3295
3296// This holder is to be used to take a reference to make sure AppDomain* is still valid
3297// Please do not use if you are aleady ADU-safe
3298typedef Wrapper<AppDomain*,AppDomain::RefTakerAcquire,AppDomain::RefTakerRelease,NULL> AppDomainRefTaker;
3299
3300// Just a ref holder
3301typedef ReleaseHolder<AppDomain> AppDomainRefHolder;
3302
3303typedef VPTR(class SystemDomain) PTR_SystemDomain;
3304
3305class SystemDomain : public BaseDomain
3306{
3307 friend class AppDomainNative;
3308 friend class AppDomainIterator;
3309 friend class UnsafeAppDomainIterator;
3310 friend class ClrDataAccess;
3311 friend Frame *Thread::IsRunningIn(AppDomain* pDomain, int *count);
3312
3313 VPTR_VTABLE_CLASS(SystemDomain, BaseDomain)
3314 VPTR_UNIQUE(VPTR_UNIQUE_SystemDomain)
3315 static AppDomain *GetAppDomainAtId(ADID indx);
3316
3317public:
3318 static PTR_LoaderAllocator GetGlobalLoaderAllocator();
3319 static AppDomain* GetAppDomainFromId(ADID indx,DWORD ADValidityKind)
3320 {
3321 CONTRACTL
3322 {
3323 NOTHROW;
3324 GC_NOTRIGGER;
3325 MODE_COOPERATIVE;
3326 }
3327 CONTRACTL_END;
3328 AppDomain* pRetVal;
3329 if (indx.m_dwId==DefaultADID)
3330 pRetVal= SystemDomain::System()->DefaultDomain();
3331 else
3332 pRetVal= GetAppDomainAtId(indx);
3333#ifdef _DEBUG
3334 // Only call CheckADValidity in DEBUG builds for non-NULL return values
3335 if (pRetVal != NULL)
3336 CheckADValidity(pRetVal, ADValidityKind);
3337#endif
3338 return pRetVal;
3339 }
3340 //****************************************************************************************
3341 //
3342 // To be run during the initial start up of the EE. This must be
3343 // performed prior to any class operations.
3344 static void Attach();
3345
3346 //****************************************************************************************
3347 //
3348 // To be run during shutdown. This must be done after all operations
3349 // that require the use of system classes (i.e., exceptions).
3350 // DetachBegin stops all domains, while DetachEnd deallocates domain resources.
3351 static void DetachBegin();
3352
3353 //****************************************************************************************
3354 //
3355 // To be run during shutdown. This must be done after all operations
3356 // that require the use of system classes (i.e., exceptions).
3357 // DetachBegin stops release resources held by systemdomain and the default domain.
3358 static void DetachEnd();
3359
3360 //****************************************************************************************
3361 //
3362 // Initializes and shutdowns the single instance of the SystemDomain
3363 // in the EE
3364#ifndef DACCESS_COMPILE
3365 void *operator new(size_t size, void *pInPlace);
3366 void operator delete(void *pMem);
3367#endif
3368 void Init();
3369 void Stop();
3370 void Terminate();
3371 static void LazyInitGlobalStringLiteralMap();
3372
3373 //****************************************************************************************
3374 //
3375 // Load the base system classes, these classes are required before
3376 // any other classes are loaded
3377 void LoadBaseSystemClasses();
3378
3379 AppDomain* DefaultDomain()
3380 {
3381 LIMITED_METHOD_DAC_CONTRACT;
3382
3383 return AppDomain::GetCurrentDomain();
3384 }
3385
3386 // Notification when an assembly is loaded into the system domain
3387 void OnAssemblyLoad(Assembly *assem);
3388
3389 //****************************************************************************************
3390 //
3391 // Global Static to get the one and only system domain
3392 static SystemDomain * System()
3393 {
3394 LIMITED_METHOD_DAC_CONTRACT;
3395
3396 return m_pSystemDomain;
3397 }
3398
3399 static PEAssembly* SystemFile()
3400 {
3401 WRAPPER_NO_CONTRACT;
3402
3403 _ASSERTE(m_pSystemDomain);
3404 return System()->m_pSystemFile;
3405 }
3406
3407 static Assembly* SystemAssembly()
3408 {
3409 WRAPPER_NO_CONTRACT;
3410
3411 return System()->m_pSystemAssembly;
3412 }
3413
3414 static Module* SystemModule()
3415 {
3416 WRAPPER_NO_CONTRACT;
3417
3418 return SystemAssembly()->GetManifestModule();
3419 }
3420
3421 static BOOL IsSystemLoaded()
3422 {
3423 WRAPPER_NO_CONTRACT;
3424
3425 return System()->m_pSystemAssembly != NULL;
3426 }
3427
3428#ifndef DACCESS_COMPILE
3429 static GlobalStringLiteralMap *GetGlobalStringLiteralMap()
3430 {
3431 WRAPPER_NO_CONTRACT;
3432
3433 if (m_pGlobalStringLiteralMap == NULL)
3434 {
3435 SystemDomain::LazyInitGlobalStringLiteralMap();
3436 }
3437 _ASSERTE(m_pGlobalStringLiteralMap);
3438 return m_pGlobalStringLiteralMap;
3439 }
3440 static GlobalStringLiteralMap *GetGlobalStringLiteralMapNoCreate()
3441 {
3442 LIMITED_METHOD_CONTRACT;
3443
3444 _ASSERTE(m_pGlobalStringLiteralMap);
3445 return m_pGlobalStringLiteralMap;
3446 }
3447#endif // DACCESS_COMPILE
3448
3449#if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3450 static Thread::ApartmentState GetEntryPointThreadAptState(IMDInternalImport* pScope, mdMethodDef mdMethod);
3451 static void SetThreadAptState(Thread::ApartmentState state);
3452#endif
3453
3454 //****************************************************************************************
3455 //
3456 // Use an already exising & inited Application Domain (e.g. a subclass).
3457 static void LoadDomain(AppDomain *pDomain);
3458
3459 //****************************************************************************************
3460 // Methods used to get the callers module and hence assembly and app domain.
3461 __declspec(deprecated("This method is deprecated, use the version that takes a StackCrawlMark instead"))
3462 static Module* GetCallersModule(int skip);
3463 static MethodDesc* GetCallersMethod(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
3464 static MethodTable* GetCallersType(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
3465 static Module* GetCallersModule(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
3466 static Assembly* GetCallersAssembly(StackCrawlMark* stackMark, AppDomain **ppAppDomain = NULL);
3467
3468 static bool IsReflectionInvocationMethod(MethodDesc* pMeth);
3469
3470#ifndef DACCESS_COMPILE
3471 //****************************************************************************************
3472 // Returns the domain associated with the current context. (this can only be a child domain)
3473 static inline AppDomain * GetCurrentDomain()
3474 {
3475 WRAPPER_NO_CONTRACT;
3476 return ::GetAppDomain();
3477 }
3478#endif //!DACCESS_COMPILE
3479
3480#ifdef DEBUGGING_SUPPORTED
3481 //****************************************************************************************
3482 // Debugger/Publisher helper function to indicate creation of new app domain to debugger
3483 // and publishing it in the IPC block
3484 static void PublishAppDomainAndInformDebugger (AppDomain *pDomain);
3485#endif // DEBUGGING_SUPPORTED
3486
3487 //****************************************************************************************
3488 // Helper function to remove a domain from the system
3489 BOOL RemoveDomain(AppDomain* pDomain); // Does not decrement the reference
3490
3491#ifdef PROFILING_SUPPORTED
3492 //****************************************************************************************
3493 // Tell profiler about system created domains which are created before the profiler is
3494 // actually activated.
3495 static void NotifyProfilerStartup();
3496
3497 //****************************************************************************************
3498 // Tell profiler at shutdown that system created domains are going away. They are not
3499 // torn down using the normal sequence.
3500 static HRESULT NotifyProfilerShutdown();
3501#endif // PROFILING_SUPPORTED
3502
3503 //****************************************************************************************
3504 // return the dev path
3505
3506#ifndef DACCESS_COMPILE
3507 void IncrementNumAppDomains ()
3508 {
3509 LIMITED_METHOD_CONTRACT;
3510
3511 s_dNumAppDomains++;
3512 }
3513
3514 void DecrementNumAppDomains ()
3515 {
3516 LIMITED_METHOD_CONTRACT;
3517
3518 s_dNumAppDomains--;
3519 }
3520
3521 ULONG GetNumAppDomains ()
3522 {
3523 LIMITED_METHOD_CONTRACT;
3524
3525 return s_dNumAppDomains;
3526 }
3527#endif // DACCESS_COMPILE
3528
3529 //
3530 // AppDomains currently have both an index and an ID. The
3531 // index is "densely" assigned; indices are reused as domains
3532 // are unloaded. The Id's on the other hand, are not reclaimed
3533 // so may be sparse.
3534 //
3535 // Another important difference - it's OK to call GetAppDomainAtId for
3536 // an unloaded domain (it will return NULL), while GetAppDomainAtIndex
3537 // will assert if the domain is unloaded.
3538 //<TODO>
3539 // @todo:
3540 // I'm not really happy with this situation, but
3541 // (a) we need an ID for a domain which will last the process lifetime for the
3542 // remoting code.
3543 // (b) we need a dense ID, for the handle table index.
3544 // So for now, I'm leaving both, but hopefully in the future we can come up
3545 // with something better.
3546 //</TODO>
3547
3548 static ADIndex GetNewAppDomainIndex(AppDomain * pAppDomain);
3549 static void ReleaseAppDomainIndex(ADIndex indx);
3550 static PTR_AppDomain GetAppDomainAtIndex(ADIndex indx);
3551 static PTR_AppDomain TestGetAppDomainAtIndex(ADIndex indx);
3552 static DWORD GetCurrentAppDomainMaxIndex()
3553 {
3554 WRAPPER_NO_CONTRACT;
3555
3556 ArrayListStatic* list = (ArrayListStatic *)&m_appDomainIndexList;
3557 PREFIX_ASSUME(list!=NULL);
3558 return list->GetCount();
3559 }
3560
3561 static ADID GetNewAppDomainId(AppDomain *pAppDomain);
3562 static void ReleaseAppDomainId(ADID indx);
3563
3564#ifndef DACCESS_COMPILE
3565 static ADID GetCurrentAppDomainMaxId() { ADID id; id.m_dwId=m_appDomainIdList.GetCount(); return id;}
3566#endif // DACCESS_COMPILE
3567
3568
3569#ifndef DACCESS_COMPILE
3570 DWORD RequireAppDomainCleanup()
3571 {
3572 LIMITED_METHOD_CONTRACT;
3573 return m_pDelayedUnloadListOfLoaderAllocators != 0;
3574 }
3575
3576 void AddToDelayedUnloadList(LoaderAllocator * pAllocator)
3577 {
3578 CONTRACTL
3579 {
3580 NOTHROW;
3581 GC_NOTRIGGER;
3582 MODE_COOPERATIVE;
3583 }
3584 CONTRACTL_END;
3585
3586 CrstHolder lh(&m_DelayedUnloadCrst);
3587 pAllocator->m_pLoaderAllocatorDestroyNext=m_pDelayedUnloadListOfLoaderAllocators;
3588 m_pDelayedUnloadListOfLoaderAllocators=pAllocator;
3589
3590 int iGCRefPoint=GCHeapUtilities::GetGCHeap()->CollectionCount(GCHeapUtilities::GetGCHeap()->GetMaxGeneration());
3591 if (GCHeapUtilities::IsGCInProgress())
3592 iGCRefPoint++;
3593 pAllocator->SetGCRefPoint(iGCRefPoint);
3594 }
3595
3596 void ProcessDelayedUnloadLoaderAllocators();
3597
3598 static void EnumAllStaticGCRefs(promote_func* fn, ScanContext* sc);
3599
3600#endif // DACCESS_COMPILE
3601
3602#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3603 // The *AD* methods are what we got from tracing through EE roots.
3604 // RecordTotalSurvivedBytes is the total promoted from a GC.
3605 static void ResetADSurvivedBytes();
3606 static ULONGLONG GetADSurvivedBytes();
3607 static void RecordTotalSurvivedBytes(size_t totalSurvivedBytes);
3608 static ULONGLONG GetTotalSurvivedBytes()
3609 {
3610 LIMITED_METHOD_CONTRACT;
3611 return m_totalSurvivedBytes;
3612 }
3613#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3614
3615 //****************************************************************************************
3616 // Routines to deal with the base library (currently mscorlib.dll)
3617 LPCWSTR BaseLibrary()
3618 {
3619 WRAPPER_NO_CONTRACT;
3620
3621 return m_BaseLibrary;
3622 }
3623
3624#ifndef DACCESS_COMPILE
3625 BOOL IsBaseLibrary(SString &path)
3626 {
3627 WRAPPER_NO_CONTRACT;
3628
3629 // See if it is the installation path to mscorlib
3630 if (path.EqualsCaseInsensitive(m_BaseLibrary, PEImage::GetFileSystemLocale()))
3631 return TRUE;
3632
3633 // Or, it might be the GAC location of mscorlib
3634 if (System()->SystemAssembly() != NULL
3635 && path.EqualsCaseInsensitive(System()->SystemAssembly()->GetManifestFile()->GetPath(),
3636 PEImage::GetFileSystemLocale()))
3637 return TRUE;
3638
3639 return FALSE;
3640 }
3641
3642 BOOL IsBaseLibrarySatellite(SString &path)
3643 {
3644 WRAPPER_NO_CONTRACT;
3645
3646 // See if it is the installation path to mscorlib.resources
3647 SString s(SString::Ascii,g_psBaseLibrarySatelliteAssemblyName);
3648 if (path.EqualsCaseInsensitive(s, PEImage::GetFileSystemLocale()))
3649 return TRUE;
3650
3651 // workaround! Must implement some code to do this string comparison for
3652 // mscorlib.resources in a culture-specific directory in the GAC.
3653
3654 /*
3655 // Or, it might be the GAC location of mscorlib.resources
3656 if (System()->SystemAssembly() != NULL
3657 && path.EqualsCaseInsensitive(System()->SystemAssembly()->GetManifestFile()->GetPath(),
3658 PEImage::GetFileSystemLocale()))
3659 return TRUE;
3660 */
3661
3662 return FALSE;
3663 }
3664#endif // DACCESS_COMPILE
3665
3666 // Return the system directory
3667 LPCWSTR SystemDirectory()
3668 {
3669 WRAPPER_NO_CONTRACT;
3670
3671 return m_SystemDirectory;
3672 }
3673
3674private:
3675
3676 //****************************************************************************************
3677 // Helper function to create the single COM domain
3678 void CreateDefaultDomain();
3679
3680 //****************************************************************************************
3681 // Helper function to add a domain to the global list
3682 void AddDomain(AppDomain* pDomain);
3683
3684 void CreatePreallocatedExceptions();
3685
3686 void PreallocateSpecialObjects();
3687
3688 //****************************************************************************************
3689 //
3690 static StackWalkAction CallersMethodCallback(CrawlFrame* pCrawlFrame, VOID* pClientData);
3691 static StackWalkAction CallersMethodCallbackWithStackMark(CrawlFrame* pCrawlFrame, VOID* pClientData);
3692
3693#ifndef DACCESS_COMPILE
3694 // This class is not to be created through normal allocation.
3695 SystemDomain()
3696 {
3697 STANDARD_VM_CONTRACT;
3698
3699 m_pDelayedUnloadListOfLoaderAllocators=NULL;
3700
3701 m_GlobalAllocator.Init(this);
3702 }
3703#endif
3704
3705 PTR_PEAssembly m_pSystemFile; // Single assembly (here for quicker reference);
3706 PTR_Assembly m_pSystemAssembly; // Single assembly (here for quicker reference);
3707
3708 GlobalLoaderAllocator m_GlobalAllocator;
3709
3710
3711 InlineSString<100> m_BaseLibrary;
3712
3713 InlineSString<100> m_SystemDirectory;
3714
3715 // <TODO>@TODO: CTS, we can keep the com modules in a single assembly or in different assemblies.
3716 // We are currently using different assemblies but this is potentitially to slow...</TODO>
3717
3718 // Global domain that every one uses
3719 SPTR_DECL(SystemDomain, m_pSystemDomain);
3720
3721 LoaderAllocator * m_pDelayedUnloadListOfLoaderAllocators;
3722
3723#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3724 // This is what gets promoted for the whole GC heap.
3725 static size_t m_totalSurvivedBytes;
3726#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3727
3728 SVAL_DECL(ArrayListStatic, m_appDomainIndexList);
3729#ifndef DACCESS_COMPILE
3730 static CrstStatic m_DelayedUnloadCrst;
3731 static CrstStatic m_SystemDomainCrst;
3732
3733
3734 static ArrayListStatic m_appDomainIdList;
3735
3736 static GlobalStringLiteralMap *m_pGlobalStringLiteralMap;
3737
3738 static ULONG s_dNumAppDomains; // Maintain a count of children app domains.
3739
3740 static DWORD m_dwLowestFreeIndex;
3741#endif // DACCESS_COMPILE
3742
3743protected:
3744
3745 // These flags let the correct native image of mscorlib to be loaded.
3746 // This is important for hardbinding to it
3747
3748 SVAL_DECL(BOOL, s_fForceDebug);
3749 SVAL_DECL(BOOL, s_fForceProfiling);
3750 SVAL_DECL(BOOL, s_fForceInstrument);
3751
3752public:
3753 static void SetCompilationOverrides(BOOL fForceDebug,
3754 BOOL fForceProfiling,
3755 BOOL fForceInstrument);
3756
3757 static void GetCompilationOverrides(BOOL * fForceDebug,
3758 BOOL * fForceProfiling,
3759 BOOL * fForceInstrument);
3760public:
3761 //****************************************************************************************
3762 //
3763
3764#ifndef DACCESS_COMPILE
3765#ifdef _DEBUG
3766inline static BOOL IsUnderDomainLock() { LIMITED_METHOD_CONTRACT; return m_SystemDomainCrst.OwnedByCurrentThread();};
3767#endif
3768
3769 // This lock controls adding and removing domains from the system domain
3770 class LockHolder : public CrstHolder
3771 {
3772 public:
3773 LockHolder()
3774 : CrstHolder(&m_SystemDomainCrst)
3775 {
3776 WRAPPER_NO_CONTRACT;
3777 }
3778 };
3779#endif // DACCESS_COMPILE
3780
3781public:
3782 DWORD GetTotalNumSizedRefHandles();
3783
3784#ifdef DACCESS_COMPILE
3785public:
3786 virtual void EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
3787 bool enumThis);
3788#endif
3789
3790}; // class SystemDomain
3791
3792
3793//
3794// an UnsafeAppDomainIterator is used to iterate over all existing domains
3795//
3796// The iteration is guaranteed to include all domains that exist at the
3797// start & end of the iteration. This iterator is considered unsafe because it does not
3798// reference count the various appdomains, and can only be used when the runtime is stopped,
3799// or external synchronization is used. (and therefore no other thread may cause the appdomain list to change.)
3800//
3801class UnsafeAppDomainIterator
3802{
3803 friend class SystemDomain;
3804public:
3805 UnsafeAppDomainIterator(BOOL bOnlyActive)
3806 {
3807 m_bOnlyActive = bOnlyActive;
3808 }
3809
3810 void Init()
3811 {
3812 LIMITED_METHOD_CONTRACT;
3813 SystemDomain* sysDomain = SystemDomain::System();
3814 if (sysDomain)
3815 {
3816 ArrayListStatic* list = &sysDomain->m_appDomainIndexList;
3817 PREFIX_ASSUME(list != NULL);
3818 m_i = list->Iterate();
3819 }
3820 else
3821 {
3822 m_i.SetEmpty();
3823 }
3824
3825 m_pCurrent = NULL;
3826 }
3827
3828 BOOL Next()
3829 {
3830 WRAPPER_NO_CONTRACT;
3831
3832 while (m_i.Next())
3833 {
3834 m_pCurrent = dac_cast<PTR_AppDomain>(m_i.GetElement());
3835 if (m_pCurrent != NULL &&
3836 (m_bOnlyActive ?
3837 m_pCurrent->IsActive() : m_pCurrent->IsValid()))
3838 {
3839 return TRUE;
3840 }
3841 }
3842
3843 m_pCurrent = NULL;
3844 return FALSE;
3845 }
3846
3847 AppDomain * GetDomain()
3848 {
3849 LIMITED_METHOD_DAC_CONTRACT;
3850
3851 return m_pCurrent;
3852 }
3853
3854 private:
3855
3856 ArrayList::Iterator m_i;
3857 AppDomain * m_pCurrent;
3858 BOOL m_bOnlyActive;
3859}; // class UnsafeAppDomainIterator
3860
3861//
3862// an AppDomainIterator is used to iterate over all existing domains.
3863//
3864// The iteration is guaranteed to include all domains that exist at the
3865// start & end of the iteration. Any domains added or deleted during
3866// iteration may or may not be included. The iterator also guarantees
3867// that the current iterated appdomain (GetDomain()) will not be deleted.
3868//
3869
3870class AppDomainIterator : public UnsafeAppDomainIterator
3871{
3872 friend class SystemDomain;
3873
3874 public:
3875 AppDomainIterator(BOOL bOnlyActive) : UnsafeAppDomainIterator(bOnlyActive)
3876 {
3877 WRAPPER_NO_CONTRACT;
3878 Init();
3879 }
3880
3881 ~AppDomainIterator()
3882 {
3883 WRAPPER_NO_CONTRACT;
3884
3885#ifndef DACCESS_COMPILE
3886 if (GetDomain() != NULL)
3887 {
3888#ifdef _DEBUG
3889 GetDomain()->IteratorRelease();
3890#endif
3891 GetDomain()->Release();
3892 }
3893#endif
3894 }
3895
3896 BOOL Next()
3897 {
3898 WRAPPER_NO_CONTRACT;
3899
3900#ifndef DACCESS_COMPILE
3901 if (GetDomain() != NULL)
3902 {
3903#ifdef _DEBUG
3904 GetDomain()->IteratorRelease();
3905#endif
3906 GetDomain()->Release();
3907 }
3908
3909 SystemDomain::LockHolder lh;
3910#endif
3911
3912 if (UnsafeAppDomainIterator::Next())
3913 {
3914#ifndef DACCESS_COMPILE
3915 GetDomain()->AddRef();
3916#ifdef _DEBUG
3917 GetDomain()->IteratorAcquire();
3918#endif
3919#endif
3920 return TRUE;
3921 }
3922
3923 return FALSE;
3924 }
3925}; // class AppDomainIterator
3926
3927#include "comreflectioncache.inl"
3928
3929#define INVALID_APPDOMAIN_ID ((DWORD)-1)
3930#define CURRENT_APPDOMAIN_ID ((ADID)(DWORD)0)
3931
3932#endif
3933