Merge pull request #16709 from sdmaclea/PR-ARM64-Bootstrapping
[platform/upstream/coreclr.git] / src / vm / appdomain.cpp
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 #include "common.h"
7
8 #include "appdomain.hpp"
9 #include "peimagelayout.inl"
10 #include "field.h"
11 #include "strongnameinternal.h"
12 #include "excep.h"
13 #include "eeconfig.h"
14 #include "gcheaputilities.h"
15 #include "eventtrace.h"
16 #include "perfcounters.h"
17 #include "assemblyname.hpp"
18 #include "eeprofinterfaces.h"
19 #include "dbginterface.h"
20 #ifndef DACCESS_COMPILE
21 #include "eedbginterfaceimpl.h"
22 #endif
23 #include "comdynamic.h"
24 #include "mlinfo.h"
25 #include "posterror.h"
26 #include "assemblynative.hpp"
27 #include "shimload.h"
28 #include "stringliteralmap.h"
29 #include "codeman.h"
30 #include "comcallablewrapper.h"
31 #include "apithreadstress.h"
32 #include "eventtrace.h"
33 #include "comdelegate.h"
34 #include "siginfo.hpp"
35 #include "typekey.h"
36
37 #include "caparser.h"
38 #include "ecall.h"
39 #include "finalizerthread.h"
40 #include "threadsuspend.h"
41
42 #ifdef FEATURE_PREJIT
43 #include "corcompile.h"
44 #include "compile.h"
45 #endif // FEATURE_PREJIT
46
47 #ifdef FEATURE_COMINTEROP
48 #include "comtoclrcall.h"
49 #include "runtimecallablewrapper.h"
50 #include "mngstdinterfaces.h"
51 #include "olevariant.h"
52 #include "rcwrefcache.h"
53 #include "olecontexthelpers.h"
54 #endif // FEATURE_COMINTEROP
55 #ifdef FEATURE_TYPEEQUIVALENCE
56 #include "typeequivalencehash.hpp"
57 #endif
58
59 #include "appdomain.inl"
60 #include "typeparse.h"
61 #include "mdaassistants.h"
62 #include "threadpoolrequest.h"
63
64 #include "nativeoverlapped.h"
65
66 #ifndef FEATURE_PAL
67 #include "dwreport.h"
68 #endif // !FEATURE_PAL
69
70 #include "stringarraylist.h"
71
72 #include "../binder/inc/clrprivbindercoreclr.h"
73
74
75 #include "clrprivtypecachewinrt.h"
76
77
78 #pragma warning(push)
79 #pragma warning(disable:4324) 
80 #include "marvin32.h"
81 #pragma warning(pop)
82
83 // this file handles string conversion errors for itself
84 #undef  MAKE_TRANSLATIONFAILED
85
86 // Define these macro's to do strict validation for jit lock and class
87 // init entry leaks.  This defines determine if the asserts that
88 // verify for these leaks are defined or not.  These asserts can
89 // sometimes go off even if no entries have been leaked so this
90 // defines should be used with caution.
91 //
92 // If we are inside a .cctor when the application shut's down then the
93 // class init lock's head will be set and this will cause the assert
94 // to go off.
95 //
96 // If we are jitting a method when the application shut's down then
97 // the jit lock's head will be set causing the assert to go off.
98
99 //#define STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
100
101 static const WCHAR DEFAULT_DOMAIN_FRIENDLY_NAME[] = W("DefaultDomain");
102 static const WCHAR OTHER_DOMAIN_FRIENDLY_NAME_PREFIX[] = W("Domain");
103
104 #define STATIC_OBJECT_TABLE_BUCKET_SIZE 1020
105
106 #define MAX_URL_LENGTH                  2084 // same as INTERNET_MAX_URL_LENGTH
107
108 //#define _DEBUG_ADUNLOAD 1
109
110 HRESULT RunDllMain(MethodDesc *pMD, HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved); // clsload.cpp
111
112
113
114
115
116 // Statics
117
118 SPTR_IMPL(SystemDomain, SystemDomain, m_pSystemDomain);
119 SVAL_IMPL(ArrayListStatic, SystemDomain, m_appDomainIndexList);
120 SPTR_IMPL(SharedDomain, SharedDomain, m_pSharedDomain);
121 SVAL_IMPL(BOOL, SystemDomain, s_fForceDebug);
122 SVAL_IMPL(BOOL, SystemDomain, s_fForceProfiling);
123 SVAL_IMPL(BOOL, SystemDomain, s_fForceInstrument);
124
125 #ifndef DACCESS_COMPILE
126
127 // Base Domain Statics
128 CrstStatic          BaseDomain::m_SpecialStaticsCrst;
129
130 int                 BaseDomain::m_iNumberOfProcessors = 0;
131
132 // Shared Domain Statics
133 DECLSPEC_ALIGN(16) 
134 static BYTE         g_pSharedDomainMemory[sizeof(SharedDomain)];
135
136 // System Domain Statics
137 GlobalStringLiteralMap* SystemDomain::m_pGlobalStringLiteralMap = NULL;
138
139 DECLSPEC_ALIGN(16) 
140 static BYTE         g_pSystemDomainMemory[sizeof(SystemDomain)];
141
142 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
143 size_t              SystemDomain::m_totalSurvivedBytes = 0;
144 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
145
146 CrstStatic          SystemDomain::m_SystemDomainCrst;
147 CrstStatic          SystemDomain::m_DelayedUnloadCrst;
148
149 ULONG               SystemDomain::s_dNumAppDomains = 0;
150
151 AppDomain *         SystemDomain::m_pAppDomainBeingUnloaded = NULL;
152 ADIndex             SystemDomain::m_dwIndexOfAppDomainBeingUnloaded;
153 Thread            *SystemDomain::m_pAppDomainUnloadRequestingThread = 0;
154 Thread            *SystemDomain::m_pAppDomainUnloadingThread = 0;
155
156 ArrayListStatic     SystemDomain::m_appDomainIdList;
157
158 DWORD               SystemDomain::m_dwLowestFreeIndex        = 0;
159
160
161
162 // comparison function to be used for matching clsids in our clsid hash table
163 BOOL CompareCLSID(UPTR u1, UPTR u2)
164 {
165     CONTRACTL
166     {
167         THROWS;
168         GC_TRIGGERS;
169         MODE_ANY;
170         SO_INTOLERANT;
171         INJECT_FAULT(COMPlusThrowOM(););
172     }
173     CONTRACTL_END;
174
175     GUID *pguid = (GUID *)(u1 << 1);
176     _ASSERTE(pguid != NULL);
177
178     MethodTable *pMT= (MethodTable *)u2;
179     _ASSERTE(pMT!= NULL);
180
181     GUID guid;
182     pMT->GetGuid(&guid, TRUE);
183     if (!IsEqualIID(guid, *pguid))
184         return FALSE;
185
186     return TRUE;
187 }
188
189 #ifndef CROSSGEN_COMPILE
190 // Constructor for the LargeHeapHandleBucket class.
191 LargeHeapHandleBucket::LargeHeapHandleBucket(LargeHeapHandleBucket *pNext, DWORD Size, BaseDomain *pDomain, BOOL bCrossAD)
192 : m_pNext(pNext)
193 , m_ArraySize(Size)
194 , m_CurrentPos(0)
195 , m_CurrentEmbeddedFreePos(0) // hint for where to start a search for an embedded free item
196 {
197     CONTRACTL
198     {
199         THROWS;
200         GC_TRIGGERS;
201         MODE_COOPERATIVE;
202         PRECONDITION(CheckPointer(pDomain));
203         INJECT_FAULT(COMPlusThrowOM(););
204     }
205     CONTRACTL_END;
206
207     PTRARRAYREF HandleArrayObj;
208
209     // Allocate the array in the large object heap.
210     if (!bCrossAD) 
211     {
212         OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
213         HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, TRUE);
214     }
215     else 
216     {
217         // During AD creation we don't want to assign the handle array to the currently running AD but
218         // to the AD being created.  Ensure that AllocateArrayEx doesn't set the AD and then set it here.
219         AppDomain *pAD = pDomain->AsAppDomain();
220         _ASSERTE(pAD);
221         _ASSERTE(pAD->IsBeingCreated());
222
223         OBJECTREF array;
224         {
225             OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
226             array = AllocateArrayEx(
227                 ClassLoader::LoadArrayTypeThrowing(g_pObjectClass),
228                 (INT32 *)(&Size),
229                 1,
230                 TRUE
231                 DEBUG_ARG(TRUE));
232         }
233
234         array->SetAppDomain(pAD);
235
236         HandleArrayObj = (PTRARRAYREF)array;
237     }
238
239     // Retrieve the pointer to the data inside the array. This is legal since the array
240     // is located in the large object heap and is guaranteed not to move.
241     m_pArrayDataPtr = (OBJECTREF *)HandleArrayObj->GetDataPtr();
242
243     // Store the array in a strong handle to keep it alive.
244     m_hndHandleArray = pDomain->CreatePinningHandle((OBJECTREF)HandleArrayObj);
245 }
246
247
248 // Destructor for the LargeHeapHandleBucket class.
249 LargeHeapHandleBucket::~LargeHeapHandleBucket()
250 {
251     CONTRACTL
252     {
253         NOTHROW;
254         GC_NOTRIGGER;
255     }
256     CONTRACTL_END;
257
258     if (m_hndHandleArray)
259     {
260         DestroyPinningHandle(m_hndHandleArray);
261         m_hndHandleArray = NULL;
262     }
263 }
264
265
266 // Allocate handles from the bucket.
267 OBJECTREF *LargeHeapHandleBucket::AllocateHandles(DWORD nRequested)
268 {
269     CONTRACTL
270     {
271         NOTHROW;
272         GC_NOTRIGGER;
273         MODE_COOPERATIVE;
274     }
275     CONTRACTL_END;
276
277     _ASSERTE(nRequested > 0 && nRequested <= GetNumRemainingHandles());
278     _ASSERTE(m_pArrayDataPtr == (OBJECTREF*)((PTRARRAYREF)ObjectFromHandle(m_hndHandleArray))->GetDataPtr());
279
280     // Store the handles in the buffer that was passed in
281     OBJECTREF* ret = &m_pArrayDataPtr[m_CurrentPos];
282     m_CurrentPos += nRequested;
283
284     return ret;
285 }
286
287 // look for a free item embedded in the table
288 OBJECTREF *LargeHeapHandleBucket::TryAllocateEmbeddedFreeHandle()
289 {
290     CONTRACTL
291     {
292         NOTHROW;
293         GC_NOTRIGGER;
294         MODE_COOPERATIVE;
295     }
296     CONTRACTL_END;
297
298     OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
299     _ASSERTE(pPreallocatedSentinalObject  != NULL);
300
301     for (int  i = m_CurrentEmbeddedFreePos; i < m_CurrentPos; i++)
302     {
303         if (m_pArrayDataPtr[i] == pPreallocatedSentinalObject)
304         {
305             m_CurrentEmbeddedFreePos = i;
306             m_pArrayDataPtr[i] = NULL;
307             return &m_pArrayDataPtr[i];
308         }
309     }
310
311     // didn't find it (we don't bother wrapping around for a full search, it's not worth it to try that hard, we'll get it next time)
312
313     m_CurrentEmbeddedFreePos = 0;
314     return NULL;
315 }
316
317
318 // Maximum bucket size will be 64K on 32-bit and 128K on 64-bit. 
319 // We subtract out a small amount to leave room for the object
320 // header and length of the array.
321
322 #define MAX_BUCKETSIZE (16384 - 4)
323
324 // Constructor for the LargeHeapHandleTable class.
325 LargeHeapHandleTable::LargeHeapHandleTable(BaseDomain *pDomain, DWORD InitialBucketSize)
326 : m_pHead(NULL)
327 , m_pDomain(pDomain)
328 , m_NextBucketSize(InitialBucketSize)
329 , m_pFreeSearchHint(NULL)
330 , m_cEmbeddedFree(0)
331 {
332     CONTRACTL
333     {
334         THROWS;
335         GC_TRIGGERS;
336         MODE_COOPERATIVE;
337         PRECONDITION(CheckPointer(pDomain));
338         INJECT_FAULT(COMPlusThrowOM(););
339     }
340     CONTRACTL_END;
341
342 #ifdef _DEBUG
343     m_pCrstDebug = NULL;
344 #endif
345 }
346
347
348 // Destructor for the LargeHeapHandleTable class.
349 LargeHeapHandleTable::~LargeHeapHandleTable()
350 {
351     CONTRACTL
352     {
353         NOTHROW;
354         GC_NOTRIGGER;
355     }
356     CONTRACTL_END;
357
358     // Delete the buckets.
359     while (m_pHead)
360     {
361         LargeHeapHandleBucket *pOld = m_pHead;
362         m_pHead = pOld->GetNext();
363         delete pOld;
364     }
365 }
366
367 //*****************************************************************************
368 //
369 // LOCKING RULES FOR AllocateHandles() and ReleaseHandles()  12/08/2004
370 //
371 //
372 // These functions are not protected by any locking in this location but rather the callers are
373 // assumed to be doing suitable locking  for the handle table.  The handle table itself is
374 // behaving rather like a thread-agnostic collection class -- it doesn't want to know
375 // much about the outside world and so it is just doing its job with no awareness of
376 // thread notions.
377 //
378 // The instance in question is
379 // There are two locations you can find a LargeHeapHandleTable
380 // 1) there is one in every BaseDomain, it is used to keep track of the static members
381 //     in that domain
382 // 2) there is one in the System Domain that is used for the GlobalStringLiteralMap
383 //
384 // the one in (2) is not the same as the one that is in the BaseDomain object that corresponds
385 // to the SystemDomain -- that one is basically stilborn because the string literals don't go
386 // there and of course the System Domain has no code loaded into it -- only regular
387 // AppDomains (like Domain 0) actually execute code.  As a result handle tables are in
388 // practice used either for string literals or for static members but never for both.
389 // At least not at this writing.
390 //
391 // Now it's useful to consider what the locking discipline is for these classes.
392 //
393 // ---------
394 //
395 // First case: (easiest) is the statics members
396 //
397 // Each BaseDomain has its own critical section
398 //
399 // BaseDomain::AllocateObjRefPtrsInLargeTable takes a lock with
400 //        CrstHolder ch(&m_LargeHeapHandleTableCrst);
401 //
402 // it does this before it calls AllocateHandles which suffices.  It does not call ReleaseHandles
403 // at any time (although ReleaseHandles may be called via AllocateHandles if the request
404 // doesn't fit in the current block, the remaining handles at the end of the block are released
405 // automatically as part of allocation/recycling)
406 //
407 // note: Recycled handles are only used during String Literal allocation because we only try
408 // to recycle handles if the allocation request is for exactly one handle.
409 //
410 // The handles in the BaseDomain handle table are released when the Domain is unloaded
411 // as the GC objects become rootless at that time.
412 //
413 // This dispenses with all of the Handle tables except the one that is used for string literals
414 //
415 // ---------
416 //
417 // Second case:  Allocation for use in a string literal
418 //
419 // AppDomainStringLiteralMap::GetStringLiteral
420 // leads to calls to
421 //     LargeHeapHandleBlockHolder constructor
422 //     leads to calls to
423 //          m_Data = pOwner->AllocateHandles(nCount);
424 //
425 // before doing this  AppDomainStringLiteralMap::GetStringLiteral takes this lock
426 //
427 //    CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
428 //
429 // which is the lock for the hash table that it owns
430 //
431 // STRINGREF *AppDomainStringLiteralMap::GetInternedString
432 //
433 // has a similar call path and uses the same approach and  the same lock
434 // this covers all the paths which allocate
435 //
436 // ---------
437 //
438 // Third case:  Releases for use in a string literal entry
439 //
440 // CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
441 // taken in the AppDomainStringLiteralMap functions below protects the 4 ways that this can happen
442 //
443 // case 3a)
444 //
445 // in an appdomain unload case
446 //
447 // AppDomainStringLiteralMap::~AppDomainStringLiteralMap() takes the lock then
448 // leads to calls to
449 //     StringLiteralEntry::Release
450 //    which leads to
451 //        SystemDomain::GetGlobalStringLiteralMapNoCreate()->RemoveStringLiteralEntry(this)
452 //        which leads to
453 //            m_LargeHeapHandleTable.ReleaseHandles((OBJECTREF*)pObjRef, 1);
454 //
455 // case 3b)
456 //
457 // AppDomainStringLiteralMap::GetStringLiteral() can call StringLiteralEntry::Release in some
458 // error cases, leading to the same stack as above
459 //
460 // case 3c)
461 //
462 // AppDomainStringLiteralMap::GetInternedString() can call StringLiteralEntry::Release in some
463 // error cases, leading to the same stack as above
464 //
465 // case 3d)
466 //
467 // The same code paths in 3b and 3c and also end up releasing if an exception is thrown
468 // during their processing.  Both these paths use a StringLiteralEntryHolder to assist in cleanup,
469 // the StaticRelease method of the StringLiteralEntry gets called, which in turn calls the
470 // Release method.
471
472
473 // Allocate handles from the large heap handle table.
474 OBJECTREF* LargeHeapHandleTable::AllocateHandles(DWORD nRequested, BOOL bCrossAD)
475 {
476     CONTRACTL
477     {
478         THROWS;
479         GC_TRIGGERS;
480         MODE_COOPERATIVE;
481         PRECONDITION(nRequested > 0);
482         INJECT_FAULT(COMPlusThrowOM(););
483     }
484     CONTRACTL_END;
485
486     // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
487
488     // the lock must be registered and already held by the caller per contract
489 #ifdef _DEBUG
490     _ASSERTE(m_pCrstDebug != NULL);
491     _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
492 #endif
493
494     if (nRequested == 1 && m_cEmbeddedFree != 0)
495     {
496         // special casing singleton requests to look for slots that can be re-used
497
498         // we need to do this because string literals are allocated one at a time and then sometimes
499         // released.  we do not wish for the number of handles consumed by string literals to
500         // increase forever as assemblies are loaded and unloaded
501
502         if (m_pFreeSearchHint == NULL)
503             m_pFreeSearchHint = m_pHead;
504
505         while (m_pFreeSearchHint)
506         {
507             OBJECTREF* pObjRef = m_pFreeSearchHint->TryAllocateEmbeddedFreeHandle();
508             if (pObjRef != NULL)
509             {
510                 // the slot is to have been prepared with a null ready to go
511                 _ASSERTE(*pObjRef == NULL);
512                 m_cEmbeddedFree--;
513                 return pObjRef;
514             }
515             m_pFreeSearchHint = m_pFreeSearchHint->GetNext();
516         }
517
518         // the search doesn't wrap around so it's possible that we might have embedded free items
519         // and not find them but that's ok, we'll get them on the next alloc... all we're trying to do
520         // is to not have big leaks over time.
521     }
522
523
524     // Retrieve the remaining number of handles in the bucket.
525     DWORD NumRemainingHandlesInBucket = (m_pHead != NULL) ? m_pHead->GetNumRemainingHandles() : 0;
526
527     // create a new block if this request doesn't fit in the current block
528     if (nRequested > NumRemainingHandlesInBucket)
529     {
530         if (m_pHead != NULL)
531         {
532             // mark the handles in that remaining region as available for re-use
533             ReleaseHandles(m_pHead->CurrentPos(), NumRemainingHandlesInBucket);
534
535             // mark what's left as having been used
536             m_pHead->ConsumeRemaining();
537         }
538
539         // create a new bucket for this allocation
540
541         // We need a block big enough to hold the requested handles
542         DWORD NewBucketSize = max(m_NextBucketSize, nRequested);
543
544         m_pHead = new LargeHeapHandleBucket(m_pHead, NewBucketSize, m_pDomain, bCrossAD);
545
546         m_NextBucketSize = min(m_NextBucketSize * 2, MAX_BUCKETSIZE);
547     }
548
549     return m_pHead->AllocateHandles(nRequested);
550 }
551
552 //*****************************************************************************
553 // Release object handles allocated using AllocateHandles().
554 void LargeHeapHandleTable::ReleaseHandles(OBJECTREF *pObjRef, DWORD nReleased)
555 {
556     CONTRACTL
557     {
558         NOTHROW;
559         GC_NOTRIGGER;
560         MODE_COOPERATIVE;
561         PRECONDITION(CheckPointer(pObjRef));
562     }
563     CONTRACTL_END;
564
565     // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
566
567     // the lock must be registered and already held by the caller per contract
568 #ifdef _DEBUG
569     _ASSERTE(m_pCrstDebug != NULL);
570     _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
571 #endif
572
573     OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
574     _ASSERTE(pPreallocatedSentinalObject  != NULL);
575
576
577     // Add the released handles to the list of available handles.
578     for (DWORD i = 0; i < nReleased; i++)
579     {
580         SetObjectReference(&pObjRef[i], pPreallocatedSentinalObject, NULL);
581     }
582
583     m_cEmbeddedFree += nReleased;
584 }
585
586
587
588
589 // Constructor for the ThreadStaticHandleBucket class.
590 ThreadStaticHandleBucket::ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain)
591 : m_pNext(pNext)
592 , m_ArraySize(Size)
593 {
594     CONTRACTL
595     {
596         THROWS;
597         GC_TRIGGERS;
598         MODE_COOPERATIVE;
599         PRECONDITION(CheckPointer(pDomain));
600         INJECT_FAULT(COMPlusThrowOM(););
601     }
602     CONTRACTL_END;
603
604     PTRARRAYREF HandleArrayObj;
605
606     // Allocate the array on the GC heap.
607     OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
608     HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, FALSE);
609
610     // Store the array in a strong handle to keep it alive.
611     m_hndHandleArray = pDomain->CreateStrongHandle((OBJECTREF)HandleArrayObj);
612 }
613
614 // Destructor for the ThreadStaticHandleBucket class.
615 ThreadStaticHandleBucket::~ThreadStaticHandleBucket()
616 {
617     CONTRACTL
618     {
619         NOTHROW;
620         GC_NOTRIGGER;
621         MODE_COOPERATIVE;
622     }
623     CONTRACTL_END;
624
625     if (m_hndHandleArray)
626     {
627         DestroyStrongHandle(m_hndHandleArray);
628         m_hndHandleArray = NULL;
629     }
630 }
631
632 // Allocate handles from the bucket.
633 OBJECTHANDLE ThreadStaticHandleBucket::GetHandles()
634 {
635     CONTRACTL
636     {
637         NOTHROW;
638         GC_NOTRIGGER;
639         MODE_COOPERATIVE;
640     }
641     CONTRACTL_END;
642
643     return m_hndHandleArray;
644 }
645
646 // Constructor for the ThreadStaticHandleTable class.
647 ThreadStaticHandleTable::ThreadStaticHandleTable(BaseDomain *pDomain)
648 : m_pHead(NULL)
649 , m_pDomain(pDomain)
650 {
651     CONTRACTL
652     {
653         NOTHROW;
654         GC_NOTRIGGER;
655         MODE_ANY;
656         PRECONDITION(CheckPointer(pDomain));
657     }
658     CONTRACTL_END;
659 }
660
661 // Destructor for the ThreadStaticHandleTable class.
662 ThreadStaticHandleTable::~ThreadStaticHandleTable()
663 {
664     CONTRACTL
665     {
666         NOTHROW;
667         GC_NOTRIGGER;
668     }
669     CONTRACTL_END;
670
671     // Delete the buckets.
672     while (m_pHead)
673     {
674         ThreadStaticHandleBucket *pOld = m_pHead;
675         m_pHead = pOld->GetNext();
676         delete pOld;
677     }
678 }
679
680 // Allocate handles from the large heap handle table.
681 OBJECTHANDLE ThreadStaticHandleTable::AllocateHandles(DWORD nRequested)
682 {
683     CONTRACTL
684     {
685         THROWS;
686         GC_TRIGGERS;
687         MODE_COOPERATIVE;
688         PRECONDITION(nRequested > 0);
689         INJECT_FAULT(COMPlusThrowOM(););
690     }
691     CONTRACTL_END;
692
693     // create a new bucket for this allocation
694     m_pHead = new ThreadStaticHandleBucket(m_pHead, nRequested, m_pDomain);
695
696     return m_pHead->GetHandles();
697 }
698
699 #endif // CROSSGEN_COMPILE
700
701
702 //*****************************************************************************
703 // BaseDomain
704 //*****************************************************************************
705 void BaseDomain::Attach()
706 {
707     m_SpecialStaticsCrst.Init(CrstSpecialStatics);
708 }
709
710 BaseDomain::BaseDomain()
711 {
712     // initialize fields so the domain can be safely destructed
713     // shouldn't call anything that can fail here - use ::Init instead
714     CONTRACTL
715     {
716         THROWS;
717         GC_TRIGGERS;
718         MODE_ANY;
719         FORBID_FAULT;
720     }
721     CONTRACTL_END;
722
723     m_fDisableInterfaceCache = FALSE;
724
725     m_pFusionContext = NULL;
726     m_pTPABinderContext = NULL;
727
728     // Make sure the container is set to NULL so that it gets loaded when it is used.
729     m_pLargeHeapHandleTable = NULL;
730
731 #ifndef CROSSGEN_COMPILE
732     // Note that m_handleStore is overridden by app domains
733     m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
734 #else
735     m_handleStore = NULL;
736 #endif
737
738     m_pMarshalingData = NULL;
739
740     m_dwContextStatics = 0;
741 #ifdef FEATURE_COMINTEROP
742     m_pMngStdInterfacesInfo = NULL;
743     m_pWinRtBinder = NULL;
744 #endif
745     m_FileLoadLock.PreInit();
746     m_JITLock.PreInit();
747     m_ClassInitLock.PreInit();
748     m_ILStubGenLock.PreInit();
749
750 #ifdef FEATURE_CODE_VERSIONING
751     m_codeVersionManager.PreInit(this == (BaseDomain *)g_pSharedDomainMemory);
752 #endif
753
754 } //BaseDomain::BaseDomain
755
756 //*****************************************************************************
757 void BaseDomain::Init()
758 {
759     CONTRACTL
760     {
761         THROWS;
762         GC_TRIGGERS;
763         MODE_ANY;
764         INJECT_FAULT(COMPlusThrowOM(););
765     }
766     CONTRACTL_END;
767
768     //
769     // Initialize the domain locks
770     //
771
772     if (this == reinterpret_cast<BaseDomain*>(&g_pSharedDomainMemory[0]))
773         m_DomainCrst.Init(CrstSharedBaseDomain);
774     else if (this == reinterpret_cast<BaseDomain*>(&g_pSystemDomainMemory[0]))
775         m_DomainCrst.Init(CrstSystemBaseDomain);
776     else
777         m_DomainCrst.Init(CrstBaseDomain);
778
779     m_DomainCacheCrst.Init(CrstAppDomainCache);
780     m_DomainLocalBlockCrst.Init(CrstDomainLocalBlock);
781
782     m_InteropDataCrst.Init(CrstInteropData, CRST_REENTRANCY);
783
784     m_WinRTFactoryCacheCrst.Init(CrstWinRTFactoryCache, CRST_UNSAFE_COOPGC);
785
786     // NOTE: CRST_UNSAFE_COOPGC prevents a GC mode switch to preemptive when entering this crst.
787     // If you remove this flag, we will switch to preemptive mode when entering
788     // m_FileLoadLock, which means all functions that enter it will become
789     // GC_TRIGGERS.  (This includes all uses of PEFileListLockHolder, LoadLockHolder, etc.)  So be sure
790     // to update the contracts if you remove this flag.
791     m_FileLoadLock.Init(CrstAssemblyLoader,
792                         CrstFlags(CRST_HOST_BREAKABLE), TRUE);
793
794     //
795     //   The JIT lock and the CCtor locks are at the same level (and marked as
796     //   UNSAFE_SAME_LEVEL) because they are all part of the same deadlock detection mechanism. We
797     //   see through cycles of JITting and .cctor execution and then explicitly allow the cycle to
798     //   be broken by giving access to uninitialized classes.  If there is no cycle or if the cycle
799     //   involves other locks that arent part of this special deadlock-breaking semantics, then
800     //   we continue to block.
801     //
802     m_JITLock.Init(CrstJit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
803     m_ClassInitLock.Init(CrstClassInit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
804
805     m_ILStubGenLock.Init(CrstILStubGen, CrstFlags(CRST_REENTRANCY), TRUE);
806
807     // Large heap handle table CRST.
808     m_LargeHeapHandleTableCrst.Init(CrstAppDomainHandleTable);
809
810     m_crstLoaderAllocatorReferences.Init(CrstLoaderAllocatorReferences);
811     // Has to switch thread to GC_NOTRIGGER while being held (see code:BaseDomain#AssemblyListLock)
812     m_crstAssemblyList.Init(CrstAssemblyList, CrstFlags(
813         CRST_GC_NOTRIGGER_WHEN_TAKEN | CRST_DEBUGGER_THREAD | CRST_TAKEN_DURING_SHUTDOWN));
814
815     // Initialize the EE marshaling data to NULL.
816     m_pMarshalingData = NULL;
817
818 #ifdef FEATURE_COMINTEROP
819     // Allocate the managed standard interfaces information.
820     m_pMngStdInterfacesInfo = new MngStdInterfacesInfo();
821     
822     {
823         CLRPrivBinderWinRT::NamespaceResolutionKind fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_WindowsAPI;
824         if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DesignerNamespaceResolutionEnabled) != FALSE)
825         {
826             fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_DesignerResolveEvent;
827         }
828         CLRPrivTypeCacheWinRT * pWinRtTypeCache = CLRPrivTypeCacheWinRT::GetOrCreateTypeCache();
829         m_pWinRtBinder = CLRPrivBinderWinRT::GetOrCreateBinder(pWinRtTypeCache, fNamespaceResolutionKind);
830     }
831 #endif // FEATURE_COMINTEROP
832
833     // Init the COM Interop data hash
834     {
835         LockOwner lock = {&m_InteropDataCrst, IsOwnerOfCrst};
836         m_interopDataHash.Init(0, NULL, false, &lock);
837     }
838
839     m_dwSizedRefHandles = 0;
840     if (!m_iNumberOfProcessors)
841     {
842         m_iNumberOfProcessors = GetCurrentProcessCpuCount();
843     }
844 }
845
846 #undef LOADERHEAP_PROFILE_COUNTER
847
848 #ifndef CROSSGEN_COMPILE
849 //*****************************************************************************
850 void BaseDomain::Terminate()
851 {
852     CONTRACTL
853     {
854         NOTHROW;
855         GC_TRIGGERS;
856         MODE_ANY;
857     }
858     CONTRACTL_END;
859
860     m_crstLoaderAllocatorReferences.Destroy();
861     m_DomainCrst.Destroy();
862     m_DomainCacheCrst.Destroy();
863     m_DomainLocalBlockCrst.Destroy();
864     m_InteropDataCrst.Destroy();
865
866     JitListLockEntry* pJitElement;
867     ListLockEntry* pElement;
868
869     // All the threads that are in this domain had better be stopped by this
870     // point.
871     //
872     // We might be jitting or running a .cctor so we need to empty that queue.
873     pJitElement = m_JITLock.Pop(TRUE);
874     while (pJitElement)
875     {
876 #ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
877         _ASSERTE ((m_JITLock.m_pHead->m_dwRefCount == 1
878             && m_JITLock.m_pHead->m_hrResultCode == E_FAIL) ||
879             dbg_fDrasticShutdown || g_fInControlC);
880 #endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
881         delete(pJitElement);
882         pJitElement = m_JITLock.Pop(TRUE);
883
884     }
885     m_JITLock.Destroy();
886
887     pElement = m_ClassInitLock.Pop(TRUE);
888     while (pElement)
889     {
890 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
891         _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
892 #endif
893         delete(pElement);
894         pElement = m_ClassInitLock.Pop(TRUE);
895     }
896     m_ClassInitLock.Destroy();
897
898     FileLoadLock* pFileElement;
899     pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
900     while (pFileElement)
901     {
902 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
903         _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
904 #endif
905         pFileElement->Release();
906         pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
907     }
908     m_FileLoadLock.Destroy();
909
910     pElement = m_ILStubGenLock.Pop(TRUE);
911     while (pElement)
912     {
913 #ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
914         _ASSERTE ((m_ILStubGenLock.m_pHead->m_dwRefCount == 1
915             && m_ILStubGenLock.m_pHead->m_hrResultCode == E_FAIL) ||
916             dbg_fDrasticShutdown || g_fInControlC);
917 #endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
918         delete(pElement);
919         pElement = m_ILStubGenLock.Pop(TRUE);
920     }
921     m_ILStubGenLock.Destroy();
922
923     m_LargeHeapHandleTableCrst.Destroy();
924
925     if (m_pLargeHeapHandleTable != NULL)
926     {
927         delete m_pLargeHeapHandleTable;
928         m_pLargeHeapHandleTable = NULL;
929     }
930
931     if (!IsAppDomain())
932     {
933         // Kind of a workaround - during unloading, we need to have an EE halt
934         // around deleting this stuff. So it gets deleted in AppDomain::Terminate()
935         // for those things (because there is a convenient place there.)
936         GetLoaderAllocator()->CleanupStringLiteralMap();
937     }
938
939 #ifdef FEATURE_COMINTEROP
940     if (m_pMngStdInterfacesInfo)
941     {
942         delete m_pMngStdInterfacesInfo;
943         m_pMngStdInterfacesInfo = NULL;
944     }
945     
946     if (m_pWinRtBinder != NULL)
947     {
948         m_pWinRtBinder->Release();
949     }
950 #endif // FEATURE_COMINTEROP
951
952     ClearFusionContext();
953
954     m_dwSizedRefHandles = 0;
955 }
956 #endif // CROSSGEN_COMPILE
957
958 void BaseDomain::InitVSD()
959 {
960     STANDARD_VM_CONTRACT;
961
962     // This is a workaround for gcc, since it fails to successfully resolve
963     // "TypeIDMap::STARTING_SHARED_DOMAIN_ID" when used within the ?: operator.
964     UINT32 startingId;
965     if (IsSharedDomain())
966     {
967         startingId = TypeIDMap::STARTING_SHARED_DOMAIN_ID;
968     }
969     else
970     {
971         startingId = TypeIDMap::STARTING_UNSHARED_DOMAIN_ID;
972     }
973
974     // By passing false as the last parameter, interfaces loaded in the
975     // shared domain will not be given fat type ids if RequiresFatDispatchTokens
976     // is set. This is correct, as the fat dispatch tokens are only needed to solve
977     // uniqueness problems involving domain specific types.
978     m_typeIDMap.Init(startingId, 2, !IsSharedDomain());
979
980 #ifndef CROSSGEN_COMPILE
981     GetLoaderAllocator()->InitVirtualCallStubManager(this);
982 #endif
983 }
984
985 #ifndef CROSSGEN_COMPILE
986
987 DWORD BaseDomain::AllocateContextStaticsOffset(DWORD* pOffsetSlot)
988 {
989     CONTRACTL
990     {
991         THROWS;
992         GC_TRIGGERS;
993     }
994     CONTRACTL_END;
995
996     CrstHolder ch(&m_SpecialStaticsCrst);
997
998     DWORD dwOffset = *pOffsetSlot;
999
1000     if (dwOffset == (DWORD)-1)
1001     {
1002         // Allocate the slot
1003         dwOffset = m_dwContextStatics++;
1004         *pOffsetSlot = dwOffset;
1005     }
1006
1007     return dwOffset;
1008 }
1009
1010 void BaseDomain::ClearFusionContext()
1011 {
1012     CONTRACTL
1013     {
1014         NOTHROW;
1015         GC_TRIGGERS;
1016         MODE_PREEMPTIVE;
1017     }
1018     CONTRACTL_END;
1019
1020     if(m_pFusionContext) {
1021         m_pFusionContext->Release();
1022         m_pFusionContext = NULL;
1023     }
1024     if (m_pTPABinderContext) {
1025         m_pTPABinderContext->Release();
1026         m_pTPABinderContext = NULL;
1027     }
1028 }
1029
1030 #ifdef  FEATURE_PREJIT
1031 void AppDomain::DeleteNativeCodeRanges()
1032 {
1033     CONTRACTL
1034     {
1035         NOTHROW;
1036         GC_NOTRIGGER;
1037         MODE_PREEMPTIVE;
1038         FORBID_FAULT;
1039     }
1040     CONTRACTL_END;
1041
1042     // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized 
1043     // and yet we are destroying it.  (This is the case if we OOM during AppDomain creation.)
1044     if (m_Assemblies.IsEmpty())
1045         return;
1046
1047     // Shutdown assemblies
1048     AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad) );
1049     CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1050
1051     while (i.Next(pDomainAssembly.This()))
1052     {
1053         Assembly * assembly = pDomainAssembly->m_pAssembly;
1054         if ((assembly != NULL) && !assembly->IsDomainNeutral())
1055             assembly->DeleteNativeCodeRanges();
1056     }
1057 }
1058 #endif
1059
1060 void AppDomain::ShutdownAssemblies()
1061 {
1062     CONTRACTL
1063     {
1064         NOTHROW;
1065         GC_TRIGGERS;
1066         MODE_ANY;
1067     }
1068     CONTRACTL_END;
1069
1070     // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized 
1071     // and yet we are destroying it.  (This is the case if we OOM during AppDomain creation.)
1072     if (m_Assemblies.IsEmpty())
1073         return;
1074
1075     // Shutdown assemblies
1076     // has two stages because Terminate needs info from the Assembly's dependencies
1077
1078     // Stage 1: call code:Assembly::Terminate
1079     AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1080         kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
1081     DomainAssembly * pDomainAssembly = NULL;
1082
1083     while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1084     {
1085         // Note: cannot use DomainAssembly::GetAssembly() here as it asserts that the assembly has been
1086         // loaded to at least the FILE_LOAD_ALLOCATE level. Since domain shutdown can take place
1087         // asynchronously this property cannot be guaranteed. Access the m_pAssembly field directly instead.
1088         Assembly * assembly = pDomainAssembly->m_pAssembly;
1089         if (assembly && !assembly->IsDomainNeutral())
1090             assembly->Terminate();
1091     }
1092     
1093     // Stage 2: Clear the list of assemblies
1094     i = IterateAssembliesEx((AssemblyIterationFlags)(
1095         kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
1096     while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1097     {
1098         // We are in shutdown path, no one else can get to the list anymore
1099         delete pDomainAssembly;
1100     }
1101     m_Assemblies.Clear(this);
1102     
1103     // Stage 2: Clear the loader allocators registered for deletion from code:Assembly:Terminate calls in 
1104     // stage 1
1105     // Note: It is not clear to me why we cannot delete the loader allocator from within 
1106     // code:DomainAssembly::~DomainAssembly
1107     ShutdownFreeLoaderAllocators(FALSE);
1108 } // AppDomain::ShutdownAssemblies
1109
1110 void AppDomain::ShutdownFreeLoaderAllocators(BOOL bFromManagedCode)
1111 {
1112     // If we're called from managed code (i.e. the finalizer thread) we take a lock in
1113     // LoaderAllocator::CleanupFailedTypeInit, which may throw. Otherwise we're called
1114     // from the app-domain shutdown path in which we can avoid taking the lock.
1115     CONTRACTL
1116     {
1117         GC_TRIGGERS;
1118         if (bFromManagedCode) THROWS; else NOTHROW;
1119         MODE_ANY;
1120         CAN_TAKE_LOCK;
1121     }
1122     CONTRACTL_END;
1123
1124     CrstHolder ch(GetLoaderAllocatorReferencesLock());
1125     
1126     // Shutdown the LoaderAllocators associated with collectible assemblies
1127     while (m_pDelayedLoaderAllocatorUnloadList != NULL)
1128     {
1129         LoaderAllocator * pCurrentLoaderAllocator = m_pDelayedLoaderAllocatorUnloadList;
1130         // Remove next loader allocator from the list
1131         m_pDelayedLoaderAllocatorUnloadList = m_pDelayedLoaderAllocatorUnloadList->m_pLoaderAllocatorDestroyNext;
1132
1133         if (bFromManagedCode)
1134         {
1135             // For loader allocator finalization, we need to be careful about cleaning up per-appdomain allocations
1136             // and synchronizing with GC using delay unload list. We need to wait for next Gen2 GC to finish to ensure
1137             // that GC heap does not have any references to the MethodTables being unloaded.
1138
1139             pCurrentLoaderAllocator->CleanupFailedTypeInit();
1140
1141             pCurrentLoaderAllocator->CleanupHandles();
1142
1143             GCX_COOP();
1144             SystemDomain::System()->AddToDelayedUnloadList(pCurrentLoaderAllocator);
1145         }
1146         else
1147         {
1148             // For appdomain unload, delete the loader allocator right away
1149             delete pCurrentLoaderAllocator;
1150         }
1151     }
1152 } // AppDomain::ShutdownFreeLoaderAllocators
1153
1154 //---------------------------------------------------------------------------------------
1155 // 
1156 // Register the loader allocator for deletion in code:AppDomain::ShutdownFreeLoaderAllocators.
1157 // 
1158 void AppDomain::RegisterLoaderAllocatorForDeletion(LoaderAllocator * pLoaderAllocator)
1159 {
1160     CONTRACTL
1161     {
1162         GC_TRIGGERS;
1163         NOTHROW;
1164         MODE_ANY;
1165         CAN_TAKE_LOCK;
1166     }
1167     CONTRACTL_END;
1168     
1169     CrstHolder ch(GetLoaderAllocatorReferencesLock());
1170     
1171     pLoaderAllocator->m_pLoaderAllocatorDestroyNext = m_pDelayedLoaderAllocatorUnloadList;
1172     m_pDelayedLoaderAllocatorUnloadList = pLoaderAllocator;
1173 }
1174
1175 void AppDomain::ShutdownNativeDllSearchDirectories()
1176 {
1177     LIMITED_METHOD_CONTRACT;
1178     // Shutdown assemblies
1179     PathIterator i = IterateNativeDllSearchDirectories();
1180
1181     while (i.Next())
1182     {
1183         delete i.GetPath();
1184     }
1185
1186     m_NativeDllSearchDirectories.Clear();
1187 }
1188
1189 void AppDomain::ReleaseDomainBoundInfo()
1190 {
1191     CONTRACTL
1192     {
1193         NOTHROW;
1194         GC_TRIGGERS;
1195         MODE_ANY;
1196     }
1197     CONTRACTL_END;;
1198     // Shutdown assemblies
1199     m_AssemblyCache.OnAppDomainUnload();
1200
1201     AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeFailedToLoad) );
1202     CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1203     
1204     while (i.Next(pDomainAssembly.This()))
1205     {
1206        pDomainAssembly->ReleaseManagedData();
1207     }
1208 }
1209
1210 void AppDomain::ReleaseFiles()
1211 {
1212     STANDARD_VM_CONTRACT;
1213
1214     // Shutdown assemblies
1215     AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1216         kIncludeLoaded  | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeLoading));
1217     CollectibleAssemblyHolder<DomainAssembly *> pAsm;
1218
1219     while (i.Next(pAsm.This()))
1220     {
1221         if (pAsm->GetCurrentAssembly() == NULL)
1222         {
1223             // Might be domain neutral or not, but should have no live objects as it has not been
1224             // really loaded yet. Just reset it.
1225             _ASSERTE(FitsIn<DWORD>(i.GetIndex()));
1226             m_Assemblies.Set(this, static_cast<DWORD>(i.GetIndex()), NULL);
1227             delete pAsm.Extract();
1228         }
1229         else
1230         {
1231             if (!pAsm->GetCurrentAssembly()->IsDomainNeutral())
1232                 pAsm->ReleaseFiles();
1233         }
1234     }
1235 } // AppDomain::ReleaseFiles
1236
1237
1238 OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate, BOOL bCrossAD)
1239 {
1240     CONTRACTL
1241     {
1242         THROWS;
1243         GC_TRIGGERS;
1244         MODE_ANY;
1245         PRECONDITION((nRequested > 0));
1246         INJECT_FAULT(COMPlusThrowOM(););
1247     }
1248     CONTRACTL_END;
1249
1250     if (ppLazyAllocate && *ppLazyAllocate)
1251     {
1252         // Allocation already happened
1253         return *ppLazyAllocate;
1254     }
1255
1256     // Enter preemptive state, take the lock and go back to cooperative mode.
1257     {
1258         CrstHolder ch(&m_LargeHeapHandleTableCrst);
1259         GCX_COOP();
1260
1261         if (ppLazyAllocate && *ppLazyAllocate)
1262         {
1263             // Allocation already happened
1264             return *ppLazyAllocate;
1265         }
1266
1267         // Make sure the large heap handle table is initialized.
1268         if (!m_pLargeHeapHandleTable)
1269             InitLargeHeapHandleTable();
1270
1271         // Allocate the handles.
1272         OBJECTREF* result = m_pLargeHeapHandleTable->AllocateHandles(nRequested, bCrossAD);
1273
1274         if (ppLazyAllocate)
1275         {
1276             *ppLazyAllocate = result;
1277         }
1278
1279         return result;
1280     }
1281 }
1282 #endif // CROSSGEN_COMPILE
1283
1284 #endif // !DACCESS_COMPILE
1285
1286 /*static*/
1287 PTR_BaseDomain BaseDomain::ComputeBaseDomain(
1288     BaseDomain * pGenericDefinitionDomain,   // the domain that owns the generic type or method
1289     Instantiation classInst,                // the type arguments to the type (if any)
1290     Instantiation methodInst)               // the type arguments to the method (if any)
1291 {
1292     CONTRACT(PTR_BaseDomain)
1293     {
1294         NOTHROW;
1295         GC_NOTRIGGER;
1296         FORBID_FAULT;
1297         MODE_ANY;
1298         POSTCONDITION(CheckPointer(RETVAL));
1299         SUPPORTS_DAC;
1300         SO_TOLERANT;
1301     }
1302     CONTRACT_END
1303
1304     if (pGenericDefinitionDomain && pGenericDefinitionDomain->IsAppDomain())
1305         RETURN PTR_BaseDomain(pGenericDefinitionDomain);
1306
1307     for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
1308     {
1309         PTR_BaseDomain pArgDomain = classInst[i].GetDomain();
1310         if (pArgDomain->IsAppDomain())
1311             RETURN pArgDomain;
1312     }
1313
1314     for (DWORD i = 0; i < methodInst.GetNumArgs(); i++)
1315     {
1316         PTR_BaseDomain pArgDomain = methodInst[i].GetDomain();
1317         if (pArgDomain->IsAppDomain())
1318             RETURN pArgDomain;
1319     }
1320     RETURN (pGenericDefinitionDomain ? 
1321             PTR_BaseDomain(pGenericDefinitionDomain) : 
1322             PTR_BaseDomain(SystemDomain::System()));
1323 }
1324
1325 PTR_BaseDomain BaseDomain::ComputeBaseDomain(TypeKey * pKey)
1326 {
1327     CONTRACTL
1328     {
1329         NOTHROW;
1330         GC_NOTRIGGER;
1331         MODE_ANY;
1332         SUPPORTS_DAC;
1333     }
1334     CONTRACTL_END;
1335
1336
1337     if (pKey->GetKind() == ELEMENT_TYPE_CLASS)
1338         return BaseDomain::ComputeBaseDomain(pKey->GetModule()->GetDomain(),
1339                                              pKey->GetInstantiation());
1340     else if (pKey->GetKind() != ELEMENT_TYPE_FNPTR)
1341         return pKey->GetElementType().GetDomain();
1342     else
1343         return BaseDomain::ComputeBaseDomain(NULL,Instantiation(pKey->GetRetAndArgTypes(), pKey->GetNumArgs()+1));
1344 }
1345
1346
1347
1348
1349
1350 #ifndef DACCESS_COMPILE
1351
1352 // Insert class in the hash table
1353 void AppDomain::InsertClassForCLSID(MethodTable* pMT, BOOL fForceInsert /*=FALSE*/)
1354 {
1355     CONTRACTL
1356     {
1357         GC_TRIGGERS;
1358         MODE_ANY;
1359         THROWS;
1360         INJECT_FAULT(COMPlusThrowOM(););
1361     }
1362     CONTRACTL_END;
1363
1364     CVID cvid;
1365
1366     // Ensure that registered classes are activated for allocation
1367     pMT->EnsureInstanceActive();
1368
1369     // Note that it is possible for multiple classes to claim the same CLSID, and in such a
1370     // case it is arbitrary which one we will return for a future query for a given app domain.
1371
1372     pMT->GetGuid(&cvid, fForceInsert);
1373
1374     if (!IsEqualIID(cvid, GUID_NULL))
1375     {
1376         //<TODO>@todo get a better key</TODO>
1377         LPVOID val = (LPVOID)pMT;
1378         {
1379             LockHolder lh(this);
1380
1381             if (LookupClass(cvid) != pMT)
1382             {
1383                 m_clsidHash.InsertValue(GetKeyFromGUID(&cvid), val);
1384             }
1385         }
1386     }
1387 }
1388
1389 void AppDomain::InsertClassForCLSID(MethodTable* pMT, GUID *pGuid)
1390 {
1391     CONTRACT_VOID
1392     {
1393         NOTHROW;
1394         PRECONDITION(CheckPointer(pMT));
1395         PRECONDITION(CheckPointer(pGuid));
1396     }
1397     CONTRACT_END;
1398
1399     LPVOID val = (LPVOID)pMT;
1400     {
1401         LockHolder lh(this);
1402
1403         CVID* cvid = pGuid;
1404         if (LookupClass(*cvid) != pMT)
1405         {
1406             m_clsidHash.InsertValue(GetKeyFromGUID(pGuid), val);
1407         }
1408     }
1409
1410     RETURN;
1411 }
1412 #endif // DACCESS_COMPILE
1413
1414 #ifdef FEATURE_COMINTEROP
1415
1416 #ifndef DACCESS_COMPILE
1417 void AppDomain::CacheTypeByName(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1418 {
1419     WRAPPER_NO_CONTRACT;
1420     LockHolder lh(this);
1421     CacheTypeByNameWorker(ssClassName, vCacheVersion, typeHandle, bFlags, bReplaceExisting);
1422 }
1423
1424 void AppDomain::CacheTypeByNameWorker(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1425 {
1426     CONTRACTL
1427     {
1428         THROWS;
1429         GC_TRIGGERS;
1430         PRECONDITION(!typeHandle.IsNull());
1431     }
1432     CONTRACTL_END;
1433
1434     NewArrayHolder<WCHAR> wzClassName(DuplicateStringThrowing(ssClassName.GetUnicode()));
1435
1436     if (m_vNameToTypeMapVersion != vCacheVersion)
1437         return;
1438
1439     if (m_pNameToTypeMap == nullptr)
1440     {
1441         m_pNameToTypeMap = new NameToTypeMapTable();
1442     }
1443
1444     NameToTypeMapEntry e;
1445     e.m_key.m_wzName = wzClassName;
1446     e.m_key.m_cchName = ssClassName.GetCount();
1447     e.m_typeHandle = typeHandle;
1448     e.m_nEpoch = this->m_nEpoch;
1449     e.m_bFlags = bFlags;
1450     if (!bReplaceExisting)
1451         m_pNameToTypeMap->Add(e);
1452     else
1453         m_pNameToTypeMap->AddOrReplace(e);
1454
1455     wzClassName.SuppressRelease();
1456 }
1457 #endif // DACCESS_COMPILE
1458
1459 TypeHandle AppDomain::LookupTypeByName(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1460 {
1461     WRAPPER_NO_CONTRACT;
1462     LockHolder lh(this);
1463     return LookupTypeByNameWorker(ssClassName, pvCacheVersion, pbFlags);
1464 }
1465
1466 TypeHandle AppDomain::LookupTypeByNameWorker(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1467 {
1468     CONTRACTL
1469     {
1470         THROWS;
1471         GC_TRIGGERS;
1472         SUPPORTS_DAC;
1473         PRECONDITION(CheckPointer(pbFlags, NULL_OK));
1474     }
1475     CONTRACTL_END;
1476
1477     *pvCacheVersion = m_vNameToTypeMapVersion;
1478
1479     if (m_pNameToTypeMap == nullptr)
1480         return TypeHandle();  // a null TypeHandle
1481
1482     NameToTypeMapEntry::Key key;
1483     key.m_cchName = ssClassName.GetCount();
1484     key.m_wzName  = ssClassName.GetUnicode();
1485
1486     const NameToTypeMapEntry * pEntry = m_pNameToTypeMap->LookupPtr(key);
1487     if (pEntry == NULL)
1488         return TypeHandle();  // a null TypeHandle
1489
1490     if (pbFlags != NULL)
1491         *pbFlags = pEntry->m_bFlags;
1492
1493     return pEntry->m_typeHandle;
1494 }
1495
1496 PTR_MethodTable AppDomain::LookupTypeByGuid(const GUID & guid)
1497 {
1498     CONTRACTL
1499     {
1500         THROWS;
1501         GC_TRIGGERS;
1502         MODE_ANY;
1503         SUPPORTS_DAC;
1504     }
1505     CONTRACTL_END;
1506
1507     SString sGuid;
1508     {
1509         WCHAR wszGuid[64];
1510         GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1511         sGuid.Append(wszGuid);
1512     }
1513     UINT ver;
1514     TypeHandle th = LookupTypeByName(sGuid, &ver, NULL);
1515
1516     if (!th.IsNull())
1517     {
1518         _ASSERTE(!th.IsTypeDesc());
1519         return th.AsMethodTable();
1520     }
1521
1522 #ifdef FEATURE_PREJIT
1523     else
1524     {
1525         // Next look in each ngen'ed image in turn
1526         AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1527             kIncludeLoaded | kIncludeExecution));
1528         CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1529         while (assemblyIterator.Next(pDomainAssembly.This()))
1530         {
1531             CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1532
1533             DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1534             while (i.Next())
1535             {
1536                 Module * pModule = i.GetLoadedModule();
1537                 if (!pModule->HasNativeImage())
1538                     continue;
1539                 _ASSERTE(!pModule->IsCollectible());
1540                 PTR_MethodTable pMT = pModule->LookupTypeByGuid(guid);
1541                 if (pMT != NULL)
1542                 {
1543                     return pMT;
1544                 }
1545             }
1546         }
1547     }
1548 #endif // FEATURE_PREJIT
1549     return NULL;
1550 }
1551
1552 #ifndef DACCESS_COMPILE
1553 void AppDomain::CacheWinRTTypeByGuid(TypeHandle typeHandle)
1554 {
1555     CONTRACTL
1556     {
1557         THROWS;
1558         GC_TRIGGERS;
1559         MODE_ANY;
1560         PRECONDITION(!typeHandle.IsTypeDesc());
1561         PRECONDITION(CanCacheWinRTTypeByGuid(typeHandle));
1562     }
1563     CONTRACTL_END;
1564
1565     PTR_MethodTable pMT = typeHandle.AsMethodTable();
1566
1567     GUID guid;
1568     if (pMT->GetGuidForWinRT(&guid))
1569     {
1570         SString sGuid;
1571
1572         {
1573             WCHAR wszGuid[64];
1574             GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1575             sGuid.Append(wszGuid);
1576         }
1577
1578         BYTE bFlags = 0x80;
1579         TypeHandle th;
1580         UINT vCacheVersion;
1581         {
1582             LockHolder lh(this);
1583             th = LookupTypeByNameWorker(sGuid, &vCacheVersion, &bFlags);
1584
1585             if (th.IsNull())
1586             {
1587                 // no other entry with the same GUID exists in the cache
1588                 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags);
1589             }
1590             else if (typeHandle.AsMethodTable() != th.AsMethodTable() && th.IsProjectedFromWinRT())
1591             {
1592                 // If we found a native WinRT type cached with the same GUID, replace it.
1593                 // Otherwise simply add the new mapping to the cache.
1594                 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags, TRUE);
1595             }
1596         }
1597     }
1598 }
1599 #endif // DACCESS_COMPILE
1600
1601 void AppDomain::GetCachedWinRTTypes(
1602                         SArray<PTR_MethodTable> * pTypes, 
1603                         SArray<GUID> * pGuids, 
1604                         UINT minEpoch, 
1605                         UINT * pCurEpoch)
1606 {
1607     CONTRACTL
1608     {
1609         THROWS;
1610         GC_TRIGGERS;
1611         MODE_ANY;
1612         SUPPORTS_DAC;
1613     }
1614     CONTRACTL_END;
1615
1616     LockHolder lh(this);
1617
1618     for (auto it = m_pNameToTypeMap->Begin(), end = m_pNameToTypeMap->End(); 
1619             it != end; 
1620             ++it)
1621     {
1622         NameToTypeMapEntry entry = (NameToTypeMapEntry)(*it);
1623         TypeHandle th = entry.m_typeHandle;
1624         if (th.AsMethodTable() != NULL && 
1625             entry.m_key.m_wzName[0] == W('{') &&
1626             entry.m_nEpoch >= minEpoch)
1627         {
1628             _ASSERTE(!th.IsTypeDesc());
1629             PTR_MethodTable pMT = th.AsMethodTable();
1630             // we're parsing the GUID value from the cache, because projected types do not cache the 
1631             // COM GUID in their GetGuid() but rather the legacy GUID
1632             GUID iid;
1633             if (LPWSTRToGuid(&iid, entry.m_key.m_wzName, 38) && iid != GUID_NULL)
1634             {
1635                 pTypes->Append(pMT);
1636                 pGuids->Append(iid);
1637             }
1638         }
1639     }
1640
1641 #ifdef FEATURE_PREJIT
1642     // Next look in each ngen'ed image in turn
1643     AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1644         kIncludeLoaded | kIncludeExecution));
1645     CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1646     while (assemblyIterator.Next(pDomainAssembly.This()))
1647     {
1648         CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1649
1650         DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1651         while (i.Next())
1652         {
1653             Module * pModule = i.GetLoadedModule();
1654             if (!pModule->HasNativeImage())
1655                 continue;
1656             _ASSERTE(!pModule->IsCollectible());
1657
1658             pModule->GetCachedWinRTTypes(pTypes, pGuids);
1659         }
1660     }
1661 #endif // FEATURE_PREJIT
1662
1663     if (pCurEpoch != NULL)
1664         *pCurEpoch = m_nEpoch;
1665     ++m_nEpoch;
1666 }
1667
1668 #ifndef CROSSGEN_COMPILE
1669 #ifndef DACCESS_COMPILE
1670 // static
1671 void WinRTFactoryCacheTraits::OnDestructPerEntryCleanupAction(const WinRTFactoryCacheEntry& e)
1672 {
1673     WRAPPER_NO_CONTRACT;
1674     if (e.m_pCtxEntry != NULL)
1675     {
1676         e.m_pCtxEntry->Release();
1677     }
1678     // the AD is going away, no need to destroy the OBJECTHANDLE
1679 }
1680
1681 void AppDomain::CacheWinRTFactoryObject(MethodTable *pClassMT, OBJECTREF *refFactory, LPVOID lpCtxCookie)
1682 {
1683     CONTRACTL
1684     {
1685         THROWS;
1686         GC_TRIGGERS;
1687         MODE_COOPERATIVE;
1688         PRECONDITION(CheckPointer(pClassMT));
1689     }
1690     CONTRACTL_END;
1691
1692     CtxEntryHolder pNewCtxEntry;
1693     if (lpCtxCookie != NULL)
1694     {
1695         // We don't want to insert the context cookie in the cache because it's just an address
1696         // of an internal COM data structure which will be freed when the apartment is torn down.
1697         // What's worse, if another apartment is later created, its context cookie may have exactly
1698         // the same value leading to incorrect cache hits. We'll use our CtxEntry instead which
1699         // is ref-counted and keeps the COM data structure alive even after the apartment ceases
1700         // to exist.
1701         pNewCtxEntry = CtxEntryCache::GetCtxEntryCache()->FindCtxEntry(lpCtxCookie, GetThread());
1702     }
1703
1704     WinRTFactoryCacheLockHolder lh(this);
1705
1706     if (m_pWinRTFactoryCache == nullptr)
1707     {
1708         m_pWinRTFactoryCache = new WinRTFactoryCache();
1709     }
1710
1711     WinRTFactoryCacheEntry *pEntry = const_cast<WinRTFactoryCacheEntry*>(m_pWinRTFactoryCache->LookupPtr(pClassMT));
1712     if (!pEntry)
1713     {
1714         //
1715         // No existing entry for this cache
1716         // Create a new one
1717         //
1718         WinRTFactoryCacheEntry e;
1719
1720         OBJECTHANDLEHolder ohNewHandle(CreateHandle(*refFactory));
1721
1722         e.key               = pClassMT;
1723         e.m_pCtxEntry       = pNewCtxEntry;
1724         e.m_ohFactoryObject = ohNewHandle;
1725
1726         m_pWinRTFactoryCache->Add(e);
1727      
1728         // suppress release of the CtxEntry and handle after we successfully inserted the new entry
1729         pNewCtxEntry.SuppressRelease();
1730         ohNewHandle.SuppressRelease();
1731     }
1732     else
1733     {
1734         //
1735         // Existing entry
1736         //
1737         // release the old CtxEntry and update the entry
1738         CtxEntry *pTemp = pNewCtxEntry.Extract();
1739         pNewCtxEntry = pEntry->m_pCtxEntry;
1740         pEntry->m_pCtxEntry = pTemp;
1741
1742         IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
1743         mgr->StoreObjectInHandle(pEntry->m_ohFactoryObject, OBJECTREFToObject(*refFactory));
1744     }
1745 }
1746
1747 OBJECTREF AppDomain::LookupWinRTFactoryObject(MethodTable *pClassMT, LPVOID lpCtxCookie)
1748 {
1749     CONTRACTL
1750     {
1751         THROWS;
1752         GC_NOTRIGGER;
1753         MODE_COOPERATIVE;
1754         PRECONDITION(CheckPointer(pClassMT));
1755         PRECONDITION(CheckPointer(m_pWinRTFactoryCache, NULL_OK));
1756     }
1757     CONTRACTL_END;
1758
1759
1760     if (m_pWinRTFactoryCache == nullptr)
1761         return NULL;
1762             
1763     //
1764     // Retrieve cached factory
1765     //
1766     WinRTFactoryCacheLockHolder lh(this);
1767
1768     const WinRTFactoryCacheEntry *pEntry = m_pWinRTFactoryCache->LookupPtr(pClassMT);
1769     if (pEntry == NULL)
1770         return NULL;
1771     
1772     //
1773     // Ignore factories from a different context, unless lpCtxCookie == NULL, 
1774     // which means the factory is free-threaded
1775     // Note that we cannot touch the RCW to retrieve cookie at this point
1776     // because the RCW might belong to a STA thread and that STA thread might die
1777     // and take the RCW with it. Therefore we have to save cookie in this cache    
1778     //
1779     if (pEntry->m_pCtxEntry == NULL || pEntry->m_pCtxEntry->GetCtxCookie() == lpCtxCookie)
1780         return ObjectFromHandle(pEntry->m_ohFactoryObject);
1781     
1782     return NULL;
1783 }
1784
1785 void AppDomain::RemoveWinRTFactoryObjects(LPVOID pCtxCookie)
1786 {
1787     CONTRACTL
1788     {
1789         THROWS;
1790         GC_TRIGGERS;
1791         MODE_ANY;
1792     }
1793     CONTRACTL_END;
1794
1795     if (m_pWinRTFactoryCache == nullptr)
1796         return;
1797
1798     // helper class for delayed CtxEntry cleanup
1799     class CtxEntryListReleaseHolder
1800     {
1801     public:
1802         CQuickArrayList<CtxEntry *> m_list;
1803
1804         ~CtxEntryListReleaseHolder()
1805         {
1806             CONTRACTL
1807             {
1808                 NOTHROW;
1809                 GC_TRIGGERS;
1810                 MODE_ANY;
1811             }
1812             CONTRACTL_END;
1813
1814             for (SIZE_T i = 0; i < m_list.Size(); i++)
1815             {
1816                 m_list[i]->Release();
1817             }
1818         }
1819     } ctxEntryListReleaseHolder;
1820
1821     GCX_COOP();
1822     {
1823         WinRTFactoryCacheLockHolder lh(this);
1824
1825         // Go through the hash table and remove items in the given context
1826         for (WinRTFactoryCache::Iterator it = m_pWinRTFactoryCache->Begin(); it != m_pWinRTFactoryCache->End(); it++)
1827         {
1828             if (it->m_pCtxEntry != NULL && it->m_pCtxEntry->GetCtxCookie() == pCtxCookie)
1829             {
1830                 // Releasing the CtxEntry may trigger GC which we can't do under the lock so we push
1831                 // it on our local list and release them all after we're done iterating the hashtable.
1832                 ctxEntryListReleaseHolder.m_list.Push(it->m_pCtxEntry);
1833
1834                 DestroyHandle(it->m_ohFactoryObject);
1835                 m_pWinRTFactoryCache->Remove(it);
1836             }
1837         }
1838     }
1839 }
1840
1841 OBJECTREF AppDomain::GetMissingObject()
1842 {
1843     CONTRACTL
1844     {
1845         THROWS;
1846         GC_TRIGGERS;
1847         MODE_COOPERATIVE;
1848     }
1849     CONTRACTL_END;
1850
1851     if (!m_hndMissing)
1852     {
1853         // Get the field
1854         FieldDesc *pValueFD = MscorlibBinder::GetField(FIELD__MISSING__VALUE);
1855
1856         pValueFD->CheckRunClassInitThrowing();
1857
1858         // Retrieve the value static field and store it.
1859         OBJECTHANDLE hndMissing = CreateHandle(pValueFD->GetStaticOBJECTREF());
1860
1861         if (FastInterlockCompareExchangePointer(&m_hndMissing, hndMissing, NULL) != NULL)
1862         {
1863             // Exchanged failed. The m_hndMissing did not equal NULL and was returned.
1864             DestroyHandle(hndMissing);
1865         }
1866     }
1867
1868     return ObjectFromHandle(m_hndMissing);
1869 }
1870
1871 #endif // DACCESS_COMPILE
1872 #endif //CROSSGEN_COMPILE
1873 #endif // FEATURE_COMINTEROP
1874
1875 #ifndef DACCESS_COMPILE
1876
1877 EEMarshalingData *BaseDomain::GetMarshalingData()
1878 {
1879     CONTRACT (EEMarshalingData*)
1880     {
1881         THROWS;
1882         GC_TRIGGERS;
1883         MODE_ANY;
1884         INJECT_FAULT(COMPlusThrowOM());
1885         POSTCONDITION(CheckPointer(m_pMarshalingData));
1886     }
1887     CONTRACT_END;
1888
1889     if (!m_pMarshalingData)
1890     {
1891         // Take the lock
1892         CrstHolder holder(&m_InteropDataCrst);
1893
1894         if (!m_pMarshalingData)
1895         {
1896             LoaderHeap* pHeap = GetLoaderAllocator()->GetLowFrequencyHeap();
1897             m_pMarshalingData = new (pHeap) EEMarshalingData(this, pHeap, &m_DomainCrst);
1898         }
1899     }
1900
1901     RETURN m_pMarshalingData;
1902 }
1903
1904 void BaseDomain::DeleteMarshalingData()
1905 {
1906     CONTRACTL
1907     {
1908         NOTHROW;
1909         GC_TRIGGERS;
1910         MODE_ANY;
1911     }
1912     CONTRACTL_END;
1913
1914     // We are in shutdown - no need to take any lock
1915     if (m_pMarshalingData)
1916     {
1917         delete m_pMarshalingData;
1918         m_pMarshalingData = NULL;
1919     }
1920 }
1921
1922 #ifndef CROSSGEN_COMPILE
1923
1924 STRINGREF *BaseDomain::IsStringInterned(STRINGREF *pString)
1925 {
1926     CONTRACTL
1927     {
1928         GC_TRIGGERS;
1929         THROWS;
1930         MODE_COOPERATIVE;
1931         PRECONDITION(CheckPointer(pString));
1932         INJECT_FAULT(COMPlusThrowOM(););
1933     }
1934     CONTRACTL_END;
1935
1936     return GetLoaderAllocator()->IsStringInterned(pString);
1937 }
1938
1939 STRINGREF *BaseDomain::GetOrInternString(STRINGREF *pString)
1940 {
1941     CONTRACTL
1942     {
1943         GC_TRIGGERS;
1944         THROWS;
1945         MODE_COOPERATIVE;
1946         PRECONDITION(CheckPointer(pString));
1947         INJECT_FAULT(COMPlusThrowOM(););
1948     }
1949     CONTRACTL_END;
1950
1951     return GetLoaderAllocator()->GetOrInternString(pString);
1952 }
1953
1954 void BaseDomain::InitLargeHeapHandleTable()
1955 {
1956     CONTRACTL
1957     {
1958         THROWS;
1959         GC_TRIGGERS;
1960         MODE_ANY;
1961         PRECONDITION(m_pLargeHeapHandleTable==NULL);
1962         INJECT_FAULT(COMPlusThrowOM(););
1963     }
1964     CONTRACTL_END;
1965
1966     m_pLargeHeapHandleTable = new LargeHeapHandleTable(this, STATIC_OBJECT_TABLE_BUCKET_SIZE);
1967
1968 #ifdef _DEBUG
1969     m_pLargeHeapHandleTable->RegisterCrstDebug(&m_LargeHeapHandleTableCrst);
1970 #endif
1971 }
1972
1973 #ifdef FEATURE_COMINTEROP
1974 MethodTable* AppDomain::GetLicenseInteropHelperMethodTable()
1975 {
1976     CONTRACTL
1977     {
1978         THROWS;
1979         GC_TRIGGERS;
1980     }
1981     CONTRACTL_END;
1982
1983     if(m_pLicenseInteropHelperMT == NULL)
1984     {
1985         // Do this work outside of the lock so we don't have an unbreakable lock condition
1986
1987         TypeHandle licenseMgrTypeHnd;
1988         MethodDescCallSite  loadLM(METHOD__MARSHAL__LOAD_LICENSE_MANAGER);
1989
1990         licenseMgrTypeHnd = (MethodTable*) loadLM.Call_RetLPVOID((ARG_SLOT*)NULL);
1991
1992         //
1993         // Look up this method by name, because the type is actually declared in System.dll.  <TODO>@todo: why?</TODO>
1994         //
1995
1996         MethodDesc *pGetLIHMD = MemberLoader::FindMethod(licenseMgrTypeHnd.AsMethodTable(),
1997                 "GetLicenseInteropHelperType", &gsig_SM_Void_RetIntPtr);
1998         _ASSERTE(pGetLIHMD);
1999
2000         TypeHandle lihTypeHnd;
2001
2002         MethodDescCallSite getLIH(pGetLIHMD);
2003         lihTypeHnd = (MethodTable*) getLIH.Call_RetLPVOID((ARG_SLOT*)NULL);
2004
2005         BaseDomain::LockHolder lh(this);
2006
2007         if(m_pLicenseInteropHelperMT == NULL)
2008             m_pLicenseInteropHelperMT = lihTypeHnd.AsMethodTable();
2009     }
2010     return m_pLicenseInteropHelperMT;
2011 }
2012
2013 COMorRemotingFlag AppDomain::GetComOrRemotingFlag()
2014 {
2015     CONTRACTL
2016     {
2017         NOTHROW;
2018         GC_TRIGGERS;
2019         MODE_ANY;
2020     }
2021     CONTRACTL_END;
2022
2023     // 0. check if the value is already been set
2024     if (m_COMorRemotingFlag != COMorRemoting_NotInitialized)
2025         return m_COMorRemotingFlag;
2026
2027     // 1. check whether the process is AppX
2028     if (AppX::IsAppXProcess())
2029     {
2030         // do not use Remoting in AppX
2031         m_COMorRemotingFlag = COMorRemoting_COM;
2032         return m_COMorRemotingFlag;
2033     }
2034
2035     // 2. check the xml file
2036     m_COMorRemotingFlag = GetPreferComInsteadOfManagedRemotingFromConfigFile();
2037     if (m_COMorRemotingFlag != COMorRemoting_NotInitialized)
2038     {
2039         return m_COMorRemotingFlag;
2040     }
2041
2042     // 3. check the global setting
2043     if (NULL != g_pConfig && g_pConfig->ComInsteadOfManagedRemoting())
2044     {
2045         m_COMorRemotingFlag = COMorRemoting_COM;
2046     }
2047     else
2048     {
2049         m_COMorRemotingFlag = COMorRemoting_Remoting;
2050     }
2051
2052     return m_COMorRemotingFlag;
2053 }
2054
2055 BOOL AppDomain::GetPreferComInsteadOfManagedRemoting()
2056 {
2057     WRAPPER_NO_CONTRACT;
2058
2059     return (GetComOrRemotingFlag() == COMorRemoting_COM);
2060 }
2061
2062 COMorRemotingFlag AppDomain::GetPreferComInsteadOfManagedRemotingFromConfigFile()
2063 {
2064     CONTRACTL
2065     {
2066         NOTHROW;
2067         GC_TRIGGERS;
2068         MODE_ANY;
2069     }
2070     CONTRACTL_END;
2071
2072     return COMorRemoting_COM;
2073 }
2074 #endif // FEATURE_COMINTEROP
2075
2076 #endif // CROSSGEN_COMPILE
2077
2078 //*****************************************************************************
2079 //*****************************************************************************
2080 //*****************************************************************************
2081
2082 void *SystemDomain::operator new(size_t size, void *pInPlace)
2083 {
2084     LIMITED_METHOD_CONTRACT;
2085     return pInPlace;
2086 }
2087
2088
2089 void SystemDomain::operator delete(void *pMem)
2090 {
2091     LIMITED_METHOD_CONTRACT;
2092     // Do nothing - new() was in-place
2093 }
2094
2095
2096 void    SystemDomain::SetCompilationOverrides(BOOL fForceDebug,
2097                                               BOOL fForceProfiling,
2098                                               BOOL fForceInstrument)
2099 {
2100     LIMITED_METHOD_CONTRACT;
2101     s_fForceDebug = fForceDebug;
2102     s_fForceProfiling = fForceProfiling;
2103     s_fForceInstrument = fForceInstrument;
2104 }
2105
2106 #endif //!DACCESS_COMPILE
2107
2108 void    SystemDomain::GetCompilationOverrides(BOOL * fForceDebug,
2109                                               BOOL * fForceProfiling,
2110                                               BOOL * fForceInstrument)
2111 {
2112     LIMITED_METHOD_DAC_CONTRACT;
2113     *fForceDebug = s_fForceDebug;
2114     *fForceProfiling = s_fForceProfiling;
2115     *fForceInstrument = s_fForceInstrument;
2116 }
2117
2118 #ifndef DACCESS_COMPILE
2119
2120 void SystemDomain::Attach()
2121 {
2122     CONTRACTL
2123     {
2124         THROWS;
2125         GC_TRIGGERS;
2126         MODE_ANY;
2127         PRECONDITION(m_pSystemDomain == NULL);
2128         INJECT_FAULT(COMPlusThrowOM(););
2129     }
2130     CONTRACTL_END;
2131
2132 #ifndef CROSSGEN_COMPILE
2133     // Initialize stub managers
2134     PrecodeStubManager::Init();
2135     DelegateInvokeStubManager::Init();
2136     JumpStubStubManager::Init();
2137     RangeSectionStubManager::Init();
2138     ILStubManager::Init();
2139     InteropDispatchStubManager::Init();
2140     StubLinkStubManager::Init();
2141
2142     ThunkHeapStubManager::Init();
2143
2144     TailCallStubManager::Init();
2145
2146     PerAppDomainTPCountList::InitAppDomainIndexList();
2147 #endif // CROSSGEN_COMPILE
2148
2149     m_appDomainIndexList.Init();
2150     m_appDomainIdList.Init();
2151
2152     m_SystemDomainCrst.Init(CrstSystemDomain, (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN));
2153     m_DelayedUnloadCrst.Init(CrstSystemDomainDelayedUnloadList, CRST_UNSAFE_COOPGC);
2154
2155     // Initialize the ID dispenser that is used for domain neutral module IDs
2156     g_pModuleIndexDispenser = new IdDispenser();
2157
2158     // Create the global SystemDomain and initialize it.
2159     m_pSystemDomain = new (&g_pSystemDomainMemory[0]) SystemDomain();
2160     // No way it can fail since g_pSystemDomainMemory is a static array.
2161     CONSISTENCY_CHECK(CheckPointer(m_pSystemDomain));
2162
2163     LOG((LF_CLASSLOADER,
2164          LL_INFO10,
2165          "Created system domain at %p\n",
2166          m_pSystemDomain));
2167
2168     // We need to initialize the memory pools etc. for the system domain.
2169     m_pSystemDomain->BaseDomain::Init(); // Setup the memory heaps
2170
2171     // Create the default domain
2172     m_pSystemDomain->CreateDefaultDomain();
2173     SharedDomain::Attach();
2174
2175     // Each domain gets its own ReJitManager, and ReJitManager has its own static
2176     // initialization to run
2177     ReJitManager::InitStatic();
2178 }
2179
2180 #ifndef CROSSGEN_COMPILE
2181
2182 void SystemDomain::DetachBegin()
2183 {
2184     WRAPPER_NO_CONTRACT;
2185     // Shut down the domain and its children (but don't deallocate anything just
2186     // yet).
2187
2188     // TODO: we should really not running managed DLLMain during process detach.
2189     if (GetThread() == NULL)
2190     {
2191         return;
2192     }
2193
2194     if(m_pSystemDomain)
2195         m_pSystemDomain->Stop();
2196 }
2197
2198 void SystemDomain::DetachEnd()
2199 {
2200     CONTRACTL
2201     {
2202         NOTHROW;
2203         GC_TRIGGERS;
2204         MODE_ANY;
2205     }
2206     CONTRACTL_END;
2207     // Shut down the domain and its children (but don't deallocate anything just
2208     // yet).
2209     if(m_pSystemDomain)
2210     {
2211         GCX_PREEMP();
2212         m_pSystemDomain->ClearFusionContext();
2213         if (m_pSystemDomain->m_pDefaultDomain)
2214             m_pSystemDomain->m_pDefaultDomain->ClearFusionContext();
2215     }
2216 }
2217
2218 void SystemDomain::Stop()
2219 {
2220     WRAPPER_NO_CONTRACT;
2221     AppDomainIterator i(TRUE);
2222
2223     while (i.Next())
2224         if (i.GetDomain()->m_Stage < AppDomain::STAGE_CLEARED)
2225             i.GetDomain()->Stop();
2226 }
2227
2228
2229 void SystemDomain::Terminate() // bNotifyProfiler is ignored
2230 {
2231     CONTRACTL
2232     {
2233         NOTHROW;
2234         GC_TRIGGERS;
2235         MODE_ANY;
2236     }
2237     CONTRACTL_END;
2238
2239     // This ignores the refences and terminates the appdomains
2240     AppDomainIterator i(FALSE);
2241
2242     while (i.Next())
2243     {
2244         delete i.GetDomain();
2245         // Keep the iterator from Releasing the current domain
2246         i.m_pCurrent = NULL;
2247     }
2248
2249     if (m_pSystemFile != NULL) {
2250         m_pSystemFile->Release();
2251         m_pSystemFile = NULL;
2252     }
2253
2254     m_pSystemAssembly = NULL;
2255
2256     if(m_pwDevpath) {
2257         delete[] m_pwDevpath;
2258         m_pwDevpath = NULL;
2259     }
2260     m_dwDevpath = 0;
2261     m_fDevpath = FALSE;
2262
2263     if (m_pGlobalStringLiteralMap) {
2264         delete m_pGlobalStringLiteralMap;
2265         m_pGlobalStringLiteralMap = NULL;
2266     }
2267
2268
2269     SharedDomain::Detach();
2270
2271     BaseDomain::Terminate();
2272
2273 #ifdef FEATURE_COMINTEROP
2274     if (g_pRCWCleanupList != NULL)
2275         delete g_pRCWCleanupList;
2276 #endif // FEATURE_COMINTEROP
2277     m_GlobalAllocator.Terminate();
2278 }
2279
2280
2281 void SystemDomain::PreallocateSpecialObjects()
2282 {
2283     CONTRACTL
2284     {
2285         THROWS;
2286         GC_TRIGGERS;
2287         MODE_COOPERATIVE;
2288         INJECT_FAULT(COMPlusThrowOM(););
2289     }
2290     CONTRACTL_END;
2291
2292     _ASSERTE(g_pPreallocatedSentinelObject == NULL);
2293
2294     OBJECTREF pPreallocatedSentinalObject = AllocateObject(g_pObjectClass);
2295     g_pPreallocatedSentinelObject = CreatePinningHandle( pPreallocatedSentinalObject );
2296
2297 #ifdef FEATURE_PREJIT
2298     if (SystemModule()->HasNativeImage())
2299     {
2300         CORCOMPILE_EE_INFO_TABLE *pEEInfo = SystemModule()->GetNativeImage()->GetNativeEEInfoTable();
2301         pEEInfo->emptyString = (CORINFO_Object **)StringObject::GetEmptyStringRefPtr();
2302     }
2303 #endif
2304 }
2305
2306 void SystemDomain::CreatePreallocatedExceptions()
2307 {
2308     CONTRACTL
2309     {
2310         THROWS;
2311         GC_TRIGGERS;
2312         MODE_COOPERATIVE;
2313         INJECT_FAULT(COMPlusThrowOM(););
2314     }
2315     CONTRACTL_END;
2316
2317     EXCEPTIONREF pBaseException = (EXCEPTIONREF)AllocateObject(g_pExceptionClass);
2318     pBaseException->SetHResult(COR_E_EXCEPTION);
2319     pBaseException->SetXCode(EXCEPTION_COMPLUS);
2320     _ASSERTE(g_pPreallocatedBaseException == NULL);
2321     g_pPreallocatedBaseException = CreateHandle(pBaseException);
2322
2323
2324     EXCEPTIONREF pOutOfMemory = (EXCEPTIONREF)AllocateObject(g_pOutOfMemoryExceptionClass);
2325     pOutOfMemory->SetHResult(COR_E_OUTOFMEMORY);
2326     pOutOfMemory->SetXCode(EXCEPTION_COMPLUS);
2327     _ASSERTE(g_pPreallocatedOutOfMemoryException == NULL);
2328     g_pPreallocatedOutOfMemoryException = CreateHandle(pOutOfMemory);
2329
2330
2331     EXCEPTIONREF pStackOverflow = (EXCEPTIONREF)AllocateObject(g_pStackOverflowExceptionClass);
2332     pStackOverflow->SetHResult(COR_E_STACKOVERFLOW);
2333     pStackOverflow->SetXCode(EXCEPTION_COMPLUS);
2334     _ASSERTE(g_pPreallocatedStackOverflowException == NULL);
2335     g_pPreallocatedStackOverflowException = CreateHandle(pStackOverflow);
2336
2337
2338     EXCEPTIONREF pExecutionEngine = (EXCEPTIONREF)AllocateObject(g_pExecutionEngineExceptionClass);
2339     pExecutionEngine->SetHResult(COR_E_EXECUTIONENGINE);
2340     pExecutionEngine->SetXCode(EXCEPTION_COMPLUS);
2341     _ASSERTE(g_pPreallocatedExecutionEngineException == NULL);
2342     g_pPreallocatedExecutionEngineException = CreateHandle(pExecutionEngine);
2343
2344
2345     EXCEPTIONREF pRudeAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2346     pRudeAbortException->SetHResult(COR_E_THREADABORTED);
2347     pRudeAbortException->SetXCode(EXCEPTION_COMPLUS);
2348     _ASSERTE(g_pPreallocatedRudeThreadAbortException == NULL);
2349     g_pPreallocatedRudeThreadAbortException = CreateHandle(pRudeAbortException);
2350
2351
2352     EXCEPTIONREF pAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2353     pAbortException->SetHResult(COR_E_THREADABORTED);
2354     pAbortException->SetXCode(EXCEPTION_COMPLUS);
2355     _ASSERTE(g_pPreallocatedThreadAbortException == NULL);
2356     g_pPreallocatedThreadAbortException = CreateHandle( pAbortException );
2357 }
2358 #endif // CROSSGEN_COMPILE
2359
2360 void SystemDomain::Init()
2361 {
2362     STANDARD_VM_CONTRACT;
2363
2364     HRESULT hr = S_OK;
2365
2366 #ifdef _DEBUG
2367     LOG((
2368         LF_EEMEM,
2369         LL_INFO10,
2370         "sizeof(EEClass)     = %d\n"
2371         "sizeof(MethodTable) = %d\n"
2372         "sizeof(MethodDesc)= %d\n"
2373         "sizeof(FieldDesc)   = %d\n"
2374         "sizeof(Module)      = %d\n",
2375         sizeof(EEClass),
2376         sizeof(MethodTable),
2377         sizeof(MethodDesc),
2378         sizeof(FieldDesc),
2379         sizeof(Module)
2380     ));
2381 #endif // _DEBUG
2382
2383     // The base domain is initialized in SystemDomain::Attach()
2384     // to allow stub caches to use the memory pool. Do not
2385     // initialze it here!
2386
2387 #ifndef CROSSGEN_COMPILE
2388 #ifdef _DEBUG
2389     Context     *curCtx = GetCurrentContext();
2390 #endif
2391     _ASSERTE(curCtx);
2392     _ASSERTE(curCtx->GetDomain() != NULL);
2393 #endif
2394
2395 #ifdef FEATURE_PREJIT
2396     if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapDisable) != 0)
2397         g_fAllowNativeImages = false;
2398 #endif
2399
2400     m_pSystemFile = NULL;
2401     m_pSystemAssembly = NULL;
2402
2403     DWORD size = 0;
2404
2405
2406     // Get the install directory so we can find mscorlib
2407     hr = GetInternalSystemDirectory(NULL, &size);
2408     if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
2409         ThrowHR(hr);
2410
2411     // GetInternalSystemDirectory returns a size, including the null!
2412     WCHAR *buffer = m_SystemDirectory.OpenUnicodeBuffer(size-1);
2413     IfFailThrow(GetInternalSystemDirectory(buffer, &size));
2414     m_SystemDirectory.CloseBuffer();
2415     m_SystemDirectory.Normalize();
2416
2417     // At this point m_SystemDirectory should already be canonicalized
2418
2419
2420     m_BaseLibrary.Append(m_SystemDirectory);
2421     if (!m_BaseLibrary.EndsWith(DIRECTORY_SEPARATOR_CHAR_W))
2422     {
2423         m_BaseLibrary.Append(DIRECTORY_SEPARATOR_CHAR_W);
2424     }
2425     m_BaseLibrary.Append(g_pwBaseLibrary);
2426     m_BaseLibrary.Normalize();
2427
2428     LoadBaseSystemClasses();
2429
2430     {
2431         // We are about to start allocating objects, so we must be in cooperative mode.
2432         // However, many of the entrypoints to the system (DllGetClassObject and all
2433         // N/Direct exports) get called multiple times.  Sometimes they initialize the EE,
2434         // but generally they remain in preemptive mode.  So we really want to push/pop
2435         // the state here:
2436         GCX_COOP();
2437
2438 #ifndef CROSSGEN_COMPILE
2439         if (!NingenEnabled())
2440         {
2441             CreatePreallocatedExceptions();
2442
2443             PreallocateSpecialObjects();
2444         }
2445 #endif
2446
2447         // Finish loading mscorlib now.
2448         m_pSystemAssembly->GetDomainAssembly()->EnsureActive();
2449     }
2450
2451 #ifdef _DEBUG
2452     BOOL fPause = EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_PauseOnLoad, FALSE);
2453
2454     while(fPause)
2455     {
2456         ClrSleepEx(20, TRUE);
2457     }
2458 #endif // _DEBUG
2459 }
2460
2461 #ifndef CROSSGEN_COMPILE
2462 void SystemDomain::LazyInitGlobalStringLiteralMap()
2463 {
2464     CONTRACTL
2465     {
2466         THROWS;
2467         GC_TRIGGERS;
2468         MODE_ANY;
2469         INJECT_FAULT(COMPlusThrowOM(););
2470     }
2471     CONTRACTL_END;
2472
2473     // Allocate the global string literal map.
2474     NewHolder<GlobalStringLiteralMap> pGlobalStringLiteralMap(new GlobalStringLiteralMap());
2475
2476     // Initialize the global string literal map.
2477     pGlobalStringLiteralMap->Init();
2478
2479     if (InterlockedCompareExchangeT<GlobalStringLiteralMap *>(&m_pGlobalStringLiteralMap, pGlobalStringLiteralMap, NULL) == NULL)
2480     {
2481         pGlobalStringLiteralMap.SuppressRelease();
2482     }
2483 }
2484
2485 void AppDomain::CreateADUnloadStartEvent()
2486 {
2487     CONTRACTL
2488     {
2489         THROWS;
2490         GC_NOTRIGGER;
2491         SO_TOLERANT;
2492         MODE_ANY;
2493     }
2494     CONTRACTL_END;
2495
2496     g_pUnloadStartEvent = new CLREvent();
2497     g_pUnloadStartEvent->CreateAutoEvent(FALSE);
2498 }
2499
2500 /*static*/ void SystemDomain::EnumAllStaticGCRefs(promote_func* fn, ScanContext* sc)
2501 {
2502     CONTRACT_VOID
2503     {
2504         NOTHROW;
2505         GC_NOTRIGGER;
2506         MODE_COOPERATIVE;
2507     }
2508     CONTRACT_END;
2509
2510     // We don't do a normal AppDomainIterator because we can't take the SystemDomain lock from
2511     // here.
2512     // We're only supposed to call this from a Server GC. We're walking here m_appDomainIdList
2513     // m_appDomainIdList will have an AppDomain* or will be NULL. So the only danger is if we
2514     // Fetch an AppDomain and then in some other thread the AppDomain is deleted.
2515     //
2516     // If the thread deleting the AppDomain (AppDomain::~AppDomain)was in Preemptive mode
2517     // while doing SystemDomain::EnumAllStaticGCRefs we will issue a GCX_COOP(), which will wait
2518     // for the GC to finish, so we are safe
2519     //
2520     // If the thread is in cooperative mode, it must have been suspended for the GC so a delete
2521     // can't happen.
2522
2523     _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
2524              GCHeapUtilities::IsServerHeap()   &&
2525              IsGCSpecialThread());
2526
2527     SystemDomain* sysDomain = SystemDomain::System();
2528     if (sysDomain)
2529     {
2530         DWORD i;
2531         DWORD count = (DWORD) m_appDomainIdList.GetCount();
2532         for (i = 0 ; i < count ; i++)
2533         {
2534             AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2535             if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
2536             {
2537 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2538                 if (g_fEnableARM)
2539                 {
2540                     sc->pCurrentDomain = pAppDomain;
2541                 }
2542 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2543                 pAppDomain->EnumStaticGCRefs(fn, sc);
2544             }
2545         }
2546     }
2547
2548     RETURN;
2549 }
2550
2551 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2552 void SystemDomain::ResetADSurvivedBytes()
2553 {
2554     CONTRACT_VOID
2555     {
2556         NOTHROW;
2557         GC_NOTRIGGER;
2558         MODE_ANY;
2559     }
2560     CONTRACT_END;
2561
2562     _ASSERTE(GCHeapUtilities::IsGCInProgress());
2563
2564     SystemDomain* sysDomain = SystemDomain::System();
2565     if (sysDomain)
2566     {
2567         DWORD i;
2568         DWORD count = (DWORD) m_appDomainIdList.GetCount();
2569         for (i = 0 ; i < count ; i++)
2570         {
2571             AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2572             if (pAppDomain && pAppDomain->IsUserActive())
2573             {
2574                 pAppDomain->ResetSurvivedBytes();
2575             }
2576         }
2577     }
2578
2579     RETURN;
2580 }
2581
2582 ULONGLONG SystemDomain::GetADSurvivedBytes()
2583 {
2584     CONTRACTL
2585     {
2586         NOTHROW;
2587         GC_NOTRIGGER;
2588         MODE_ANY;
2589     }
2590     CONTRACTL_END;
2591
2592     SystemDomain* sysDomain = SystemDomain::System();
2593     ULONGLONG ullTotalADSurvived = 0;
2594     if (sysDomain)
2595     {
2596         DWORD i;
2597         DWORD count = (DWORD) m_appDomainIdList.GetCount();
2598         for (i = 0 ; i < count ; i++)
2599         {
2600             AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2601             if (pAppDomain && pAppDomain->IsUserActive())
2602             {
2603                 ULONGLONG ullSurvived = pAppDomain->GetSurvivedBytes();
2604                 ullTotalADSurvived += ullSurvived;
2605             }
2606         }
2607     }
2608
2609     return ullTotalADSurvived;
2610 }
2611
2612 void SystemDomain::RecordTotalSurvivedBytes(size_t totalSurvivedBytes)
2613 {
2614     CONTRACT_VOID
2615     {
2616         NOTHROW;
2617         GC_NOTRIGGER;
2618         MODE_ANY;
2619     }
2620     CONTRACT_END;
2621
2622     m_totalSurvivedBytes = totalSurvivedBytes;
2623
2624     SystemDomain* sysDomain = SystemDomain::System();
2625     if (sysDomain)
2626     {
2627         DWORD i;
2628         DWORD count = (DWORD) m_appDomainIdList.GetCount();
2629         for (i = 0 ; i < count ; i++)
2630         {
2631             AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2632             if (pAppDomain && pAppDomain->IsUserActive())
2633             {
2634                 FireEtwAppDomainMemSurvived((ULONGLONG)pAppDomain, pAppDomain->GetSurvivedBytes(), totalSurvivedBytes, GetClrInstanceId());
2635             }
2636         }
2637     }
2638
2639     RETURN;
2640 }
2641 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2642
2643 // Only called when EE is suspended.
2644 DWORD SystemDomain::GetTotalNumSizedRefHandles()
2645 {
2646     CONTRACTL
2647     {
2648         NOTHROW;
2649         GC_NOTRIGGER;
2650         MODE_ANY;
2651     }
2652     CONTRACTL_END;
2653
2654     SystemDomain* sysDomain = SystemDomain::System();
2655     DWORD dwTotalNumSizedRefHandles = 0;
2656     if (sysDomain)
2657     {
2658         DWORD i;
2659         DWORD count = (DWORD) m_appDomainIdList.GetCount();
2660         for (i = 0 ; i < count ; i++)
2661         {
2662             AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2663             if (pAppDomain && pAppDomain->IsActive() && !pAppDomain->IsUnloading())
2664             {
2665                 dwTotalNumSizedRefHandles += pAppDomain->GetNumSizedRefHandles();
2666             }
2667         }
2668     }
2669
2670     return dwTotalNumSizedRefHandles;
2671 }
2672 #endif // CROSSGEN_COMPILE
2673
2674 void SystemDomain::LoadBaseSystemClasses()
2675 {
2676     STANDARD_VM_CONTRACT;
2677
2678     ETWOnStartup(LdSysBases_V1, LdSysBasesEnd_V1);
2679
2680     {
2681         m_pSystemFile = PEAssembly::OpenSystem(NULL);
2682     }
2683     // Only partially load the system assembly. Other parts of the code will want to access
2684     // the globals in this function before finishing the load.
2685     m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemFile, FILE_LOAD_POST_LOADLIBRARY)->GetCurrentAssembly();
2686
2687     // Set up binder for mscorlib
2688     MscorlibBinder::AttachModule(m_pSystemAssembly->GetManifestModule());
2689
2690     // Load Object
2691     g_pObjectClass = MscorlibBinder::GetClass(CLASS__OBJECT);
2692
2693     // Now that ObjectClass is loaded, we can set up
2694     // the system for finalizers.  There is no point in deferring this, since we need
2695     // to know this before we allocate our first object.
2696     g_pObjectFinalizerMD = MscorlibBinder::GetMethod(METHOD__OBJECT__FINALIZE);
2697
2698
2699     g_pCanonMethodTableClass = MscorlibBinder::GetClass(CLASS____CANON);
2700
2701     // NOTE: !!!IMPORTANT!!! ValueType and Enum MUST be loaded one immediately after
2702     //                       the other, because we have coded MethodTable::IsChildValueType
2703     //                       in such a way that it depends on this behaviour.
2704     // Load the ValueType class
2705     g_pValueTypeClass = MscorlibBinder::GetClass(CLASS__VALUE_TYPE);
2706
2707     // Load the enum class
2708     g_pEnumClass = MscorlibBinder::GetClass(CLASS__ENUM);
2709     _ASSERTE(!g_pEnumClass->IsValueType());
2710
2711     // Load System.RuntimeType
2712     g_pRuntimeTypeClass = MscorlibBinder::GetClass(CLASS__CLASS);
2713     _ASSERTE(g_pRuntimeTypeClass->IsFullyLoaded());
2714
2715     // Load Array class
2716     g_pArrayClass = MscorlibBinder::GetClass(CLASS__ARRAY);
2717
2718     // Calling a method on IList<T> for an array requires redirection to a method on
2719     // the SZArrayHelper class. Retrieving such methods means calling
2720     // GetActualImplementationForArrayGenericIListMethod, which calls FetchMethod for
2721     // the corresponding method on SZArrayHelper. This basically results in a class
2722     // load due to a method call, which the debugger cannot handle, so we pre-load
2723     // the SZArrayHelper class here.
2724     g_pSZArrayHelperClass = MscorlibBinder::GetClass(CLASS__SZARRAYHELPER);
2725
2726     // Load ByReference class
2727     //
2728     // NOTE: ByReference<T> must be the first by-ref-like system type to be loaded,
2729     //       because MethodTable::ClassifyEightBytesWithManagedLayout depends on it.
2730     g_pByReferenceClass = MscorlibBinder::GetClass(CLASS__BYREFERENCE);
2731
2732     // Load Nullable class
2733     g_pNullableClass = MscorlibBinder::GetClass(CLASS__NULLABLE);
2734
2735     // Load the Object array class.
2736     g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pObjectClass)).AsArray();
2737
2738     // We have delayed allocation of mscorlib's static handles until we load the object class
2739     MscorlibBinder::GetModule()->AllocateRegularStaticHandles(DefaultDomain());
2740
2741     g_TypedReferenceMT = MscorlibBinder::GetClass(CLASS__TYPED_REFERENCE);
2742
2743     // Make sure all primitive types are loaded
2744     for (int et = ELEMENT_TYPE_VOID; et <= ELEMENT_TYPE_R8; et++)
2745         MscorlibBinder::LoadPrimitiveType((CorElementType)et);
2746
2747     MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_I);
2748     MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_U);
2749
2750     // unfortunately, the following cannot be delay loaded since the jit
2751     // uses it to compute method attributes within a function that cannot
2752     // handle Complus exception and the following call goes through a path
2753     // where a complus exception can be thrown. It is unfortunate, because
2754     // we know that the delegate class and multidelegate class are always
2755     // guaranteed to be found.
2756     g_pDelegateClass = MscorlibBinder::GetClass(CLASS__DELEGATE);
2757     g_pMulticastDelegateClass = MscorlibBinder::GetClass(CLASS__MULTICAST_DELEGATE);
2758
2759     // used by IsImplicitInterfaceOfSZArray
2760     MscorlibBinder::GetClass(CLASS__IENUMERABLEGENERIC);
2761     MscorlibBinder::GetClass(CLASS__ICOLLECTIONGENERIC);
2762     MscorlibBinder::GetClass(CLASS__ILISTGENERIC);
2763     MscorlibBinder::GetClass(CLASS__IREADONLYCOLLECTIONGENERIC);
2764     MscorlibBinder::GetClass(CLASS__IREADONLYLISTGENERIC);
2765
2766     // Load String
2767     g_pStringClass = MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_STRING);
2768     _ASSERTE(g_pStringClass->GetBaseSize() == ObjSizeOf(StringObject)+sizeof(WCHAR));
2769     _ASSERTE(g_pStringClass->GetComponentSize() == 2);
2770
2771     // Used by Buffer::BlockCopy
2772     g_pByteArrayMT = ClassLoader::LoadArrayTypeThrowing(
2773         TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1))).AsArray()->GetMethodTable();
2774
2775 #ifndef CROSSGEN_COMPILE
2776     ECall::PopulateManagedStringConstructors();
2777 #endif // CROSSGEN_COMPILE
2778
2779     g_pExceptionClass = MscorlibBinder::GetClass(CLASS__EXCEPTION);
2780     g_pOutOfMemoryExceptionClass = MscorlibBinder::GetException(kOutOfMemoryException);
2781     g_pStackOverflowExceptionClass = MscorlibBinder::GetException(kStackOverflowException);
2782     g_pExecutionEngineExceptionClass = MscorlibBinder::GetException(kExecutionEngineException);
2783     g_pThreadAbortExceptionClass = MscorlibBinder::GetException(kThreadAbortException);
2784
2785
2786     // used by gc to handle predefined agility checking
2787     g_pThreadClass = MscorlibBinder::GetClass(CLASS__THREAD);
2788
2789 #ifdef FEATURE_COMINTEROP
2790     g_pBaseCOMObject = MscorlibBinder::GetClass(CLASS__COM_OBJECT);
2791     g_pBaseRuntimeClass = MscorlibBinder::GetClass(CLASS__RUNTIME_CLASS);
2792     
2793     MscorlibBinder::GetClass(CLASS__IDICTIONARYGENERIC);
2794     MscorlibBinder::GetClass(CLASS__IREADONLYDICTIONARYGENERIC);
2795     MscorlibBinder::GetClass(CLASS__ATTRIBUTE);
2796     MscorlibBinder::GetClass(CLASS__EVENT_HANDLERGENERIC);
2797
2798     MscorlibBinder::GetClass(CLASS__IENUMERABLE);
2799     MscorlibBinder::GetClass(CLASS__ICOLLECTION);
2800     MscorlibBinder::GetClass(CLASS__ILIST);
2801     MscorlibBinder::GetClass(CLASS__IDISPOSABLE);
2802
2803 #ifdef _DEBUG
2804     WinRTInterfaceRedirector::VerifyRedirectedInterfaceStubs();
2805 #endif // _DEBUG
2806 #endif
2807
2808 #ifdef FEATURE_ICASTABLE
2809     g_pICastableInterface = MscorlibBinder::GetClass(CLASS__ICASTABLE);
2810 #endif // FEATURE_ICASTABLE
2811
2812     // Load a special marker method used to detect Constrained Execution Regions
2813     // at jit time.
2814     g_pExecuteBackoutCodeHelperMethod = MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__EXECUTE_BACKOUT_CODE_HELPER);
2815
2816     // Make sure that FCall mapping for Monitor.Enter is initialized. We need it in case Monitor.Enter is used only as JIT helper. 
2817     // For more details, see comment in code:JITutil_MonEnterWorker around "__me = GetEEFuncEntryPointMacro(JIT_MonEnter)".
2818     ECall::GetFCallImpl(MscorlibBinder::GetMethod(METHOD__MONITOR__ENTER));
2819
2820 #ifdef PROFILING_SUPPORTED
2821     // Note that g_profControlBlock.fBaseSystemClassesLoaded must be set to TRUE only after
2822     // all base system classes are loaded.  Profilers are not allowed to call any type-loading
2823     // APIs until g_profControlBlock.fBaseSystemClassesLoaded is TRUE.  It is important that
2824     // all base system classes need to be loaded before profilers can trigger the type loading.
2825     g_profControlBlock.fBaseSystemClassesLoaded = TRUE;
2826 #endif // PROFILING_SUPPORTED
2827
2828 #if defined(_DEBUG) && !defined(CROSSGEN_COMPILE)
2829     if (!NingenEnabled())
2830     {
2831         g_Mscorlib.Check();
2832     }
2833 #endif
2834
2835 #if defined(HAVE_GCCOVER) && defined(FEATURE_PREJIT)
2836     if (GCStress<cfg_instr_ngen>::IsEnabled())
2837     {
2838         // Setting up gc coverage requires the base system classes
2839         //  to be initialized. So we have deferred it until now for mscorlib.
2840         Module *pModule = MscorlibBinder::GetModule();
2841         _ASSERTE(pModule->IsSystem());
2842         if(pModule->HasNativeImage())
2843         {
2844             SetupGcCoverageForNativeImage(pModule);
2845         }
2846     }
2847 #endif // defined(HAVE_GCCOVER) && !defined(FEATURE_PREJIT)
2848 }
2849
2850 /*static*/
2851 void SystemDomain::LoadDomain(AppDomain *pDomain)
2852 {
2853     CONTRACTL
2854     {
2855         THROWS;
2856         GC_TRIGGERS;
2857         MODE_ANY;
2858         PRECONDITION(CheckPointer(System()));
2859         INJECT_FAULT(COMPlusThrowOM(););
2860     }
2861     CONTRACTL_END;
2862
2863     pDomain->SetCanUnload();    // by default can unload any domain
2864     SystemDomain::System()->AddDomain(pDomain);
2865 }
2866
2867 ADIndex SystemDomain::GetNewAppDomainIndex(AppDomain *pAppDomain)
2868 {
2869     STANDARD_VM_CONTRACT;
2870
2871     DWORD count = m_appDomainIndexList.GetCount();
2872     DWORD i;
2873
2874 #ifdef _DEBUG
2875     if (count < 2000)
2876     {
2877         // So that we can keep AD index inside object header.
2878         // We do not want to create syncblock unless needed.
2879         i = count;
2880     }
2881     else
2882     {
2883 #endif // _DEBUG
2884         //
2885         // Look for an unused index.  Note that in a checked build,
2886         // we never reuse indexes - this makes it easier to tell
2887         // when we are looking at a stale app domain.
2888         //
2889
2890         i = m_appDomainIndexList.FindElement(m_dwLowestFreeIndex, NULL);
2891         if (i == (DWORD) ArrayList::NOT_FOUND)
2892             i = count;
2893         m_dwLowestFreeIndex = i+1;
2894 #ifdef _DEBUG
2895         if (m_dwLowestFreeIndex >= 2000)
2896         {
2897             m_dwLowestFreeIndex = 0;
2898         }
2899     }
2900 #endif // _DEBUG
2901
2902     if (i == count)
2903         IfFailThrow(m_appDomainIndexList.Append(pAppDomain));
2904     else
2905         m_appDomainIndexList.Set(i, pAppDomain);
2906
2907     _ASSERTE(i < m_appDomainIndexList.GetCount());
2908
2909     // Note that index 0 means domain agile.
2910     return ADIndex(i+1);
2911 }
2912
2913 void SystemDomain::ReleaseAppDomainIndex(ADIndex index)
2914 {
2915     WRAPPER_NO_CONTRACT;
2916     SystemDomain::LockHolder lh;
2917     // Note that index 0 means domain agile.
2918     index.m_dwIndex--;
2919
2920     _ASSERTE(m_appDomainIndexList.Get(index.m_dwIndex) != NULL);
2921
2922     m_appDomainIndexList.Set(index.m_dwIndex, NULL);
2923
2924 #ifndef _DEBUG
2925     if (index.m_dwIndex < m_dwLowestFreeIndex)
2926         m_dwLowestFreeIndex = index.m_dwIndex;
2927 #endif // !_DEBUG
2928 }
2929
2930 #endif // !DACCESS_COMPILE
2931
2932 PTR_AppDomain SystemDomain::GetAppDomainAtIndex(ADIndex index)
2933 {
2934     LIMITED_METHOD_CONTRACT;
2935     SUPPORTS_DAC;
2936     _ASSERTE(index.m_dwIndex != 0);
2937
2938     PTR_AppDomain pAppDomain = TestGetAppDomainAtIndex(index);
2939
2940     _ASSERTE(pAppDomain || !"Attempt to access unloaded app domain");
2941
2942     return pAppDomain;
2943 }
2944
2945 PTR_AppDomain SystemDomain::TestGetAppDomainAtIndex(ADIndex index)
2946 {
2947     LIMITED_METHOD_CONTRACT;
2948     SUPPORTS_DAC;
2949     _ASSERTE(index.m_dwIndex != 0);
2950     index.m_dwIndex--;
2951
2952 #ifndef DACCESS_COMPILE
2953     _ASSERTE(index.m_dwIndex < (DWORD)m_appDomainIndexList.GetCount());
2954     AppDomain *pAppDomain = (AppDomain*) m_appDomainIndexList.Get(index.m_dwIndex);
2955 #else // DACCESS_COMPILE
2956     PTR_ArrayListStatic pList = &m_appDomainIndexList;
2957     AppDomain *pAppDomain = dac_cast<PTR_AppDomain>(pList->Get(index.m_dwIndex));
2958 #endif // DACCESS_COMPILE
2959     return PTR_AppDomain(pAppDomain);
2960 }
2961
2962 #ifndef DACCESS_COMPILE
2963
2964 // See also code:SystemDomain::ReleaseAppDomainId
2965 ADID SystemDomain::GetNewAppDomainId(AppDomain *pAppDomain)
2966 {
2967     CONTRACTL
2968     {
2969         THROWS;
2970         GC_TRIGGERS;
2971         MODE_ANY;
2972         INJECT_FAULT(COMPlusThrowOM(););
2973     }
2974     CONTRACTL_END;
2975
2976     DWORD i = m_appDomainIdList.GetCount();
2977
2978     IfFailThrow(m_appDomainIdList.Append(pAppDomain));
2979
2980     _ASSERTE(i < m_appDomainIdList.GetCount());
2981
2982     return ADID(i+1);
2983 }
2984
2985 AppDomain *SystemDomain::GetAppDomainAtId(ADID index)
2986 {
2987     CONTRACTL
2988     {
2989 #ifdef _DEBUG
2990         if (!SystemDomain::IsUnderDomainLock() && !IsGCThread()) { MODE_COOPERATIVE;} else { DISABLED(MODE_ANY);}
2991 #endif
2992         GC_NOTRIGGER;
2993         SO_TOLERANT;
2994         NOTHROW;
2995     }
2996     CONTRACTL_END;
2997
2998     if(index.m_dwId == 0)
2999         return NULL;
3000     DWORD requestedID = index.m_dwId - 1;
3001
3002     if(requestedID  >= (DWORD)m_appDomainIdList.GetCount())
3003         return NULL;
3004
3005     AppDomain * result = (AppDomain *)m_appDomainIdList.Get(requestedID);
3006
3007 #ifndef CROSSGEN_COMPILE
3008     if(result==NULL && GetThread() == FinalizerThread::GetFinalizerThread() &&
3009         SystemDomain::System()->AppDomainBeingUnloaded()!=NULL &&
3010         SystemDomain::System()->AppDomainBeingUnloaded()->GetId()==index)
3011         result=SystemDomain::System()->AppDomainBeingUnloaded();
3012     // If the current thread can't enter the AppDomain, then don't return it.
3013     if (!result || !result->CanThreadEnter(GetThread()))
3014         return NULL;
3015 #endif // CROSSGEN_COMPILE
3016
3017     return result;
3018 }
3019
3020 // Releases an appdomain index.   Note that today we have code that depends on these
3021 // indexes not being recycled, so we don't actually shrink m_appDomainIdList, but 
3022 // simply zero out an entry.   THus we 'leak' the memory associated the slot in
3023 // m_appDomainIdList.  
3024 // 
3025 // TODO make this a sparse structure so that we avoid that leak.  
3026 //
3027 void SystemDomain::ReleaseAppDomainId(ADID index)
3028 {
3029     LIMITED_METHOD_CONTRACT;
3030     index.m_dwId--;
3031
3032     _ASSERTE(index.m_dwId < (DWORD)m_appDomainIdList.GetCount());
3033
3034     m_appDomainIdList.Set(index.m_dwId, NULL);
3035 }
3036
3037 #if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3038
3039 #ifdef _DEBUG
3040 int g_fMainThreadApartmentStateSet = 0;
3041 #endif
3042
3043 Thread::ApartmentState SystemDomain::GetEntryPointThreadAptState(IMDInternalImport* pScope, mdMethodDef mdMethod)
3044 {
3045     STANDARD_VM_CONTRACT;
3046
3047     HRESULT hr;
3048     IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
3049                                                       DEFAULTDOMAIN_MTA_TYPE,
3050                                                       NULL,
3051                                                       NULL));
3052     BOOL fIsMTA = FALSE;
3053     if(hr == S_OK)
3054         fIsMTA = TRUE;
3055
3056     IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
3057                                                       DEFAULTDOMAIN_STA_TYPE,
3058                                                       NULL,
3059                                                       NULL));
3060     BOOL fIsSTA = FALSE;
3061     if (hr == S_OK)
3062         fIsSTA = TRUE;
3063
3064     if (fIsSTA && fIsMTA)
3065         COMPlusThrowHR(COR_E_CUSTOMATTRIBUTEFORMAT);
3066
3067     if (fIsSTA)
3068         return Thread::AS_InSTA;
3069     else if (fIsMTA)
3070         return Thread::AS_InMTA;
3071
3072     return Thread::AS_Unknown;
3073 }
3074
3075 void SystemDomain::SetThreadAptState (Thread::ApartmentState state)
3076 {
3077     STANDARD_VM_CONTRACT;
3078
3079     Thread* pThread = GetThread();
3080     _ASSERTE(pThread);
3081
3082     if(state == Thread::AS_InSTA)
3083     {
3084         Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InSTA, TRUE);
3085         _ASSERTE(pState == Thread::AS_InSTA);
3086     }
3087     else if (state == Thread::AS_InMTA)
3088     {
3089         Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InMTA, TRUE);
3090         _ASSERTE(pState == Thread::AS_InMTA);
3091     }
3092
3093 #ifdef _DEBUG
3094     g_fMainThreadApartmentStateSet++;
3095 #endif
3096 }
3097 #endif // defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
3098
3099 // Looks in all the modules for the DefaultDomain attribute
3100 // The order is assembly and then the modules. It is first
3101 // come, first serve.
3102 BOOL SystemDomain::SetGlobalSharePolicyUsingAttribute(IMDInternalImport* pScope, mdMethodDef mdMethod)
3103 {
3104     STANDARD_VM_CONTRACT;
3105
3106
3107     return FALSE;
3108 }
3109
3110 void SystemDomain::SetupDefaultDomain()
3111 {
3112     CONTRACT_VOID
3113     {
3114         THROWS;
3115         GC_TRIGGERS;
3116         MODE_ANY;
3117         INJECT_FAULT(COMPlusThrowOM(););
3118     }
3119     CONTRACT_END;
3120
3121
3122     Thread *pThread = GetThread();
3123     _ASSERTE(pThread);
3124
3125     AppDomain *pDomain;
3126     pDomain = pThread->GetDomain();
3127     _ASSERTE(pDomain);
3128
3129     GCX_COOP();
3130
3131     ENTER_DOMAIN_PTR(SystemDomain::System()->DefaultDomain(),ADV_DEFAULTAD)
3132     {
3133         // Push this frame around loading the main assembly to ensure the
3134         // debugger can properly recgonize any managed code that gets run
3135         // as "class initializaion" code.
3136         FrameWithCookie<DebuggerClassInitMarkFrame> __dcimf;
3137
3138         {
3139             GCX_PREEMP();
3140             InitializeDefaultDomain(TRUE);
3141         }
3142
3143         __dcimf.Pop();
3144     }
3145     END_DOMAIN_TRANSITION;
3146
3147     RETURN;
3148 }
3149
3150 HRESULT SystemDomain::SetupDefaultDomainNoThrow()
3151 {
3152     CONTRACTL
3153     {
3154         NOTHROW;
3155         MODE_ANY;
3156     }
3157     CONTRACTL_END;
3158
3159     HRESULT hr = S_OK;
3160
3161     EX_TRY
3162     {
3163         SystemDomain::SetupDefaultDomain();
3164     }
3165     EX_CATCH_HRESULT(hr);
3166
3167     return hr;
3168 }
3169
3170 #ifdef _DEBUG
3171 int g_fInitializingInitialAD = 0;
3172 #endif
3173
3174 // This routine completes the initialization of the default domaine.
3175 // After this call mananged code can be executed.
3176 void SystemDomain::InitializeDefaultDomain(
3177     BOOL allowRedirects,
3178     ICLRPrivBinder * pBinder)
3179 {
3180     STANDARD_VM_CONTRACT;
3181
3182     WCHAR* pwsConfig = NULL;
3183     WCHAR* pwsPath = NULL;
3184
3185     ETWOnStartup (InitDefaultDomain_V1, InitDefaultDomainEnd_V1);
3186
3187
3188     // Setup the default AppDomain.
3189
3190 #ifdef _DEBUG
3191     g_fInitializingInitialAD++;
3192 #endif
3193
3194     AppDomain* pDefaultDomain = SystemDomain::System()->DefaultDomain();
3195
3196     if (pBinder != nullptr)
3197     {
3198         pDefaultDomain->SetLoadContextHostBinder(pBinder);
3199     }
3200
3201     {
3202         GCX_COOP();
3203
3204         pDefaultDomain->InitializeDomainContext(allowRedirects, pwsPath, pwsConfig);
3205
3206 #ifndef CROSSGEN_COMPILE
3207         if (!NingenEnabled())
3208         {
3209     
3210             if (!IsSingleAppDomain())
3211             {
3212                 pDefaultDomain->InitializeDefaultDomainManager();
3213             }
3214         }
3215 #endif // CROSSGEN_COMPILE
3216     }
3217
3218     // DefaultDomain Load event
3219     ETW::LoaderLog::DomainLoad(pDefaultDomain);
3220
3221 #ifdef _DEBUG
3222     g_fInitializingInitialAD--;
3223 #endif
3224
3225     TESTHOOKCALL(RuntimeStarted(RTS_DEFAULTADREADY));
3226 }
3227
3228
3229
3230 #ifndef CROSSGEN_COMPILE
3231
3232 #ifdef _DEBUG
3233 Volatile<LONG> g_fInExecuteMainMethod = 0;
3234 #endif
3235
3236
3237
3238
3239 #endif // CROSSGEN_COMPILE
3240
3241
3242
3243 // Helper function to load an assembly. This is called from LoadCOMClass.
3244 /* static */
3245
3246 Assembly *AppDomain::LoadAssemblyHelper(LPCWSTR wszAssembly,
3247                                         LPCWSTR wszCodeBase)
3248 {
3249     CONTRACT(Assembly *)
3250     {
3251         THROWS;
3252         POSTCONDITION(CheckPointer(RETVAL));
3253         PRECONDITION(wszAssembly || wszCodeBase);
3254         INJECT_FAULT(COMPlusThrowOM(););
3255     }
3256     CONTRACT_END;
3257
3258     AssemblySpec spec;
3259     if(wszAssembly) {
3260         #define MAKE_TRANSLATIONFAILED  { ThrowOutOfMemory(); }
3261         MAKE_UTF8PTR_FROMWIDE(szAssembly,wszAssembly);
3262         #undef  MAKE_TRANSLATIONFAILED
3263        
3264         IfFailThrow(spec.Init(szAssembly));
3265     }
3266
3267     if (wszCodeBase) {
3268         spec.SetCodeBase(wszCodeBase);
3269     }
3270     RETURN spec.LoadAssembly(FILE_LOADED);
3271 }
3272
3273 #if defined(FEATURE_CLASSIC_COMINTEROP) && !defined(CROSSGEN_COMPILE)
3274
3275 MethodTable *AppDomain::LoadCOMClass(GUID clsid,
3276                                      BOOL bLoadRecord/*=FALSE*/,
3277                                      BOOL* pfAssemblyInReg/*=NULL*/)
3278 {
3279     // @CORESYSTODO: what to do here?
3280     return NULL;
3281 }
3282
3283 #endif // FEATURE_CLASSIC_COMINTEROP && !CROSSGEN_COMPILE
3284
3285
3286 /*static*/
3287 bool SystemDomain::IsReflectionInvocationMethod(MethodDesc* pMeth)
3288 {
3289     CONTRACTL
3290     {
3291         THROWS;
3292         GC_TRIGGERS;
3293         MODE_ANY;
3294     }
3295     CONTRACTL_END;
3296
3297     MethodTable* pCaller = pMeth->GetMethodTable();
3298
3299     // All Reflection Invocation methods are defined in mscorlib.dll
3300     if (!pCaller->GetModule()->IsSystem())
3301         return false;
3302
3303     /* List of types that should be skipped to identify true caller */
3304     static const BinderClassID reflectionInvocationTypes[] = {
3305         CLASS__METHOD,
3306         CLASS__METHOD_BASE,
3307         CLASS__METHOD_INFO,
3308         CLASS__CONSTRUCTOR,
3309         CLASS__CONSTRUCTOR_INFO,
3310         CLASS__CLASS,
3311         CLASS__TYPE_HANDLE,
3312         CLASS__METHOD_HANDLE,
3313         CLASS__FIELD_HANDLE,
3314         CLASS__TYPE,
3315         CLASS__FIELD,
3316         CLASS__RT_FIELD_INFO,
3317         CLASS__FIELD_INFO,
3318         CLASS__EVENT,
3319         CLASS__EVENT_INFO,
3320         CLASS__PROPERTY,
3321         CLASS__PROPERTY_INFO,
3322         CLASS__ACTIVATOR,
3323         CLASS__ARRAY,
3324         CLASS__ASSEMBLYBASE,
3325         CLASS__ASSEMBLY,
3326         CLASS__TYPE_DELEGATOR,
3327         CLASS__RUNTIME_HELPERS,
3328         CLASS__LAZY_INITIALIZER,
3329         CLASS__DYNAMICMETHOD,
3330         CLASS__DELEGATE,
3331         CLASS__MULTICAST_DELEGATE,
3332         CLASS__APP_DOMAIN
3333     };
3334
3335     static const BinderClassID genericReflectionInvocationTypes[] = {
3336         CLASS__LAZY
3337     };
3338
3339     static mdTypeDef genericReflectionInvocationTypeDefs[NumItems(genericReflectionInvocationTypes)];
3340
3341     static bool fInited = false;
3342
3343     if (!VolatileLoad(&fInited))
3344     {
3345         // Make sure all types are loaded so that we can use faster GetExistingClass()
3346         for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3347         {
3348             MscorlibBinder::GetClass(reflectionInvocationTypes[i]);
3349         }
3350
3351         // Make sure all types are loaded so that we can use faster GetExistingClass()
3352         for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypes); i++)
3353         {
3354             genericReflectionInvocationTypeDefs[i] = MscorlibBinder::GetClass(genericReflectionInvocationTypes[i])->GetCl();
3355         }
3356
3357         MscorlibBinder::GetClass(CLASS__APP_DOMAIN);
3358
3359         VolatileStore(&fInited, true);
3360     }
3361
3362     if (pCaller->HasInstantiation())
3363     {
3364         // For generic types, pCaller will be an instantiated type and never equal to the type definition.
3365         // So we compare their TypeDef tokens instead.
3366         for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypeDefs); i++)
3367         {
3368             if (pCaller->GetCl() == genericReflectionInvocationTypeDefs[i])
3369                 return true;
3370         }
3371     }
3372     else
3373     {
3374         for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3375         {
3376             if (MscorlibBinder::GetExistingClass(reflectionInvocationTypes[i]) == pCaller)
3377                 return true;
3378         }
3379     }
3380
3381     return false;
3382 }
3383
3384 #ifndef CROSSGEN_COMPILE
3385 struct CallersDataWithStackMark
3386 {
3387     StackCrawlMark* stackMark;
3388     BOOL foundMe;
3389     MethodDesc* pFoundMethod;
3390     MethodDesc* pPrevMethod;
3391     AppDomain*  pAppDomain;
3392 };
3393
3394 /*static*/
3395 MethodDesc* SystemDomain::GetCallersMethod(StackCrawlMark* stackMark,
3396                                            AppDomain **ppAppDomain/*=NULL*/)
3397
3398 {
3399     CONTRACTL
3400     {
3401         THROWS;
3402         GC_TRIGGERS;
3403         MODE_ANY;
3404         INJECT_FAULT(COMPlusThrowOM(););
3405     }
3406     CONTRACTL_END;
3407
3408     GCX_COOP();
3409
3410     CallersDataWithStackMark cdata;
3411     ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3412     cdata.stackMark = stackMark;
3413
3414     GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3415
3416     if(cdata.pFoundMethod) {
3417         if (ppAppDomain)
3418             *ppAppDomain = cdata.pAppDomain;
3419         return cdata.pFoundMethod;
3420     } else
3421         return NULL;
3422 }
3423
3424 /*static*/
3425 MethodTable* SystemDomain::GetCallersType(StackCrawlMark* stackMark,
3426                                           AppDomain **ppAppDomain/*=NULL*/)
3427
3428 {
3429     CONTRACTL
3430     {
3431         THROWS;
3432         GC_TRIGGERS;
3433         MODE_COOPERATIVE;
3434         INJECT_FAULT(COMPlusThrowOM(););
3435     }
3436     CONTRACTL_END;
3437
3438     CallersDataWithStackMark cdata;
3439     ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3440     cdata.stackMark = stackMark;
3441
3442     GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3443
3444     if(cdata.pFoundMethod) {
3445         if (ppAppDomain)
3446             *ppAppDomain = cdata.pAppDomain;
3447         return cdata.pFoundMethod->GetMethodTable();
3448     } else
3449         return NULL;
3450 }
3451
3452 /*static*/
3453 Module* SystemDomain::GetCallersModule(StackCrawlMark* stackMark,
3454                                        AppDomain **ppAppDomain/*=NULL*/)
3455
3456 {
3457     CONTRACTL
3458     {
3459         THROWS;
3460         GC_TRIGGERS;
3461         MODE_ANY;
3462         INJECT_FAULT(COMPlusThrowOM(););
3463     }
3464     CONTRACTL_END;
3465
3466     GCX_COOP();
3467
3468     CallersDataWithStackMark cdata;
3469     ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3470     cdata.stackMark = stackMark;
3471
3472     GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3473
3474     if(cdata.pFoundMethod) {
3475         if (ppAppDomain)
3476             *ppAppDomain = cdata.pAppDomain;
3477         return cdata.pFoundMethod->GetModule();
3478     } else
3479         return NULL;
3480 }
3481
3482 struct CallersData
3483 {
3484     int skip;
3485     MethodDesc* pMethod;
3486 };
3487
3488 /*static*/
3489 Assembly* SystemDomain::GetCallersAssembly(StackCrawlMark *stackMark,
3490                                            AppDomain **ppAppDomain/*=NULL*/)
3491 {
3492     WRAPPER_NO_CONTRACT;
3493     Module* mod = GetCallersModule(stackMark, ppAppDomain);
3494     if (mod)
3495         return mod->GetAssembly();
3496     return NULL;
3497 }
3498
3499 /*static*/
3500 Module* SystemDomain::GetCallersModule(int skip)
3501 {
3502     CONTRACTL
3503     {
3504         THROWS;
3505         GC_TRIGGERS;
3506         MODE_ANY;
3507         INJECT_FAULT(COMPlusThrowOM(););
3508     }
3509     CONTRACTL_END;
3510
3511     GCX_COOP();
3512
3513     CallersData cdata;
3514     ZeroMemory(&cdata, sizeof(CallersData));
3515     cdata.skip = skip;
3516
3517     StackWalkFunctions(GetThread(), CallersMethodCallback, &cdata);
3518
3519     if(cdata.pMethod)
3520         return cdata.pMethod->GetModule();
3521     else
3522         return NULL;
3523 }
3524
3525 /*private static*/
3526 StackWalkAction SystemDomain::CallersMethodCallbackWithStackMark(CrawlFrame* pCf, VOID* data)
3527 {
3528     CONTRACTL
3529     {
3530         THROWS;
3531         GC_TRIGGERS;
3532         MODE_COOPERATIVE;
3533         SO_INTOLERANT;
3534         INJECT_FAULT(COMPlusThrowOM(););
3535     }
3536     CONTRACTL_END;
3537
3538
3539     MethodDesc *pFunc = pCf->GetFunction();
3540
3541     /* We asked to be called back only for functions */
3542     _ASSERTE(pFunc);
3543
3544     CallersDataWithStackMark* pCaller = (CallersDataWithStackMark*) data;
3545     if (pCaller->stackMark)
3546     {
3547         if (!pCf->IsInCalleesFrames(pCaller->stackMark))
3548         {
3549             // save the current in case it is the one we want
3550             pCaller->pPrevMethod = pFunc;
3551             pCaller->pAppDomain = pCf->GetAppDomain();
3552             return SWA_CONTINUE;
3553         }
3554
3555         // LookForMe stack crawl marks needn't worry about reflection or
3556         // remoting frames on the stack. Each frame above (newer than) the
3557         // target will be captured by the logic above. Once we transition to
3558         // finding the stack mark below the AofRA, we know that we hit the
3559         // target last time round and immediately exit with the cached result.
3560
3561         if (*(pCaller->stackMark) == LookForMe)
3562         {
3563             pCaller->pFoundMethod = pCaller->pPrevMethod;
3564             return SWA_ABORT;
3565         }
3566     }
3567
3568     // Skip reflection and remoting frames that could lie between a stack marked
3569     // method and its true caller (or that caller and its own caller). These
3570     // frames are infrastructure and logically transparent to the stack crawling
3571     // algorithm.
3572
3573     // Skipping remoting frames. We always skip entire client to server spans
3574     // (though we see them in the order server then client during a stack crawl
3575     // obviously).
3576
3577     // We spot the server dispatcher end because all calls are dispatched
3578     // through a single method: StackBuilderSink._PrivateProcessMessage.
3579
3580     Frame* frame = pCf->GetFrame();
3581     _ASSERTE(pCf->IsFrameless() || frame);
3582
3583
3584
3585     // Skipping reflection frames. We don't need to be quite as exhaustive here
3586     // as the security or reflection stack walking code since we know this logic
3587     // is only invoked for selected methods in mscorlib itself. So we're
3588     // reasonably sure we won't have any sensitive methods late bound invoked on
3589     // constructors, properties or events. This leaves being invoked via
3590     // MethodInfo, Type or Delegate (and depending on which invoke overload is
3591     // being used, several different reflection classes may be involved).
3592
3593     g_IBCLogger.LogMethodDescAccess(pFunc);
3594
3595     if (SystemDomain::IsReflectionInvocationMethod(pFunc))
3596         return SWA_CONTINUE;
3597
3598     if (frame && frame->GetFrameType() == Frame::TYPE_MULTICAST)
3599     {
3600         // This must be either a secure delegate frame or a true multicast delegate invocation.
3601
3602         _ASSERTE(pFunc->GetMethodTable()->IsDelegate());
3603
3604         DELEGATEREF del = (DELEGATEREF)((SecureDelegateFrame*)frame)->GetThis(); // This can throw.
3605
3606         if (COMDelegate::IsSecureDelegate(del))
3607         {
3608             if (del->IsWrapperDelegate())
3609             {
3610                 // On ARM, we use secure delegate infrastructure to preserve R4 register.
3611                 return SWA_CONTINUE;
3612             }
3613             // For a secure delegate frame, we should return the delegate creator instead
3614             // of the delegate method itself.
3615             pFunc = (MethodDesc*) del->GetMethodPtrAux();
3616         }
3617         else
3618         {
3619             _ASSERTE(COMDelegate::IsTrueMulticastDelegate(del));
3620             return SWA_CONTINUE;
3621         }
3622     }
3623
3624     // Return the first non-reflection/remoting frame if no stack mark was
3625     // supplied.
3626     if (!pCaller->stackMark)
3627     {
3628         pCaller->pFoundMethod = pFunc;
3629         pCaller->pAppDomain = pCf->GetAppDomain();
3630         return SWA_ABORT;
3631     }
3632
3633     // If we got here, we must already be in the frame containing the stack mark and we are not looking for "me".
3634     _ASSERTE(pCaller->stackMark &&
3635              pCf->IsInCalleesFrames(pCaller->stackMark) &&
3636              *(pCaller->stackMark) != LookForMe);
3637
3638     // When looking for caller's caller, we delay returning results for another
3639     // round (the way this is structured, we will still be able to skip
3640     // reflection and remoting frames between the caller and the caller's
3641     // caller).
3642
3643     if ((*(pCaller->stackMark) == LookForMyCallersCaller) &&
3644         (pCaller->pFoundMethod == NULL))
3645     {
3646         pCaller->pFoundMethod = pFunc;
3647         return SWA_CONTINUE;
3648     }
3649
3650     // If remoting is not available, we only set the caller if the crawlframe is from the same domain.
3651     // Why? Because if the callerdomain is different from current domain,
3652     // there have to be interop/native frames in between.
3653     // For example, in the CORECLR, if we find the caller to be in a different domain, then the 
3654     // call into reflection is due to an unmanaged call into mscorlib. For that
3655     // case, the caller really is an INTEROP method.
3656     // In general, if the caller is INTEROP, we set the caller/callerdomain to be NULL 
3657     // (To be precise: they are already NULL and we don't change them).
3658     if (pCf->GetAppDomain() == GetAppDomain())
3659     // We must either be looking for the caller, or the caller's caller when
3660     // we've already found the caller (we used a non-null value in pFoundMethod
3661     // simply as a flag, the correct method to return in both case is the
3662     // current method).
3663     {
3664         pCaller->pFoundMethod = pFunc;
3665         pCaller->pAppDomain = pCf->GetAppDomain();
3666     }
3667
3668     return SWA_ABORT;
3669 }
3670
3671 /*private static*/
3672 StackWalkAction SystemDomain::CallersMethodCallback(CrawlFrame* pCf, VOID* data)
3673 {
3674     LIMITED_METHOD_CONTRACT;
3675     STATIC_CONTRACT_SO_TOLERANT;
3676     MethodDesc *pFunc = pCf->GetFunction();
3677
3678     /* We asked to be called back only for functions */
3679     _ASSERTE(pFunc);
3680
3681     CallersData* pCaller = (CallersData*) data;
3682     if(pCaller->skip == 0) {
3683         pCaller->pMethod = pFunc;
3684         return SWA_ABORT;
3685     }
3686     else {
3687         pCaller->skip--;
3688         return SWA_CONTINUE;
3689     }
3690
3691 }
3692 #endif // CROSSGEN_COMPILE
3693
3694 #ifdef CROSSGEN_COMPILE
3695 // defined in compile.cpp
3696 extern CompilationDomain * theDomain;
3697 #endif
3698
3699 void SystemDomain::CreateDefaultDomain()
3700 {
3701     STANDARD_VM_CONTRACT;
3702
3703 #ifdef CROSSGEN_COMPILE
3704     AppDomainRefHolder pDomain(theDomain);
3705 #else
3706     AppDomainRefHolder pDomain(new AppDomain());
3707 #endif
3708
3709     SystemDomain::LockHolder lh;
3710     pDomain->Init();
3711
3712     // need to make this assignment here since we'll be releasing
3713     // the lock before calling AddDomain. So any other thread
3714     // grabbing this lock after we release it will find that
3715     // the COM Domain has already been created
3716     m_pDefaultDomain = pDomain;
3717     _ASSERTE (pDomain->GetId().m_dwId == DefaultADID);
3718
3719     // allocate a Virtual Call Stub Manager for the default domain
3720     m_pDefaultDomain->InitVSD();
3721
3722     pDomain->SetStage(AppDomain::STAGE_OPEN);
3723     pDomain.SuppressRelease();
3724
3725     LOG((LF_CLASSLOADER | LF_CORDB,
3726          LL_INFO10,
3727          "Created default domain at %p\n", m_pDefaultDomain));
3728 }
3729
3730 #ifdef DEBUGGING_SUPPORTED
3731
3732 void SystemDomain::PublishAppDomainAndInformDebugger (AppDomain *pDomain)
3733 {
3734     CONTRACTL
3735     {
3736         if(!g_fEEInit) {THROWS;} else {DISABLED(NOTHROW);};
3737         if(!g_fEEInit) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);};
3738         MODE_ANY;
3739     }
3740     CONTRACTL_END;
3741
3742     LOG((LF_CORDB, LL_INFO100, "SD::PADAID: Adding 0x%x\n", pDomain));
3743
3744     // Call the publisher API to add this appdomain entry to the list
3745     // The publisher will handle failures, so we don't care if this succeeds or fails.
3746     if (g_pDebugInterface != NULL)
3747     {
3748         g_pDebugInterface->AddAppDomainToIPC(pDomain);
3749     }
3750 }
3751
3752 #endif // DEBUGGING_SUPPORTED
3753
3754 void SystemDomain::AddDomain(AppDomain* pDomain)
3755 {
3756     CONTRACTL
3757     {
3758         NOTHROW;
3759         MODE_ANY;
3760         GC_TRIGGERS;
3761         PRECONDITION(CheckPointer((pDomain)));
3762     }
3763     CONTRACTL_END;
3764
3765     {
3766         LockHolder lh;
3767
3768         _ASSERTE (pDomain->m_Stage != AppDomain::STAGE_CREATING);
3769         if (pDomain->m_Stage == AppDomain::STAGE_READYFORMANAGEDCODE ||
3770             pDomain->m_Stage == AppDomain::STAGE_ACTIVE)
3771         {
3772             pDomain->SetStage(AppDomain::STAGE_OPEN);
3773             IncrementNumAppDomains(); // Maintain a count of app domains added to the list.
3774         }
3775     }
3776
3777     // Note that if you add another path that can reach here without calling
3778     // PublishAppDomainAndInformDebugger, then you should go back & make sure
3779     // that PADAID gets called.  Right after this call, if not sooner.
3780     LOG((LF_CORDB, LL_INFO1000, "SD::AD:Would have added domain here! 0x%x\n",
3781         pDomain));
3782 }
3783
3784 BOOL SystemDomain::RemoveDomain(AppDomain* pDomain)
3785 {
3786     CONTRACTL
3787     {
3788         NOTHROW;
3789         GC_TRIGGERS;
3790         MODE_ANY;
3791         PRECONDITION(CheckPointer(pDomain));
3792         PRECONDITION(!pDomain->IsDefaultDomain());    
3793     }
3794     CONTRACTL_END;
3795
3796     // You can not remove the default domain.
3797
3798
3799     if (!pDomain->IsActive())
3800         return FALSE;
3801
3802     pDomain->Release();
3803
3804     return TRUE;
3805 }
3806
3807
3808 #ifdef PROFILING_SUPPORTED
3809 void SystemDomain::NotifyProfilerStartup()
3810 {
3811     CONTRACTL
3812     {
3813         NOTHROW;
3814         GC_TRIGGERS;
3815         MODE_PREEMPTIVE;
3816     }
3817     CONTRACTL_END;
3818
3819     {
3820         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3821         _ASSERTE(System());
3822         g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System());
3823         END_PIN_PROFILER();
3824     }
3825
3826     {
3827         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3828         _ASSERTE(System());
3829         g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System(), S_OK);
3830         END_PIN_PROFILER();
3831     }
3832
3833     {
3834         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3835         _ASSERTE(System()->DefaultDomain());
3836         g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System()->DefaultDomain());
3837         END_PIN_PROFILER();
3838     }
3839
3840     {
3841         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3842         _ASSERTE(System()->DefaultDomain());
3843         g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3844         END_PIN_PROFILER();
3845     }
3846
3847     {
3848         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3849         _ASSERTE(SharedDomain::GetDomain());
3850         g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) SharedDomain::GetDomain());
3851         END_PIN_PROFILER();
3852     }
3853
3854     {
3855         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3856         _ASSERTE(SharedDomain::GetDomain());
3857         g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) SharedDomain::GetDomain(), S_OK);
3858         END_PIN_PROFILER();
3859     }
3860 }
3861
3862 HRESULT SystemDomain::NotifyProfilerShutdown()
3863 {
3864     CONTRACTL
3865     {
3866         NOTHROW;
3867         GC_TRIGGERS;
3868         MODE_PREEMPTIVE;
3869     }
3870     CONTRACTL_END;
3871
3872     {
3873         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3874         _ASSERTE(System());
3875         g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System());
3876         END_PIN_PROFILER();
3877     }
3878
3879     {
3880         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3881         _ASSERTE(System());
3882         g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System(), S_OK);
3883         END_PIN_PROFILER();
3884     }
3885
3886     {
3887         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3888         _ASSERTE(System()->DefaultDomain());
3889         g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System()->DefaultDomain());
3890         END_PIN_PROFILER();
3891     }
3892
3893     {
3894         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3895         _ASSERTE(System()->DefaultDomain());
3896         g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3897         END_PIN_PROFILER();
3898     }
3899     return (S_OK);
3900 }
3901 #endif // PROFILING_SUPPORTED
3902
3903
3904 #ifdef _DEBUG
3905 struct AppDomain::ThreadTrackInfo {
3906     Thread *pThread;
3907     CDynArray<Frame *> frameStack;
3908 };
3909 #endif // _DEBUG
3910
3911 AppDomain::AppDomain()
3912 {
3913     // initialize fields so the appdomain can be safely destructed
3914     // shouldn't call anything that can fail here - use ::Init instead
3915     CONTRACTL
3916     {
3917         THROWS;
3918         GC_TRIGGERS;
3919         MODE_ANY;
3920         FORBID_FAULT;
3921     }
3922     CONTRACTL_END;
3923
3924     m_cRef=1;
3925     m_pNextInDelayedUnloadList = NULL;
3926     m_fRudeUnload = FALSE;
3927     m_pUnloadRequestThread = NULL;
3928     m_ADUnloadSink=NULL;
3929
3930
3931     // Initialize Shared state. Assemblies are loaded
3932     // into each domain by default.
3933 #ifdef FEATURE_LOADER_OPTIMIZATION    
3934     m_SharePolicy = SHARE_POLICY_UNSPECIFIED;
3935 #endif
3936
3937     m_pRootAssembly = NULL;
3938
3939     m_pwDynamicDir = NULL;
3940
3941     m_dwFlags = 0;
3942     m_pDefaultContext = NULL;
3943 #ifdef FEATURE_COMINTEROP
3944     m_pComCallWrapperCache = NULL;
3945     m_pRCWCache = NULL;
3946     m_pRCWRefCache = NULL;
3947     m_pLicenseInteropHelperMT = NULL;
3948     m_COMorRemotingFlag = COMorRemoting_NotInitialized;
3949     memset(m_rpCLRTypes, 0, sizeof(m_rpCLRTypes));
3950 #endif // FEATURE_COMINTEROP
3951
3952     m_pUMEntryThunkCache = NULL;
3953
3954     m_pAsyncPool = NULL;
3955     m_handleStore = NULL;
3956
3957     m_ExposedObject = NULL;
3958     m_pComIPForExposedObject = NULL;
3959
3960  #ifdef _DEBUG
3961     m_pThreadTrackInfoList = NULL;
3962     m_TrackSpinLock = 0;
3963     m_Assemblies.Debug_SetAppDomain(this);
3964 #endif // _DEBUG
3965
3966     m_dwThreadEnterCount = 0;
3967     m_dwThreadsStillInAppDomain = (ULONG)-1;
3968
3969 #ifdef FEATURE_COMINTEROP
3970     m_pRefDispIDCache = NULL;
3971     m_hndMissing = NULL;
3972 #endif
3973
3974     m_pRefClassFactHash = NULL;
3975     m_anonymouslyHostedDynamicMethodsAssembly = NULL;
3976
3977     m_ReversePInvokeCanEnter=TRUE;
3978     m_ForceTrivialWaitOperations = false;
3979     m_Stage=STAGE_CREATING;
3980
3981     m_bForceGCOnUnload=FALSE;
3982     m_bUnloadingFromUnloadEvent=FALSE;
3983 #ifdef _DEBUG
3984     m_dwIterHolders=0;
3985     m_dwRefTakers=0;
3986     m_dwCreationHolders=0;
3987 #endif
3988
3989 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3990     m_ullTotalProcessorUsage = 0;
3991     m_pullAllocBytes = NULL;
3992     m_pullSurvivedBytes = NULL;
3993 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3994
3995 #ifdef FEATURE_TYPEEQUIVALENCE
3996     m_pTypeEquivalenceTable = NULL;
3997 #endif // FEATURE_TYPEEQUIVALENCE
3998
3999 #ifdef FEATURE_COMINTEROP
4000     m_pNameToTypeMap = NULL;
4001     m_vNameToTypeMapVersion = 0;
4002     m_nEpoch = 0;
4003     m_pWinRTFactoryCache = NULL;
4004 #endif // FEATURE_COMINTEROP
4005
4006 #ifdef FEATURE_PREJIT
4007     m_pDomainFileWithNativeImageList = NULL;
4008 #endif
4009
4010     m_fIsBindingModelLocked.Store(FALSE);
4011
4012 } // AppDomain::AppDomain
4013
4014 AppDomain::~AppDomain()
4015 {
4016     CONTRACTL
4017     {
4018         NOTHROW;
4019         GC_TRIGGERS;
4020         MODE_ANY;
4021     }
4022     CONTRACTL_END;
4023
4024 #ifndef CROSSGEN_COMPILE
4025
4026     _ASSERTE(m_dwCreationHolders == 0);
4027
4028     // release the TPIndex.  note that since TPIndex values are recycled the TPIndex
4029     // can only be released once all threads in the AppDomain have exited.
4030     if (GetTPIndex().m_dwIndex != 0)
4031         PerAppDomainTPCountList::ResetAppDomainIndex(GetTPIndex());
4032
4033     if (m_dwId.m_dwId!=0)
4034         SystemDomain::ReleaseAppDomainId(m_dwId);
4035
4036     m_AssemblyCache.Clear();
4037
4038     if (m_ADUnloadSink)
4039         m_ADUnloadSink->Release();
4040
4041     if(!g_fEEInit)
4042         Terminate();
4043
4044
4045
4046
4047 #ifdef FEATURE_COMINTEROP
4048     if (m_pNameToTypeMap != nullptr)
4049     {
4050         delete m_pNameToTypeMap;
4051         m_pNameToTypeMap = nullptr;
4052     }
4053     if (m_pWinRTFactoryCache != nullptr)
4054     {
4055         delete m_pWinRTFactoryCache;
4056         m_pWinRTFactoryCache = nullptr;
4057     }
4058 #endif //FEATURE_COMINTEROP
4059     
4060 #ifdef _DEBUG
4061     // If we were tracking thread AD transitions, cleanup the list on shutdown
4062     if (m_pThreadTrackInfoList)
4063     {
4064         while (m_pThreadTrackInfoList->Count() > 0)
4065         {
4066             // Get the very last element
4067             ThreadTrackInfo *pElem = *(m_pThreadTrackInfoList->Get(m_pThreadTrackInfoList->Count() - 1));
4068             _ASSERTE(pElem);
4069
4070             // Free the memory
4071             delete pElem;
4072
4073             // Remove pointer entry from the list
4074             m_pThreadTrackInfoList->Delete(m_pThreadTrackInfoList->Count() - 1);
4075         }
4076
4077         // Now delete the list itself
4078         delete m_pThreadTrackInfoList;
4079         m_pThreadTrackInfoList = NULL;
4080     }
4081 #endif // _DEBUG
4082
4083 #endif // CROSSGEN_COMPILE
4084 }
4085
4086 //*****************************************************************************
4087 //*****************************************************************************
4088 //*****************************************************************************
4089 void AppDomain::Init()
4090 {
4091     CONTRACTL
4092     {
4093         STANDARD_VM_CHECK;
4094         PRECONDITION(SystemDomain::IsUnderDomainLock());
4095     }
4096     CONTRACTL_END;
4097
4098     m_pDelayedLoaderAllocatorUnloadList = NULL;
4099
4100     SetStage( STAGE_CREATING);
4101
4102
4103     // The lock is taken also during stack walking (GC or profiler)
4104     //  - To prevent deadlock with GC thread, we cannot trigger GC while holding the lock
4105     //  - To prevent deadlock with profiler thread, we cannot allow thread suspension
4106     m_crstHostAssemblyMap.Init(
4107         CrstHostAssemblyMap, 
4108         (CrstFlags)(CRST_GC_NOTRIGGER_WHEN_TAKEN 
4109                     | CRST_DEBUGGER_THREAD 
4110                     INDEBUG(| CRST_DEBUG_ONLY_CHECK_FORBID_SUSPEND_THREAD)));
4111     m_crstHostAssemblyMapAdd.Init(CrstHostAssemblyMapAdd);
4112
4113     m_dwId = SystemDomain::GetNewAppDomainId(this);
4114
4115     m_LoaderAllocator.Init(this);
4116
4117 #ifndef CROSSGEN_COMPILE
4118     //Allocate the threadpool entry before the appdomin id list. Otherwise,
4119     //the thread pool list will be out of sync if insertion of id in 
4120     //the appdomain fails. 
4121     m_tpIndex = PerAppDomainTPCountList::AddNewTPIndex();    
4122 #endif // CROSSGEN_COMPILE
4123
4124     m_dwIndex = SystemDomain::GetNewAppDomainIndex(this);
4125
4126 #ifndef CROSSGEN_COMPILE
4127     PerAppDomainTPCountList::SetAppDomainId(m_tpIndex, m_dwId);
4128
4129     m_ADUnloadSink=new ADUnloadSink();
4130 #endif
4131
4132     BaseDomain::Init();
4133
4134     // Set up the IL stub cache
4135     m_ILStubCache.Init(GetLoaderAllocator()->GetHighFrequencyHeap());
4136
4137 // Set up the binding caches
4138     m_AssemblyCache.Init(&m_DomainCacheCrst, GetHighFrequencyHeap());
4139     m_UnmanagedCache.InitializeTable(this, &m_DomainCacheCrst);
4140
4141     m_MemoryPressure = 0;
4142
4143     m_sDomainLocalBlock.Init(this);
4144
4145 #ifndef CROSSGEN_COMPILE
4146
4147 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4148     // NOTE: it's important that we initialize ARM data structures before calling
4149     // Ref_CreateHandleTableBucket, this is because AD::Init() can race with GC
4150     // and once we add ourselves to the handle table map the GC can start walking
4151     // our handles and calling AD::RecordSurvivedBytes() which touches ARM data.
4152     if (GCHeapUtilities::IsServerHeap())
4153         m_dwNumHeaps = CPUGroupInfo::CanEnableGCCPUGroups() ?
4154                            CPUGroupInfo::GetNumActiveProcessors() :
4155                            GetCurrentProcessCpuCount();
4156     else
4157         m_dwNumHeaps = 1;
4158     m_pullAllocBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
4159     m_pullSurvivedBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
4160     for (DWORD i = 0; i < m_dwNumHeaps; i++)
4161     {
4162         m_pullAllocBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
4163         m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
4164     }
4165     m_ullLastEtwAllocBytes = 0;
4166 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4167
4168     // Default domain reuses the handletablemap that was created during EEStartup since
4169     // default domain cannot be unloaded.
4170     if (GetId().m_dwId == DefaultADID)
4171     {
4172         m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
4173     }
4174     else
4175     {
4176         m_handleStore = GCHandleUtilities::GetGCHandleManager()->CreateHandleStore((void*)(uintptr_t)m_dwIndex.m_dwIndex);
4177     }
4178
4179     if (!m_handleStore)
4180     {
4181         COMPlusThrowOM();
4182     }
4183
4184 #endif // CROSSGEN_COMPILE
4185
4186 #ifdef FEATURE_TYPEEQUIVALENCE
4187     m_TypeEquivalenceCrst.Init(CrstTypeEquivalenceMap);
4188 #endif
4189
4190     m_ReflectionCrst.Init(CrstReflection, CRST_UNSAFE_ANYMODE);
4191     m_RefClassFactCrst.Init(CrstClassFactInfoHash);
4192
4193     {
4194         LockOwner lock = {&m_DomainCrst, IsOwnerOfCrst};
4195         m_clsidHash.Init(0,&CompareCLSID,true, &lock); // init hash table
4196     }
4197
4198     SetStage(STAGE_READYFORMANAGEDCODE);
4199
4200 #ifndef CROSSGEN_COMPILE
4201     m_pDefaultContext = new Context(this);
4202
4203     m_ExposedObject = CreateHandle(NULL);
4204
4205     // Create the Application Security Descriptor
4206
4207     COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains++);
4208
4209 #ifdef FEATURE_COMINTEROP
4210     if (!AppX::IsAppXProcess())
4211     {
4212     }
4213 #endif //FEATURE_COMINTEROP
4214
4215 #ifdef FEATURE_TIERED_COMPILATION
4216     m_tieredCompilationManager.Init(GetId());
4217 #endif
4218 #endif // CROSSGEN_COMPILE
4219 } // AppDomain::Init
4220
4221
4222 /*********************************************************************/
4223
4224 BOOL AppDomain::IsCompilationDomain()
4225 {
4226     LIMITED_METHOD_CONTRACT;
4227
4228     BOOL isCompilationDomain = (m_dwFlags & COMPILATION_DOMAIN) != 0;
4229 #ifdef FEATURE_PREJIT
4230     _ASSERTE(!isCompilationDomain ||
4231              (IsCompilationProcess() && IsPassiveDomain()));
4232 #endif // FEATURE_PREJIT
4233     return isCompilationDomain;
4234 }
4235
4236 #ifndef CROSSGEN_COMPILE
4237
4238 extern int g_fADUnloadWorkerOK;
4239
4240 // Notes:
4241 //   This helper will send the AppDomain creation notifications for profiler / debugger.
4242 //   If it throws, its backout code will also send a notification.
4243 //   If it succeeds, then we still need to send a AppDomainCreateFinished notification.
4244 void AppDomain::CreateUnmanagedObject(AppDomainCreationHolder<AppDomain>& pDomain)
4245 {
4246     CONTRACTL
4247     {
4248         THROWS;
4249         MODE_COOPERATIVE;
4250         GC_TRIGGERS;
4251         INJECT_FAULT(COMPlusThrowOM(););
4252     }
4253     CONTRACTL_END;
4254
4255     GCX_PREEMP();
4256
4257     pDomain.Assign(new AppDomain());
4258     if (g_fADUnloadWorkerOK<0)
4259     {
4260         AppDomain::CreateADUnloadWorker();
4261     }
4262
4263     //@todo: B#25921
4264     // We addref Appdomain object here and notify a profiler that appdomain 
4265     // creation has started, then return to managed code which will  call 
4266     // the function that releases the appdomain and notifies a profiler that we finished
4267     // creating the appdomain. If an exception is raised while we're in that managed code
4268     // we will leak memory and the profiler will not be notified about the failure
4269
4270 #ifdef PROFILING_SUPPORTED
4271     // Signal profile if present.
4272     {
4273         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
4274         g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) (AppDomain*) pDomain);
4275         END_PIN_PROFILER();
4276     }
4277     EX_TRY
4278 #endif // PROFILING_SUPPORTED
4279     {
4280         {
4281             SystemDomain::LockHolder lh;
4282             pDomain->Init(); 
4283             // allocate a Virtual Call Stub Manager for this domain
4284             pDomain->InitVSD();
4285         }
4286
4287         pDomain->SetCanUnload();    // by default can unload any domain
4288         
4289         #ifdef DEBUGGING_SUPPORTED    
4290         // Notify the debugger here, before the thread transitions into the 
4291         // AD to finish the setup, and before any assemblies are loaded into it.
4292         SystemDomain::PublishAppDomainAndInformDebugger(pDomain);
4293         #endif // DEBUGGING_SUPPORTED
4294
4295         STRESS_LOG2 (LF_APPDOMAIN, LL_INFO100, "Create domain [%d] %p\n", pDomain->GetId().m_dwId, (AppDomain*)pDomain);
4296         pDomain->LoadSystemAssemblies();
4297         pDomain->SetupSharedStatics();
4298
4299         pDomain->SetStage(AppDomain::STAGE_ACTIVE);    
4300     }        
4301 #ifdef PROFILING_SUPPORTED
4302     EX_HOOK
4303     {
4304         // Need the first assembly loaded in to get any data on an app domain.
4305         {
4306             BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
4307             g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID)(AppDomain*) pDomain, GET_EXCEPTION()->GetHR());
4308             END_PIN_PROFILER();
4309         }
4310     }
4311     EX_END_HOOK;
4312
4313     // On success, caller must still send the AppDomainCreationFinished notification.
4314 #endif // PROFILING_SUPPORTED
4315 }
4316
4317 void AppDomain::Stop()
4318 {
4319     CONTRACTL
4320     {
4321         NOTHROW;
4322         MODE_ANY;
4323         GC_TRIGGERS;
4324     }
4325     CONTRACTL_END;
4326
4327 #ifdef FEATURE_MULTICOREJIT
4328     GetMulticoreJitManager().StopProfile(true);
4329 #endif
4330
4331     // Set the unloaded flag before notifying the debugger
4332     GetLoaderAllocator()->SetIsUnloaded();
4333
4334 #ifdef DEBUGGING_SUPPORTED
4335     if (IsDebuggerAttached())
4336         NotifyDebuggerUnload();
4337 #endif // DEBUGGING_SUPPORTED
4338
4339     m_pRootAssembly = NULL; // This assembly is in the assembly list;
4340
4341 #ifdef DEBUGGING_SUPPORTED
4342     if (NULL != g_pDebugInterface)
4343     {
4344         // Call the publisher API to delete this appdomain entry from the list
4345         CONTRACT_VIOLATION(ThrowsViolation);
4346         g_pDebugInterface->RemoveAppDomainFromIPC (this);
4347     }
4348 #endif // DEBUGGING_SUPPORTED
4349 }
4350
4351 void AppDomain::Terminate()
4352 {
4353     CONTRACTL
4354     {
4355         NOTHROW;
4356         GC_TRIGGERS;
4357         MODE_ANY;
4358     }
4359     CONTRACTL_END;
4360
4361     GCX_PREEMP();
4362
4363
4364     _ASSERTE(m_dwThreadEnterCount == 0 || IsDefaultDomain());
4365
4366     if (m_pComIPForExposedObject)
4367     {
4368         m_pComIPForExposedObject->Release();
4369         m_pComIPForExposedObject = NULL;
4370     }
4371
4372     delete m_pDefaultContext;
4373     m_pDefaultContext = NULL;
4374
4375     if (m_pUMEntryThunkCache)
4376     {
4377         delete m_pUMEntryThunkCache;
4378         m_pUMEntryThunkCache = NULL;
4379     }
4380
4381 #ifdef FEATURE_COMINTEROP
4382     if (m_pRCWCache)
4383     {
4384         delete m_pRCWCache;
4385         m_pRCWCache = NULL;
4386     }
4387
4388     if (m_pRCWRefCache)
4389     {
4390         delete m_pRCWRefCache;
4391         m_pRCWRefCache = NULL;
4392     }
4393     
4394     if (m_pComCallWrapperCache)
4395     {
4396         m_pComCallWrapperCache->Neuter();
4397         m_pComCallWrapperCache->Release();
4398     }
4399
4400     // if the above released the wrapper cache, then it will call back and reset our
4401     // m_pComCallWrapperCache to null. If not null, then need to set it's domain pointer to
4402     // null.
4403     if (! m_pComCallWrapperCache)
4404     {
4405         LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::Terminate ComCallWrapperCache released\n"));
4406     }
4407 #ifdef _DEBUG
4408     else
4409     {
4410         m_pComCallWrapperCache = NULL;
4411         LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::Terminate ComCallWrapperCache not released\n"));
4412     }
4413 #endif // _DEBUG
4414
4415 #endif // FEATURE_COMINTEROP
4416
4417
4418     if (!IsAtProcessExit())
4419     {
4420         // if we're not shutting down everything then clean up the string literals associated
4421         // with this appdomain -- note that is no longer needs to happen while suspended
4422         // because the appropriate locks are taken in the GlobalStringLiteralMap
4423         // this is important as this locks have a higher lock number than does the
4424         // thread-store lock which is taken when we suspend.
4425         GetLoaderAllocator()->CleanupStringLiteralMap();
4426
4427         // Suspend the EE to do some clean up that can only occur
4428         // while no threads are running.
4429         GCX_COOP (); // SuspendEE may require current thread to be in Coop mode
4430         ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
4431     }
4432
4433     // Note that this must be performed before restarting the EE. It will clean
4434     // the cache and prevent others from using stale cache entries.
4435     //@TODO: Would be nice to get this back to BaseDomain, but need larger fix for that.
4436     // NOTE: Must have the runtime suspended to unlink managers
4437     // NOTE: May be NULL due to OOM during initialization. Can skip in that case.
4438     GetLoaderAllocator()->UninitVirtualCallStubManager();
4439     MethodTable::ClearMethodDataCache();
4440     ClearJitGenericHandleCache(this);
4441
4442     // @TODO s_TPMethodTableCrst prevents us from from keeping the whole
4443     // assembly shutdown logic here. See if we can do better in the next milestone
4444 #ifdef  FEATURE_PREJIT
4445     DeleteNativeCodeRanges();
4446 #endif
4447
4448     if (!IsAtProcessExit())
4449     {
4450         // Resume the EE.
4451         ThreadSuspend::RestartEE(FALSE, TRUE);
4452     }
4453
4454     ShutdownAssemblies();
4455     ShutdownNativeDllSearchDirectories();
4456
4457     if (m_pRefClassFactHash)
4458     {
4459         m_pRefClassFactHash->Destroy();
4460         // storage for m_pRefClassFactHash itself is allocated on the loader heap
4461     }
4462
4463 #ifdef FEATURE_TYPEEQUIVALENCE
4464     m_TypeEquivalenceCrst.Destroy();
4465 #endif
4466
4467     m_ReflectionCrst.Destroy();
4468     m_RefClassFactCrst.Destroy();
4469
4470     m_LoaderAllocator.Terminate();
4471
4472     BaseDomain::Terminate();
4473
4474     if (m_handleStore)
4475     {
4476         GCHandleUtilities::GetGCHandleManager()->DestroyHandleStore(m_handleStore);
4477         m_handleStore = NULL;
4478     }
4479
4480 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
4481     if (m_pullAllocBytes)
4482     {
4483         delete [] m_pullAllocBytes;
4484     }
4485     if (m_pullSurvivedBytes)
4486     {
4487         delete [] m_pullSurvivedBytes;
4488     }
4489 #endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
4490
4491     if(m_dwIndex.m_dwIndex != 0)
4492         SystemDomain::ReleaseAppDomainIndex(m_dwIndex);
4493 } // AppDomain::Terminate
4494
4495 void AppDomain::CloseDomain()
4496 {
4497     CONTRACTL
4498     {
4499         NOTHROW;
4500         GC_TRIGGERS;
4501         MODE_ANY;
4502     }
4503     CONTRACTL_END;
4504
4505
4506     BOOL bADRemoved=FALSE;;
4507
4508     AddRef();  // Hold a reference
4509     AppDomainRefHolder AdHolder(this);
4510     {
4511         SystemDomain::LockHolder lh;
4512
4513         SystemDomain::System()->DecrementNumAppDomains(); // Maintain a count of app domains added to the list.
4514         bADRemoved = SystemDomain::System()->RemoveDomain(this);
4515     }
4516
4517     if(bADRemoved)
4518         Stop();
4519 }
4520
4521 /*********************************************************************/
4522
4523 struct GetExposedObject_Args
4524 {
4525     AppDomain *pDomain;
4526     OBJECTREF *ref;
4527 };
4528
4529 static void GetExposedObject_Wrapper(LPVOID ptr)
4530 {
4531     CONTRACTL
4532     {
4533         THROWS;
4534         GC_TRIGGERS;
4535         MODE_COOPERATIVE;
4536     }
4537     CONTRACTL_END;
4538     GetExposedObject_Args *args = (GetExposedObject_Args *) ptr;
4539     *(args->ref) = args->pDomain->GetExposedObject();
4540 }
4541
4542
4543 OBJECTREF AppDomain::GetExposedObject()
4544 {
4545     CONTRACTL
4546     {
4547         MODE_COOPERATIVE;
4548         THROWS;
4549         GC_TRIGGERS;
4550         INJECT_FAULT(COMPlusThrowOM(););
4551     }
4552     CONTRACTL_END;
4553
4554     OBJECTREF ref = GetRawExposedObject();
4555     if (ref == NULL)
4556     {
4557         APPDOMAINREF obj = NULL;
4558
4559         Thread *pThread = GetThread();
4560         if (pThread->GetDomain() != this)
4561         {
4562             GCPROTECT_BEGIN(ref);
4563             GetExposedObject_Args args = {this, &ref};
4564             // call through DoCallBack with a domain transition
4565             pThread->DoADCallBack(this,GetExposedObject_Wrapper, &args,ADV_CREATING|ADV_RUNNINGIN);
4566             GCPROTECT_END();
4567             return ref;
4568         }
4569         MethodTable *pMT = MscorlibBinder::GetClass(CLASS__APP_DOMAIN);
4570
4571         // Create the module object
4572         obj = (APPDOMAINREF) AllocateObject(pMT);
4573         obj->SetDomain(this);
4574
4575         if (!StoreFirstObjectInHandle(m_ExposedObject, (OBJECTREF) obj))
4576         {
4577             obj = (APPDOMAINREF) GetRawExposedObject();
4578             _ASSERTE(obj);
4579         }
4580
4581         return (OBJECTREF) obj;
4582     }
4583
4584     return ref;
4585 }
4586
4587
4588
4589 OBJECTREF AppDomain::DoSetup(OBJECTREF* setupInfo)
4590 {
4591     CONTRACTL
4592     {
4593         MODE_COOPERATIVE;
4594         THROWS;
4595         GC_TRIGGERS;
4596         INJECT_FAULT(COMPlusThrowOM(););
4597     }
4598     CONTRACTL_END;
4599
4600     ADID adid=GetAppDomain()->GetId();
4601
4602     OBJECTREF retval=NULL;
4603     GCPROTECT_BEGIN(retval);    
4604
4605     ENTER_DOMAIN_PTR(this,ADV_CREATING);
4606
4607     MethodDescCallSite setup(METHOD__APP_DOMAIN__SETUP);
4608
4609     ARG_SLOT args[1];
4610
4611     args[0]=ObjToArgSlot(*setupInfo);
4612
4613     OBJECTREF activator;
4614     activator=setup.Call_RetOBJECTREF(args);
4615     _ASSERTE(activator==NULL);
4616     
4617 #if defined(FEATURE_MULTICOREJIT)
4618     // Disable AutoStartProfile in default domain from this code path.
4619     // It's called from SystemDomain::ExecuteMainMethod for normal program, not needed for SL and Asp.Net
4620     if (! IsDefaultDomain())
4621     {
4622         GCX_PREEMP();
4623
4624         GetMulticoreJitManager().AutoStartProfile(this);
4625     }
4626 #endif
4627
4628     END_DOMAIN_TRANSITION;
4629     GCPROTECT_END();
4630     return retval;
4631 }
4632
4633 #endif // !CROSSGEN_COMPILE
4634
4635 #ifdef FEATURE_COMINTEROP
4636 #ifndef CROSSGEN_COMPILE
4637 HRESULT AppDomain::GetComIPForExposedObject(IUnknown **pComIP)
4638 {
4639     // Assumption: This function is called for AppDomain's that the current
4640     //             thread is in or has entered, or the AppDomain is kept alive.
4641     //
4642     // Assumption: This function can now throw.  The caller is responsible for any
4643     //             BEGIN_EXTERNAL_ENTRYPOINT, EX_TRY, or other
4644     //             techniques to convert to a COM HRESULT protocol.
4645     CONTRACTL
4646     {
4647         THROWS;
4648         GC_TRIGGERS;
4649         MODE_ANY;
4650     }
4651     CONTRACTL_END;
4652
4653     HRESULT hr = S_OK;
4654     Thread *pThread = GetThread();
4655     if (m_pComIPForExposedObject)
4656     {
4657         GCX_PREEMP_THREAD_EXISTS(pThread);
4658         m_pComIPForExposedObject->AddRef();
4659         *pComIP = m_pComIPForExposedObject;
4660         return S_OK;
4661     }
4662
4663     IUnknown* punk = NULL;
4664
4665     OBJECTREF ref = NULL;
4666     GCPROTECT_BEGIN(ref);
4667
4668     EnsureComStarted();
4669
4670     ENTER_DOMAIN_PTR(this,ADV_DEFAULTAD)
4671     {
4672         ref = GetExposedObject();
4673         punk = GetComIPFromObjectRef(&ref);
4674         if (FastInterlockCompareExchangePointer(&m_pComIPForExposedObject, punk, NULL) == NULL)
4675         {
4676             GCX_PREEMP_THREAD_EXISTS(pThread);
4677             m_pComIPForExposedObject->AddRef();
4678         }
4679     }
4680     END_DOMAIN_TRANSITION;
4681
4682     GCPROTECT_END();
4683
4684     if(SUCCEEDED(hr))
4685     {
4686         *pComIP = m_pComIPForExposedObject;
4687     }
4688
4689     return hr;
4690 }
4691 #endif //#ifndef CROSSGEN_COMPILE
4692
4693 MethodTable *AppDomain::GetRedirectedType(WinMDAdapter::RedirectedTypeIndex index)
4694 {
4695     CONTRACTL
4696     {
4697         THROWS;
4698         GC_TRIGGERS;
4699         MODE_ANY;
4700     }
4701     CONTRACTL_END;
4702
4703     // If we have the type loaded already, use that
4704     if (m_rpCLRTypes[index] != nullptr)
4705     {
4706         return m_rpCLRTypes[index];
4707     }
4708
4709     WinMDAdapter::FrameworkAssemblyIndex frameworkAssemblyIndex;
4710     WinMDAdapter::GetRedirectedTypeInfo(index, nullptr, nullptr, nullptr, &frameworkAssemblyIndex, nullptr, nullptr);
4711     MethodTable * pMT = LoadRedirectedType(index, frameworkAssemblyIndex);
4712     m_rpCLRTypes[index] = pMT;
4713     return pMT;
4714 }
4715
4716 MethodTable* AppDomain::LoadRedirectedType(WinMDAdapter::RedirectedTypeIndex index, WinMDAdapter::FrameworkAssemblyIndex assembly)
4717 {
4718     CONTRACTL
4719     {
4720         THROWS;
4721         GC_TRIGGERS;
4722         MODE_ANY;
4723         PRECONDITION(index < WinMDAdapter::RedirectedTypeIndex_Count);
4724     }
4725     CONTRACTL_END;
4726
4727     LPCSTR szClrNamespace;
4728     LPCSTR szClrName;
4729     LPCSTR szFullWinRTName;
4730     WinMDAdapter::FrameworkAssemblyIndex nFrameworkAssemblyIndex;
4731
4732     WinMDAdapter::GetRedirectedTypeInfo(index, &szClrNamespace, &szClrName, &szFullWinRTName, &nFrameworkAssemblyIndex, nullptr, nullptr);
4733
4734     _ASSERTE(nFrameworkAssemblyIndex >= WinMDAdapter::FrameworkAssembly_Mscorlib &&
4735              nFrameworkAssemblyIndex < WinMDAdapter::FrameworkAssembly_Count);
4736
4737     if (assembly != nFrameworkAssemblyIndex)
4738     {
4739         // The framework type does not live in the assembly we were requested to load redirected types from
4740         return nullptr;
4741     }
4742     else if (nFrameworkAssemblyIndex == WinMDAdapter::FrameworkAssembly_Mscorlib)
4743     {
4744         return ClassLoader::LoadTypeByNameThrowing(MscorlibBinder::GetModule()->GetAssembly(),
4745                                                    szClrNamespace,
4746                                                    szClrName,
4747                                                    ClassLoader::ThrowIfNotFound,
4748                                                    ClassLoader::LoadTypes,
4749                                                    CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4750     }
4751     else
4752     {
4753         LPCSTR pSimpleName;
4754         AssemblyMetaDataInternal context;
4755         const BYTE * pbKeyToken;
4756         DWORD cbKeyTokenLength;
4757         DWORD dwFlags;
4758
4759         WinMDAdapter::GetExtraAssemblyRefProps(nFrameworkAssemblyIndex,
4760                                                &pSimpleName,
4761                                                &context,
4762                                                &pbKeyToken,
4763                                                &cbKeyTokenLength,
4764                                                &dwFlags);
4765
4766         Assembly* pAssembly = AssemblySpec::LoadAssembly(pSimpleName,
4767                                                          &context,
4768                                                          pbKeyToken,
4769                                                          cbKeyTokenLength,
4770                                                          dwFlags);
4771
4772         return ClassLoader::LoadTypeByNameThrowing(
4773             pAssembly,
4774             szClrNamespace,
4775             szClrName,
4776             ClassLoader::ThrowIfNotFound,
4777             ClassLoader::LoadTypes,
4778             CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4779     }
4780 }
4781 #endif //FEATURE_COMINTEROP
4782
4783 #endif //!DACCESS_COMPILE
4784
4785 #ifndef DACCESS_COMPILE
4786
4787 bool IsPlatformAssembly(LPCSTR szName, DomainAssembly *pDomainAssembly)
4788 {
4789     CONTRACTL
4790     {
4791         THROWS;
4792         GC_TRIGGERS;
4793         MODE_ANY;
4794         PRECONDITION(CheckPointer(szName));
4795         PRECONDITION(CheckPointer(pDomainAssembly));
4796     }
4797     CONTRACTL_END;
4798
4799     PEAssembly *pPEAssembly = pDomainAssembly->GetFile();
4800
4801     if (strcmp(szName, pPEAssembly->GetSimpleName()) != 0)
4802     {
4803         return false;
4804     }
4805     
4806     DWORD cbPublicKey;
4807     const BYTE *pbPublicKey = static_cast<const BYTE *>(pPEAssembly->GetPublicKey(&cbPublicKey));
4808     if (pbPublicKey == nullptr)
4809     {
4810         return false;
4811     }
4812
4813     return StrongNameIsSilverlightPlatformKey(pbPublicKey, cbPublicKey);
4814 }
4815
4816 void AppDomain::AddAssembly(DomainAssembly * assem)
4817 {
4818     CONTRACTL
4819     {
4820         THROWS;
4821         GC_TRIGGERS;
4822         MODE_ANY;
4823         INJECT_FAULT(COMPlusThrowOM(););
4824     }
4825     CONTRACTL_END;
4826     
4827     {
4828         CrstHolder ch(GetAssemblyListLock());
4829     
4830         // Attempt to find empty space in assemblies list
4831         DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4832         for (DWORD i = 0; i < asmCount; ++i)
4833         {
4834             if (m_Assemblies.Get_UnlockedNoReference(i) == NULL)
4835             {
4836                 m_Assemblies.Set_Unlocked(i, assem);
4837                 return;
4838             }
4839         }
4840
4841         // If empty space not found, simply add to end of list
4842         IfFailThrow(m_Assemblies.Append_Unlocked(assem));
4843     }
4844 }
4845
4846 void AppDomain::RemoveAssembly_Unlocked(DomainAssembly * pAsm)
4847 {
4848     CONTRACTL
4849     {
4850         NOTHROW;
4851         GC_NOTRIGGER;
4852     }
4853     CONTRACTL_END;
4854     
4855     _ASSERTE(GetAssemblyListLock()->OwnedByCurrentThread());
4856     
4857     DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4858     for (DWORD i = 0; i < asmCount; ++i)
4859     {
4860         if (m_Assemblies.Get_UnlockedNoReference(i) == pAsm)
4861         {
4862             m_Assemblies.Set_Unlocked(i, NULL);
4863             return;
4864         }
4865     }
4866     
4867     _ASSERTE(!"Unreachable");
4868 }
4869
4870 BOOL AppDomain::ContainsAssembly(Assembly * assem)
4871 {
4872     WRAPPER_NO_CONTRACT;
4873     AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
4874         kIncludeLoaded | 
4875         (assem->IsIntrospectionOnly() ? kIncludeIntrospection : kIncludeExecution)));
4876     CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
4877
4878     while (i.Next(pDomainAssembly.This()))
4879     {
4880         CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
4881         if (pAssembly == assem)
4882             return TRUE;
4883     }
4884
4885     return FALSE;
4886 }
4887
4888 EEClassFactoryInfoHashTable* AppDomain::SetupClassFactHash()
4889 {
4890     CONTRACTL
4891     {
4892         THROWS;
4893         GC_TRIGGERS;
4894         MODE_ANY;
4895         INJECT_FAULT(COMPlusThrowOM(););
4896     }
4897     CONTRACTL_END;
4898
4899     CrstHolder ch(&m_ReflectionCrst);
4900
4901     if (m_pRefClassFactHash == NULL)
4902     {
4903         AllocMemHolder<void> pCache(GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (EEClassFactoryInfoHashTable))));
4904         EEClassFactoryInfoHashTable *tmp = new (pCache) EEClassFactoryInfoHashTable;
4905         LockOwner lock = {&m_RefClassFactCrst,IsOwnerOfCrst};
4906         if (!tmp->Init(20, &lock))
4907             COMPlusThrowOM();
4908         pCache.SuppressRelease();
4909         m_pRefClassFactHash = tmp;
4910     }
4911
4912     return m_pRefClassFactHash;
4913 }
4914
4915 #ifdef FEATURE_COMINTEROP
4916 DispIDCache* AppDomain::SetupRefDispIDCache()
4917 {
4918     CONTRACTL
4919     {
4920         THROWS;
4921         GC_TRIGGERS;
4922         MODE_ANY;
4923         INJECT_FAULT(COMPlusThrowOM(););
4924     }
4925     CONTRACTL_END;
4926
4927     CrstHolder ch(&m_ReflectionCrst);
4928
4929     if (m_pRefDispIDCache == NULL)
4930     {
4931         AllocMemHolder<void> pCache = GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (DispIDCache)));
4932
4933         DispIDCache *tmp = new (pCache) DispIDCache;
4934         tmp->Init();
4935
4936         pCache.SuppressRelease();
4937         m_pRefDispIDCache = tmp;
4938     }
4939
4940     return m_pRefDispIDCache;
4941 }
4942
4943 #endif // FEATURE_COMINTEROP
4944
4945 FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
4946 {
4947     CONTRACTL
4948     {
4949         THROWS;
4950         GC_TRIGGERS;
4951         MODE_ANY;
4952         PRECONDITION(pLock->HasLock());
4953         PRECONDITION(pLock->FindFileLock(pFile) == NULL);
4954         INJECT_FAULT(COMPlusThrowOM(););
4955     }
4956     CONTRACTL_END;
4957
4958     NewHolder<FileLoadLock> result(new FileLoadLock(pLock, pFile, pDomainFile));
4959
4960     pLock->AddElement(result);
4961     result->AddRef(); // Add one ref on behalf of the ListLock's reference. The corresponding Release() happens in FileLoadLock::CompleteLoadLevel.
4962     return result.Extract();
4963 }
4964
4965 FileLoadLock::~FileLoadLock()
4966 {
4967     CONTRACTL
4968     {
4969         DESTRUCTOR_CHECK;
4970         NOTHROW;
4971         GC_TRIGGERS;
4972         MODE_ANY;
4973     }
4974     CONTRACTL_END;
4975     ((PEFile *) m_data)->Release();
4976 }
4977
4978 DomainFile *FileLoadLock::GetDomainFile()
4979 {
4980     LIMITED_METHOD_CONTRACT;
4981     return m_pDomainFile;
4982 }
4983
4984 FileLoadLevel FileLoadLock::GetLoadLevel()
4985 {
4986     LIMITED_METHOD_CONTRACT;
4987     return m_level;
4988 }
4989
4990 ADID FileLoadLock::GetAppDomainId()
4991 {
4992     LIMITED_METHOD_CONTRACT;
4993     return m_AppDomainId;
4994 }
4995
4996 // Acquire will return FALSE and not take the lock if the file
4997 // has already been loaded to the target level.  Otherwise,
4998 // it will return TRUE and take the lock.
4999 //
5000 // Note that the taker must release the lock via IncrementLoadLevel.
5001
5002 BOOL FileLoadLock::Acquire(FileLoadLevel targetLevel)
5003 {
5004     WRAPPER_NO_CONTRACT;
5005
5006     // If we are already loaded to the desired level, the lock is "free".
5007     if (m_level >= targetLevel)
5008         return FALSE;
5009
5010     if (!DeadlockAwareEnter())
5011     {
5012         // We failed to get the lock due to a deadlock.
5013         return FALSE;
5014     }
5015
5016     if (m_level >= targetLevel)
5017     {
5018         Leave();
5019         return FALSE;
5020     }
5021
5022     return TRUE;
5023 }
5024
5025 BOOL FileLoadLock::CanAcquire(FileLoadLevel targetLevel)
5026 {
5027     // If we are already loaded to the desired level, the lock is "free".
5028     if (m_level >= targetLevel)
5029         return FALSE;
5030
5031     return CanDeadlockAwareEnter();
5032 }
5033
5034 #if !defined(DACCESS_COMPILE) && (defined(LOGGING) || defined(STRESS_LOG))
5035 static const char *fileLoadLevelName[] =
5036 {
5037     "CREATE",                             // FILE_LOAD_CREATE
5038     "BEGIN",                              // FILE_LOAD_BEGIN
5039     "FIND_NATIVE_IMAGE",                  // FILE_LOAD_FIND_NATIVE_IMAGE
5040     "VERIFY_NATIVE_IMAGE_DEPENDENCIES",   // FILE_LOAD_VERIFY_NATIVE_IMAGE_DEPENDENCIES
5041     "ALLOCATE",                           // FILE_LOAD_ALLOCATE
5042     "ADD_DEPENDENCIES",                   // FILE_LOAD_ADD_DEPENDENCIES
5043     "PRE_LOADLIBRARY",                    // FILE_LOAD_PRE_LOADLIBRARY
5044     "LOADLIBRARY",                        // FILE_LOAD_LOADLIBRARY
5045     "POST_LOADLIBRARY",                   // FILE_LOAD_POST_LOADLIBRARY                
5046     "EAGER_FIXUPS",                       // FILE_LOAD_EAGER_FIXUPS
5047     "VTABLE FIXUPS",                      // FILE_LOAD_VTABLE_FIXUPS
5048     "DELIVER_EVENTS",                     // FILE_LOAD_DELIVER_EVENTS
5049     "LOADED",                             // FILE_LOADED
5050     "VERIFY_EXECUTION",                   // FILE_LOAD_VERIFY_EXECUTION
5051     "ACTIVE",                             // FILE_ACTIVE
5052 };
5053 #endif // !DACCESS_COMPILE && (LOGGING || STRESS_LOG)
5054
5055 BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success)
5056 {
5057     CONTRACTL
5058     {
5059         MODE_ANY;
5060         GC_TRIGGERS;
5061         THROWS;
5062         PRECONDITION(HasLock());
5063     }
5064     CONTRACTL_END;
5065
5066     // Increment may happen more than once if reentrancy occurs (e.g. LoadLibrary)
5067     if (level > m_level)
5068     {
5069         // Must complete each level in turn, unless we have an error
5070         CONSISTENCY_CHECK(m_pDomainFile->IsError() || (level == (m_level+1)));
5071         // Remove the lock from the list if the load is completed
5072         if (level >= FILE_ACTIVE)
5073         {
5074             {
5075                 GCX_COOP();
5076                 PEFileListLockHolder lock((PEFileListLock*)m_pList);
5077
5078 #if _DEBUG
5079                 BOOL fDbgOnly_SuccessfulUnlink =
5080 #endif                
5081                     m_pList->Unlink(this);
5082                 _ASSERTE(fDbgOnly_SuccessfulUnlink);
5083
5084                 m_pDomainFile->ClearLoading();
5085
5086                 CONSISTENCY_CHECK(m_dwRefCount >= 2); // Caller (LoadDomainFile) should have 1 refcount and m_pList should have another which was acquired in FileLoadLock::Create.
5087
5088                 m_level = (FileLoadLevel)level;
5089
5090                 // Dev11 bug 236344
5091                 // In AppDomain::IsLoading, if the lock is taken on m_pList and then FindFileLock returns NULL,
5092                 // we depend on the DomainFile's load level being up to date. Hence we must update the load
5093                 // level while the m_pList lock is held.
5094                 if (success)
5095                     m_pDomainFile->SetLoadLevel(level);
5096             }
5097
5098
5099             Release(); // Release m_pList's refcount on this lock, which was acquired in FileLoadLock::Create
5100
5101         }
5102         else
5103         {
5104             m_level = (FileLoadLevel)level;
5105
5106             if (success)
5107                 m_pDomainFile->SetLoadLevel(level);
5108         }
5109
5110 #ifndef DACCESS_COMPILE
5111         switch(level)
5112         {
5113             case FILE_LOAD_ALLOCATE:
5114             case FILE_LOAD_ADD_DEPENDENCIES:
5115             case FILE_LOAD_DELIVER_EVENTS:
5116             case FILE_LOADED:
5117             case FILE_ACTIVE: // The timing of stress logs is not critical, so even for the FILE_ACTIVE stage we need not do it while the m_pList lock is held.
5118                 STRESS_LOG4(LF_CLASSLOADER, LL_INFO100, "Completed Load Level %s for DomainFile %p in AD %i - success = %i\n", fileLoadLevelName[level], m_pDomainFile, m_AppDomainId.m_dwId, success);
5119                 break;
5120             default:
5121                 break;
5122         }
5123 #endif
5124
5125         return TRUE;
5126     }
5127     else
5128         return FALSE;
5129 }
5130
5131 void FileLoadLock::SetError(Exception *ex)
5132 {
5133     CONTRACTL
5134     {
5135         MODE_ANY;
5136         GC_TRIGGERS;
5137         THROWS;
5138         PRECONDITION(CheckPointer(ex));
5139         PRECONDITION(HasLock());
5140         INJECT_FAULT(COMPlusThrowOM(););
5141     }
5142     CONTRACTL_END;
5143
5144     m_cachedHR = ex->GetHR();
5145
5146     LOG((LF_LOADER, LL_WARNING, "LOADER: %x:***%s*\t!!!Non-transient error 0x%x\n",
5147          m_pDomainFile->GetAppDomain(), m_pDomainFile->GetSimpleName(), m_cachedHR));
5148
5149     m_pDomainFile->SetError(ex);
5150
5151     CompleteLoadLevel(FILE_ACTIVE, FALSE);
5152 }
5153
5154 void FileLoadLock::AddRef()
5155 {
5156     LIMITED_METHOD_CONTRACT;
5157     FastInterlockIncrement((LONG *) &m_dwRefCount);
5158 }
5159
5160 UINT32 FileLoadLock::Release()
5161 {
5162     CONTRACTL
5163     {
5164         NOTHROW;
5165         GC_TRIGGERS;
5166         MODE_ANY;
5167     }
5168     CONTRACTL_END;
5169
5170     LONG count = FastInterlockDecrement((LONG *) &m_dwRefCount);
5171     if (count == 0)
5172         delete this;
5173
5174     return count;
5175 }
5176
5177 FileLoadLock::FileLoadLock(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
5178   : ListLockEntry(pLock, pFile, "File load lock"),
5179     m_level((FileLoadLevel) (FILE_LOAD_CREATE)),
5180     m_pDomainFile(pDomainFile),
5181     m_cachedHR(S_OK),
5182     m_AppDomainId(pDomainFile->GetAppDomain()->GetId())
5183 {
5184     WRAPPER_NO_CONTRACT;
5185     pFile->AddRef();
5186 }
5187
5188 void FileLoadLock::HolderLeave(FileLoadLock *pThis)
5189 {
5190     LIMITED_METHOD_CONTRACT;
5191     pThis->Leave();
5192 }
5193
5194
5195
5196
5197
5198
5199 //
5200 // Assembly loading:
5201 //
5202 // Assembly loading is carefully layered to avoid deadlocks in the
5203 // presence of circular loading dependencies.
5204 // A LoadLevel is associated with each assembly as it is being loaded.  During the
5205 // act of loading (abstractly, increasing its load level), its lock is
5206 // held, and the current load level is stored on the thread.  Any
5207 // recursive loads during that period are automatically restricted to
5208 // only partially load the dependent assembly to the same level as the
5209 // caller (or to one short of that level in the presence of a deadlock
5210 // loop.)
5211 //
5212 // Each loading stage must be carfully constructed so that
5213 // this constraint is expected and can be dealt with.
5214 //
5215 // Note that there is one case where this still doesn't handle recursion, and that is the
5216 // security subsytem. The security system runs managed code, and thus must typically fully
5217 // initialize assemblies of permission sets it is trying to use. (And of course, these may be used
5218 // while those assemblies are initializing.)  This is dealt with in the historical manner - namely
5219 // the security system passes in a special flag which says that it will deal with null return values
5220 // in the case where a load cannot be safely completed due to such issues.
5221 //
5222
5223 void AppDomain::LoadSystemAssemblies()
5224 {
5225     STANDARD_VM_CONTRACT;
5226
5227     // The only reason to make an assembly a "system assembly" is if the EE is caching
5228     // pointers to stuff in the assembly.  Because this is going on, we need to preserve
5229     // the invariant that the assembly is loaded into every app domain.
5230     //
5231     // Right now we have only one system assembly. We shouldn't need to add any more.
5232
5233     LoadAssembly(NULL, SystemDomain::System()->SystemFile(), FILE_ACTIVE);
5234 }
5235
5236 FileLoadLevel AppDomain::GetDomainFileLoadLevel(DomainFile *pFile)
5237 {
5238     CONTRACTL
5239     {
5240         THROWS;
5241         GC_TRIGGERS;
5242         MODE_ANY;
5243     }
5244     CONTRACTL_END
5245
5246     LoadLockHolder lock(this);
5247
5248     FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5249
5250     if (pLockEntry == NULL)
5251         return pFile->GetLoadLevel();
5252     else
5253         return pLockEntry->GetLoadLevel();
5254 }
5255
5256 // This checks if the thread has initiated (or completed) loading at the given level.  A false guarantees that
5257 // (a) The current thread (or a thread blocking on the current thread) has not started loading the file
5258 //      at the given level, and
5259 // (b) No other thread had started loading the file at this level at the start of this function call.
5260
5261 // Note that another thread may start loading the file at that level in a race with the completion of
5262 // this function.  However, the caller still has the guarantee that such a load started after this
5263 // function was called (and e.g. any state in place before the function call will be seen by the other thread.)
5264 //
5265 // Conversely, a true guarantees that either the current thread has started the load step, or another
5266 // thread has completed the load step.
5267 //
5268
5269 BOOL AppDomain::IsLoading(DomainFile *pFile, FileLoadLevel level)
5270 {
5271     // Cheap out
5272     if (pFile->GetLoadLevel() < level)
5273     {
5274         FileLoadLock *pLock = NULL;
5275         {
5276             LoadLockHolder lock(this);
5277
5278             pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5279
5280             if (pLock == NULL)
5281             {
5282                 // No thread involved with loading
5283                 return pFile->GetLoadLevel() >= level;
5284             }
5285
5286             pLock->AddRef();
5287         }
5288
5289         FileLoadLockRefHolder lockRef(pLock);
5290
5291         if (pLock->Acquire(level))
5292         {
5293             // We got the lock - therefore no other thread has started this loading step yet.
5294             pLock->Leave();
5295             return FALSE;
5296         }
5297
5298         // We didn't get the lock - either this thread is already doing the load,
5299         // or else the load has already finished.
5300     }
5301     return TRUE;
5302 }
5303
5304 // CheckLoading is a weaker form of IsLoading, which will not block on
5305 // other threads waiting for their status.  This is appropriate for asserts.
5306 CHECK AppDomain::CheckLoading(DomainFile *pFile, FileLoadLevel level)
5307 {
5308     // Cheap out
5309     if (pFile->GetLoadLevel() < level)
5310     {
5311         FileLoadLock *pLock = NULL;
5312
5313         LoadLockHolder lock(this);
5314
5315         pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5316
5317         if (pLock != NULL
5318             && pLock->CanAcquire(level))
5319         {
5320             // We can get the lock - therefore no other thread has started this loading step yet.
5321             CHECK_FAILF(("Loading step %d has not been initiated yet", level));
5322         }
5323
5324         // We didn't get the lock - either this thread is already doing the load,
5325         // or else the load has already finished.
5326     }
5327
5328     CHECK_OK;
5329 }
5330
5331 CHECK AppDomain::CheckCanLoadTypes(Assembly *pAssembly)
5332 {
5333     CONTRACTL
5334     {
5335         THROWS;
5336         GC_TRIGGERS;
5337         MODE_ANY;
5338     }
5339     CONTRACTL_END;
5340     CHECK_MSG(CheckValidModule(pAssembly->GetManifestModule()),
5341               "Type loading can occur only when executing in the assembly's app domain");
5342     CHECK_OK;
5343 }
5344
5345 CHECK AppDomain::CheckCanExecuteManagedCode(MethodDesc* pMD)
5346 {
5347     CONTRACTL
5348     {
5349         THROWS;
5350         GC_TRIGGERS;
5351         MODE_ANY;
5352     }
5353     CONTRACTL_END;
5354
5355     Module* pModule=pMD->GetModule();
5356
5357     CHECK_MSG(CheckValidModule(pModule),
5358               "Managed code can only run when executing in the module's app domain");
5359
5360     if (!pMD->IsInterface() || pMD->IsStatic()) //interfaces require no activation for instance methods
5361     {
5362         //cctor could have been interupted by ADU
5363         CHECK_MSG(HasUnloadStarted() || pModule->CheckActivated(),
5364               "Managed code can only run when its module has been activated in the current app domain");
5365     }
5366
5367     CHECK_MSG(!IsPassiveDomain() || pModule->CanExecuteCode(),
5368               "Executing managed code from an unsafe assembly in a Passive AppDomain");
5369
5370     CHECK_OK;
5371 }
5372
5373 #endif // !DACCESS_COMPILE
5374
5375 void AppDomain::LoadDomainFile(DomainFile *pFile,
5376                                FileLoadLevel targetLevel)
5377 {
5378     CONTRACTL
5379     {
5380         if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
5381         if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
5382         if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM();); }
5383         INJECT_FAULT(COMPlusThrowOM(););
5384     }
5385     CONTRACTL_END;
5386
5387     // Quick exit if finished
5388     if (pFile->GetLoadLevel() >= targetLevel)
5389         return;
5390
5391     // Handle the error case
5392     pFile->ThrowIfError(targetLevel);
5393
5394
5395 #ifndef DACCESS_COMPILE
5396
5397     if (pFile->IsLoading())
5398     {
5399         GCX_PREEMP();
5400
5401         // Load some more if appropriate
5402         LoadLockHolder lock(this);
5403
5404         FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
5405         if (pLockEntry == NULL)
5406         {
5407             _ASSERTE (!pFile->IsLoading());
5408             return;
5409         }
5410
5411         pLockEntry->AddRef();
5412
5413         lock.Release();
5414
5415         LoadDomainFile(pLockEntry, targetLevel);
5416     }
5417
5418 #else // DACCESS_COMPILE
5419     DacNotImpl();
5420 #endif // DACCESS_COMPILE
5421 }
5422
5423 #ifndef DACCESS_COMPILE
5424
5425 FileLoadLevel AppDomain::GetThreadFileLoadLevel()
5426 {
5427     WRAPPER_NO_CONTRACT;
5428     if (GetThread()->GetLoadLevelLimiter() == NULL)
5429         return FILE_ACTIVE;
5430     else
5431         return (FileLoadLevel)(GetThread()->GetLoadLevelLimiter()->GetLoadLevel()-1);
5432 }
5433
5434
5435 Assembly *AppDomain::LoadAssembly(AssemblySpec* pIdentity,
5436                                   PEAssembly *pFile,
5437                                   FileLoadLevel targetLevel)
5438 {
5439     CONTRACT(Assembly *)
5440     {
5441         GC_TRIGGERS;
5442         THROWS;
5443         MODE_ANY;
5444         PRECONDITION(CheckPointer(pFile));
5445         POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // May be NULL in recursive load case
5446         INJECT_FAULT(COMPlusThrowOM(););
5447     }
5448     CONTRACT_END;
5449
5450     DomainAssembly *pAssembly = LoadDomainAssembly(pIdentity, pFile, targetLevel);
5451     PREFIX_ASSUME(pAssembly != NULL);
5452
5453     RETURN pAssembly->GetAssembly();
5454 }
5455
5456 #ifndef CROSSGEN_COMPILE
5457 // Thread stress
5458 class LoadDomainAssemblyStress : APIThreadStress
5459 {
5460 public:
5461     AppDomain *pThis;
5462     AssemblySpec* pSpec;
5463     PEAssembly *pFile;
5464     FileLoadLevel targetLevel;
5465
5466     LoadDomainAssemblyStress(AppDomain *pThis, AssemblySpec* pSpec, PEAssembly *pFile, FileLoadLevel targetLevel)
5467         : pThis(pThis), pSpec(pSpec), pFile(pFile), targetLevel(targetLevel) {LIMITED_METHOD_CONTRACT;}
5468
5469     void Invoke()
5470     {
5471         WRAPPER_NO_CONTRACT;
5472         STATIC_CONTRACT_SO_INTOLERANT;
5473         SetupThread();
5474         pThis->LoadDomainAssembly(pSpec, pFile, targetLevel);
5475     }
5476 };
5477 #endif // CROSSGEN_COMPILE
5478
5479 extern BOOL AreSameBinderInstance(ICLRPrivBinder *pBinderA, ICLRPrivBinder *pBinderB);
5480
5481 DomainAssembly* AppDomain::LoadDomainAssembly( AssemblySpec* pSpec,
5482                                                 PEAssembly *pFile, 
5483                                                 FileLoadLevel targetLevel)
5484 {
5485     STATIC_CONTRACT_THROWS;
5486
5487     if (pSpec == nullptr)
5488     {
5489         // skip caching, since we don't have anything to base it on
5490         return LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
5491     }
5492
5493     DomainAssembly* pRetVal = NULL;
5494     EX_TRY
5495     {
5496         pRetVal = LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
5497     }
5498     EX_HOOK
5499     {
5500         Exception* pEx=GET_EXCEPTION();
5501         if (!pEx->IsTransient())
5502         {
5503             // Setup the binder reference in AssemblySpec from the PEAssembly if one is not already set.
5504             ICLRPrivBinder* pCurrentBindingContext = pSpec->GetBindingContext();
5505             ICLRPrivBinder* pBindingContextFromPEAssembly = pFile->GetBindingContext();
5506             
5507             if (pCurrentBindingContext == NULL)
5508             {
5509                 // Set the binding context we got from the PEAssembly if AssemblySpec does not
5510                 // have that information
5511                 _ASSERTE(pBindingContextFromPEAssembly != NULL);
5512                 pSpec->SetBindingContext(pBindingContextFromPEAssembly);
5513             }
5514 #if defined(_DEBUG)            
5515             else
5516             {
5517                 // Binding context in the spec should be the same as the binding context in the PEAssembly
5518                 _ASSERTE(AreSameBinderInstance(pCurrentBindingContext, pBindingContextFromPEAssembly));
5519             }
5520 #endif // _DEBUG            
5521
5522             if (!EEFileLoadException::CheckType(pEx))
5523             {
5524                 StackSString name;
5525                 pSpec->GetFileOrDisplayName(0, name);
5526                 pEx=new EEFileLoadException(name, pEx->GetHR(), NULL, pEx);
5527                 AddExceptionToCache(pSpec, pEx);
5528                 PAL_CPP_THROW(Exception *, pEx);
5529             }
5530             else
5531                 AddExceptionToCache(pSpec, pEx);
5532         }
5533     }
5534     EX_END_HOOK;
5535
5536     return pRetVal;
5537 }
5538
5539
5540 DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
5541                                               PEAssembly *pFile,
5542                                               FileLoadLevel targetLevel)
5543 {
5544     CONTRACT(DomainAssembly *)
5545     {
5546         GC_TRIGGERS;
5547         THROWS;
5548         MODE_ANY;
5549         PRECONDITION(CheckPointer(pFile));
5550         PRECONDITION(pFile->IsSystem() || ::GetAppDomain()==this);
5551         POSTCONDITION(CheckPointer(RETVAL));
5552         POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
5553                       || RETVAL->GetLoadLevel() >= targetLevel);
5554         POSTCONDITION(RETVAL->CheckNoError(targetLevel));
5555         INJECT_FAULT(COMPlusThrowOM(););
5556     }
5557     CONTRACT_END;
5558
5559
5560     DomainAssembly * result;
5561
5562 #ifndef CROSSGEN_COMPILE
5563     LoadDomainAssemblyStress ts (this, pIdentity, pFile, targetLevel);
5564 #endif
5565
5566     // Go into preemptive mode since this may take a while.
5567     GCX_PREEMP();
5568
5569     // Check for existing fully loaded assembly, or for an assembly which has failed during the loading process.
5570     result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
5571     
5572     if (result == NULL)
5573     {
5574         // Allocate the DomainAssembly a bit early to avoid GC mode problems. We could potentially avoid
5575         // a rare redundant allocation by moving this closer to FileLoadLock::Create, but it's not worth it.
5576
5577         NewHolder<DomainAssembly> pDomainAssembly;
5578         pDomainAssembly = new DomainAssembly(this, pFile, this->GetLoaderAllocator());
5579
5580         LoadLockHolder lock(this);
5581
5582         // Find the list lock entry
5583         FileLoadLock * fileLock = (FileLoadLock *)lock->FindFileLock(pFile);
5584         if (fileLock == NULL)
5585         {
5586             // Check again in case we were racing
5587             result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
5588             if (result == NULL)
5589             {
5590                 // We are the first one in - create the DomainAssembly
5591                 fileLock = FileLoadLock::Create(lock, pFile, pDomainAssembly);
5592                 pDomainAssembly.SuppressRelease();
5593             }
5594         }
5595         else
5596         {
5597             fileLock->AddRef();
5598         }
5599
5600         lock.Release();
5601
5602         if (result == NULL)
5603         {
5604             // We pass our ref on fileLock to LoadDomainFile to release.
5605
5606             // Note that if we throw here, we will poison fileLock with an error condition,
5607             // so it will not be removed until app domain unload.  So there is no need
5608             // to release our ref count.
5609             result = (DomainAssembly *)LoadDomainFile(fileLock, targetLevel);
5610         }
5611         else
5612         {
5613             result->EnsureLoadLevel(targetLevel);
5614         }
5615     }
5616     else
5617         result->EnsureLoadLevel(targetLevel);
5618
5619     // Malformed metadata may contain a Module reference to what is actually
5620     // an Assembly. In this case we need to throw an exception, since returning
5621     // a DomainModule as a DomainAssembly is a type safety violation.
5622     if (!result->IsAssembly())
5623     {
5624         ThrowHR(COR_E_ASSEMBLYEXPECTED);
5625     }
5626
5627     // Cache result in all cases, since found pFile could be from a different AssemblyRef than pIdentity
5628     // Do not cache WindowsRuntime assemblies, they are cached in code:CLRPrivTypeCacheWinRT
5629     if ((pIdentity != NULL) && (pIdentity->CanUseWithBindingCache()) && (result->CanUseWithBindingCache()))
5630         GetAppDomain()->AddAssemblyToCache(pIdentity, result);
5631     
5632     RETURN result;
5633 } // AppDomain::LoadDomainAssembly
5634
5635
5636 struct LoadFileArgs
5637 {
5638     FileLoadLock *pLock;
5639     FileLoadLevel targetLevel;
5640     DomainFile *result;
5641 };
5642
5643 #ifndef CROSSGEN_COMPILE
5644 static void LoadDomainFile_Wrapper(void *ptr)
5645 {
5646     WRAPPER_NO_CONTRACT;
5647     STATIC_CONTRACT_SO_INTOLERANT;
5648     GCX_PREEMP();
5649     LoadFileArgs *args = (LoadFileArgs *) ptr;
5650     args->result = GetAppDomain()->LoadDomainFile(args->pLock, args->targetLevel);
5651 }
5652 #endif // !CROSSGEN_COMPILE
5653
5654 DomainFile *AppDomain::LoadDomainFile(FileLoadLock *pLock, FileLoadLevel targetLevel)
5655 {
5656     CONTRACT(DomainFile *)
5657     {
5658         STANDARD_VM_CHECK;
5659         PRECONDITION(CheckPointer(pLock));
5660         PRECONDITION(pLock->GetDomainFile()->GetAppDomain() == this);
5661         POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
5662                       || RETVAL->GetLoadLevel() >= targetLevel);
5663         POSTCONDITION(RETVAL->CheckNoError(targetLevel));
5664     }
5665     CONTRACT_END;
5666
5667
5668     if(!CanLoadCode())
5669         COMPlusThrow(kAppDomainUnloadedException);
5670
5671     // Thread stress
5672     APIThreadStress::SyncThreadStress();
5673
5674     DomainFile *pFile = pLock->GetDomainFile();
5675
5676     // Make sure we release the lock on exit
5677     FileLoadLockRefHolder lockRef(pLock);
5678
5679     // We need to perform the early steps of loading mscorlib without a domain transition.  This is
5680     // important for bootstrapping purposes - we need to get mscorlib at least partially loaded
5681     // into a domain before we can run serialization code to do the transition.
5682     //
5683     // Note that we cannot do this in general for all assemblies, because some of the security computations
5684     // require the managed exposed object, which must be created in the correct app domain.
5685
5686     if (this != GetAppDomain()
5687         && pFile->GetFile()->IsSystem()
5688         && targetLevel > FILE_LOAD_ALLOCATE)
5689     {
5690         // Re-call the routine with a limited load level. This will cause the first part of the load to
5691         // get performed in the current app domain.
5692
5693         pLock->AddRef();
5694         LoadDomainFile(pLock, targetLevel > FILE_LOAD_ALLOCATE ? FILE_LOAD_ALLOCATE : targetLevel);
5695
5696         // Now continue on to complete the rest of the load, if any.
5697     }
5698
5699     // Do a quick out check for the already loaded case.
5700     if (pLock->GetLoadLevel() >= targetLevel)
5701     {
5702         pFile->ThrowIfError(targetLevel);
5703
5704         RETURN pFile;
5705     }
5706
5707 #ifndef CROSSGEN_COMPILE
5708     // Make sure we are in the right domain.  Many of the load operations require the target domain
5709     // to be the current app domain, most notably anything involving managed code or managed object
5710     // creation.
5711     if (this != GetAppDomain()
5712         && (!pFile->GetFile()->IsSystem() || targetLevel > FILE_LOAD_ALLOCATE))
5713     {
5714         // Transition to the correct app domain and perform the load there.
5715         GCX_COOP();
5716
5717         // we will release the lock in the other app domain
5718         lockRef.SuppressRelease();
5719
5720         if(!CanLoadCode() || GetDefaultContext() ==NULL)
5721             COMPlusThrow(kAppDomainUnloadedException);
5722         LoadFileArgs args = {pLock, targetLevel, NULL};
5723         GetThread()->DoADCallBack(this, LoadDomainFile_Wrapper, (void *) &args, ADV_CREATING);
5724
5725         RETURN args.result;
5726     }
5727 #endif // CROSSGEN_COMPILE
5728
5729     // Initialize a loading queue.  This will hold any loads which are triggered recursively but
5730     // which cannot be immediately satisfied due to anti-deadlock constraints.
5731
5732     // PendingLoadQueues are allocated on the stack during a load, and
5733     // shared with all nested loads on the same thread. (Note that we won't use
5734     // "candidate" if we are in a recursive load; that's OK since they are cheap to
5735     // construct.)
5736     FileLoadLevel immediateTargetLevel = targetLevel;
5737     {
5738         LoadLevelLimiter limit;
5739         limit.Activate();
5740
5741         // We cannot set a target level higher than that allowed by the limiter currently.
5742         // This is because of anti-deadlock constraints.
5743         if (immediateTargetLevel > limit.GetLoadLevel())
5744             immediateTargetLevel = limit.GetLoadLevel();
5745
5746         LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t>>>Load initiated, %s/%s\n",
5747              pFile->GetAppDomain(), pFile->GetSimpleName(),
5748              fileLoadLevelName[immediateTargetLevel], fileLoadLevelName[targetLevel]));
5749
5750         // Now loop and do the load incrementally to the target level.
5751         if (pLock->GetLoadLevel() < immediateTargetLevel)
5752         {
5753             // Thread stress
5754             APIThreadStress::SyncThreadStress();
5755
5756             while (pLock->Acquire(immediateTargetLevel))
5757             {
5758                 FileLoadLevel workLevel;
5759                 {
5760                     FileLoadLockHolder fileLock(pLock);
5761
5762                     // Work level is next step to do
5763                     workLevel = (FileLoadLevel)(fileLock->GetLoadLevel()+1);
5764
5765                     // Set up the anti-deadlock constraint: we cannot safely recursively load any assemblies
5766                     // on this thread to a higher level than this assembly is being loaded now.
5767                     // Note that we do allow work at a parallel level; any deadlocks caused here will
5768                     // be resolved by the deadlock detection in the FileLoadLocks.
5769                     limit.SetLoadLevel(workLevel);
5770
5771                     LOG((LF_LOADER,
5772                          (workLevel == FILE_LOAD_BEGIN
5773                           || workLevel == FILE_LOADED
5774                           || workLevel == FILE_ACTIVE)
5775                          ? LL_INFO10 : LL_INFO1000,
5776                          "LOADER: %p:***%s*\t   loading at level %s\n",
5777                          this, pFile->GetSimpleName(), fileLoadLevelName[workLevel]));
5778
5779                     TryIncrementalLoad(pFile, workLevel, fileLock);
5780                 }
5781                 TESTHOOKCALL(CompletedFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5782             }
5783
5784             if (pLock->GetLoadLevel() == immediateTargetLevel-1)
5785             {
5786                 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load limited due to detected deadlock, %s\n",
5787                      pFile->GetAppDomain(), pFile->GetSimpleName(),
5788                      fileLoadLevelName[immediateTargetLevel-1]));
5789             }
5790         }
5791
5792         LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load completed, %s\n",
5793              pFile->GetAppDomain(), pFile->GetSimpleName(),
5794              fileLoadLevelName[pLock->GetLoadLevel()]));
5795
5796     }
5797
5798     // There may have been an error stored on the domain file by another thread, or from a previous load
5799     pFile->ThrowIfError(targetLevel);
5800
5801     // There are two normal results from the above loop.
5802     //
5803     // 1. We succeeded in loading the file to the current thread's load level.
5804     // 2. We succeeded in loading the file to the current thread's load level - 1, due
5805     //      to deadlock condition with another thread loading the same assembly.
5806     //
5807     // Either of these are considered satisfactory results, as code inside a load must expect
5808     // a parial load result.
5809     //
5810     // However, if load level elevation has occurred, then it is possible for a deadlock to
5811     // prevent us from loading an assembly which was loading before the elevation at a radically
5812     // lower level.  In such a case, we throw an exception which transiently fails the current
5813     // load, since it is likely we have not satisfied the caller.
5814     // (An alternate, and possibly preferable, strategy here would be for all callers to explicitly
5815     // identify the minimum load level acceptable via CheckLoadDomainFile and throw from there.)
5816
5817     pFile->RequireLoadLevel((FileLoadLevel)(immediateTargetLevel-1));
5818
5819
5820     RETURN pFile;
5821 }
5822
5823 void AppDomain::TryIncrementalLoad(DomainFile *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder)
5824 {
5825     STANDARD_VM_CONTRACT;
5826
5827     // This is factored out so we don't call EX_TRY in a loop (EX_TRY can _alloca)
5828
5829     BOOL released = FALSE;
5830     FileLoadLock* pLoadLock = lockHolder.GetValue();
5831
5832     EX_TRY
5833     {
5834
5835         // Special case: for LoadLibrary, we cannot hold the lock during the
5836         // actual LoadLibrary call, because we might get a callback from _CorDllMain on any
5837         // other thread.  (Note that this requires DomainFile's LoadLibrary to be independently threadsafe.)
5838
5839         if (workLevel == FILE_LOAD_LOADLIBRARY)
5840         {
5841             lockHolder.Release();
5842             released = TRUE;
5843         }
5844
5845         // Do the work
5846         TESTHOOKCALL(NextFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5847         BOOL success = pFile->DoIncrementalLoad(workLevel);
5848         TESTHOOKCALL(CompletingFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5849         if (released)
5850         {
5851             // Reobtain lock to increment level. (Note that another thread may
5852             // have already done it which is OK.
5853             if (pLoadLock->Acquire(workLevel))
5854             {
5855                 // note lockHolder.Acquire isn't wired up to actually take the lock
5856                 lockHolder = pLoadLock;
5857                 released = FALSE;
5858             }
5859         }
5860
5861         if (!released)
5862         {
5863             // Complete the level.
5864             if (pLoadLock->CompleteLoadLevel(workLevel, success) &&
5865                 pLoadLock->GetLoadLevel()==FILE_LOAD_DELIVER_EVENTS)
5866             {
5867                 lockHolder.Release();
5868                 released = TRUE;
5869                 pFile->DeliverAsyncEvents();
5870             };
5871         }
5872     }
5873     EX_HOOK
5874     {
5875         Exception *pEx = GET_EXCEPTION();
5876
5877
5878         //We will cache this error and wire this load to forever fail,
5879         // unless the exception is transient or the file is loaded OK but just cannot execute
5880         if (!pEx->IsTransient() && !pFile->IsLoaded())
5881         {
5882
5883             if (released)
5884             {
5885                 // Reobtain lock to increment level. (Note that another thread may
5886                 // have already done it which is OK.
5887                 if (pLoadLock->Acquire(workLevel)) // note pLockHolder->Acquire isn't wired up to actually take the lock
5888                 {
5889                     // note lockHolder.Acquire isn't wired up to actually take the lock
5890                     lockHolder = pLoadLock;
5891                     released = FALSE;
5892                 }
5893             }
5894
5895             if (!released)
5896             {
5897                 // Report the error in the lock
5898                 pLoadLock->SetError(pEx);
5899             }
5900
5901             if (!EEFileLoadException::CheckType(pEx))
5902                 EEFileLoadException::Throw(pFile->GetFile(), pEx->GetHR(), pEx);
5903         }
5904
5905         // Otherwise, we simply abort this load, and can retry later on.
5906         // @todo cleanup: make sure that each level is restartable after an exception, and
5907         // leaves no bad side effects
5908     }
5909     EX_END_HOOK;
5910 }
5911
5912 // Checks whether the module is valid to be in the given app domain (need not be yet loaded)
5913 CHECK AppDomain::CheckValidModule(Module * pModule)
5914 {
5915     CONTRACTL
5916     {
5917         THROWS;
5918         GC_TRIGGERS;
5919         MODE_ANY;
5920     }
5921     CONTRACTL_END;
5922
5923     if (pModule->FindDomainFile(this) != NULL)
5924         CHECK_OK;
5925
5926     CCHECK_START
5927     {
5928         Assembly * pAssembly = pModule->GetAssembly();
5929
5930         CCHECK(pAssembly->IsDomainNeutral());
5931 #ifdef FEATURE_LOADER_OPTIMIZATION        
5932         Assembly * pSharedAssembly = NULL;
5933         _ASSERTE(this == ::GetAppDomain());
5934         {
5935             SharedAssemblyLocator locator(pAssembly->GetManifestFile());
5936             pSharedAssembly = SharedDomain::GetDomain()->FindShareableAssembly(&locator);
5937         }
5938
5939         CCHECK(pAssembly == pSharedAssembly);
5940 #endif         
5941     }
5942     CCHECK_END;
5943
5944     CHECK_OK;
5945 }
5946
5947 #ifdef FEATURE_LOADER_OPTIMIZATION
5948 // Loads an existing Module into an AppDomain
5949 // WARNING: this can only be done in a very limited scenario - the Module must be an unloaded domain neutral
5950 // dependency in the app domain in question.  Normal code should not call this!
5951 DomainFile *AppDomain::LoadDomainNeutralModuleDependency(Module *pModule, FileLoadLevel targetLevel)
5952 {
5953     CONTRACT(DomainFile *)
5954     {
5955         THROWS;
5956         GC_TRIGGERS;
5957         MODE_ANY;
5958         PRECONDITION(::GetAppDomain()==this);
5959         PRECONDITION(CheckPointer(pModule));
5960         POSTCONDITION(CheckValidModule(pModule));
5961         POSTCONDITION(CheckPointer(RETVAL));
5962         POSTCONDITION(RETVAL->GetModule() == pModule);
5963     }
5964     CONTRACT_END;
5965
5966     DomainFile *pDomainFile = pModule->FindDomainFile(this);
5967
5968     STRESS_LOG3(LF_CLASSLOADER, LL_INFO100,"LDNMD: DomainFile %p for module %p in AppDomain %i\n",pDomainFile,pModule,GetId().m_dwId);
5969
5970     if (pDomainFile == NULL)
5971     {
5972         GCX_PREEMP();
5973
5974         Assembly *pAssembly = pModule->GetAssembly();
5975
5976         DomainAssembly *pDomainAssembly = pAssembly->FindDomainAssembly(this);
5977         if (pDomainAssembly == NULL)
5978         {
5979             AssemblySpec spec(this);
5980             spec.InitializeSpec(pAssembly->GetManifestFile());
5981
5982             pDomainAssembly = spec.LoadDomainAssembly(targetLevel);
5983         }
5984         else
5985         {
5986             //if the domain assembly already exists, we need to load it to the target level
5987             pDomainAssembly->EnsureLoadLevel (targetLevel);
5988         }
5989
5990         if(pAssembly != pDomainAssembly->GetAssembly())
5991         {
5992             ThrowHR(SECURITY_E_INCOMPATIBLE_SHARE);
5993         }
5994
5995         _ASSERTE (pModule == pAssembly->GetManifestModule());
5996         pDomainFile = pDomainAssembly;
5997     }
5998     else
5999     {
6000         // If the DomainFile already exists, we need to load it to the target level.
6001         pDomainFile->EnsureLoadLevel (targetLevel);
6002     }
6003
6004     RETURN pDomainFile;
6005 }
6006
6007 AppDomain::SharePolicy AppDomain::GetSharePolicy()
6008 {
6009     LIMITED_METHOD_CONTRACT;
6010
6011     return SHARE_POLICY_NEVER;
6012 }
6013 #endif // FEATURE_LOADER_OPTIMIZATION
6014
6015
6016 void AppDomain::CheckForMismatchedNativeImages(AssemblySpec * pSpec, const GUID * pGuid)
6017 {
6018     STANDARD_VM_CONTRACT;
6019
6020     //
6021     // The native images are ever used only for trusted images in CoreCLR.
6022     // We don't wish to open the IL file at runtime so we just forgo any
6023     // eager consistency checking. But we still want to prevent mistmatched 
6024     // NGen images from being used. We record all mappings between assembly 
6025     // names and MVID, and fail once we detect mismatch.
6026     //
6027
6028     if (pSpec->IsStrongNamed() && pSpec->HasPublicKey())
6029     {
6030         pSpec->ConvertPublicKeyToToken();
6031     }
6032
6033     //
6034     // CoreCLR binder unifies assembly versions. Ignore assembly version here to 
6035     // detect more types of potential mismatches.
6036     //
6037     AssemblyMetaDataInternal * pContext = pSpec->GetContext();
6038     pContext->usMajorVersion = (USHORT)-1;
6039     pContext->usMinorVersion = (USHORT)-1;
6040     pContext->usBuildNumber = (USHORT)-1;
6041     pContext->usRevisionNumber = (USHORT)-1;
6042
6043     // Ignore the WinRT type while considering if two assemblies have the same identity.
6044     pSpec->SetWindowsRuntimeType(NULL, NULL);
6045
6046     CrstHolder ch(&m_DomainCrst);
6047
6048     const NativeImageDependenciesEntry * pEntry = m_NativeImageDependencies.Lookup(pSpec);
6049
6050     if (pEntry != NULL)
6051     {
6052         if (*pGuid != pEntry->m_guidMVID)
6053         {
6054             SString msg;
6055             msg.Printf("ERROR: Native images generated against multiple versions of assembly %s. ", pSpec->GetName());
6056             WszOutputDebugString(msg.GetUnicode());
6057             COMPlusThrowNonLocalized(kFileLoadException, msg.GetUnicode());
6058         }
6059     }
6060     else
6061     {
6062         //
6063         // No entry yet - create one
6064         //
6065         AllocMemTracker amTracker;
6066         AllocMemTracker *pamTracker = &amTracker;
6067
6068         NativeImageDependenciesEntry * pNewEntry = 
6069             new (pamTracker->Track(GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(NativeImageDependenciesEntry)))))
6070                 NativeImageDependenciesEntry();
6071
6072         pNewEntry->m_AssemblySpec.CopyFrom(pSpec);
6073         pNewEntry->m_AssemblySpec.CloneFieldsToLoaderHeap(AssemblySpec::ALL_OWNED, GetLowFrequencyHeap(), pamTracker);
6074
6075         pNewEntry->m_guidMVID = *pGuid;
6076
6077         m_NativeImageDependencies.Add(pNewEntry);
6078         amTracker.SuppressRelease();
6079     }
6080 }
6081
6082
6083 void AppDomain::SetupSharedStatics()
6084 {
6085     CONTRACTL
6086     {
6087         THROWS;
6088         GC_TRIGGERS;
6089         MODE_ANY;
6090         INJECT_FAULT(COMPlusThrowOM(););
6091     }
6092     CONTRACTL_END;
6093
6094 #ifndef CROSSGEN_COMPILE
6095     if (NingenEnabled())
6096         return;
6097
6098     LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: SetupSharedStatics()"));
6099
6100     // don't do any work in init stage. If not init only do work in non-shared case if are default domain
6101     _ASSERTE(!g_fEEInit);
6102
6103     // Because we are allocating/referencing objects, need to be in cooperative mode
6104     GCX_COOP();
6105
6106     static OBJECTHANDLE hSharedStaticsHandle = NULL;
6107
6108     if (hSharedStaticsHandle == NULL) {
6109         // Note that there is no race here since the default domain is always set up first
6110         _ASSERTE(IsDefaultDomain());
6111
6112         MethodTable *pMT = MscorlibBinder::GetClass(CLASS__SHARED_STATICS);
6113         _ASSERTE(pMT->IsClassPreInited());
6114
6115         hSharedStaticsHandle = CreateGlobalHandle(AllocateObject(pMT));
6116     }
6117
6118     DomainLocalModule *pLocalModule;
6119
6120     if (IsSingleAppDomain())
6121     {
6122         pLocalModule = MscorlibBinder::GetModule()->GetDomainLocalModule();
6123     }
6124     else
6125     {
6126         pLocalModule = GetDomainLocalBlock()->GetModuleSlot(
6127             MscorlibBinder::GetModule()->GetModuleIndex());
6128     }
6129
6130     FieldDesc *pFD = MscorlibBinder::GetField(FIELD__SHARED_STATICS__SHARED_STATICS);
6131
6132     OBJECTREF* pHandle = (OBJECTREF*)
6133         ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pFD->GetOffset());
6134     SetObjectReference( pHandle, ObjectFromHandle(hSharedStaticsHandle), this );
6135
6136     // This is a convenient place to initialize String.Empty.
6137     // It is treated as intrinsic by the JIT as so the static constructor would never run.
6138     // Leaving it uninitialized would confuse debuggers.
6139
6140     // String should not have any static constructors.
6141     _ASSERTE(g_pStringClass->IsClassPreInited());
6142
6143     FieldDesc * pEmptyStringFD = MscorlibBinder::GetField(FIELD__STRING__EMPTY);
6144     OBJECTREF* pEmptyStringHandle = (OBJECTREF*)
6145         ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pEmptyStringFD->GetOffset());
6146     SetObjectReference( pEmptyStringHandle, StringObject::GetEmptyString(), this );
6147 #endif // CROSSGEN_COMPILE
6148 }
6149
6150 DomainAssembly * AppDomain::FindAssembly(PEAssembly * pFile, FindAssemblyOptions options/* = FindAssemblyOptions_None*/)
6151 {
6152     CONTRACTL
6153     {
6154         THROWS;
6155         GC_TRIGGERS;
6156         MODE_ANY;
6157         INJECT_FAULT(COMPlusThrowOM(););
6158     }
6159     CONTRACTL_END;
6160
6161     const bool includeFailedToLoad = (options & FindAssemblyOptions_IncludeFailedToLoad) != 0;
6162
6163     if (pFile->HasHostAssembly())
6164     {
6165         DomainAssembly * pDA = FindAssembly(pFile->GetHostAssembly());
6166         if (pDA != nullptr && (pDA->IsLoaded() || (includeFailedToLoad && pDA->IsError())))
6167         {
6168             return pDA;
6169         }
6170         return nullptr;
6171     }
6172
6173     AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
6174         kIncludeLoaded | 
6175         (includeFailedToLoad ? kIncludeFailedToLoad : 0) |
6176         (pFile->IsIntrospectionOnly() ? kIncludeIntrospection : kIncludeExecution)));
6177     CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
6178
6179     while (i.Next(pDomainAssembly.This()))
6180     {
6181         PEFile * pManifestFile = pDomainAssembly->GetFile();
6182         if (pManifestFile && 
6183             !pManifestFile->IsResource() && 
6184             pManifestFile->Equals(pFile))
6185         {
6186             // Caller already has PEAssembly, so we can give DomainAssembly away freely without AddRef
6187             return pDomainAssembly.Extract();
6188         }
6189     }
6190     return NULL;
6191 }
6192
6193 static const AssemblyIterationFlags STANDARD_IJW_ITERATOR_FLAGS = 
6194     (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kExcludeCollectible);
6195
6196
6197 void AppDomain::SetFriendlyName(LPCWSTR pwzFriendlyName, BOOL fDebuggerCares/*=TRUE*/)
6198 {
6199     CONTRACTL
6200     {
6201         THROWS;
6202         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6203         MODE_ANY;
6204         INJECT_FAULT(COMPlusThrowOM(););
6205     }
6206     CONTRACTL_END;
6207
6208     // Do all computations into a temporary until we're ensured of success
6209     SString tmpFriendlyName;
6210
6211
6212     if (pwzFriendlyName)
6213         tmpFriendlyName.Set(pwzFriendlyName);
6214     else
6215     {
6216         // If there is an assembly, try to get the name from it.
6217         // If no assembly, but if it's the DefaultDomain, then give it a name
6218
6219         if (m_pRootAssembly)
6220         {
6221             tmpFriendlyName.SetUTF8(m_pRootAssembly->GetSimpleName());
6222
6223             SString::Iterator i = tmpFriendlyName.End();
6224             if (tmpFriendlyName.FindBack(i, '.'))
6225                 tmpFriendlyName.Truncate(i);
6226         }
6227         else
6228         {
6229             if (IsDefaultDomain())
6230                 tmpFriendlyName.Set(DEFAULT_DOMAIN_FRIENDLY_NAME);
6231
6232             // This is for the profiler - if they call GetFriendlyName on an AppdomainCreateStarted
6233             // event, then we want to give them a temporary name they can use.
6234             else if (GetId().m_dwId != 0)
6235             {
6236                 tmpFriendlyName.Clear();
6237                 tmpFriendlyName.Printf(W("%s %d"), OTHER_DOMAIN_FRIENDLY_NAME_PREFIX, GetId().m_dwId);
6238             }
6239         }
6240
6241     }
6242
6243     tmpFriendlyName.Normalize();
6244
6245
6246     m_friendlyName = tmpFriendlyName;
6247     m_friendlyName.Normalize();
6248
6249     if(g_pDebugInterface) 
6250     {
6251         // update the name in the IPC publishing block
6252         if (SUCCEEDED(g_pDebugInterface->UpdateAppDomainEntryInIPC(this)))
6253         {
6254             // inform the attached debugger that the name of this appdomain has changed.
6255             if (IsDebuggerAttached() && fDebuggerCares)
6256                 g_pDebugInterface->NameChangeEvent(this, NULL);
6257         }
6258     }
6259 }
6260
6261 void AppDomain::ResetFriendlyName(BOOL fDebuggerCares/*=TRUE*/)
6262 {
6263     WRAPPER_NO_CONTRACT;
6264     SetFriendlyName(NULL, fDebuggerCares);
6265 }
6266
6267 LPCWSTR AppDomain::GetFriendlyName(BOOL fDebuggerCares/*=TRUE*/)
6268 {
6269     CONTRACT (LPCWSTR)
6270     {
6271         THROWS;
6272         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6273         MODE_ANY;
6274         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
6275         INJECT_FAULT(COMPlusThrowOM(););
6276     }
6277     CONTRACT_END;
6278
6279 #if _DEBUG
6280     // Handle NULL this pointer - this happens sometimes when printing log messages
6281     // but in general shouldn't occur in real code
6282     if (this == NULL)
6283         RETURN NULL;
6284 #endif // _DEBUG
6285
6286     if (m_friendlyName.IsEmpty())
6287         SetFriendlyName(NULL, fDebuggerCares);
6288
6289     RETURN m_friendlyName;
6290 }
6291
6292 LPCWSTR AppDomain::GetFriendlyNameForLogging()
6293 {
6294     CONTRACT(LPWSTR)
6295     {
6296         NOTHROW;
6297         GC_NOTRIGGER;
6298         MODE_ANY;
6299         POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
6300     }
6301     CONTRACT_END;
6302 #if _DEBUG
6303     // Handle NULL this pointer - this happens sometimes when printing log messages
6304     // but in general shouldn't occur in real code
6305     if (this == NULL)
6306         RETURN NULL;
6307 #endif // _DEBUG
6308     RETURN (m_friendlyName.IsEmpty() ?W(""):(LPCWSTR)m_friendlyName);
6309 }
6310
6311 LPCWSTR AppDomain::GetFriendlyNameForDebugger()
6312 {
6313     CONTRACT (LPCWSTR)
6314     {
6315         NOTHROW;
6316         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
6317         MODE_ANY;
6318         POSTCONDITION(CheckPointer(RETVAL));
6319     }
6320     CONTRACT_END;
6321
6322
6323     if (m_friendlyName.IsEmpty())
6324     {
6325         BOOL fSuccess = FALSE;
6326
6327         EX_TRY
6328         {
6329             SetFriendlyName(NULL);
6330
6331             fSuccess = TRUE;
6332         }
6333         EX_CATCH
6334         {
6335             // Gobble all exceptions.
6336         }
6337         EX_END_CATCH(SwallowAllExceptions);
6338
6339         if (!fSuccess)
6340         {
6341             RETURN W("");
6342         }
6343     }
6344
6345     RETURN m_friendlyName;
6346 }
6347
6348
6349 #endif // !DACCESS_COMPILE
6350
6351 #ifdef DACCESS_COMPILE
6352
6353 PVOID AppDomain::GetFriendlyNameNoSet(bool* isUtf8)
6354 {
6355     SUPPORTS_DAC;
6356
6357     if (!m_friendlyName.IsEmpty())
6358     {
6359         *isUtf8 = false;
6360         return m_friendlyName.DacGetRawContent();
6361     }
6362     else if (m_pRootAssembly)
6363     {
6364         *isUtf8 = true;
6365         return (PVOID)m_pRootAssembly->GetSimpleName();
6366     }
6367     else if (dac_cast<TADDR>(this) ==
6368              dac_cast<TADDR>(SystemDomain::System()->DefaultDomain()))
6369     {
6370         *isUtf8 = false;
6371         return (PVOID)DEFAULT_DOMAIN_FRIENDLY_NAME;
6372     }
6373     else
6374     {
6375         return NULL;
6376     }
6377 }
6378
6379 #endif // DACCESS_COMPILE
6380
6381 #ifndef DACCESS_COMPILE
6382
6383 BOOL AppDomain::AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAllowFailure)
6384 {
6385     CONTRACTL
6386     {
6387         THROWS;
6388         GC_TRIGGERS;
6389         MODE_ANY;
6390         PRECONDITION(CheckPointer(pSpec));
6391         // Hosted fusion binder makes an exception here, so we cannot assert.
6392         //PRECONDITION(pSpec->CanUseWithBindingCache());
6393         //PRECONDITION(pFile->CanUseWithBindingCache());
6394         INJECT_FAULT(COMPlusThrowOM(););
6395     }
6396     CONTRACTL_END;
6397
6398     CrstHolder holder(&m_DomainCacheCrst);
6399     // !!! suppress exceptions
6400     if(!m_AssemblyCache.StoreFile(pSpec, pFile) && !fAllowFailure)
6401     {
6402         // TODO: Disabling the below assertion as currently we experience
6403         // inconsistency on resolving the Microsoft.Office.Interop.MSProject.dll
6404         // This causes below assertion to fire and crashes the VS. This issue
6405         // is being tracked with Dev10 Bug 658555. Brought back it when this bug 
6406         // is fixed.
6407         // _ASSERTE(FALSE);
6408
6409         EEFileLoadException::Throw(pSpec, FUSION_E_CACHEFILE_FAILED, NULL);
6410     }
6411
6412     return TRUE;
6413 }
6414
6415 BOOL AppDomain::AddAssemblyToCache(AssemblySpec* pSpec, DomainAssembly *pAssembly)
6416 {
6417     CONTRACTL
6418     {
6419         THROWS;
6420         GC_TRIGGERS;
6421         MODE_ANY;
6422         PRECONDITION(CheckPointer(pSpec));
6423         PRECONDITION(CheckPointer(pAssembly));
6424         PRECONDITION(pSpec->CanUseWithBindingCache());
6425         PRECONDITION(pAssembly->CanUseWithBindingCache());
6426         INJECT_FAULT(COMPlusThrowOM(););
6427     }
6428     CONTRACTL_END;
6429     
6430     CrstHolder holder(&m_DomainCacheCrst);
6431     // !!! suppress exceptions
6432     BOOL bRetVal = m_AssemblyCache.StoreAssembly(pSpec, pAssembly);
6433     return bRetVal;
6434 }
6435
6436 BOOL AppDomain::AddExceptionToCache(AssemblySpec* pSpec, Exception *ex)
6437 {
6438     CONTRACTL
6439     {
6440         THROWS;
6441         GC_TRIGGERS;
6442         MODE_ANY;
6443         PRECONDITION(CheckPointer(pSpec));
6444         PRECONDITION(pSpec->CanUseWithBindingCache());
6445         INJECT_FAULT(COMPlusThrowOM(););
6446     }
6447     CONTRACTL_END;
6448     
6449     if (ex->IsTransient())
6450         return TRUE;
6451
6452     CrstHolder holder(&m_DomainCacheCrst);
6453     // !!! suppress exceptions
6454     return m_AssemblyCache.StoreException(pSpec, ex);
6455 }
6456
6457 void AppDomain::AddUnmanagedImageToCache(LPCWSTR libraryName, HMODULE hMod)
6458 {
6459     CONTRACTL
6460     {
6461         THROWS;
6462         GC_TRIGGERS;
6463         MODE_ANY;
6464         PRECONDITION(CheckPointer(libraryName));
6465         INJECT_FAULT(COMPlusThrowOM(););
6466     }
6467     CONTRACTL_END;
6468     if (libraryName)
6469     {
6470         AssemblySpec spec;
6471         spec.SetCodeBase(libraryName);
6472         m_UnmanagedCache.InsertEntry(&spec, hMod);
6473     }
6474     return ;
6475 }
6476
6477
6478 HMODULE AppDomain::FindUnmanagedImageInCache(LPCWSTR libraryName)
6479 {
6480     CONTRACT(HMODULE)
6481     {
6482         THROWS;
6483         GC_TRIGGERS;
6484         MODE_ANY;
6485         PRECONDITION(CheckPointer(libraryName,NULL_OK));
6486         POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
6487         INJECT_FAULT(COMPlusThrowOM(););
6488     }
6489     CONTRACT_END;
6490     if(libraryName == NULL) RETURN NULL;
6491
6492     AssemblySpec spec;
6493     spec.SetCodeBase(libraryName);
6494     RETURN (HMODULE) m_UnmanagedCache.LookupEntry(&spec, 0);
6495 }
6496
6497
6498 BOOL AppDomain::IsCached(AssemblySpec *pSpec)
6499 {
6500     WRAPPER_NO_CONTRACT;
6501
6502     // Check to see if this fits our rather loose idea of a reference to mscorlib.
6503     // If so, don't use fusion to bind it - do it ourselves.
6504     if (pSpec->IsMscorlib())
6505         return TRUE;
6506
6507     return m_AssemblyCache.Contains(pSpec);
6508 }
6509
6510 void AppDomain::GetCacheAssemblyList(SetSHash<PTR_DomainAssembly>& assemblyList)
6511 {
6512     CrstHolder holder(&m_DomainCacheCrst);
6513     m_AssemblyCache.GetAllAssemblies(assemblyList);
6514 }
6515
6516 PEAssembly* AppDomain::FindCachedFile(AssemblySpec* pSpec, BOOL fThrow /*=TRUE*/)
6517 {
6518     CONTRACTL
6519     {
6520         if (fThrow) {
6521             GC_TRIGGERS;
6522             THROWS;
6523         }
6524         else {
6525             GC_NOTRIGGER;
6526             NOTHROW;
6527         }
6528         MODE_ANY;
6529     }
6530     CONTRACTL_END;
6531
6532     // Check to see if this fits our rather loose idea of a reference to mscorlib.
6533     // If so, don't use fusion to bind it - do it ourselves.
6534     if (fThrow && pSpec->IsMscorlib())
6535     {
6536         CONSISTENCY_CHECK(SystemDomain::System()->SystemAssembly() != NULL);
6537         PEAssembly *pFile = SystemDomain::System()->SystemFile();
6538         pFile->AddRef();
6539         return pFile;
6540     }
6541
6542     return m_AssemblyCache.LookupFile(pSpec, fThrow);
6543 }
6544
6545
6546 BOOL AppDomain::PostBindResolveAssembly(AssemblySpec  *pPrePolicySpec,
6547                                         AssemblySpec  *pPostPolicySpec,
6548                                         HRESULT        hrBindResult,
6549                                         AssemblySpec **ppFailedSpec)
6550 {
6551     STATIC_CONTRACT_THROWS;
6552     STATIC_CONTRACT_GC_TRIGGERS;
6553     PRECONDITION(CheckPointer(pPrePolicySpec));
6554     PRECONDITION(CheckPointer(pPostPolicySpec));
6555     PRECONDITION(CheckPointer(ppFailedSpec));
6556
6557     BOOL fFailure = TRUE;
6558     *ppFailedSpec = pPrePolicySpec;
6559
6560
6561     PEAssemblyHolder result;
6562
6563     if ((EEFileLoadException::GetFileLoadKind(hrBindResult) == kFileNotFoundException) ||
6564         (hrBindResult == FUSION_E_REF_DEF_MISMATCH) ||
6565         (hrBindResult == FUSION_E_INVALID_NAME))
6566     {
6567         result = TryResolveAssembly(*ppFailedSpec, FALSE /* fPreBind */);
6568
6569         if (result != NULL && pPrePolicySpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
6570         {
6571             fFailure = FALSE;
6572
6573             // Given the post-policy resolve event construction of the CLR binder,
6574             // chained managed resolve events can race with each other, therefore we do allow
6575             // the adding of the result to fail. Checking for already chached specs
6576             // is not an option as it would introduce another race window.
6577             // The binder does a re-fetch of the
6578             // orignal binding spec and therefore will not cause inconsistency here.
6579             // For the purposes of the resolve event, failure to add to the cache still is a success.
6580             AddFileToCache(pPrePolicySpec, result, TRUE /* fAllowFailure */);
6581             if (*ppFailedSpec != pPrePolicySpec && pPostPolicySpec->CanUseWithBindingCache())
6582             {
6583                 AddFileToCache(pPostPolicySpec, result, TRUE /* fAllowFailure */ );
6584             }
6585         }
6586     }
6587
6588     return fFailure;
6589 }
6590
6591 //----------------------------------------------------------------------------------------
6592 // Helper class for hosted binder
6593
6594 class PEAssemblyAsPrivAssemblyInfo : public IUnknownCommon<ICLRPrivAssemblyInfo>
6595 {
6596 public:
6597     //------------------------------------------------------------------------------------
6598     // Ctor
6599
6600     PEAssemblyAsPrivAssemblyInfo(PEAssembly *pPEAssembly)
6601     {
6602         LIMITED_METHOD_CONTRACT;
6603         STATIC_CONTRACT_THROWS;
6604
6605         if (pPEAssembly == nullptr)
6606             ThrowHR(E_UNEXPECTED);
6607
6608         pPEAssembly->AddRef();
6609         m_pPEAssembly = pPEAssembly;
6610     }
6611
6612     //------------------------------------------------------------------------------------
6613     // ICLRPrivAssemblyInfo methods
6614
6615     //------------------------------------------------------------------------------------
6616     STDMETHOD(GetAssemblyName)(
6617         __in  DWORD cchBuffer,
6618         __out_opt LPDWORD pcchBuffer,
6619         __out_ecount_part_opt(cchBuffer, *pcchBuffer) LPWSTR wzBuffer)
6620     {
6621         CONTRACTL
6622         {
6623             NOTHROW;
6624             GC_TRIGGERS;
6625             MODE_ANY;
6626         }
6627         CONTRACTL_END;
6628
6629         HRESULT hr = S_OK;
6630
6631         if ((cchBuffer == 0) != (wzBuffer == nullptr))
6632         {
6633             return E_INVALIDARG;
6634         }
6635
6636         LPCUTF8 szName = m_pPEAssembly->GetSimpleName();
6637
6638         bool bIsAscii;
6639         DWORD cchName;
6640         IfFailRet(FString::Utf8_Unicode_Length(szName, &bIsAscii, &cchName));
6641
6642         if (cchBuffer < cchName + 1)
6643         {
6644             if (pcchBuffer != nullptr)
6645             {
6646                 *pcchBuffer = cchName + 1;
6647             }
6648             return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6649         }
6650         else
6651         {
6652             IfFailRet(FString::Utf8_Unicode(szName, bIsAscii, wzBuffer, cchName));
6653             if (pcchBuffer != nullptr)
6654             {
6655                 *pcchBuffer = cchName;
6656             }
6657             return S_OK;
6658         }
6659     }
6660
6661     //------------------------------------------------------------------------------------
6662     STDMETHOD(GetAssemblyVersion)(
6663         USHORT *pMajor,
6664         USHORT *pMinor,
6665         USHORT *pBuild,
6666         USHORT *pRevision)
6667     {
6668         WRAPPER_NO_CONTRACT;
6669         return m_pPEAssembly->GetVersion(pMajor, pMinor, pBuild, pRevision);
6670     }
6671
6672     //------------------------------------------------------------------------------------
6673     STDMETHOD(GetAssemblyPublicKey)(
6674         DWORD cbBuffer,
6675         LPDWORD pcbBuffer,
6676         BYTE *pbBuffer)
6677     {
6678         STATIC_CONTRACT_LIMITED_METHOD;
6679         STATIC_CONTRACT_CAN_TAKE_LOCK;
6680
6681         VALIDATE_PTR_RET(pcbBuffer);
6682         VALIDATE_CONDITION((pbBuffer == nullptr) == (cbBuffer == 0), return E_INVALIDARG);
6683
6684         HRESULT hr = S_OK;
6685
6686         EX_TRY
6687         {
6688             // Note: PEAssembly::GetPublicKey will return bogus data pointer when *pcbBuffer == 0
6689             LPCVOID pbKey = m_pPEAssembly->GetPublicKey(pcbBuffer);
6690
6691             if (*pcbBuffer != 0)
6692             {
6693                 if (pbBuffer != nullptr && cbBuffer >= *pcbBuffer)
6694                 {
6695                     memcpy(pbBuffer, pbKey, *pcbBuffer);
6696                     hr = S_OK;
6697                 }
6698                 else
6699                 {
6700                     hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6701                 }
6702             }
6703             else
6704             {
6705                 hr = S_FALSE; // ==> No public key
6706             }
6707         }
6708         EX_CATCH_HRESULT(hr);
6709
6710         return hr;
6711     }
6712
6713 private:
6714     ReleaseHolder<PEAssembly> m_pPEAssembly;
6715 };
6716
6717 //-----------------------------------------------------------------------------------------------------------------
6718 static HRESULT VerifyBindHelper(
6719     ICLRPrivAssembly *pPrivAssembly,
6720     IAssemblyName *pAssemblyName,
6721     PEAssembly *pPEAssembly)
6722 {
6723     STATIC_CONTRACT_THROWS;
6724     STATIC_CONTRACT_GC_TRIGGERS;
6725
6726     HRESULT hr = S_OK;
6727     // Create an ICLRPrivAssemblyInfo to call to ICLRPrivAssembly::VerifyBind
6728     NewHolder<PEAssemblyAsPrivAssemblyInfo> pPrivAssemblyInfoImpl = new PEAssemblyAsPrivAssemblyInfo(pPEAssembly);
6729     ReleaseHolder<ICLRPrivAssemblyInfo> pPrivAssemblyInfo;
6730     IfFailRet(pPrivAssemblyInfoImpl->QueryInterface(__uuidof(ICLRPrivAssemblyInfo), (LPVOID *)&pPrivAssemblyInfo));
6731     pPrivAssemblyInfoImpl.SuppressRelease();
6732
6733     // Call VerifyBind to give the host a chance to reject the bind based on assembly image contents.
6734     IfFailRet(pPrivAssembly->VerifyBind(pAssemblyName, pPrivAssembly, pPrivAssemblyInfo));
6735
6736     return hr;
6737 }
6738
6739 //-----------------------------------------------------------------------------------------------------------------
6740 HRESULT AppDomain::BindAssemblySpecForHostedBinder(
6741     AssemblySpec *   pSpec, 
6742     IAssemblyName *  pAssemblyName, 
6743     ICLRPrivBinder * pBinder, 
6744     PEAssembly **    ppAssembly)
6745 {
6746     STANDARD_VM_CONTRACT;
6747     
6748     PRECONDITION(CheckPointer(pSpec));
6749     PRECONDITION(pSpec->GetAppDomain() == this);
6750     PRECONDITION(CheckPointer(ppAssembly));
6751     PRECONDITION(pSpec->GetCodeBase() == nullptr);
6752
6753     HRESULT hr = S_OK;
6754
6755
6756     // The Fusion binder can throw (to preserve compat, since it will actually perform an assembly
6757     // load as part of it's bind), so we need to be careful here to catch any FileNotFoundException
6758     // objects if fThrowIfNotFound is false.
6759     ReleaseHolder<ICLRPrivAssembly> pPrivAssembly;
6760
6761     // We return HRESULTs here on failure instead of throwing as failures here are not necessarily indicative
6762     // of an actual application problem. Returning an error code is substantially faster than throwing, and
6763     // should be used when possible.
6764     IfFailRet(pBinder->BindAssemblyByName(pAssemblyName, &pPrivAssembly));
6765
6766     IfFailRet(BindHostedPrivAssembly(nullptr, pPrivAssembly, pAssemblyName, ppAssembly));
6767
6768
6769     return S_OK;
6770 }
6771
6772 //-----------------------------------------------------------------------------------------------------------------
6773 HRESULT 
6774 AppDomain::BindHostedPrivAssembly(
6775     PEAssembly *       pParentAssembly,
6776     ICLRPrivAssembly * pPrivAssembly, 
6777     IAssemblyName *    pAssemblyName, 
6778     PEAssembly **      ppAssembly, 
6779     BOOL               fIsIntrospectionOnly) // = FALSE
6780 {
6781     STANDARD_VM_CONTRACT;
6782
6783     PRECONDITION(CheckPointer(pPrivAssembly));
6784     PRECONDITION(CheckPointer(ppAssembly));
6785     
6786     HRESULT hr = S_OK;
6787     
6788     *ppAssembly = nullptr;
6789     
6790     // See if result has been previously loaded.
6791     {
6792         DomainAssembly* pDomainAssembly = FindAssembly(pPrivAssembly);
6793         if (pDomainAssembly != nullptr)
6794         {
6795             *ppAssembly = clr::SafeAddRef(pDomainAssembly->GetFile());
6796         }
6797     }
6798
6799     if (*ppAssembly != nullptr)
6800     {   // Already exists: ask the binder to verify and return the assembly.
6801         return VerifyBindHelper(pPrivAssembly, pAssemblyName, *ppAssembly);
6802     }
6803
6804     // Get the IL PEFile.
6805     PEImageHolder pPEImageIL;
6806     {
6807         // Does not already exist, so get the resource for the assembly and load it.
6808         DWORD dwImageType;
6809         ReleaseHolder<ICLRPrivResource> pIResourceIL;
6810
6811         IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_IL, &dwImageType, &pIResourceIL));
6812         _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_IL);
6813
6814         pPEImageIL = PEImage::OpenImage(pIResourceIL, MDInternalImport_Default);
6815     }
6816
6817     // See if an NI is available.
6818     DWORD dwAvailableImages;
6819     IfFailRet(pPrivAssembly->GetAvailableImageTypes(&dwAvailableImages));
6820     _ASSERTE(dwAvailableImages & ASSEMBLY_IMAGE_TYPE_IL); // Just double checking that IL bit is always set.
6821
6822     // Get the NI PEFile if available.
6823     PEImageHolder pPEImageNI;
6824     if (dwAvailableImages & ASSEMBLY_IMAGE_TYPE_NATIVE)
6825     {
6826         DWORD dwImageType;
6827         ReleaseHolder<ICLRPrivResource> pIResourceNI;
6828
6829         IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_NATIVE, &dwImageType, &pIResourceNI));
6830         _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_NATIVE || FAILED(hr));
6831
6832         pPEImageNI = PEImage::OpenImage(pIResourceNI, MDInternalImport_TrustedNativeImage);
6833     }
6834     _ASSERTE(pPEImageIL != nullptr);
6835     
6836     // Create a PEAssembly using the IL and NI images.
6837     PEAssemblyHolder pPEAssembly = PEAssembly::Open(pParentAssembly, pPEImageIL, pPEImageNI, pPrivAssembly, fIsIntrospectionOnly);
6838
6839
6840     // Ask the binder to verify.
6841     IfFailRet(VerifyBindHelper(pPrivAssembly, pAssemblyName, pPEAssembly));
6842
6843     // The result.    
6844     *ppAssembly = pPEAssembly.Extract();
6845
6846     return S_OK;
6847 } // AppDomain::BindHostedPrivAssembly
6848
6849 //---------------------------------------------------------------------------------------------------------------------
6850 PEAssembly * AppDomain::BindAssemblySpec(
6851     AssemblySpec *         pSpec, 
6852     BOOL                   fThrowOnFileNotFound, 
6853     BOOL                   fRaisePrebindEvents, 
6854     StackCrawlMark *       pCallerStackMark, 
6855     BOOL                   fUseHostBinderIfAvailable)
6856 {
6857     STATIC_CONTRACT_THROWS;
6858     STATIC_CONTRACT_GC_TRIGGERS;
6859     PRECONDITION(CheckPointer(pSpec));
6860     PRECONDITION(pSpec->GetAppDomain() == this);
6861     PRECONDITION(this==::GetAppDomain());
6862
6863     GCX_PREEMP();
6864
6865     BOOL fForceReThrow = FALSE;
6866
6867 #if defined(FEATURE_COMINTEROP)
6868     // Handle WinRT assemblies in the classic/hybrid scenario. If this is an AppX process,
6869     // then this case will be handled by the previous block as part of the full set of
6870     // available binding hosts.
6871     if (pSpec->IsContentType_WindowsRuntime())
6872     {
6873         HRESULT hr = S_OK;
6874
6875         // Get the assembly display name.
6876         ReleaseHolder<IAssemblyName> pAssemblyName;
6877
6878         IfFailThrow(pSpec->CreateFusionName(&pAssemblyName, TRUE, TRUE));
6879
6880
6881         PEAssemblyHolder pAssembly;
6882
6883         EX_TRY
6884         {
6885             hr = BindAssemblySpecForHostedBinder(pSpec, pAssemblyName, m_pWinRtBinder, &pAssembly);
6886             if (FAILED(hr))
6887                 goto EndTry2; // Goto end of try block.
6888 EndTry2:;
6889         }
6890         // The combination of this conditional catch/ the following if statement which will throw reduces the count of exceptions 
6891         // thrown in scenarios where the exception does not escape the method. We cannot get rid of the try/catch block, as
6892         // there are cases within some of the clrpriv binder's which throw.
6893         // Note: In theory, FileNotFound should always come here as HRESULT, never as exception.
6894         EX_CATCH_HRESULT_IF(hr,
6895             !fThrowOnFileNotFound && Assembly::FileNotFound(hr))
6896
6897         if (FAILED(hr) && (fThrowOnFileNotFound || !Assembly::FileNotFound(hr)))
6898         {
6899             if (Assembly::FileNotFound(hr))
6900             {
6901                 _ASSERTE(fThrowOnFileNotFound);
6902                 // Uses defaultScope
6903                 EEFileLoadException::Throw(pSpec, hr);
6904             }
6905
6906             // WinRT type bind failures
6907             _ASSERTE(pSpec->IsContentType_WindowsRuntime());
6908             if (hr == HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE)) // Returned by RoResolveNamespace when using 3rd party WinRT types in classic process
6909             {
6910                 if (fThrowOnFileNotFound)
6911                 {   // Throw NotSupportedException (with custom message) wrapped by TypeLoadException to give user type name for diagnostics
6912                     // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6913                     EEMessageException ex(kNotSupportedException, IDS_EE_WINRT_THIRDPARTY_NOTSUPPORTED);
6914                     EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
6915                 }
6916             }
6917             else if ((hr == CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT) || // Returned e.g. for WinRT type name without namespace
6918                      (hr == COR_E_PLATFORMNOTSUPPORTED)) // Using WinRT on pre-Win8 OS
6919             {
6920                 if (fThrowOnFileNotFound)
6921                 {   // Throw ArgumentException/PlatformNotSupportedException wrapped by TypeLoadException to give user type name for diagnostics
6922                     // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6923                     EEMessageException ex(hr);
6924                     EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
6925                 }
6926             }
6927             else
6928             {
6929                 IfFailThrow(hr);
6930             }
6931         }
6932         _ASSERTE((FAILED(hr) && !fThrowOnFileNotFound) || pAssembly != nullptr);
6933
6934         return pAssembly.Extract();
6935     }
6936     else
6937 #endif // FEATURE_COMINTEROP
6938     if (pSpec->HasUniqueIdentity())
6939     {
6940         HRESULT hrBindResult = S_OK;
6941         PEAssemblyHolder result;
6942         
6943
6944         EX_TRY
6945         {
6946             if (!IsCached(pSpec))
6947             {
6948
6949                 {
6950                     bool fAddFileToCache = false;
6951
6952                     BOOL fIsWellKnown = FALSE;
6953
6954                     // Use CoreClr's fusion alternative
6955                     CoreBindResult bindResult;
6956
6957                     pSpec->Bind(this, fThrowOnFileNotFound, &bindResult, FALSE /* fNgenExplicitBind */, FALSE /* fExplicitBindToNativeImage */, pCallerStackMark);
6958                     hrBindResult = bindResult.GetHRBindResult();
6959
6960                     if (bindResult.Found()) 
6961                     {
6962                         if (SystemDomain::SystemFile() && bindResult.IsMscorlib())
6963                         {
6964                             // Avoid rebinding to another copy of mscorlib
6965                             result = SystemDomain::SystemFile();
6966                             result.SuppressRelease(); // Didn't get a refcount
6967                         }
6968                         else
6969                         {
6970                             // IsSystem on the PEFile should be false, even for mscorlib satellites
6971                             result = PEAssembly::Open(&bindResult,
6972                                                       FALSE, pSpec->IsIntrospectionOnly());
6973                         }
6974                         fAddFileToCache = true;
6975                         
6976                         // Setup the reference to the binder, which performed the bind, into the AssemblySpec
6977                         ICLRPrivBinder* pBinder = result->GetBindingContext();
6978                         _ASSERTE(pBinder != NULL);
6979                         pSpec->SetBindingContext(pBinder);
6980                     }
6981
6982
6983                     if (fAddFileToCache)
6984                     {
6985
6986
6987                         if (pSpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
6988                         {
6989                             // Failure to add simply means someone else beat us to it. In that case
6990                             // the FindCachedFile call below (after catch block) will update result
6991                             // to the cached value.
6992                             AddFileToCache(pSpec, result, TRUE /*fAllowFailure*/);
6993                         }
6994                     }
6995                     else if (!fIsWellKnown)
6996                     {
6997                         _ASSERTE(fThrowOnFileNotFound == FALSE);
6998
6999                         // Don't trigger the resolve event for the CoreLib satellite assembly. A misbehaving resolve event may
7000                         // return an assembly that does not match, and this can cause recursive resource lookups during error
7001                         // reporting. The CoreLib satellite assembly is loaded from relative locations based on the culture, see
7002                         // AssemblySpec::Bind().
7003                         if (!pSpec->IsMscorlibSatellite())
7004                         {
7005                             // Trigger the resolve event also for non-throw situation.
7006                             // However, this code path will behave as if the resolve handler has thrown,
7007                             // that is, not trigger an MDA.
7008
7009                             AssemblySpec NewSpec(this);
7010                             AssemblySpec *pFailedSpec = NULL;
7011
7012                             fForceReThrow = TRUE; // Managed resolve event handler can throw
7013
7014                             // Purposly ignore return value
7015                             PostBindResolveAssembly(pSpec, &NewSpec, hrBindResult, &pFailedSpec);
7016                         }
7017                     }
7018                 }
7019             }
7020         }
7021         EX_CATCH
7022         {
7023             Exception *ex = GET_EXCEPTION();
7024
7025             AssemblySpec NewSpec(this);
7026             AssemblySpec *pFailedSpec = NULL;
7027
7028             // Let transient exceptions or managed resolve event handler exceptions propagate
7029             if (ex->IsTransient() || fForceReThrow)
7030             {
7031                 EX_RETHROW;
7032             }
7033
7034             {
7035                 // This is not executed for SO exceptions so we need to disable the backout
7036                 // stack validation to prevent false violations from being reported.
7037                 DISABLE_BACKOUT_STACK_VALIDATION;
7038
7039                 BOOL fFailure = PostBindResolveAssembly(pSpec, &NewSpec, ex->GetHR(), &pFailedSpec);
7040                 if (fFailure)
7041                 {
7042                     BOOL bFileNotFoundException =
7043                         (EEFileLoadException::GetFileLoadKind(ex->GetHR()) == kFileNotFoundException);
7044                 
7045                     if (!bFileNotFoundException)
7046                     {
7047                         fFailure = AddExceptionToCache(pFailedSpec, ex);
7048                     } // else, fFailure stays TRUE
7049                     // Effectively, fFailure == bFileNotFoundException || AddExceptionToCache(pFailedSpec, ex)
7050
7051                     // Only throw this exception if we are the first in the cache
7052                     if (fFailure)
7053                     {
7054                         //
7055                         // If the BindingFailure MDA is enabled, trigger one for this failure
7056                         // Note: TryResolveAssembly() can also throw if an AssemblyResolve event subscriber throws
7057                         //       and the MDA isn't sent in this case (or for transient failure cases)
7058                         //
7059 #ifdef MDA_SUPPORTED
7060                         MdaBindingFailure* pProbe = MDA_GET_ASSISTANT(BindingFailure);
7061                         if (pProbe)
7062                         {
7063                             // Transition to cooperative GC mode before using any OBJECTREFs.
7064                             GCX_COOP();
7065
7066                             OBJECTREF exceptionObj = GET_THROWABLE();
7067                             GCPROTECT_BEGIN(exceptionObj)
7068                             {
7069                                 pProbe->BindFailed(pFailedSpec, &exceptionObj);
7070                             }
7071                             GCPROTECT_END();
7072                         }
7073 #endif
7074
7075                         // In the same cases as for the MDA, store the failure information for DAC to read
7076                         if (IsDebuggerAttached()) {
7077                             FailedAssembly *pFailed = new FailedAssembly();
7078                             pFailed->Initialize(pFailedSpec, ex);
7079                             IfFailThrow(m_failedAssemblies.Append(pFailed));
7080                         }
7081
7082                         if (!bFileNotFoundException || fThrowOnFileNotFound)
7083                         {
7084
7085                             // V1.1 App-compatibility workaround. See VSW530166 if you want to whine about it.
7086                             //
7087                             // In Everett, if we failed to download an assembly because of a broken network cable,
7088                             // we returned a FileNotFoundException with a COR_E_FILENOTFOUND hr embedded inside
7089                             // (which would be exposed when marshaled to native.)
7090                             //
7091                             // In Whidbey, we now set the more appropriate INET_E_RESOURCE_NOT_FOUND hr. But
7092                             // the online/offline switch code in VSTO for Everett hardcoded a check for
7093                             // COR_E_FILENOTFOUND. 
7094                             //
7095                             // So now, to keep that code from breaking, we have to remap INET_E_RESOURCE_NOT_FOUND
7096                             // back to COR_E_FILENOTFOUND. We're doing it here rather down in Fusion so as to affect
7097                             // the least number of callers.
7098                             
7099                             if (ex->GetHR() == INET_E_RESOURCE_NOT_FOUND)
7100                             {
7101                                 EEFileLoadException::Throw(pFailedSpec, COR_E_FILENOTFOUND, ex);
7102                             }
7103
7104                             if (EEFileLoadException::CheckType(ex))
7105                             {
7106                                 if (pFailedSpec == pSpec)
7107                                 {
7108                                     EX_RETHROW; //preserve the information
7109                                 }
7110                                 else
7111                                 {
7112                                     StackSString exceptionDisplayName, failedSpecDisplayName;
7113
7114                                     ((EEFileLoadException*)ex)->GetName(exceptionDisplayName);
7115                                     pFailedSpec->GetFileOrDisplayName(0, failedSpecDisplayName);
7116
7117                                     if (exceptionDisplayName.CompareCaseInsensitive(failedSpecDisplayName) == 0)
7118                                     {
7119                                         EX_RETHROW; // Throw the original exception. Otherwise, we'd throw an exception that contains the same message twice.
7120                                     }
7121                                 }
7122                             }
7123                             
7124                             EEFileLoadException::Throw(pFailedSpec, ex->GetHR(), ex);
7125                         }
7126
7127                     }
7128                 }
7129             }
7130         }
7131         EX_END_CATCH(RethrowTerminalExceptions);
7132
7133         // Now, if it's a cacheable bind we need to re-fetch the result from the cache, as we may have been racing with another
7134         // thread to store our result.  Note that we may throw from here, if there is a cached exception.
7135         // This will release the refcount of the current result holder (if any), and will replace
7136         // it with a non-addref'ed result
7137         if (pSpec->CanUseWithBindingCache() && (result== NULL || result->CanUseWithBindingCache()))
7138         {
7139             result = FindCachedFile(pSpec);
7140
7141             if (result != NULL)
7142                 result->AddRef();
7143         }
7144
7145         return result.Extract();
7146     }
7147     else
7148     {
7149         // Unsupported content type
7150         if (fThrowOnFileNotFound)
7151         {
7152             ThrowHR(COR_E_BADIMAGEFORMAT);
7153         }
7154         return nullptr;
7155     }
7156 } // AppDomain::BindAssemblySpec
7157
7158
7159
7160 PEAssembly *AppDomain::TryResolveAssembly(AssemblySpec *pSpec, BOOL fPreBind)
7161 {
7162     STATIC_CONTRACT_THROWS;
7163     STATIC_CONTRACT_GC_TRIGGERS;
7164     STATIC_CONTRACT_MODE_ANY;
7165
7166     PEAssembly *result = NULL;
7167
7168     EX_TRY
7169     {
7170         result = pSpec->ResolveAssemblyFile(this, fPreBind);
7171     }
7172     EX_HOOK
7173     {
7174         Exception *pEx = GET_EXCEPTION();
7175
7176         if (!pEx->IsTransient())
7177         {
7178             AddExceptionToCache(pSpec, pEx);
7179             if (!EEFileLoadException::CheckType(pEx))
7180                 EEFileLoadException::Throw(pSpec, pEx->GetHR(), pEx);
7181         }
7182     }
7183     EX_END_HOOK;
7184
7185     return result;
7186 }
7187
7188
7189 ULONG AppDomain::AddRef()
7190 {
7191     LIMITED_METHOD_CONTRACT;
7192     return InterlockedIncrement(&m_cRef);
7193 }
7194
7195 ULONG AppDomain::Release()
7196 {
7197     CONTRACTL
7198     {
7199         NOTHROW;
7200         GC_TRIGGERS;
7201         MODE_ANY;
7202         PRECONDITION(m_cRef > 0);
7203     }
7204     CONTRACTL_END;
7205
7206     ULONG   cRef = InterlockedDecrement(&m_cRef);
7207     if (!cRef)
7208     {
7209         _ASSERTE (m_Stage == STAGE_CREATING || m_Stage == STAGE_CLOSED);
7210         ADID adid=GetId();
7211         delete this;
7212         TESTHOOKCALL(AppDomainDestroyed(adid.m_dwId));
7213     }
7214     return (cRef);
7215 }
7216
7217
7218 AppDomain* AppDomain::s_pAppDomainToRaiseUnloadEvent;
7219 BOOL AppDomain::s_fProcessUnloadDomainEvent = FALSE;
7220
7221 #ifndef CROSSGEN_COMPILE
7222
7223 void AppDomain::RaiseUnloadDomainEvent_Wrapper(LPVOID ptr)
7224 {
7225     CONTRACTL
7226     {
7227         THROWS;
7228         MODE_COOPERATIVE;
7229         GC_TRIGGERS;
7230         INJECT_FAULT(COMPlusThrowOM(););
7231         SO_INTOLERANT;
7232     }
7233     CONTRACTL_END;
7234
7235     AppDomain* pDomain = (AppDomain *) ptr;
7236     pDomain->RaiseUnloadDomainEvent();
7237 }
7238
7239 void AppDomain::ProcessUnloadDomainEventOnFinalizeThread()
7240 {
7241     CONTRACTL
7242     {
7243         THROWS;
7244         GC_TRIGGERS;
7245         MODE_COOPERATIVE;
7246     }
7247     CONTRACTL_END;
7248     Thread *pThread = GetThread();
7249     _ASSERTE (pThread && IsFinalizerThread());
7250
7251     // if we are not unloading domain now, do not process the event
7252     if (SystemDomain::AppDomainBeingUnloaded() == NULL)
7253     {
7254         s_pAppDomainToRaiseUnloadEvent->SetStage(STAGE_UNLOAD_REQUESTED);
7255         s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
7256             s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7257         FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
7258         return;
7259     }
7260     FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, TRUE);
7261     AppDomain::EnableADUnloadWorkerForFinalizer();
7262     pThread->SetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
7263     s_pAppDomainToRaiseUnloadEvent->RaiseUnloadDomainEvent();
7264     pThread->ResetThreadStateNC(Thread::TSNC_RaiseUnloadEvent);
7265     s_pAppDomainToRaiseUnloadEvent->EnableADUnloadWorker(
7266         s_pAppDomainToRaiseUnloadEvent->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7267     FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, NULL);
7268     FastInterlockExchange((LONG*)&s_fProcessUnloadDomainEvent, FALSE);
7269
7270     if (pThread->IsAbortRequested())
7271     {
7272         pThread->UnmarkThreadForAbort(Thread::TAR_Thread);
7273     }
7274 }
7275
7276 void AppDomain::RaiseUnloadDomainEvent()
7277 {
7278     CONTRACTL
7279     {
7280         THROWS;
7281         MODE_COOPERATIVE;
7282         GC_TRIGGERS;
7283         SO_INTOLERANT;
7284     }
7285     CONTRACTL_END;
7286
7287     Thread *pThread = GetThread();
7288     if (this != pThread->GetDomain())
7289     {
7290         pThread->DoADCallBack(this, AppDomain::RaiseUnloadDomainEvent_Wrapper, this,ADV_FINALIZER|ADV_COMPILATION);
7291     }
7292     else
7293     {
7294         struct _gc
7295         {
7296             APPDOMAINREF Domain;
7297             OBJECTREF    Delegate;
7298         } gc;
7299         ZeroMemory(&gc, sizeof(gc));
7300
7301         GCPROTECT_BEGIN(gc);
7302         gc.Domain = (APPDOMAINREF) GetRawExposedObject();
7303         if (gc.Domain != NULL)
7304         {
7305             gc.Delegate = gc.Domain->m_pDomainUnloadEventHandler;
7306             if (gc.Delegate != NULL)
7307                 DistributeEvent(&gc.Delegate, (OBJECTREF *) &gc.Domain);
7308         }
7309         GCPROTECT_END();
7310     }
7311 }
7312
7313 void AppDomain::RaiseLoadingAssemblyEvent(DomainAssembly *pAssembly)
7314 {
7315     CONTRACTL
7316     {
7317         NOTHROW;
7318         GC_TRIGGERS;
7319         PRECONDITION(this == GetAppDomain());
7320         MODE_ANY;
7321     }
7322     CONTRACTL_END;
7323
7324     GCX_COOP();
7325     FAULT_NOT_FATAL();
7326     OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
7327
7328     EX_TRY
7329     {
7330         struct _gc {
7331             APPDOMAINREF AppDomainRef;
7332             OBJECTREF    orThis;
7333         } gc;
7334         ZeroMemory(&gc, sizeof(gc));
7335
7336         if ((gc.AppDomainRef = (APPDOMAINREF) GetRawExposedObject()) != NULL) {
7337             if (gc.AppDomainRef->m_pAssemblyEventHandler != NULL)
7338             {
7339                 ARG_SLOT args[2];
7340                 GCPROTECT_BEGIN(gc);
7341
7342                 gc.orThis = pAssembly->GetExposedAssemblyObject();
7343
7344                 MethodDescCallSite  onAssemblyLoad(METHOD__APP_DOMAIN__ON_ASSEMBLY_LOAD, &gc.orThis);
7345
7346                 // GetExposedAssemblyObject may cause a gc, so call this before filling args[0]
7347                 args[1] = ObjToArgSlot(gc.orThis);
7348                 args[0] = ObjToArgSlot(gc.AppDomainRef);
7349
7350                 onAssemblyLoad.Call(args);
7351
7352                 GCPROTECT_END();
7353             }
7354         }
7355     }
7356     EX_CATCH
7357     {
7358     }
7359     EX_END_CATCH(SwallowAllExceptions);
7360 }
7361
7362
7363 BOOL AppDomain::OnUnhandledException(OBJECTREF *pThrowable, BOOL isTerminating/*=TRUE*/) 
7364 {
7365     STATIC_CONTRACT_NOTHROW;
7366     STATIC_CONTRACT_GC_TRIGGERS;
7367     STATIC_CONTRACT_MODE_ANY;
7368
7369     BOOL retVal= FALSE;
7370
7371     GCX_COOP();
7372
7373     // The Everett behavior was to send the unhandled exception event only to the Default
7374     // AppDomain (since that's the only place that exceptions actually went unhandled).
7375     //
7376     // During Whidbey development, we broadcast the event to all AppDomains in the process.
7377     //
7378     // But the official shipping Whidbey behavior is that the unhandled exception event is
7379     // sent to the Default AppDomain and to whatever AppDomain the exception went unhandled
7380     // in.  To achieve this, we declare the exception to be unhandled *BEFORE* we marshal
7381     // it back to the Default AppDomain at the base of the Finalizer, threadpool and managed
7382     // threads.
7383     //
7384     // The rationale for sending the event to the Default AppDomain as well as the one the
7385     // exception went unhandled in is:
7386     //
7387     // 1)  This is compatible with the pre-Whidbey behavior, where only the Default AppDomain
7388     //     received the notification.
7389     //
7390     // 2)  This is convenient for hosts, which don't want to bother injecting listeners into
7391     //     every single AppDomain.
7392
7393     AppDomain *pAppDomain = GetAppDomain();
7394     OBJECTREF orSender = 0;
7395
7396     GCPROTECT_BEGIN(orSender);
7397
7398     orSender = pAppDomain->GetRawExposedObject();
7399
7400     retVal = pAppDomain->RaiseUnhandledExceptionEventNoThrow(&orSender, pThrowable, isTerminating);
7401
7402     GCPROTECT_END();
7403
7404     return retVal;
7405 }
7406
7407
7408 // Move outside of the AppDomain iteration, to avoid issues with the GC Frames being outside
7409 // the domain transition.  This is a chronic issue that causes us to report roots for an AppDomain
7410 // after we have left it.  This causes problems with AppDomain unloading that we only find
7411 // with stress coverage..
7412 void AppDomain::RaiseOneExitProcessEvent()
7413 {
7414     CONTRACTL
7415     {
7416         THROWS;
7417         GC_TRIGGERS;
7418         MODE_COOPERATIVE;
7419     }
7420     CONTRACTL_END;
7421
7422     struct _gc
7423     {
7424         APPDOMAINREF Domain;
7425         OBJECTREF    Delegate;
7426     } gc;
7427     ZeroMemory(&gc, sizeof(gc));
7428
7429     GCPROTECT_BEGIN(gc);
7430     gc.Domain = (APPDOMAINREF) SystemDomain::GetCurrentDomain()->GetRawExposedObject();
7431     if (gc.Domain != NULL)
7432     {
7433         gc.Delegate = gc.Domain->m_pProcessExitEventHandler;
7434         if (gc.Delegate != NULL)
7435             DistributeEvent(&gc.Delegate, (OBJECTREF *) &gc.Domain);
7436     }
7437     GCPROTECT_END();
7438 }
7439
7440 // Local wrapper used in AppDomain::RaiseExitProcessEvent,
7441 // introduced solely to avoid stack overflow because of _alloca in the loop.
7442 // It's just factored out body of the loop, but it has to be a member method of AppDomain,
7443 // because it calls private RaiseOneExitProcessEvent
7444 /*static*/ void AppDomain::RaiseOneExitProcessEvent_Wrapper(AppDomainIterator* pi)
7445 {
7446     STATIC_CONTRACT_MODE_COOPERATIVE;
7447     STATIC_CONTRACT_THROWS;
7448     STATIC_CONTRACT_GC_TRIGGERS;
7449
7450     ENTER_DOMAIN_PTR(pi->GetDomain(), ADV_ITERATOR)
7451     AppDomain::RaiseOneExitProcessEvent();
7452     END_DOMAIN_TRANSITION;
7453 }
7454
7455 static LONG s_ProcessedExitProcessEventCount = 0;
7456
7457 LONG GetProcessedExitProcessEventCount()
7458 {
7459     LIMITED_METHOD_CONTRACT;
7460     return s_ProcessedExitProcessEventCount;
7461 }
7462
7463 void AppDomain::RaiseExitProcessEvent()
7464 {
7465     if (!g_fEEStarted)
7466         return;
7467
7468     STATIC_CONTRACT_MODE_COOPERATIVE;
7469     STATIC_CONTRACT_THROWS;
7470     STATIC_CONTRACT_GC_TRIGGERS;
7471
7472     // Only finalizer thread during shutdown can call this function.
7473     _ASSERTE ((g_fEEShutDown&ShutDown_Finalize1) && GetThread() == FinalizerThread::GetFinalizerThread());
7474
7475     _ASSERTE (GetThread()->PreemptiveGCDisabled());
7476
7477     _ASSERTE (GetThread()->GetDomain()->IsDefaultDomain());
7478
7479     AppDomainIterator i(TRUE);
7480     while (i.Next())
7481     {
7482         RaiseOneExitProcessEvent_Wrapper(&i);
7483         FastInterlockIncrement(&s_ProcessedExitProcessEventCount);
7484     }
7485 }
7486
7487
7488 BOOL
7489 AppDomain::RaiseUnhandledExceptionEventNoThrow(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating)
7490 {
7491     CONTRACTL
7492     {
7493         NOTHROW;
7494         GC_TRIGGERS;
7495         MODE_COOPERATIVE;
7496     }
7497     CONTRACTL_END;
7498     BOOL bRetVal=FALSE;
7499
7500     EX_TRY
7501     {
7502         bRetVal = RaiseUnhandledExceptionEvent(pSender, pThrowable, isTerminating);
7503     }
7504     EX_CATCH
7505     {
7506     }
7507     EX_END_CATCH(SwallowAllExceptions)  // Swallow any errors.
7508     return bRetVal;
7509
7510 }
7511
7512 BOOL
7513 AppDomain::HasUnhandledExceptionEventHandler()
7514 {
7515     CONTRACTL
7516     {
7517         MODE_COOPERATIVE;
7518         GC_NOTRIGGER; //essential
7519         NOTHROW;
7520     }
7521     CONTRACTL_END;
7522     if (!CanThreadEnter(GetThread()))
7523         return FALSE;
7524     if (GetRawExposedObject()==NULL)
7525         return FALSE;
7526     return (((APPDOMAINREF)GetRawExposedObject())->m_pUnhandledExceptionEventHandler!=NULL);
7527 }
7528
7529 BOOL
7530 AppDomain::RaiseUnhandledExceptionEvent(OBJECTREF *pSender, OBJECTREF *pThrowable, BOOL isTerminating)
7531 {
7532     CONTRACTL
7533     {
7534         THROWS;
7535         GC_TRIGGERS;
7536         MODE_COOPERATIVE;
7537         INJECT_FAULT(COMPlusThrowOM(););
7538     }
7539     CONTRACTL_END;
7540
7541     if (!HasUnhandledExceptionEventHandler())
7542         return FALSE;
7543
7544     BOOL result = FALSE;
7545
7546     _ASSERTE(pThrowable != NULL && IsProtectedByGCFrame(pThrowable));
7547     _ASSERTE(pSender    != NULL && IsProtectedByGCFrame(pSender));
7548
7549     _ASSERTE(this == GetThread()->GetDomain());
7550
7551
7552     OBJECTREF orDelegate = NULL;
7553
7554     GCPROTECT_BEGIN(orDelegate);
7555
7556     APPDOMAINREF orAD = (APPDOMAINREF) GetAppDomain()->GetRawExposedObject();
7557
7558     if (orAD != NULL)
7559     {
7560         orDelegate = orAD->m_pUnhandledExceptionEventHandler;
7561         if (orDelegate != NULL)
7562         {
7563             result = TRUE;
7564             DistributeUnhandledExceptionReliably(&orDelegate, pSender, pThrowable, isTerminating);
7565         }
7566     }
7567     GCPROTECT_END();
7568     return result;
7569 }
7570
7571
7572
7573 #endif // CROSSGEN_COMPILE
7574
7575 // You must be in the correct context before calling this
7576 // routine. Therefore, it is only good for initializing the
7577 // default domain.
7578 void AppDomain::InitializeDomainContext(BOOL allowRedirects,
7579                                         LPCWSTR pwszPath,
7580                                         LPCWSTR pwszConfig)
7581 {
7582     CONTRACTL
7583     {
7584         MODE_COOPERATIVE;
7585         GC_TRIGGERS;
7586         THROWS;
7587         INJECT_FAULT(COMPlusThrowOM(););
7588     }
7589     CONTRACTL_END;
7590
7591     if (NingenEnabled())
7592     {
7593
7594         CreateFusionContext();
7595
7596         return;
7597     }
7598
7599 #ifndef CROSSGEN_COMPILE
7600     struct _gc {
7601         STRINGREF pFilePath;
7602         STRINGREF pConfig;
7603         OBJECTREF ref;
7604         PTRARRAYREF propertyNames;
7605         PTRARRAYREF propertyValues;
7606     } gc;
7607     ZeroMemory(&gc, sizeof(gc));
7608
7609     GCPROTECT_BEGIN(gc);
7610     if(pwszPath)
7611     {
7612         gc.pFilePath = StringObject::NewString(pwszPath);
7613     }
7614
7615     if(pwszConfig)
7616     {
7617         gc.pConfig = StringObject::NewString(pwszConfig);
7618     }
7619
7620
7621     if ((gc.ref = GetExposedObject()) != NULL)
7622     {
7623         MethodDescCallSite setupDomain(METHOD__APP_DOMAIN__SETUP_DOMAIN);
7624
7625         ARG_SLOT args[] =
7626         {
7627             ObjToArgSlot(gc.ref),
7628             BoolToArgSlot(allowRedirects),
7629             ObjToArgSlot(gc.pFilePath),
7630             ObjToArgSlot(gc.pConfig),
7631             ObjToArgSlot(gc.propertyNames),
7632             ObjToArgSlot(gc.propertyValues)
7633         };
7634         setupDomain.Call(args);
7635     }
7636     GCPROTECT_END();
7637 #endif // CROSSGEN_COMPILE
7638 }
7639
7640
7641 IUnknown *AppDomain::CreateFusionContext()
7642 {
7643     CONTRACT(IUnknown *)
7644     {
7645         GC_TRIGGERS;
7646         THROWS;
7647         MODE_ANY;
7648         POSTCONDITION(CheckPointer(RETVAL));
7649         INJECT_FAULT(COMPlusThrowOM(););
7650     }
7651     CONTRACT_END;
7652
7653     if (!m_pFusionContext)
7654     {
7655         ETWOnStartup (FusionAppCtx_V1, FusionAppCtxEnd_V1);
7656         CLRPrivBinderCoreCLR *pTPABinder = NULL;
7657
7658         GCX_PREEMP();
7659
7660         // Initialize the assembly binder for the default context loads for CoreCLR.
7661         IfFailThrow(CCoreCLRBinderHelper::DefaultBinderSetupContext(GetId().m_dwId, &pTPABinder));
7662         m_pFusionContext = reinterpret_cast<IUnknown *>(pTPABinder);
7663         
7664         // By default, initial binding context setup for CoreCLR is also the TPABinding context
7665         (m_pTPABinderContext = pTPABinder)->AddRef();
7666
7667     }
7668
7669     RETURN m_pFusionContext;
7670 }
7671
7672
7673
7674 //---------------------------------------------------------------------------------------
7675 //
7676 // AppDomain::IsDebuggerAttached - is a debugger attached to this process
7677 //
7678 // Arguments:
7679 //    None
7680 //
7681 // Return Value:
7682 //    TRUE if a debugger is attached to this process, FALSE otherwise.
7683 //
7684 // Notes:
7685 //    This is identical to CORDebuggerAttached.  This exists idependantly for legacy reasons - we used to
7686 //    support attaching to individual AppDomains.  This should probably go away eventually.
7687 //
7688
7689 BOOL AppDomain::IsDebuggerAttached()
7690 {
7691     LIMITED_METHOD_CONTRACT;
7692
7693     if (CORDebuggerAttached())
7694     {
7695         return TRUE;
7696     }
7697     else
7698     {
7699         return FALSE;
7700     }
7701 }
7702
7703 #ifdef DEBUGGING_SUPPORTED
7704
7705 // This is called from the debugger to request notification events from
7706 // Assemblies, Modules, Types in this appdomain.
7707 BOOL AppDomain::NotifyDebuggerLoad(int flags, BOOL attaching)
7708 {
7709     WRAPPER_NO_CONTRACT;
7710     BOOL result = FALSE;
7711
7712     if (!attaching && !IsDebuggerAttached())
7713         return FALSE;
7714
7715     AssemblyIterator i;
7716
7717     // Attach to our assemblies
7718     LOG((LF_CORDB, LL_INFO100, "AD::NDA: Iterating assemblies\n"));
7719     i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution));
7720     CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7721     while (i.Next(pDomainAssembly.This()))
7722     {
7723         result = (pDomainAssembly->NotifyDebuggerLoad(flags, attaching) || 
7724                   result);
7725     }
7726
7727     return result;
7728 }
7729
7730 void AppDomain::NotifyDebuggerUnload()
7731 {
7732     WRAPPER_NO_CONTRACT;    
7733     if (!IsDebuggerAttached())
7734         return;
7735
7736     LOG((LF_CORDB, LL_INFO10, "AD::NDD domain [%d] %#08x %ls\n",
7737          GetId().m_dwId, this, GetFriendlyNameForLogging()));
7738
7739     LOG((LF_CORDB, LL_INFO100, "AD::NDD: Interating domain bound assemblies\n"));
7740     AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded |  kIncludeLoading  | kIncludeExecution));
7741     CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7742
7743     // Detach from our assemblies
7744     while (i.Next(pDomainAssembly.This()))
7745     {
7746         LOG((LF_CORDB, LL_INFO100, "AD::NDD: Iterating assemblies\n"));
7747         pDomainAssembly->NotifyDebuggerUnload();
7748     }
7749 }
7750 #endif // DEBUGGING_SUPPORTED
7751
7752 void AppDomain::SetSystemAssemblyLoadEventSent(BOOL fFlag)
7753 {
7754     LIMITED_METHOD_CONTRACT;
7755     if (fFlag == TRUE)
7756         m_dwFlags |= LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
7757     else
7758         m_dwFlags &= ~LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
7759 }
7760
7761 BOOL AppDomain::WasSystemAssemblyLoadEventSent(void)
7762 {
7763     LIMITED_METHOD_CONTRACT;
7764     return ((m_dwFlags & LOAD_SYSTEM_ASSEMBLY_EVENT_SENT) == 0) ? FALSE : TRUE;
7765 }
7766
7767 #ifndef CROSSGEN_COMPILE
7768 // U->M thunks created in this domain and not associated with a delegate.
7769 UMEntryThunkCache *AppDomain::GetUMEntryThunkCache()
7770 {
7771     CONTRACTL
7772     {
7773         THROWS;
7774         GC_TRIGGERS;
7775         MODE_ANY;
7776         INJECT_FAULT(COMPlusThrowOM(););
7777     }
7778     CONTRACTL_END;
7779
7780     if (!m_pUMEntryThunkCache)
7781     {
7782         UMEntryThunkCache *pUMEntryThunkCache = new UMEntryThunkCache(this);
7783
7784         if (FastInterlockCompareExchangePointer(&m_pUMEntryThunkCache, pUMEntryThunkCache, NULL) != NULL)
7785         {
7786             // some thread swooped in and set the field
7787             delete pUMEntryThunkCache;
7788         }
7789     }
7790     _ASSERTE(m_pUMEntryThunkCache);
7791     return m_pUMEntryThunkCache;
7792 }
7793
7794 #ifdef FEATURE_COMINTEROP
7795
7796 ComCallWrapperCache *AppDomain::GetComCallWrapperCache()
7797 {
7798     CONTRACTL
7799     {
7800         THROWS;
7801         GC_TRIGGERS;
7802         MODE_ANY;
7803         INJECT_FAULT(COMPlusThrowOM(););
7804     }
7805     CONTRACTL_END;
7806
7807     if (! m_pComCallWrapperCache)
7808     {
7809         BaseDomain::LockHolder lh(this);
7810
7811         if (! m_pComCallWrapperCache)
7812             m_pComCallWrapperCache = ComCallWrapperCache::Create(this);
7813     }
7814     _ASSERTE(m_pComCallWrapperCache);
7815     return m_pComCallWrapperCache;
7816 }
7817
7818 RCWRefCache *AppDomain::GetRCWRefCache()
7819 {
7820     CONTRACT(RCWRefCache*)
7821     {
7822         THROWS;
7823         GC_NOTRIGGER;
7824         MODE_ANY;
7825         POSTCONDITION(CheckPointer(RETVAL));
7826     }
7827     CONTRACT_END;
7828
7829     if (!m_pRCWRefCache) {
7830         NewHolder<RCWRefCache> pRCWRefCache = new RCWRefCache(this);
7831         if (FastInterlockCompareExchangePointer(&m_pRCWRefCache, (RCWRefCache *)pRCWRefCache, NULL) == NULL)
7832         {
7833             pRCWRefCache.SuppressRelease();    
7834         }        
7835     }
7836     RETURN m_pRCWRefCache;
7837 }
7838
7839 RCWCache *AppDomain::CreateRCWCache()
7840 {
7841     CONTRACT(RCWCache*)
7842     {
7843         THROWS;
7844         GC_TRIGGERS;
7845         MODE_ANY;
7846         INJECT_FAULT(COMPlusThrowOM(););
7847         POSTCONDITION(CheckPointer(RETVAL));
7848     }
7849     CONTRACT_END;
7850
7851     // Initialize the global RCW cleanup list here as well. This is so that it
7852     // it guaranteed to exist if any RCW's are created, but it is not created
7853     // unconditionally.
7854     if (!g_pRCWCleanupList)
7855     {
7856         SystemDomain::LockHolder lh;
7857
7858         if (!g_pRCWCleanupList)
7859             g_pRCWCleanupList = new RCWCleanupList();
7860     }
7861     _ASSERTE(g_pRCWCleanupList);
7862
7863     {
7864         BaseDomain::LockHolder lh(this);
7865
7866         if (!m_pRCWCache)
7867             m_pRCWCache = new RCWCache(this);
7868     }
7869
7870     RETURN m_pRCWCache;
7871 }
7872
7873 void AppDomain::ReleaseRCWs(LPVOID pCtxCookie)
7874 {
7875     WRAPPER_NO_CONTRACT;
7876     if (m_pRCWCache)
7877         m_pRCWCache->ReleaseWrappersWorker(pCtxCookie);
7878
7879     RemoveWinRTFactoryObjects(pCtxCookie);
7880 }
7881
7882 void AppDomain::DetachRCWs()
7883 {
7884     WRAPPER_NO_CONTRACT;
7885     if (m_pRCWCache)
7886         m_pRCWCache->DetachWrappersWorker();
7887 }
7888
7889 #endif // FEATURE_COMINTEROP
7890
7891 BOOL AppDomain::CanThreadEnter(Thread *pThread)
7892 {
7893     WRAPPER_NO_CONTRACT;
7894
7895     if (m_Stage < STAGE_EXITED)
7896         return TRUE;
7897
7898     if (pThread == SystemDomain::System()->GetUnloadingThread())
7899         return m_Stage < STAGE_FINALIZING;
7900     if (pThread == FinalizerThread::GetFinalizerThread())
7901         return m_Stage < STAGE_FINALIZED;
7902
7903     return FALSE;
7904 }
7905
7906 void AppDomain::AllowThreadEntrance(AppDomain * pApp)
7907 {
7908     CONTRACTL
7909     {
7910         NOTHROW;
7911         GC_TRIGGERS;
7912         MODE_ANY;
7913         FORBID_FAULT;
7914         PRECONDITION(CheckPointer(pApp));
7915     }
7916     CONTRACTL_END;
7917
7918     if (pApp->GetUnloadRequestThread() == NULL)
7919     {
7920         // This is asynchonous unload, either by a host, or by AppDomain.Unload from AD unload event.
7921         if (!pApp->IsUnloadingFromUnloadEvent())
7922         {
7923             pApp->SetStage(STAGE_UNLOAD_REQUESTED);
7924             pApp->EnableADUnloadWorker(
7925                  pApp->IsRudeUnload()?EEPolicy::ADU_Rude:EEPolicy::ADU_Safe);
7926             return;
7927         }
7928     }
7929
7930     SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
7931
7932 #ifdef FEATURE_COMINTEROP
7933     if (pApp->m_pComCallWrapperCache)
7934         pApp->m_pComCallWrapperCache->ResetDomainIsUnloading();
7935 #endif // FEATURE_COMINTEROP
7936
7937     pApp->SetStage(STAGE_OPEN);
7938 }
7939
7940 void AppDomain::RestrictThreadEntrance(AppDomain * pApp)
7941 {
7942     CONTRACTL
7943     {
7944         DISABLED(NOTHROW);
7945         DISABLED(GC_TRIGGERS);
7946         MODE_ANY;
7947         DISABLED(FORBID_FAULT);
7948         PRECONDITION(CheckPointer(pApp));
7949     }
7950     CONTRACTL_END;
7951
7952 #ifdef FEATURE_COMINTEROP
7953     // Set the flag on our CCW cache so stubs won't enter
7954     if (pApp->m_pComCallWrapperCache)
7955         pApp->m_pComCallWrapperCache->SetDomainIsUnloading();
7956 #endif // FEATURE_COMINTEROP
7957
7958     SystemDomain::LockHolder lh; // we don't want to reopen appdomain if other thread can be preparing to unload it
7959     // Release our ID so remoting and thread pool won't enter
7960     pApp->SetStage(STAGE_EXITED);
7961 };
7962
7963 void AppDomain::Exit(BOOL fRunFinalizers, BOOL fAsyncExit)
7964 {
7965     CONTRACTL
7966     {
7967         THROWS;
7968         GC_TRIGGERS;
7969         MODE_COOPERATIVE;
7970     }
7971     CONTRACTL_END;
7972
7973     LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Exiting domain [%d] %#08x %ls\n",
7974          GetId().m_dwId, this, GetFriendlyNameForLogging()));
7975
7976     RestrictEnterHolder RestrictEnter(this);
7977
7978     {
7979         SystemDomain::LockHolder lh; // we don't want to close appdomain if other thread can be preparing to unload it
7980         SetStage(STAGE_EXITING);  // Note that we're trying to exit
7981     }
7982
7983     // Raise the event indicating the domain is being unloaded.
7984     if (GetDefaultContext())
7985     {
7986         FastInterlockExchangePointer(&s_pAppDomainToRaiseUnloadEvent, this);
7987
7988         DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
7989         //if (timeout == INFINITE)
7990         //{
7991         //    timeout = 20000; // 20 seconds
7992         //}
7993         DWORD timeoutForFinalizer = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
7994         ULONGLONG curTime = CLRGetTickCount64();
7995         ULONGLONG endTime = 0;
7996         if (timeout != INFINITE)
7997         {
7998             endTime = curTime + timeout;
7999             // We will try to kill AD unload event if it takes too long, and then we move on to the next registered caller.
8000             timeout /= 5;
8001         }
8002
8003         while (s_pAppDomainToRaiseUnloadEvent != NULL)
8004         {
8005             FinalizerThread::FinalizerThreadWait(s_fProcessUnloadDomainEvent?timeout:timeoutForFinalizer);
8006             if (endTime != 0 && s_pAppDomainToRaiseUnloadEvent != NULL)
8007             {
8008                 if (CLRGetTickCount64() >= endTime)
8009                 {
8010                     SString sThreadId;
8011                     sThreadId.Printf(W("%x"), FinalizerThread::GetFinalizerThread()->GetThreadId());
8012                     COMPlusThrow(kCannotUnloadAppDomainException,
8013                                  IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD,
8014                                  sThreadId);
8015                 }
8016             }
8017         }
8018     }
8019
8020     // Tell the tiered compilation manager to stop initiating any new work for background
8021     // jit optimization. Its possible the standard thread unwind mechanisms would pre-emptively
8022     // evacuate the jit threadpool worker threads from the domain on their own, but I see no reason 
8023     // to take the risk of relying on them when we can easily augment with a cooperative 
8024     // shutdown check. This notification only initiates the process of evacuating the threads
8025     // and then the UnwindThreads() call below is where blocking will occur to ensure the threads 
8026     // have exited the domain.
8027     //
8028 #ifdef FEATURE_TIERED_COMPILATION
8029     m_tieredCompilationManager.Shutdown();
8030 #endif
8031
8032     //
8033     // Set up blocks so no threads can enter except for the finalizer and the thread
8034     // doing the unload.
8035     //
8036
8037     RestrictThreadEntrance(this);
8038
8039     // Cause existing threads to abort out of this domain.  This should ensure all
8040     // normal threads are outside the domain, and we've already ensured that no new threads
8041     // can enter.
8042
8043     PerAppDomainTPCountList::AppDomainUnloadingHolder tpAdUnloadHolder(GetTPIndex());
8044
8045
8046     if (!NingenEnabled())
8047     {
8048         UnwindThreads();
8049     }
8050     
8051     TESTHOOKCALL(UnwoundThreads(GetId().m_dwId)) ;    
8052     ProcessEventForHost(Event_DomainUnload, (PVOID)(UINT_PTR)GetId().m_dwId);
8053
8054     RestrictEnter.SuppressRelease(); //after this point we don't guarantee appdomain consistency
8055 #ifdef PROFILING_SUPPORTED
8056     // Signal profile if present.
8057     {
8058         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
8059         GCX_PREEMP();
8060         g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) this);
8061         END_PIN_PROFILER();
8062     }
8063 #endif // PROFILING_SUPPORTED
8064     COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains--);
8065     COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomainsUnloaded++);
8066
8067     LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is exited.\n",
8068          GetId().m_dwId, this, GetFriendlyNameForLogging()));
8069
8070     // Send ETW events for this domain's unload and potentially iterate through this
8071     // domain's modules & assemblies to send events for their unloads as well.  This
8072     // needs to occur before STAGE_FINALIZED (to ensure everything is there), so we do
8073     // this before any finalization occurs at all.
8074     ETW::LoaderLog::DomainUnload(this);
8075
8076     CodeVersionManager::OnAppDomainExit(this);
8077
8078     //
8079     // Spin running finalizers until we flush them all.  We need to make multiple passes
8080     // in case the finalizers create more finalizable objects.  This is important to clear
8081     // the finalizable objects as roots, as well as to actually execute the finalizers. This
8082     // will only finalize instances instances of types that aren't potentially agile becuase we can't
8083     // risk finalizing agile objects. So we will be left with instances of potentially agile types
8084     // in handles or statics.
8085     //
8086     // <TODO>@todo: Need to ensure this will terminate in a reasonable amount of time.  Eventually
8087     // we should probably start passing FALSE for fRunFinalizers. Also I'm not sure we
8088     // guarantee that FinalizerThreadWait will ever terminate in general.</TODO>
8089     //
8090
8091     SetStage(STAGE_FINALIZING);
8092
8093     // Flush finalizers now.
8094     FinalizerThread::UnloadAppDomain(this, fRunFinalizers);
8095     
8096     DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8097     ULONGLONG startTime = CLRGetTickCount64();
8098     ULONGLONG elapsedTime = 0;
8099     DWORD finalizerWait = 0;
8100
8101     while (FinalizerThread::GetUnloadingAppDomain() != NULL)
8102     {
8103
8104         if (timeout != INFINITE)
8105         {
8106             elapsedTime = CLRGetTickCount64() - startTime;
8107         }
8108         if (timeout > elapsedTime)
8109         {
8110             finalizerWait = timeout - static_cast<DWORD>(elapsedTime);
8111         }
8112         FinalizerThread::FinalizerThreadWait(finalizerWait); //will set stage to finalized
8113         if (timeout != INFINITE && FinalizerThread::GetUnloadingAppDomain() != NULL)
8114         {
8115             elapsedTime = CLRGetTickCount64() - startTime;
8116             if (timeout <= elapsedTime)
8117             {
8118                 SetRudeUnload();
8119                 // TODO: Consider escalation from RudeAppDomain
8120                 timeout = INFINITE;
8121             }
8122         }
8123     }
8124
8125     tpAdUnloadHolder.SuppressRelease();
8126     PerAppDomainTPCountList::ResetAppDomainTPCounts(GetTPIndex());
8127
8128     LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is finalized.\n",
8129          GetId().m_dwId, this, GetFriendlyNameForLogging()));
8130
8131
8132     AppDomainRefHolder This(this);
8133     AddRef();           // Hold a reference so CloseDomain won't delete us yet
8134     CloseDomain();      // Remove ourself from the list of app domains
8135
8136     // This needs to be done prior to destroying the handle tables below.
8137     ReleaseDomainBoundInfo();
8138
8139     //
8140     // It should be impossible to run non-mscorlib code in this domain now.
8141     // Cleanup all of our roots except the handles. We do this to allow as many
8142     // finalizers as possible to run correctly. If we delete the handles, they
8143     // can't run.
8144     //
8145     if (!NingenEnabled())
8146     {
8147     }
8148
8149     ClearGCRoots();
8150     ClearGCHandles();
8151
8152     LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is cleared.\n",
8153          GetId().m_dwId, this, GetFriendlyNameForLogging()));
8154
8155     if (fAsyncExit && fRunFinalizers)
8156     {
8157         GCX_PREEMP();
8158         m_AssemblyCache.Clear();
8159         ClearFusionContext();
8160         ReleaseFiles();
8161         if (!NingenEnabled())
8162         {
8163             AddMemoryPressure();
8164         }
8165     }
8166     SystemDomain::System()->AddToDelayedUnloadList(this, fAsyncExit);
8167     SystemDomain::SetUnloadDomainCleared();
8168     if (m_dwId.m_dwId!=0)
8169         SystemDomain::ReleaseAppDomainId(m_dwId);
8170 #ifdef PROFILING_SUPPORTED
8171     // Always signal profile if present, even when failed.
8172     {
8173         BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
8174         GCX_PREEMP();
8175         g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) this, S_OK);
8176         END_PIN_PROFILER();
8177     }
8178 #endif // PROFILING_SUPPORTED
8179
8180 }
8181
8182 void AppDomain::Close()
8183 {
8184     CONTRACTL
8185     {
8186         GC_TRIGGERS;
8187         NOTHROW;
8188     }
8189     CONTRACTL_END;
8190
8191     LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Domain [%d] %#08x %ls is collected.\n",
8192          GetId().m_dwId, this, GetFriendlyNameForLogging()));
8193
8194     {
8195         GCX_PREEMP();
8196         RemoveMemoryPressure();
8197     }
8198     _ASSERTE(m_cRef>0); //should be alive at this point otherwise iterator can revive us and crash
8199     {
8200         SystemDomain::LockHolder lh;    // Avoid races with AppDomainIterator
8201         SetStage(STAGE_CLOSED);
8202     }
8203
8204     // CONSIDER: move releasing remoting cache from managed code to here.
8205 }
8206
8207
8208 void AppDomain::ResetUnloadRequestThread(ADID Id)
8209 {
8210     CONTRACTL
8211     {
8212         NOTHROW;
8213         MODE_ANY;
8214         PRECONDITION(!IsADUnloadHelperThread());
8215     }
8216     CONTRACTL_END;
8217
8218     GCX_COOP();
8219     AppDomainFromIDHolder ad(Id, TRUE);
8220     if(!ad.IsUnloaded() && ad->m_Stage < STAGE_UNLOAD_REQUESTED)
8221     {
8222         Thread *pThread = ad->GetUnloadRequestThread();
8223         if(pThread==GetThread())
8224         {
8225             ad->m_dwThreadsStillInAppDomain=(ULONG)-1;
8226
8227             if(pThread)
8228             {
8229                 if (pThread->GetUnloadBoundaryFrame() && pThread->IsBeingAbortedForADUnload())
8230                 {
8231                     pThread->UnmarkThreadForAbort(Thread::TAR_ADUnload);
8232                 }
8233                 ad->GetUnloadRequestThread()->ResetUnloadBoundaryFrame();
8234                 pThread->ResetBeginAbortedForADUnload();
8235             }
8236             
8237             ad->SetUnloadRequestThread(NULL);
8238         }
8239     }
8240 }
8241
8242
8243 int g_fADUnloadWorkerOK = -1;
8244
8245 HRESULT AppDomain::UnloadById(ADID dwId, BOOL fSync,BOOL fExceptionsPassThrough)
8246 {
8247     CONTRACTL
8248     {
8249         if(fExceptionsPassThrough) {THROWS;} else {NOTHROW;}
8250         MODE_ANY;
8251         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
8252         FORBID_FAULT;
8253     }
8254     CONTRACTL_END;
8255
8256     if (dwId==(ADID)DefaultADID)
8257         return COR_E_CANNOTUNLOADAPPDOMAIN;
8258
8259     Thread *pThread = GetThread();
8260
8261     // Finalizer thread can not wait until AD unload is done,
8262     // because AD unload is going to wait for Finalizer Thread.
8263     if (fSync && pThread == FinalizerThread::GetFinalizerThread() && 
8264         !pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent))
8265         return COR_E_CANNOTUNLOADAPPDOMAIN;
8266
8267
8268     // AD unload helper thread should have been created.
8269     _ASSERTE (g_fADUnloadWorkerOK == 1);
8270
8271     _ASSERTE (!IsADUnloadHelperThread());
8272
8273     BOOL fIsRaisingUnloadEvent = (pThread != NULL && pThread->HasThreadStateNC(Thread::TSNC_RaiseUnloadEvent));
8274
8275     if (fIsRaisingUnloadEvent)
8276     {
8277         AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_GC);
8278
8279         if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
8280             return COR_E_APPDOMAINUNLOADED;
8281
8282         pApp->EnableADUnloadWorker();
8283
8284         return S_FALSE;
8285     }
8286
8287
8288     ADUnloadSinkHolder pSink;
8289
8290     {
8291         SystemDomain::LockHolder ulh;
8292
8293         AppDomainFromIDHolder pApp(dwId, TRUE, AppDomainFromIDHolder::SyncType_ADLock);
8294
8295         if (pApp.IsUnloaded() || ! pApp->CanLoadCode() || pApp->GetId().m_dwId == 0)
8296             return COR_E_APPDOMAINUNLOADED;
8297
8298         if (g_fADUnloadWorkerOK != 1)
8299         {
8300             _ASSERTE(FALSE);
8301             return E_UNEXPECTED;
8302         }
8303
8304         if (!fSync)
8305         {
8306             pApp->EnableADUnloadWorker();
8307             return S_OK;
8308         }
8309
8310         pSink = pApp->PrepareForWaitUnloadCompletion();
8311
8312         pApp->EnableADUnloadWorker();
8313
8314         // release the holders - we don't care anymore if the appdomain is gone
8315     }
8316
8317 #ifdef FEATURE_TESTHOOKS        
8318     if (fExceptionsPassThrough)
8319     {
8320         CONTRACT_VIOLATION(FaultViolation);
8321         return UnloadWaitNoCatch(dwId,pSink);
8322     }
8323 #endif            
8324
8325     return UnloadWait(dwId,pSink);
8326 }
8327
8328 HRESULT AppDomain::UnloadWait(ADID Id, ADUnloadSink * pSink)
8329 {
8330     CONTRACTL
8331     {
8332         NOTHROW;
8333         MODE_ANY;
8334         if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_TRIGGERS);}
8335     }
8336     CONTRACTL_END;
8337     
8338     HRESULT hr=S_OK;
8339     EX_TRY
8340     {
8341         // IF you ever try to change this to something not using events, please address the fact that
8342         // AppDomain::StopEEAndUnwindThreads relies on that events are used.
8343
8344         pSink->WaitUnloadCompletion();
8345     }
8346     EX_CATCH_HRESULT(hr);
8347
8348     if (SUCCEEDED(hr))
8349         hr=pSink->GetUnloadResult();
8350
8351     if (FAILED(hr))
8352     {
8353         ResetUnloadRequestThread(Id);
8354     }
8355     return hr;
8356 }
8357
8358 #ifdef FEATURE_TESTHOOKS        
8359 HRESULT AppDomain::UnloadWaitNoCatch(ADID Id, ADUnloadSink * pSink)
8360 {
8361     STATIC_CONTRACT_THROWS;
8362     STATIC_CONTRACT_MODE_ANY;    
8363
8364     Holder<ADID, DoNothing<ADID>, AppDomain::ResetUnloadRequestThread> resetUnloadHolder(Id);
8365
8366     // IF you ever try to change this to something not using events, please address the fact that
8367     // AppDomain::StopEEAndUnwindThreads relies on that events are used.
8368     pSink->WaitUnloadCompletion();
8369
8370     HRESULT hr = pSink->GetUnloadResult();
8371
8372     if (SUCCEEDED(hr))
8373         resetUnloadHolder.SuppressRelease();
8374
8375     return hr;
8376 }
8377 #endif
8378
8379 void AppDomain::Unload(BOOL fForceUnload)
8380 {
8381     CONTRACTL
8382     {
8383         THROWS;
8384         MODE_COOPERATIVE;
8385         GC_TRIGGERS;
8386         INJECT_FAULT(COMPlusThrowOM(););
8387     }
8388     CONTRACTL_END;
8389
8390 #ifdef FEATURE_MULTICOREJIT
8391
8392     // Avoid profiling file is partially written in ASP.net scenarios, call it earlier
8393     GetMulticoreJitManager().StopProfile(true);
8394
8395 #endif
8396
8397     Thread *pThread = GetThread();
8398
8399
8400     if (! fForceUnload && !g_pConfig->AppDomainUnload())
8401         return;
8402
8403     EPolicyAction action;
8404     EClrOperation operation;
8405     if (!IsRudeUnload())
8406     {
8407         operation = OPR_AppDomainUnload;
8408     }
8409     else
8410     {
8411         operation = OPR_AppDomainRudeUnload;
8412     }
8413     action = GetEEPolicy()->GetDefaultAction(operation,NULL);
8414     GetEEPolicy()->NotifyHostOnDefaultAction(operation,action);
8415
8416     switch (action)
8417     {
8418     case eUnloadAppDomain:
8419         break;
8420     case eRudeUnloadAppDomain:
8421         SetRudeUnload();
8422         break;
8423     case eExitProcess:
8424     case eFastExitProcess:
8425     case eRudeExitProcess:
8426     case eDisableRuntime:
8427         EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_ADUNLOAD);
8428         _ASSERTE (!"Should not get here");
8429         break;
8430     default:
8431         break;
8432     }
8433
8434 #if (defined(_DEBUG) || defined(BREAK_ON_UNLOAD) || defined(AD_LOG_MEMORY) || defined(AD_SNAPSHOT))
8435     static int unloadCount = 0;
8436 #endif
8437
8438 #ifdef AD_LOG_MEMORY
8439     {
8440         GCX_PREEMP();
8441         static int logMemory = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADLogMemory);
8442         typedef void (__cdecl *LogItFcn) ( int );
8443         static LogItFcn pLogIt = NULL;
8444
8445         if (logMemory && ! pLogIt)
8446         {
8447             HMODULE hMod = CLRLoadLibrary(W("mpdh.dll"));
8448             if (hMod)
8449             {
8450                 pLogIt = (LogItFcn)GetProcAddress(hMod, "logIt");
8451                 if (pLogIt)
8452                 {
8453                     pLogIt(9999);
8454                     pLogIt(9999);
8455                 }
8456             }
8457         }
8458     }
8459 #endif // AD_LOG_MEMORY
8460
8461     if (IsDefaultDomain() && !IsSingleAppDomain())
8462         COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_DEFAULT);
8463
8464     _ASSERTE(CanUnload());
8465
8466     if (pThread == FinalizerThread::GetFinalizerThread() || GetUnloadRequestThread() == FinalizerThread::GetFinalizerThread())
8467         COMPlusThrow(kCannotUnloadAppDomainException, IDS_EE_ADUNLOAD_IN_FINALIZER);
8468
8469     _ASSERTE(! SystemDomain::AppDomainBeingUnloaded());
8470
8471     // should not be running in this AD because unload spawned thread in default domain
8472     if (!NingenEnabled())
8473     {
8474         _ASSERTE(!pThread->IsRunningIn(this, NULL));
8475     }
8476
8477
8478 #ifdef APPDOMAIN_STATE
8479     _ASSERTE_ALL_BUILDS("clr/src/VM/AppDomain.cpp", pThread->GetDomain()->IsDefaultDomain());
8480 #endif
8481
8482     LOG((LF_APPDOMAIN | LF_CORDB, LL_INFO10, "AppDomain::Unloading domain [%d] %#08x %ls\n", GetId().m_dwId, this, GetFriendlyName()));
8483
8484     STRESS_LOG3 (LF_APPDOMAIN, LL_INFO100, "Unload domain [%d, %d] %p\n", GetId().m_dwId, GetIndex().m_dwIndex, this);
8485
8486     UnloadHolder hold(this);
8487
8488     SystemDomain::System()->SetUnloadRequestingThread(GetUnloadRequestThread());
8489     SystemDomain::System()->SetUnloadingThread(pThread);
8490
8491
8492 #ifdef _DEBUG
8493     static int dumpSB = -1;
8494
8495     if (dumpSB == -1)
8496         dumpSB = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADDumpSB);
8497
8498     if (dumpSB > 1)
8499     {
8500         LogSpewAlways("Starting unload %3.3d\n", unloadCount);
8501         DumpSyncBlockCache();
8502     }
8503 #endif // _DEBUG
8504
8505     BOOL bForceGC=m_bForceGCOnUnload;
8506
8507 #ifdef AD_LOG_MEMORY
8508     if (pLogIt)
8509         bForceGC=TRUE;
8510 #endif // AD_LOG_MEMORY
8511
8512 #ifdef AD_SNAPSHOT
8513     static int takeSnapShot = -1;
8514
8515     if (takeSnapShot == -1)
8516         takeSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeSnapShot);
8517
8518     if (takeSnapShot)
8519         bForceGC=TRUE;
8520 #endif // AD_SNAPSHOT
8521
8522 #ifdef _DEBUG
8523     if (dumpSB > 0)
8524         bForceGC=TRUE;
8525 #endif // _DEBUG
8526     static int cfgForceGC = -1;
8527
8528     if (cfgForceGC == -1)
8529         cfgForceGC =!CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ADULazyMemoryRelease);
8530
8531     bForceGC=bForceGC||cfgForceGC;
8532     AppDomainRefHolder This(this);
8533     AddRef();
8534
8535     // Do the actual unloading
8536     {
8537         // We do not want other threads to abort the current one.
8538         ThreadPreventAsyncHolder preventAsync;
8539         Exit(TRUE, !bForceGC);
8540     }
8541     if(bForceGC)
8542     {
8543         GCHeapUtilities::GetGCHeap()->GarbageCollect();
8544         FinalizerThread::FinalizerThreadWait();
8545         SetStage(STAGE_COLLECTED);
8546         Close(); //NOTHROW!
8547     }
8548
8549 #ifdef AD_LOG_MEMORY
8550     if (pLogIt)
8551     {
8552         GCX_PREEMP();
8553         pLogIt(unloadCount);
8554     }
8555 #endif // AD_LOG_MEMORY
8556
8557 #ifdef AD_SNAPSHOT
8558     if (takeSnapShot)
8559     {
8560         char buffer[1024];
8561         sprintf_s(buffer, _countof(buffer), "vadump -p %d -o > vadump.%d", GetCurrentProcessId(), unloadCount);
8562         system(buffer);
8563         sprintf_s(buffer, _countof(buffer), "umdh -p:%d -d -i:1 -f:umdh.%d", GetCurrentProcessId(), unloadCount);
8564         system(buffer);
8565         int takeDHSnapShot = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADTakeDHSnapShot);
8566         if (takeDHSnapShot)
8567         {
8568             sprintf_s(buffer, _countof(buffer), "dh -p %d -s -g -h -b -f dh.%d", GetCurrentProcessId(), unloadCount);
8569             system(buffer);
8570         }
8571     }
8572 #endif // AD_SNAPSHOT
8573
8574 #ifdef _DEBUG
8575     if (dumpSB > 0)
8576     {
8577         // do extra finalizer wait to remove any leftover sb entries
8578         FinalizerThread::FinalizerThreadWait();
8579         GCHeapUtilities::GetGCHeap()->GarbageCollect();
8580         FinalizerThread::FinalizerThreadWait();
8581         LogSpewAlways("Done unload %3.3d\n", unloadCount);
8582         DumpSyncBlockCache();
8583         ShutdownLogging();
8584         WCHAR buffer[128];
8585         swprintf_s(buffer, NumItems(buffer), W("DumpSB.%d"), unloadCount);
8586         _ASSERTE(WszMoveFileEx(W("COMPLUS.LOG"), buffer, MOVEFILE_REPLACE_EXISTING));
8587         // this will open a new file
8588         InitLogging();
8589     }
8590 #endif // _DEBUG
8591 }
8592
8593 void AppDomain::ExceptionUnwind(Frame *pFrame)
8594 {
8595     CONTRACTL
8596     {
8597         DISABLED(GC_TRIGGERS);  // EEResourceException
8598         DISABLED(THROWS);   // EEResourceException
8599         MODE_ANY;
8600     }
8601     CONTRACTL_END;
8602
8603     LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind for %8.8x\n", pFrame));
8604 #if _DEBUG_ADUNLOAD
8605     printf("%x AppDomain::ExceptionUnwind for %8.8p\n", GetThread()->GetThreadId(), pFrame);
8606 #endif
8607     Thread *pThread = GetThread();
8608     _ASSERTE(pThread);
8609
8610     if (! pThread->ShouldChangeAbortToUnload(pFrame))
8611     {
8612         LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: not first transition or abort\n"));
8613         return;
8614     }
8615
8616     LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: changing to unload\n"));
8617
8618     GCX_COOP();
8619     OBJECTREF throwable = NULL;
8620     EEResourceException e(kAppDomainUnloadedException, W("Remoting_AppDomainUnloaded_ThreadUnwound"));
8621     throwable = e.GetThrowable();
8622
8623     // reset the exception to an AppDomainUnloadedException
8624     if (throwable != NULL)
8625     {
8626         GetThread()->SafeSetThrowables(throwable);
8627     }
8628 }
8629
8630 BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread)
8631 {
8632     CONTRACTL
8633     {
8634         THROWS;
8635         GC_TRIGGERS;
8636         MODE_ANY;
8637         SO_INTOLERANT;
8638     }
8639     CONTRACTL_END;
8640
8641     Thread *pThread = NULL;
8642     DWORD nThreadsNeedMoreWork=0;
8643     if (retryCount != (unsigned int)-1 && retryCount < g_pConfig->AppDomainUnloadRetryCount())
8644     {
8645         Thread *pCurThread = GetThread();
8646         if (pCurThread->CatchAtSafePoint())
8647             pCurThread->PulseGCMode();
8648
8649         {
8650             // We know which thread is not in the domain now.  We just need to
8651             // work on those threads.  We do not need to suspend the runtime.
8652             ThreadStoreLockHolder tsl;
8653
8654             while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8655             {
8656                 if (pThread == pCurThread)
8657                 {
8658                     continue;
8659                 }
8660
8661                 if (pThread == FinalizerThread::GetFinalizerThread())
8662                 {
8663                     continue;
8664                 }
8665
8666                 if (pThread->GetUnloadBoundaryFrame() == NULL)
8667                 {
8668                     continue;
8669                 }
8670
8671                 // A thread may have UnloadBoundaryFrame set if
8672                 // 1. Being unloaded by AD unload helper thread
8673                 // 2. Escalation from OOM or SO triggers AD unload
8674                 // Here we only need to work on threads that are in the domain.  If we work on other threads,
8675                 // those threads may be stucked in a finally, and we will not be able to escalate for them,
8676                 // therefore AD unload is blocked.
8677                 if (pThread->IsBeingAbortedForADUnload() ||
8678                     pThread == SystemDomain::System()->GetUnloadRequestingThread())
8679                 {
8680                     nThreadsNeedMoreWork++;
8681                 }
8682
8683                 if (!(IsRudeUnload() ||
8684                       (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())))
8685                 {
8686                     continue;
8687                 }
8688
8689                 if ((pThread == SystemDomain::System()->GetUnloadRequestingThread()) && *pFMarkUnloadRequestThread)
8690                 {
8691                     // Mark thread for abortion only once; later on interrupt only
8692                     *pFMarkUnloadRequestThread = FALSE;
8693                     pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
8694                 }
8695                 else
8696                 {
8697                     if (pThread->m_State & Thread::TS_Interruptible)
8698                     {
8699                         pThread->UserInterrupt(Thread::TI_Abort);
8700                     }
8701                 }
8702
8703                 if (pThread->PreemptiveGCDisabledOther())
8704                 {
8705         #if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
8706                     Thread::SuspendThreadResult str = pThread->SuspendThread();
8707                     if (str == Thread::STR_Success)
8708                     {
8709                         if (pThread->PreemptiveGCDisabledOther() &&
8710                             (!pThread->IsAbortInitiated() || pThread->IsRudeAbort()))
8711                         {
8712                             pThread->HandleJITCaseForAbort();
8713                         }
8714                         pThread->ResumeThread();
8715                     }
8716         #endif
8717                 }
8718             }
8719         } // ThreadStoreLockHolder
8720
8721         m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
8722         return !nThreadsNeedMoreWork;
8723     }
8724
8725     // For now piggyback on the GC's suspend EE mechanism
8726     ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
8727 #ifdef _DEBUG
8728     // <TODO>@todo: what to do with any threads that didn't stop?</TODO>
8729     _ASSERTE(ThreadStore::s_pThreadStore->DbgBackgroundThreadCount() > 0);
8730 #endif // _DEBUG
8731
8732     int totalADCount = 0;
8733     int finalizerADCount = 0;
8734     pThread = NULL;
8735
8736     RuntimeExceptionKind reKind = kLastException;
8737     UINT resId = 0;
8738     SmallStackSString ssThreadId;
8739
8740     while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8741     {
8742         // we already checked that we're not running in the unload domain
8743         if (pThread == GetThread())
8744         {
8745             continue;
8746         }
8747
8748 #ifdef _DEBUG
8749         void PrintStackTraceWithADToLog(Thread *pThread);
8750         if (LoggingOn(LF_APPDOMAIN, LL_INFO100)) {
8751             LOG((LF_APPDOMAIN, LL_INFO100, "\nStackTrace for %x\n", pThread->GetThreadId()));
8752             PrintStackTraceWithADToLog(pThread);
8753         }
8754 #endif // _DEBUG
8755         int count = 0;
8756         Frame *pFrame = pThread->GetFirstTransitionInto(this, &count);
8757         if (! pFrame) {
8758             _ASSERTE(count == 0);
8759             if (pThread->IsBeingAbortedForADUnload())
8760             {
8761                 pThread->ResetBeginAbortedForADUnload();
8762             }
8763             continue;
8764         }
8765
8766         if (pThread != FinalizerThread::GetFinalizerThread())
8767         {
8768             totalADCount += count;
8769             nThreadsNeedMoreWork++;
8770             pThread->SetUnloadBoundaryFrame(pFrame);
8771         }
8772         else
8773         {
8774             finalizerADCount = count;
8775         }
8776
8777         // don't setup the exception info for the unloading thread unless it's the last one in
8778         if (retryCount != ((unsigned int) -1) && retryCount > g_pConfig->AppDomainUnloadRetryCount() && reKind == kLastException &&
8779             (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft()))
8780         {
8781 #ifdef AD_BREAK_ON_CANNOT_UNLOAD
8782             static int breakOnCannotUnload = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADBreakOnCannotUnload);
8783             if (breakOnCannotUnload)
8784                 _ASSERTE(!"Cannot unload AD");
8785 #endif // AD_BREAK_ON_CANNOT_UNLOAD
8786             reKind = kCannotUnloadAppDomainException;
8787             resId = IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD;
8788             ssThreadId.Printf(W("%x"), pThread->GetThreadId());
8789             STRESS_LOG2(LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads cannot stop thread %x with %d transitions\n", pThread->GetThreadId(), count);
8790             // don't break out of this early or the assert totalADCount == (int)m_dwThreadEnterCount below will fire
8791             // it's better to chew a little extra time here and make sure our counts are consistent
8792         }
8793         // only abort the thread requesting the unload if it's the last one in, that way it will get
8794         // notification that the unload failed for some other thread not being aborted. And don't abort
8795         // the finalizer thread - let it finish it's work as it's allowed to be in there. If it won't finish,
8796         // then we will eventually get a CannotUnloadException on it.
8797
8798         if (pThread != FinalizerThread::GetFinalizerThread() &&
8799             // If the domain is rudely unloaded, we will unwind the requesting thread out
8800             // Rude unload is going to succeed, or escalated to disable runtime or higher.
8801             (IsRudeUnload() ||
8802              (pThread != SystemDomain::System()->GetUnloadRequestingThread() || OnlyOneThreadLeft())
8803             )
8804            )
8805         {
8806
8807             STRESS_LOG2(LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count);
8808             LOG((LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count));
8809 #if _DEBUG_ADUNLOAD
8810             printf("AppDomain::UnwindThreads %x stopping %x with first frame %8.8p\n", GetThread()->GetThreadId(), pThread->GetThreadId(), pFrame);
8811 #endif
8812             if (pThread == SystemDomain::System()->GetUnloadRequestingThread())
8813             {
8814                 // Mark thread for abortion only once; later on interrupt only
8815                 *pFMarkUnloadRequestThread = FALSE;
8816             }
8817             pThread->SetAbortRequest(m_fRudeUnload? EEPolicy::TA_Rude : EEPolicy::TA_V1Compatible);
8818         }
8819         TESTHOOKCALL(UnwindingThreads(GetId().m_dwId)) ;
8820     }
8821     _ASSERTE(totalADCount + finalizerADCount == (int)m_dwThreadEnterCount);
8822
8823     //@TODO: This is intended to catch a stress bug. Remove when no longer needed.
8824     if (totalADCount + finalizerADCount != (int)m_dwThreadEnterCount)
8825         FreeBuildDebugBreak();
8826
8827     // if our count did get messed up, set it to whatever count we actually found in the domain to avoid looping
8828     // or other problems related to incorrect count. This is very much a bug if this happens - a thread should always
8829     // exit the domain gracefully.
8830     // m_dwThreadEnterCount = totalADCount;
8831
8832     if (reKind != kLastException)
8833     {
8834         pThread = NULL;
8835         while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8836         {
8837             if (pThread->IsBeingAbortedForADUnload())
8838             {
8839                 pThread->ResetBeginAbortedForADUnload();
8840             }
8841         }
8842     }
8843
8844     // CommonTripThread will handle the abort for any threads that we've marked
8845     ThreadSuspend::RestartEE(FALSE, TRUE);
8846     if (reKind != kLastException)
8847         COMPlusThrow(reKind, resId, ssThreadId.GetUnicode());
8848
8849     _ASSERTE((totalADCount==0 && nThreadsNeedMoreWork==0) ||(totalADCount!=0 && nThreadsNeedMoreWork!=0));
8850     
8851     m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
8852     return (totalADCount == 0);
8853 }
8854
8855 void AppDomain::UnwindThreads()
8856 {
8857     // This function should guarantee appdomain
8858     // consistency even if it fails. Everything that is going
8859     // to make the appdomain impossible to reenter
8860     // should be factored out
8861
8862     // <TODO>@todo: need real synchronization here!!!</TODO>
8863     CONTRACTL
8864     {
8865         MODE_COOPERATIVE;
8866         THROWS;
8867         GC_TRIGGERS;
8868     }
8869     CONTRACTL_END;
8870
8871     int retryCount = -1;
8872     m_dwThreadsStillInAppDomain=(ULONG)-1;
8873     ULONGLONG startTime = CLRGetTickCount64();
8874
8875     if (GetEEPolicy()->GetDefaultAction(OPR_AppDomainUnload, NULL) == eRudeUnloadAppDomain &&
8876         !IsRudeUnload())
8877     {
8878         GetEEPolicy()->NotifyHostOnDefaultAction(OPR_AppDomainUnload, eRudeUnloadAppDomain);
8879         SetRudeUnload();
8880     }
8881
8882     // Force threads to go through slow path during AD unload.
8883     TSSuspendHolder shTrap;
8884
8885     BOOL fCurrentUnloadMode = IsRudeUnload();
8886     BOOL fMarkUnloadRequestThread = TRUE;
8887
8888     // now wait for all the threads running in our AD to get out
8889     do
8890     {
8891         DWORD timeout = GetEEPolicy()->GetTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload);
8892         EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, NULL);
8893         if (timeout != INFINITE && action > eUnloadAppDomain) {
8894             // Escalation policy specified.
8895             ULONGLONG curTime = CLRGetTickCount64();
8896             ULONGLONG elapseTime = curTime - startTime;
8897             if (elapseTime > timeout)
8898             {
8899                 // Escalate
8900                 switch (action)
8901                 {
8902                 case eRudeUnloadAppDomain:
8903                     GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
8904                     SetRudeUnload();
8905                     STRESS_LOG1(LF_APPDOMAIN, LL_INFO100,"Escalating to RADU, adid=%d",GetId().m_dwId);
8906                     break;
8907                 case eExitProcess:
8908                 case eFastExitProcess:
8909                 case eRudeExitProcess:
8910                 case eDisableRuntime:
8911                     GetEEPolicy()->NotifyHostOnTimeout(m_fRudeUnload?OPR_AppDomainRudeUnload : OPR_AppDomainUnload, action);
8912                     EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
8913                     _ASSERTE (!"Should not reach here");
8914                     break;
8915                 default:
8916                     break;
8917                 }
8918             }
8919         }
8920 #ifdef _DEBUG
8921         if (LoggingOn(LF_APPDOMAIN, LL_INFO100))
8922             DumpADThreadTrack();
8923 #endif // _DEBUG
8924         BOOL fNextUnloadMode = IsRudeUnload();
8925         if (fCurrentUnloadMode != fNextUnloadMode)
8926         {
8927             // We have changed from normal unload to rude unload.  We need to mark the thread
8928             // with RudeAbort, but we can only do this safely if the runtime is suspended.
8929             fCurrentUnloadMode = fNextUnloadMode;
8930             retryCount = -1;
8931         }
8932         if (StopEEAndUnwindThreads(retryCount, &fMarkUnloadRequestThread))
8933             break;
8934         if (timeout != INFINITE)
8935         {
8936             // Turn off the timeout used by AD.
8937             retryCount = 1;
8938         }
8939         else
8940         {
8941             // GCStress takes a long time to unwind, due to expensive creation of
8942             // a threadabort exception.
8943             if (!GCStress<cfg_any>::IsEnabled())
8944                 ++retryCount;
8945             LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount));
8946 #if _DEBUG_ADUNLOAD
8947             printf("AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount);
8948 #endif
8949         }
8950
8951         if (m_dwThreadEnterCount != 0)
8952         {
8953 #ifdef _DEBUG
8954             GetThread()->UserSleep(20);
8955 #else // !_DEBUG
8956             GetThread()->UserSleep(10);
8957 #endif // !_DEBUG
8958         }
8959     }
8960     while (TRUE) ;
8961 }
8962
8963 void AppDomain::ClearGCHandles()
8964 {
8965     CONTRACTL
8966     {
8967         GC_TRIGGERS;
8968         MODE_COOPERATIVE;
8969         NOTHROW;
8970     }
8971     CONTRACTL_END;
8972
8973     SetStage(STAGE_HANDLETABLE_NOACCESS);
8974
8975     GCHeapUtilities::GetGCHeap()->WaitUntilConcurrentGCComplete();
8976
8977     // Keep async pin handles alive by moving them to default domain
8978     HandleAsyncPinHandles();
8979
8980     // Remove our handle store as a source of GC roots
8981     m_handleStore->Uproot();
8982 }
8983
8984 // When an AD is unloaded, we will release all objects in this AD.
8985 // If a future asynchronous operation, like io completion port function,
8986 // we need to keep the memory space fixed so that the gc heap is not corrupted.
8987 void AppDomain::HandleAsyncPinHandles()
8988 {
8989     CONTRACTL
8990     {
8991         GC_TRIGGERS;
8992         MODE_COOPERATIVE;
8993         NOTHROW;
8994     }
8995     CONTRACTL_END;
8996
8997     IGCHandleStore *pBucket = m_handleStore;
8998
8999     // IO completion port picks IO job using FIFO.  Here is how we know which AsyncPinHandle can be freed.
9000     // 1. We mark all non-pending AsyncPinHandle with READYTOCLEAN.
9001     // 2. We queue a dump Overlapped to the IO completion as a marker.
9002     // 3. When the Overlapped is picked up by completion port, we wait until all previous IO jobs are processed.
9003     // 4. Then we can delete all AsyncPinHandle marked with READYTOCLEAN.
9004     IGCHandleStore *pBucketInDefault = SystemDomain::System()->DefaultDomain()->m_handleStore;
9005
9006     auto clearIfComplete = [](Object* object)
9007     {
9008         LIMITED_METHOD_CONTRACT;
9009
9010         assert(object != nullptr);
9011         if (object->GetGCSafeMethodTable() != g_pOverlappedDataClass)
9012         {
9013             return;
9014         }
9015
9016         OVERLAPPEDDATAREF overlapped = (OVERLAPPEDDATAREF)(ObjectToOBJECTREF((Object*)object));
9017         if (overlapped->HasCompleted())
9018         {
9019             // IO has finished.  We don't need to pin the user buffer any longer.
9020             overlapped->m_userObject = NULL;
9021         }
9022
9023         BashMTForPinnedObject(ObjectToOBJECTREF(object));
9024     };
9025
9026     auto setHandle = [](Object* object, OBJECTHANDLE handle)
9027     {
9028         LIMITED_METHOD_CONTRACT;
9029
9030         assert(object != nullptr);
9031         assert(handle);
9032
9033         if (object->GetGCSafeMethodTable() != g_pOverlappedDataClass)
9034         {
9035             return;
9036         }
9037
9038         OverlappedDataObject* overlapped = (OverlappedDataObject*)object;
9039         overlapped->m_pinSelf = handle;
9040     };
9041
9042     pBucket->RelocateAsyncPinnedHandles(pBucketInDefault, clearIfComplete, setHandle);
9043
9044     OverlappedDataObject::RequestCleanup();
9045 }
9046
9047 void AppDomain::ClearGCRoots()
9048 {
9049     CONTRACTL
9050     {
9051         GC_TRIGGERS;
9052         MODE_COOPERATIVE;
9053         NOTHROW;
9054     }
9055     CONTRACTL_END;
9056
9057     Thread *pThread = NULL;
9058     ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
9059
9060     // Tell the JIT managers to delete any entries in their structures. All the cooperative mode threads are stopped at
9061     // this point, so only need to synchronize the preemptive mode threads.
9062     ExecutionManager::Unload(GetLoaderAllocator());
9063
9064     while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL)
9065     {
9066         // Delete the thread local static store
9067         pThread->DeleteThreadStaticData(this);
9068
9069         // <TODO>@TODO: A pre-allocated AppDomainUnloaded exception might be better.</TODO>
9070         if (m_handleStore->ContainsHandle(pThread->m_LastThrownObjectHandle))
9071         {
9072             // Never delete a handle to a preallocated exception object.
9073             if (!CLRException::IsPreallocatedExceptionHandle(pThread->m_LastThrownObjectHandle))
9074             {
9075                 DestroyHandle(pThread->m_LastThrownObjectHandle);
9076             }
9077
9078             pThread->m_LastThrownObjectHandle = NULL;
9079         }
9080
9081         // Clear out the exceptions objects held by a thread.
9082         pThread->GetExceptionState()->ClearThrowablesForUnload(m_handleStore);
9083     }
9084
9085     //delete them while we still have the runtime suspended
9086     // This must be deleted before the loader heaps are deleted.
9087     if (m_pMarshalingData != NULL)
9088     {
9089         delete m_pMarshalingData;
9090         m_pMarshalingData = NULL;
9091     }
9092
9093     if (m_pLargeHeapHandleTable != NULL)
9094     {
9095         delete m_pLargeHeapHandleTable;
9096         m_pLargeHeapHandleTable = NULL;
9097     }
9098
9099     ThreadSuspend::RestartEE(FALSE, TRUE);
9100 }
9101
9102 #ifdef _DEBUG
9103
9104 void AppDomain::TrackADThreadEnter(Thread *pThread, Frame *pFrame)
9105 {
9106     CONTRACTL
9107     {
9108         NOTHROW;
9109         GC_NOTRIGGER;
9110         // REENTRANT
9111         PRECONDITION(CheckPointer(pThread));
9112         PRECONDITION(pFrame != (Frame*)(size_t) INVALID_POINTER_CD);
9113     }
9114     CONTRACTL_END;
9115
9116     while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9117         ;
9118     if (m_pThreadTrackInfoList == NULL)
9119         m_pThreadTrackInfoList = new (nothrow) ThreadTrackInfoList;
9120     // If we don't assert here, we will AV in the for loop below
9121     _ASSERTE(m_pThreadTrackInfoList);
9122
9123     ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9124
9125     ThreadTrackInfo *pTrack = NULL;
9126     int i;
9127     for (i=0; i < pTrackList->Count(); i++) {
9128         if ((*(pTrackList->Get(i)))->pThread == pThread) {
9129             pTrack = *(pTrackList->Get(i));
9130             break;
9131         }
9132     }
9133     if (! pTrack) {
9134         pTrack = new (nothrow) ThreadTrackInfo;
9135         // If we don't assert here, we will AV in the for loop below.
9136         _ASSERTE(pTrack);
9137         pTrack->pThread = pThread;
9138         ThreadTrackInfo **pSlot = pTrackList->Append();
9139         *pSlot = pTrack;
9140     }
9141
9142     InterlockedIncrement((LONG*)&m_dwThreadEnterCount);
9143     Frame **pSlot;
9144     if (pTrack)
9145     {
9146         pSlot = pTrack->frameStack.Insert(0);
9147         *pSlot = pFrame;
9148     }
9149     int totThreads = 0;
9150     for (i=0; i < pTrackList->Count(); i++)
9151         totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
9152     _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9153
9154     InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9155 }
9156
9157
9158 void AppDomain::TrackADThreadExit(Thread *pThread, Frame *pFrame)
9159 {
9160     CONTRACTL
9161     {
9162         if (GetThread()) {MODE_COOPERATIVE;}
9163         NOTHROW;
9164         GC_NOTRIGGER;
9165     }
9166     CONTRACTL_END;
9167
9168     while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9169         ;
9170     ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9171     _ASSERTE(pTrackList);
9172     ThreadTrackInfo *pTrack = NULL;
9173     int i;
9174     for (i=0; i < pTrackList->Count(); i++)
9175     {
9176         if ((*(pTrackList->Get(i)))->pThread == pThread)
9177         {
9178             pTrack = *(pTrackList->Get(i));
9179             break;
9180         }
9181     }
9182     _ASSERTE(pTrack);
9183     _ASSERTE(*(pTrack->frameStack.Get(0)) == pFrame);
9184     pTrack->frameStack.Delete(0);
9185     InterlockedDecrement((LONG*)&m_dwThreadEnterCount);
9186
9187     int totThreads = 0;
9188     for (i=0; i < pTrackList->Count(); i++)
9189         totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
9190     _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9191
9192     InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9193 }
9194
9195 void AppDomain::DumpADThreadTrack()
9196 {
9197     CONTRACTL
9198     {
9199         NOTHROW;
9200         GC_NOTRIGGER;
9201         MODE_COOPERATIVE;
9202     }
9203     CONTRACTL_END;
9204
9205     while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
9206         ;
9207     ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
9208     if (!pTrackList)
9209         goto end;
9210
9211     {
9212         LOG((LF_APPDOMAIN, LL_INFO10000, "\nThread dump of %d threads for [%d] %#08x %S\n",
9213              m_dwThreadEnterCount, GetId().m_dwId, this, GetFriendlyNameForLogging()));
9214         int totThreads = 0;
9215         for (int i=0; i < pTrackList->Count(); i++)
9216         {
9217             ThreadTrackInfo *pTrack = *(pTrackList->Get(i));
9218             if (pTrack->frameStack.Count()==0)
9219                 continue;
9220             LOG((LF_APPDOMAIN, LL_INFO100, "  ADEnterCount for %x is %d\n", pTrack->pThread->GetThreadId(), pTrack->frameStack.Count()));
9221             totThreads += pTrack->frameStack.Count();
9222             for (int j=0; j < pTrack->frameStack.Count(); j++)
9223                 LOG((LF_APPDOMAIN, LL_INFO100, "      frame %8.8x\n", *(pTrack->frameStack.Get(j))));
9224         }
9225         _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
9226     }
9227 end:
9228     InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
9229 }
9230 #endif // _DEBUG
9231
9232
9233 #endif // CROSSGEN_COMPILE
9234
9235 void *SharedDomain::operator new(size_t size, void *pInPlace)
9236 {
9237     LIMITED_METHOD_CONTRACT;
9238     return pInPlace;
9239 }
9240
9241 void SharedDomain::operator delete(void *pMem)
9242 {
9243     LIMITED_METHOD_CONTRACT;
9244     // Do nothing - new() was in-place
9245 }
9246
9247
9248 void SharedDomain::Attach()
9249 {
9250     CONTRACTL
9251     {
9252         THROWS;
9253         GC_TRIGGERS;
9254         MODE_ANY;
9255         INJECT_FAULT(COMPlusThrowOM(););
9256     }
9257     CONTRACTL_END;
9258
9259     // Create the global SharedDomain and initialize it.
9260     m_pSharedDomain = new (&g_pSharedDomainMemory[0]) SharedDomain();
9261     SystemDomain::GetGlobalLoaderAllocator()->m_pDomain = m_pSharedDomain;
9262     // This cannot fail since g_pSharedDomainMemory is a static array.
9263     CONSISTENCY_CHECK(CheckPointer(m_pSharedDomain));
9264
9265     LOG((LF_CLASSLOADER,
9266          LL_INFO10,
9267          "Created shared domain at %p\n",
9268          m_pSharedDomain));
9269
9270     // We need to initialize the memory pools etc. for the system domain.
9271     m_pSharedDomain->Init(); // Setup the memory heaps
9272
9273     // allocate a Virtual Call Stub Manager for the shared domain
9274     m_pSharedDomain->InitVSD();
9275 }
9276
9277 #ifndef CROSSGEN_COMPILE
9278 void SharedDomain::Detach()
9279 {
9280     if (m_pSharedDomain)
9281     {
9282         m_pSharedDomain->Terminate();
9283         delete m_pSharedDomain;
9284         m_pSharedDomain = NULL;
9285     }
9286 }
9287 #endif // CROSSGEN_COMPILE
9288
9289 #endif // !DACCESS_COMPILE
9290
9291 SharedDomain *SharedDomain::GetDomain()
9292 {
9293     LIMITED_METHOD_DAC_CONTRACT;
9294
9295     return m_pSharedDomain;
9296 }
9297
9298 #ifndef DACCESS_COMPILE
9299
9300 #define INITIAL_ASSEMBLY_MAP_SIZE 17
9301 void SharedDomain::Init()
9302 {
9303     CONTRACTL
9304     {
9305         THROWS;
9306         GC_TRIGGERS;
9307         MODE_ANY;
9308         INJECT_FAULT(COMPlusThrowOM(););
9309     }
9310     CONTRACTL_END;
9311
9312     BaseDomain::Init();
9313
9314 #ifdef FEATURE_LOADER_OPTIMIZATION
9315     m_FileCreateLock.Init(CrstSharedAssemblyCreate, CRST_DEFAULT,TRUE);
9316
9317     LockOwner lock = { &m_DomainCrst, IsOwnerOfCrst };
9318     m_assemblyMap.Init(INITIAL_ASSEMBLY_MAP_SIZE, CompareSharedAssembly, TRUE, &lock);
9319 #endif // FEATURE_LOADER_OPTIMIZATION 
9320
9321     ETW::LoaderLog::DomainLoad(this);
9322 }
9323
9324 #ifndef CROSSGEN_COMPILE
9325 void SharedDomain::Terminate()
9326 {
9327     // make sure we delete the StringLiteralMap before unloading
9328     // the asemblies since the string literal map entries can
9329     // point to metadata string literals.
9330     GetLoaderAllocator()->CleanupStringLiteralMap();
9331
9332 #ifdef FEATURE_LOADER_OPTIMIZATION    
9333     PtrHashMap::PtrIterator i = m_assemblyMap.begin();
9334
9335     while (!i.end())
9336     {
9337         Assembly *pAssembly = (Assembly*) i.GetValue();
9338         delete pAssembly;
9339         ++i;
9340     }
9341
9342     ListLockEntry* pElement;
9343     pElement = m_FileCreateLock.Pop(TRUE);
9344     while (pElement)
9345     {
9346 #ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
9347         _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
9348 #endif
9349         delete(pElement);
9350         pElement = (FileLoadLock*) m_FileCreateLock.Pop(TRUE);
9351     }
9352     m_FileCreateLock.Destroy();
9353 #endif // FEATURE_LOADER_OPTIMIZATION    
9354     BaseDomain::Terminate();
9355 }
9356 #endif // CROSSGEN_COMPILE
9357
9358
9359
9360 #ifdef FEATURE_LOADER_OPTIMIZATION
9361
9362 BOOL SharedDomain::CompareSharedAssembly(UPTR u1, UPTR u2)
9363 {
9364     CONTRACTL
9365     {
9366         THROWS;
9367         GC_TRIGGERS;
9368         MODE_ANY;
9369     }
9370     CONTRACTL_END;
9371
9372     // This is the input to the lookup
9373     SharedAssemblyLocator *pLocator = (SharedAssemblyLocator *) (u1<<1);
9374
9375     // This is the value stored in the table
9376     Assembly *pAssembly = (Assembly *) u2;
9377     if (pLocator->GetType()==SharedAssemblyLocator::DOMAINASSEMBLY)
9378     {
9379         if (!pAssembly->GetManifestFile()->Equals(pLocator->GetDomainAssembly()->GetFile()))
9380             return FALSE;
9381
9382         return pAssembly->CanBeShared(pLocator->GetDomainAssembly());
9383     }
9384     else
9385     if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLY)
9386         return pAssembly->GetManifestFile()->Equals(pLocator->GetPEAssembly());
9387     else
9388     if (pLocator->GetType()==SharedAssemblyLocator::PEASSEMBLYEXACT)
9389         return pAssembly->GetManifestFile() == pLocator->GetPEAssembly();
9390      _ASSERTE(!"Unexpected type of assembly locator");
9391     return FALSE;
9392 }
9393
9394 DWORD SharedAssemblyLocator::Hash()
9395 {
9396     CONTRACTL
9397     {
9398         THROWS;
9399         GC_TRIGGERS;
9400         MODE_ANY;
9401         INJECT_FAULT(COMPlusThrowOM(););
9402     }
9403     CONTRACTL_END;
9404     if (m_type==DOMAINASSEMBLY)
9405         return GetDomainAssembly()->HashIdentity();
9406     if (m_type==PEASSEMBLY||m_type==PEASSEMBLYEXACT)
9407         return GetPEAssembly()->HashIdentity();
9408      _ASSERTE(!"Unexpected type of assembly locator");
9409      return 0;
9410 }
9411
9412 Assembly * SharedDomain::FindShareableAssembly(SharedAssemblyLocator * pLocator)
9413 {
9414     CONTRACTL
9415     {
9416         THROWS;
9417         GC_TRIGGERS;
9418         MODE_ANY;
9419         INJECT_FAULT(COMPlusThrowOM(););
9420     }
9421     CONTRACTL_END;
9422
9423     Assembly * match= (Assembly *) m_assemblyMap.LookupValue(pLocator->Hash(), pLocator);
9424     if (match != (Assembly *) INVALIDENTRY)
9425         return match;
9426     else
9427         return NULL;
9428 }
9429
9430 SIZE_T SharedDomain::GetShareableAssemblyCount()
9431 {
9432     LIMITED_METHOD_CONTRACT;
9433
9434     return m_assemblyMap.GetCount();
9435 }
9436
9437 void SharedDomain::AddShareableAssembly(Assembly * pAssembly)
9438 {
9439     CONTRACTL
9440     {
9441         THROWS;
9442         GC_TRIGGERS;
9443         MODE_ANY;
9444         INJECT_FAULT(COMPlusThrowOM(););
9445     }
9446     CONTRACTL_END;
9447
9448     // We have a lock on the file. There should be no races to add the same assembly.
9449
9450     {
9451         LockHolder holder(this);
9452
9453         EX_TRY
9454         {
9455             pAssembly->SetIsTenured();
9456             m_assemblyMap.InsertValue(pAssembly->HashIdentity(), pAssembly);
9457         }
9458         EX_HOOK
9459         {
9460             // There was an error adding the assembly to the assembly hash (probably an OOM),
9461             // so we need to unset the tenured bit so that correct cleanup can happen.
9462             pAssembly->UnsetIsTenured();
9463         }
9464         EX_END_HOOK
9465     }
9466
9467     LOG((LF_CODESHARING,
9468          LL_INFO100,
9469          "Successfully added shareable assembly \"%s\".\n",
9470          pAssembly->GetManifestFile()->GetSimpleName()));
9471 }
9472
9473 #endif // FEATURE_LOADER_OPTIMIZATION
9474 #endif // !DACCESS_COMPILE
9475
9476 DWORD DomainLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex /*=(DWORD)-1*/)
9477 {
9478     CONTRACTL {
9479         NOTHROW;
9480         GC_NOTRIGGER;
9481         SO_TOLERANT;
9482     } CONTRACTL_END;
9483
9484     {   // SO tolerance exception for debug-only assertion.
9485         CONTRACT_VIOLATION(SOToleranceViolation);
9486         CONSISTENCY_CHECK(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9487     }
9488
9489     if (pMT->IsDynamicStatics())
9490     {
9491         _ASSERTE(!pMT->ContainsGenericVariables());
9492         DWORD dynamicClassID = pMT->GetModuleDynamicEntryID();
9493         if(m_aDynamicEntries <= dynamicClassID)
9494             return FALSE;
9495         return (m_pDynamicClassTable[dynamicClassID].m_dwFlags);
9496     }
9497     else
9498     {
9499         if (iClassIndex == (DWORD)-1)
9500             iClassIndex = pMT->GetClassIndex();
9501         return GetPrecomputedStaticsClassData()[iClassIndex];
9502     }
9503 }
9504
9505 #ifndef DACCESS_COMPILE
9506
9507 void DomainLocalModule::SetClassInitialized(MethodTable* pMT)
9508 {
9509     CONTRACTL
9510     {
9511         THROWS;
9512         GC_TRIGGERS;
9513         MODE_ANY;
9514     }
9515     CONTRACTL_END;
9516
9517     BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9518
9519     _ASSERTE(!IsClassInitialized(pMT));
9520     _ASSERTE(!IsClassInitError(pMT));
9521
9522     SetClassFlags(pMT, ClassInitFlags::INITIALIZED_FLAG);
9523 }
9524
9525 void DomainLocalModule::SetClassInitError(MethodTable* pMT)
9526 {
9527     WRAPPER_NO_CONTRACT;
9528
9529     BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9530
9531     SetClassFlags(pMT, ClassInitFlags::ERROR_FLAG);
9532 }
9533
9534 void DomainLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags)
9535 {
9536     CONTRACTL {
9537         THROWS;
9538         GC_TRIGGERS;
9539         PRECONDITION(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9540         // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9541         PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9542     } CONTRACTL_END;
9543
9544     if (pMT->IsDynamicStatics())
9545     {
9546         _ASSERTE(!pMT->ContainsGenericVariables());
9547         DWORD dwID = pMT->GetModuleDynamicEntryID();
9548         EnsureDynamicClassIndex(dwID);
9549         m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags;
9550     }
9551     else
9552     {
9553         GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags;
9554     }
9555 }
9556
9557 void DomainLocalModule::EnsureDynamicClassIndex(DWORD dwID)
9558 {
9559     CONTRACTL
9560     {
9561         THROWS;
9562         GC_TRIGGERS;
9563         MODE_ANY;
9564         INJECT_FAULT(COMPlusThrowOM(););
9565         // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9566         PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9567     }
9568     CONTRACTL_END;
9569
9570     if (dwID < m_aDynamicEntries)
9571     {
9572         _ASSERTE(m_pDynamicClassTable.Load() != NULL);
9573         return;
9574     }
9575
9576     SIZE_T aDynamicEntries = max(16, m_aDynamicEntries.Load());
9577     while (aDynamicEntries <= dwID)
9578     {
9579         aDynamicEntries *= 2;
9580     }
9581
9582     DynamicClassInfo* pNewDynamicClassTable;
9583     pNewDynamicClassTable = (DynamicClassInfo*)
9584         (void*)GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
9585             S_SIZE_T(sizeof(DynamicClassInfo)) * S_SIZE_T(aDynamicEntries));
9586
9587     memcpy(pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * m_aDynamicEntries);
9588
9589     // Note: Memory allocated on loader heap is zero filled
9590     // memset(pNewDynamicClassTable + m_aDynamicEntries, 0, (aDynamicEntries - m_aDynamicEntries) * sizeof(DynamicClassInfo));
9591
9592     _ASSERTE(m_aDynamicEntries%2 == 0);
9593
9594     // Commit new dynamic table. The lock-free helpers depend on the order.
9595     MemoryBarrier();
9596     m_pDynamicClassTable = pNewDynamicClassTable;
9597     MemoryBarrier();
9598     m_aDynamicEntries = aDynamicEntries;
9599 }
9600
9601 #ifndef CROSSGEN_COMPILE
9602 void    DomainLocalModule::AllocateDynamicClass(MethodTable *pMT)
9603 {
9604     CONTRACTL
9605     {
9606         THROWS;
9607         GC_TRIGGERS;
9608         // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9609         PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
9610     }
9611     CONTRACTL_END;
9612
9613     _ASSERTE(!pMT->ContainsGenericVariables());
9614     _ASSERTE(!pMT->IsSharedByGenericInstantiations());
9615     _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
9616     _ASSERTE(pMT->IsDynamicStatics());
9617
9618     DWORD dynamicEntryIDIndex = pMT->GetModuleDynamicEntryID();
9619
9620     EnsureDynamicClassIndex(dynamicEntryIDIndex);
9621
9622     _ASSERTE(m_aDynamicEntries > dynamicEntryIDIndex);
9623
9624     EEClass *pClass = pMT->GetClass();
9625
9626     DWORD dwStaticBytes = pClass->GetNonGCRegularStaticFieldBytes();
9627     DWORD dwNumHandleStatics = pClass->GetNumHandleRegularStatics();
9628
9629     _ASSERTE(!IsClassAllocated(pMT));
9630     _ASSERTE(!IsClassInitialized(pMT));
9631     _ASSERTE(!IsClassInitError(pMT));
9632
9633     DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry;
9634
9635     // We need this check because maybe a class had a cctor but no statics
9636     if (dwStaticBytes > 0 || dwNumHandleStatics > 0)
9637     {
9638         if (pDynamicStatics == NULL)
9639         {
9640             LoaderHeap * pLoaderAllocator = GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap();
9641
9642             if (pMT->Collectible())
9643             {
9644                 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(sizeof(CollectibleDynamicEntry)));
9645             }
9646             else
9647             {
9648                 SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes;
9649
9650 #ifdef FEATURE_64BIT_ALIGNMENT
9651                 // Allocate memory with extra alignment only if it is really necessary
9652                 if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
9653                 {
9654                     static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0);
9655                     pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE);
9656                 }
9657                 else
9658 #endif
9659                     pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(dynamicEntrySize));
9660             }
9661
9662             // Note: Memory allocated on loader heap is zero filled
9663
9664             m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry = pDynamicStatics;
9665         }
9666
9667         if (pMT->Collectible() && (dwStaticBytes != 0))
9668         {
9669             GCX_COOP();
9670             OBJECTREF nongcStaticsArray = NULL;
9671             GCPROTECT_BEGIN(nongcStaticsArray);
9672 #ifdef FEATURE_64BIT_ALIGNMENT
9673             // Allocate memory with extra alignment only if it is really necessary
9674             if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
9675                 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8)-1)) / (sizeof(CLR_I8)));
9676             else
9677 #endif
9678                 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes);
9679             ((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray);
9680             GCPROTECT_END();
9681         }
9682         if (dwNumHandleStatics > 0)
9683         {
9684             if (!pMT->Collectible())
9685             {
9686                 GetAppDomain()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
9687                                                               &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics);
9688             }
9689             else
9690             {
9691                 GCX_COOP();
9692                 OBJECTREF gcStaticsArray = NULL;
9693                 GCPROTECT_BEGIN(gcStaticsArray);
9694                 gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass);
9695                 ((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(gcStaticsArray);
9696                 GCPROTECT_END();
9697             }
9698         }
9699     }
9700 }
9701
9702
9703 void DomainLocalModule::PopulateClass(MethodTable *pMT)
9704 {
9705     CONTRACTL
9706     {
9707         THROWS;
9708         GC_TRIGGERS;
9709     }
9710     CONTRACTL_END;
9711
9712     _ASSERTE(!pMT->ContainsGenericVariables());
9713
9714     // <todo> the only work actually done here for non-dynamics is the freezing related work.
9715     // See if we can eliminate this and make this a dynamic-only path </todo>
9716     DWORD iClassIndex = pMT->GetClassIndex();
9717
9718     if (!IsClassAllocated(pMT, iClassIndex))
9719     {
9720         BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
9721
9722         if (!IsClassAllocated(pMT, iClassIndex))
9723         {
9724             // Allocate dynamic space if necessary
9725             if (pMT->IsDynamicStatics())
9726                 AllocateDynamicClass(pMT);
9727
9728             // determine flags to set on the statics block
9729             DWORD dwFlags = ClassInitFlags::ALLOCATECLASS_FLAG;
9730
9731             if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics())
9732             {
9733                 _ASSERTE(!IsClassInitialized(pMT));
9734                 _ASSERTE(!IsClassInitError(pMT));
9735                 dwFlags |= ClassInitFlags::INITIALIZED_FLAG;
9736             }
9737
9738             if (pMT->Collectible())
9739             {
9740                 dwFlags |= ClassInitFlags::COLLECTIBLE_FLAG;
9741             }
9742
9743             // Set all flags at the same time to avoid races
9744             SetClassFlags(pMT, dwFlags);
9745         }
9746     }
9747
9748     return;
9749 }
9750 #endif // CROSSGEN_COMPILE
9751
9752 void DomainLocalBlock::EnsureModuleIndex(ModuleIndex index)
9753 {
9754     CONTRACTL
9755     {
9756         THROWS;
9757         GC_TRIGGERS;
9758         MODE_ANY;
9759         INJECT_FAULT(COMPlusThrowOM(););
9760         // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
9761         PRECONDITION(m_pDomain->OwnDomainLocalBlockLock());
9762     }
9763     CONTRACTL_END;
9764
9765     if (m_aModuleIndices > index.m_dwIndex)
9766     {
9767         _ASSERTE(m_pModuleSlots != NULL);
9768         return;
9769     }
9770
9771     SIZE_T aModuleIndices = max(16, m_aModuleIndices);
9772     while (aModuleIndices <= index.m_dwIndex)
9773     {
9774         aModuleIndices *= 2;
9775     }
9776
9777     PTR_DomainLocalModule* pNewModuleSlots = (PTR_DomainLocalModule*) (void*)m_pDomain->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(PTR_DomainLocalModule)) * S_SIZE_T(aModuleIndices));
9778
9779     memcpy(pNewModuleSlots, m_pModuleSlots, sizeof(SIZE_T)*m_aModuleIndices);
9780
9781     // Note: Memory allocated on loader heap is zero filled
9782     // memset(pNewModuleSlots + m_aModuleIndices, 0 , (aModuleIndices - m_aModuleIndices)*sizeof(PTR_DomainLocalModule) );
9783
9784     // Commit new table. The lock-free helpers depend on the order.
9785     MemoryBarrier();
9786     m_pModuleSlots = pNewModuleSlots;
9787     MemoryBarrier();
9788     m_aModuleIndices = aModuleIndices;
9789
9790 }
9791
9792 void DomainLocalBlock::SetModuleSlot(ModuleIndex index, PTR_DomainLocalModule pLocalModule)
9793 {
9794     // Need to synchronize with table growth in this domain
9795     BaseDomain::DomainLocalBlockLockHolder lh(m_pDomain);
9796
9797     EnsureModuleIndex(index);
9798
9799     _ASSERTE(index.m_dwIndex < m_aModuleIndices);
9800
9801     // We would like this assert here, unfortunately, loading a module in this appdomain can fail
9802     // after here  and we will keep the module around and reuse the slot when we retry (if
9803     // the failure happened due to a transient error, such as OOM). In that case the slot wont
9804     // be null.
9805     //_ASSERTE(m_pModuleSlots[index.m_dwIndex] == 0);
9806
9807     m_pModuleSlots[index.m_dwIndex] = pLocalModule;
9808 }
9809
9810 #ifndef CROSSGEN_COMPILE
9811
9812 DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef)
9813 {
9814     CONTRACTL
9815     {
9816         MODE_ANY;
9817         GC_TRIGGERS;
9818         THROWS;
9819         INJECT_FAULT(COMPlusThrowOM(););
9820     }
9821     CONTRACTL_END;
9822
9823     OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
9824
9825
9826     DomainAssembly* pResolvedAssembly = NULL;
9827     _ASSERTE(strcmp(szName, g_AppDomainClassName));
9828
9829     GCX_COOP();
9830
9831     struct _gc {
9832         OBJECTREF AppDomainRef;
9833         OBJECTREF AssemblyRef;
9834         STRINGREF str;
9835     } gc;
9836     ZeroMemory(&gc, sizeof(gc));
9837
9838     GCPROTECT_BEGIN(gc);
9839     if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9840     {
9841         if (pAssembly != NULL)
9842             gc.AssemblyRef = pAssembly->GetExposedAssemblyObject();
9843
9844         MethodDescCallSite onTypeResolve(METHOD__APP_DOMAIN__ON_TYPE_RESOLVE, &gc.AppDomainRef);
9845
9846         gc.str = StringObject::NewString(szName);
9847         ARG_SLOT args[3] =
9848         {
9849             ObjToArgSlot(gc.AppDomainRef),
9850             ObjToArgSlot(gc.AssemblyRef),
9851             ObjToArgSlot(gc.str)
9852         };
9853         ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onTypeResolve.Call_RetOBJECTREF(args);
9854
9855         if (ResultingAssemblyRef != NULL)
9856         {
9857             pResolvedAssembly = ResultingAssemblyRef->GetDomainAssembly();
9858
9859             if (pResultingAssemblyRef)
9860                 *pResultingAssemblyRef = ResultingAssemblyRef;
9861             else
9862             {
9863                 if (pResolvedAssembly->IsCollectible())
9864                 {
9865                     COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
9866                 }
9867             }
9868         }
9869     }
9870     GCPROTECT_END();
9871
9872     return pResolvedAssembly;
9873 }
9874
9875
9876 Assembly* AppDomain::RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName)
9877 {
9878     CONTRACT(Assembly*)
9879     {
9880         THROWS;
9881         GC_TRIGGERS;
9882         MODE_ANY;
9883         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9884         INJECT_FAULT(COMPlusThrowOM(););
9885     }
9886     CONTRACT_END;
9887
9888     Assembly* pResolvedAssembly = NULL;
9889
9890     GCX_COOP();
9891
9892     struct _gc {
9893         OBJECTREF AppDomainRef;
9894         OBJECTREF AssemblyRef;
9895         STRINGREF str;
9896     } gc;
9897     ZeroMemory(&gc, sizeof(gc));
9898
9899     GCPROTECT_BEGIN(gc);
9900     if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9901     {
9902         if (pAssembly != NULL)
9903             gc.AssemblyRef=pAssembly->GetExposedAssemblyObject();
9904
9905         MethodDescCallSite onResourceResolve(METHOD__APP_DOMAIN__ON_RESOURCE_RESOLVE, &gc.AppDomainRef);
9906         gc.str = StringObject::NewString(szName);
9907         ARG_SLOT args[3] =
9908         {
9909             ObjToArgSlot(gc.AppDomainRef),
9910             ObjToArgSlot(gc.AssemblyRef),
9911             ObjToArgSlot(gc.str)
9912         };
9913         ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onResourceResolve.Call_RetOBJECTREF(args);
9914         if (ResultingAssemblyRef != NULL)
9915         {
9916             pResolvedAssembly = ResultingAssemblyRef->GetAssembly();
9917             if (pResolvedAssembly->IsCollectible())
9918             {
9919                 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
9920             }
9921         }
9922     }
9923     GCPROTECT_END();
9924
9925     RETURN pResolvedAssembly;
9926 }
9927
9928
9929 Assembly * 
9930 AppDomain::RaiseAssemblyResolveEvent(
9931     AssemblySpec * pSpec, 
9932     BOOL           fIntrospection, 
9933     BOOL           fPreBind)
9934 {
9935     CONTRACT(Assembly*)
9936     {
9937         THROWS;
9938         GC_TRIGGERS;
9939         MODE_ANY;
9940         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
9941         INJECT_FAULT(COMPlusThrowOM(););
9942     }
9943     CONTRACT_END;
9944
9945     BinderMethodID methodId;
9946     StackSString ssName;
9947     pSpec->GetFileOrDisplayName(0, ssName);
9948     
9949     if (!fPreBind) 
9950     {
9951         methodId = METHOD__APP_DOMAIN__ON_ASSEMBLY_RESOLVE;  // post-bind execution event (the classic V1.0 event)
9952     }
9953     else
9954     {
9955         RETURN NULL;
9956     }
9957         
9958
9959     // Elevate threads allowed loading level.  This allows the host to load an assembly even in a restricted
9960     // condition.  Note, however, that this exposes us to possible recursion failures, if the host tries to
9961     // load the assemblies currently being loaded.  (Such cases would then throw an exception.)
9962
9963     OVERRIDE_LOAD_LEVEL_LIMIT(FILE_ACTIVE);
9964     OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
9965
9966     GCX_COOP();
9967
9968     Assembly* pAssembly = NULL;
9969
9970     struct _gc {
9971         OBJECTREF AppDomainRef;
9972         OBJECTREF AssemblyRef;
9973         STRINGREF str;
9974     } gc;
9975     ZeroMemory(&gc, sizeof(gc));
9976
9977     GCPROTECT_BEGIN(gc);
9978     if ((gc.AppDomainRef = GetRawExposedObject()) != NULL)
9979     {
9980         if (pSpec->GetParentAssembly() != NULL)
9981         {
9982             {
9983                 gc.AssemblyRef=pSpec->GetParentAssembly()->GetExposedAssemblyObject();
9984             }
9985         }
9986         MethodDescCallSite onAssemblyResolve(methodId, &gc.AppDomainRef);
9987
9988         gc.str = StringObject::NewString(ssName);
9989         ARG_SLOT args[3] = {
9990             ObjToArgSlot(gc.AppDomainRef),
9991             ObjToArgSlot(gc.AssemblyRef),
9992             ObjToArgSlot(gc.str)
9993         };
9994             
9995         ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onAssemblyResolve.Call_RetOBJECTREF(args);
9996             
9997         if (ResultingAssemblyRef != NULL)
9998         {
9999             pAssembly = ResultingAssemblyRef->GetAssembly();
10000             if (pAssembly->IsCollectible())
10001             {
10002                 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
10003             }
10004         }
10005     }
10006     GCPROTECT_END();
10007
10008     if (pAssembly != NULL)
10009     {
10010         if  ((!(pAssembly->IsIntrospectionOnly())) != (!fIntrospection))
10011         {
10012             // Cannot return an introspection assembly from an execution callback or vice-versa
10013             COMPlusThrow(kFileLoadException, pAssembly->IsIntrospectionOnly() ? IDS_CLASSLOAD_ASSEMBLY_RESOLVE_RETURNED_INTROSPECTION : IDS_CLASSLOAD_ASSEMBLY_RESOLVE_RETURNED_EXECUTION);
10014         }
10015
10016         // Check that the public key token matches the one specified in the spec
10017         // MatchPublicKeys throws as appropriate
10018         pSpec->MatchPublicKeys(pAssembly);
10019     }
10020
10021     RETURN pAssembly;
10022 } // AppDomain::RaiseAssemblyResolveEvent
10023
10024
10025 //---------------------------------------------------------------------------------------
10026 //
10027 // Determine the type of AppDomainManager to use for the default AppDomain
10028 //
10029 // Notes:
10030 //   v2.0 of the CLR used environment variables APPDOMAIN_MANAGER_ASM and APPDOMAIN_MANAGER_TYPE to set the
10031 //   domain manager. For compatibility these are still supported, along with appDomainManagerAsm and
10032 //   appDomainManagerType config file switches. If the config switches are supplied, the entry point must be
10033 //   fully trusted.  
10034 //
10035
10036 void AppDomain::InitializeDefaultDomainManager()
10037 {
10038     CONTRACTL
10039     {
10040         MODE_COOPERATIVE;
10041         GC_TRIGGERS;
10042         THROWS;
10043         INJECT_FAULT(COMPlusThrowOM(););
10044         PRECONDITION(GetId().m_dwId == DefaultADID);
10045     }
10046     CONTRACTL_END;
10047
10048     OBJECTREF orThis = GetExposedObject();
10049     GCPROTECT_BEGIN(orThis);
10050
10051     MethodDescCallSite initCompatFlags(METHOD__APP_DOMAIN__INITIALIZE_COMPATIBILITY_FLAGS);
10052     ARG_SLOT args[] =
10053     {
10054         ObjToArgSlot(orThis)
10055     };
10056
10057     initCompatFlags.Call(args);
10058
10059     GCPROTECT_END();
10060 }
10061
10062 CLREvent * AppDomain::g_pUnloadStartEvent;
10063
10064 void AppDomain::CreateADUnloadWorker()
10065 {
10066     STANDARD_VM_CONTRACT;
10067
10068     // Do not create adUnload thread if there is only default domain
10069     if(IsSingleAppDomain())
10070         return;
10071
10072 Retry:
10073     BOOL fCreator = FALSE;
10074     if (FastInterlockCompareExchange((LONG *)&g_fADUnloadWorkerOK,-2,-1)==-1)  //we're first
10075     {
10076 #ifdef _TARGET_X86_  // use the smallest possible stack on X86 
10077         DWORD stackSize = 128 * 1024;
10078 #else
10079         DWORD stackSize = 512 * 1024; // leave X64 unchanged since we have plenty of VM
10080 #endif
10081         Thread *pThread = SetupUnstartedThread();
10082         if (pThread->CreateNewThread(stackSize, ADUnloadThreadStart, pThread))
10083         {
10084             fCreator = TRUE;
10085             DWORD dwRet;
10086             dwRet = pThread->StartThread();
10087
10088             // When running under a user mode native debugger there is a race
10089             // between the moment we've created the thread (in CreateNewThread) and 
10090             // the moment we resume it (in StartThread); the debugger may receive 
10091             // the "ct" (create thread) notification, and it will attempt to 
10092             // suspend/resume all threads in the process.  Now imagine the debugger
10093             // resumes this thread first, and only later does it try to resume the
10094             // newly created thread (the ADU worker thread).  In these conditions our
10095             // call to ResumeThread may come before the debugger's call to ResumeThread
10096             // actually causing dwRet to equal 2.
10097             // We cannot use IsDebuggerPresent() in the condition below because the 
10098             // debugger may have been detached between the time it got the notification
10099             // and the moment we execute the test below.
10100             _ASSERTE(dwRet == 1 || dwRet == 2);
10101         }
10102         else
10103         {
10104             pThread->DecExternalCount(FALSE);
10105             FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK, -1);
10106             ThrowOutOfMemory();
10107         }
10108     }
10109
10110     YIELD_WHILE (g_fADUnloadWorkerOK == -2);
10111
10112     if (g_fADUnloadWorkerOK == -1) {
10113         if (fCreator)
10114         {
10115             ThrowOutOfMemory();
10116         }
10117         else
10118         {
10119             goto Retry;
10120         }
10121     }
10122 }
10123
10124 /*static*/ void AppDomain::ADUnloadWorkerHelper(AppDomain *pDomain)
10125 {
10126     STATIC_CONTRACT_NOTHROW;
10127     STATIC_CONTRACT_GC_TRIGGERS;
10128     STATIC_CONTRACT_MODE_COOPERATIVE;
10129     ADUnloadSink* pADUnloadSink=pDomain->GetADUnloadSinkForUnload();
10130     HRESULT hr=S_OK;
10131
10132     EX_TRY
10133     {
10134         pDomain->Unload(FALSE);
10135     }
10136     EX_CATCH_HRESULT(hr);
10137
10138     if(pADUnloadSink)
10139     {
10140         SystemDomain::LockHolder lh;
10141         pADUnloadSink->ReportUnloadResult(hr,NULL);
10142         pADUnloadSink->Release();
10143     }
10144 }
10145
10146 void AppDomain::DoADUnloadWork()
10147 {
10148     CONTRACTL
10149     {
10150         THROWS;
10151         GC_TRIGGERS;
10152         MODE_COOPERATIVE;
10153         INJECT_FAULT(COMPlusThrowOM(););
10154     }
10155     CONTRACTL_END;
10156
10157     DWORD i = 1;
10158     while (TRUE) {
10159
10160         AppDomain *pDomainToUnload = NULL;
10161
10162         {
10163             // Take the lock so that no domain can be added or removed from the system domain
10164             SystemDomain::LockHolder lh;
10165
10166             DWORD numDomain = SystemDomain::GetCurrentAppDomainMaxIndex();
10167             for (; i <= numDomain; i ++) {
10168                 AppDomain * pDomain = SystemDomain::TestGetAppDomainAtIndex(ADIndex(i));
10169                 //
10170                 // @todo: We used to also select a domain if pDomain->IsUnload() returned true. But that causes
10171                 // problems when we've failed to completely unload the AD in the past. If we've reached the CLEARED
10172                 // stage, for instance, then there will be no default context and AppDomain::Exit() will simply crash.
10173                 //
10174                 if (pDomain && pDomain->IsUnloadRequested())
10175                 {
10176                     pDomainToUnload = pDomain;
10177                     i ++;
10178                     break;
10179                 }
10180             }
10181         }
10182
10183         if (!pDomainToUnload) {
10184             break;
10185         }
10186
10187         // We are the only thread that can unload domains so no one else can delete the appdomain
10188         ADUnloadWorkerHelper(pDomainToUnload);            
10189     }
10190 }
10191
10192 static void DoADUnloadWorkHelper()
10193 {
10194     STATIC_CONTRACT_NOTHROW;
10195     STATIC_CONTRACT_GC_TRIGGERS;
10196     STATIC_CONTRACT_MODE_COOPERATIVE;
10197
10198     EX_TRY {
10199         AppDomain::DoADUnloadWork();
10200     }
10201     EX_CATCH
10202     {
10203     }
10204     EX_END_CATCH(SwallowAllExceptions);
10205 }
10206
10207 ULONGLONG g_ObjFinalizeStartTime = 0;
10208 Volatile<BOOL> g_FinalizerIsRunning = FALSE;
10209 Volatile<ULONG> g_FinalizerLoopCount = 0;
10210
10211 ULONGLONG GetObjFinalizeStartTime()
10212 {
10213     LIMITED_METHOD_CONTRACT;
10214     return g_ObjFinalizeStartTime;
10215 }
10216
10217 void FinalizerThreadAbortOnTimeout()
10218 {
10219     STATIC_CONTRACT_NOTHROW;
10220     STATIC_CONTRACT_MODE_COOPERATIVE;
10221     STATIC_CONTRACT_GC_TRIGGERS;
10222
10223     {
10224         // If finalizer thread is blocked because scheduler is running another task,
10225         // or it is waiting for another thread, we first see if we get finalizer thread
10226         // running again.
10227         Thread::ThreadAbortWatchDog();
10228     }
10229
10230     EX_TRY
10231     {
10232         Thread *pFinalizerThread = FinalizerThread::GetFinalizerThread();
10233         EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(OPR_FinalizerRun, pFinalizerThread);
10234         switch (action)
10235         {
10236         case eAbortThread:
10237             GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10238             pFinalizerThread->UserAbort(Thread::TAR_Thread,
10239                                         EEPolicy::TA_Safe,
10240                                         INFINITE,
10241                                         Thread::UAC_FinalizerTimeout);
10242             break;
10243         case eRudeAbortThread:
10244             GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10245             pFinalizerThread->UserAbort(Thread::TAR_Thread,
10246                                         EEPolicy::TA_Rude,
10247                                         INFINITE,
10248                                         Thread::UAC_FinalizerTimeout);
10249             break;
10250         case eUnloadAppDomain:
10251             {
10252                 AppDomain *pDomain = pFinalizerThread->GetDomain();
10253                 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10254                                             EEPolicy::TA_Safe,
10255                                             INFINITE,
10256                                             Thread::UAC_FinalizerTimeout);
10257                 if (!pDomain->IsDefaultDomain())
10258                 {
10259                     GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10260                     pDomain->EnableADUnloadWorker(EEPolicy::ADU_Safe);
10261                 }
10262             }
10263             break;
10264         case eRudeUnloadAppDomain:
10265             {
10266                 AppDomain *pDomain = pFinalizerThread->GetDomain();
10267                 pFinalizerThread->UserAbort(Thread::TAR_Thread,
10268                                             EEPolicy::TA_Rude,
10269                                             INFINITE,
10270                                             Thread::UAC_FinalizerTimeout);
10271                 if (!pDomain->IsDefaultDomain())
10272                 {
10273                     GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10274                     pDomain->EnableADUnloadWorker(EEPolicy::ADU_Rude);
10275                 }
10276             }
10277             break;
10278         case eExitProcess:
10279         case eFastExitProcess:
10280         case eRudeExitProcess:
10281         case eDisableRuntime:
10282             GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
10283             EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
10284             _ASSERTE (!"Should not get here");
10285             break;
10286         default:
10287             break;
10288         }
10289     }
10290     EX_CATCH
10291     {
10292     }
10293     EX_END_CATCH(SwallowAllExceptions);
10294 }
10295
10296 enum WorkType
10297 {
10298     WT_UnloadDomain = 0x1,
10299     WT_ThreadAbort = 0x2,
10300     WT_FinalizerThread = 0x4,
10301     WT_ClearCollectedDomains=0x8
10302 };
10303
10304 static Volatile<DWORD> s_WorkType = 0;
10305
10306
10307 DWORD WINAPI AppDomain::ADUnloadThreadStart(void *args)
10308 {
10309     CONTRACTL
10310     {
10311         NOTHROW;
10312         DISABLED(GC_TRIGGERS);
10313
10314         // This function will always be at the very bottom of the stack. The only
10315         // user code it calls is the AppDomainUnload notifications which we will
10316         // not be hardenning for Whidbey.
10317         //
10318         ENTRY_POINT;
10319     }
10320     CONTRACTL_END;
10321
10322     BEGIN_ENTRYPOINT_NOTHROW;
10323
10324     ClrFlsSetThreadType (ThreadType_ADUnloadHelper);
10325
10326     Thread *pThread = (Thread*)args;
10327     bool fOK = (pThread->HasStarted() != 0);
10328
10329     {
10330         GCX_MAYBE_PREEMP(fOK);
10331
10332         _ASSERTE (g_fADUnloadWorkerOK == -2);
10333
10334         FastInterlockExchange((LONG *)&g_fADUnloadWorkerOK,fOK?1:-1);
10335
10336         if (!fOK)
10337         {
10338             DestroyThread(pThread);
10339             goto Exit;
10340         }
10341
10342         pThread->SetBackground(TRUE);
10343
10344         pThread->SetThreadStateNC(Thread::TSNC_ADUnloadHelper);
10345
10346         while (TRUE) {
10347             DWORD TAtimeout = INFINITE;
10348             ULONGLONG endTime = Thread::GetNextSelfAbortEndTime();
10349             ULONGLONG curTime = CLRGetTickCount64();
10350             if (endTime <= curTime) {
10351                 TAtimeout = 5;
10352             }
10353             else
10354             {
10355                 ULONGLONG diff = endTime - curTime;
10356                 if (diff < MAXULONG)
10357                 {
10358                     TAtimeout = (DWORD)diff;
10359                 }
10360             }
10361             ULONGLONG finalizeStartTime = GetObjFinalizeStartTime();
10362             DWORD finalizeTimeout = INFINITE;
10363             DWORD finalizeTimeoutSetting = GetEEPolicy()->GetTimeout(OPR_FinalizerRun);
10364             if (finalizeTimeoutSetting != INFINITE && g_FinalizerIsRunning)
10365             {
10366                 if (finalizeStartTime == 0)
10367                 {
10368                     finalizeTimeout = finalizeTimeoutSetting;
10369                 }
10370                 else
10371                 {
10372                     endTime = finalizeStartTime + finalizeTimeoutSetting;
10373                     if (endTime <= curTime) {
10374                         finalizeTimeout = 0;
10375                     }
10376                     else
10377                     {
10378                         ULONGLONG diff = endTime - curTime;
10379                         if (diff < MAXULONG)
10380                         {
10381                             finalizeTimeout = (DWORD)diff;
10382                         }
10383                     }
10384                 }
10385             }
10386
10387             if (AppDomain::HasWorkForFinalizerThread())
10388             {
10389                 if (finalizeTimeout > finalizeTimeoutSetting)
10390                 {
10391                     finalizeTimeout = finalizeTimeoutSetting;
10392                 }
10393             }
10394
10395             DWORD timeout = INFINITE;
10396             if (finalizeTimeout <= TAtimeout)
10397             {
10398                 timeout = finalizeTimeout;
10399             }
10400             else
10401             {
10402                 timeout = TAtimeout;
10403             }
10404
10405             if (timeout != 0)
10406             {
10407                 LOG((LF_APPDOMAIN, LL_INFO10, "Waiting to start unload\n"));
10408                 g_pUnloadStartEvent->Wait(timeout,FALSE);
10409             }
10410
10411             if (finalizeTimeout != INFINITE || (s_WorkType & WT_FinalizerThread) != 0)
10412             {
10413                 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for Finalizer thread\n");
10414                 FastInterlockAnd(&s_WorkType, ~WT_FinalizerThread);
10415                 // only watch finalizer thread is finalizer method or unloadevent is being processed
10416                 if (GetObjFinalizeStartTime() == finalizeStartTime && finalizeStartTime != 0 && g_FinalizerIsRunning)
10417                 {
10418                     if (CLRGetTickCount64() >= finalizeStartTime+finalizeTimeoutSetting)
10419                     {
10420                         GCX_COOP();
10421                         FinalizerThreadAbortOnTimeout();
10422                     }
10423                 }
10424                 if (s_fProcessUnloadDomainEvent && g_FinalizerIsRunning)
10425                 {
10426                     GCX_COOP();
10427                     FinalizerThreadAbortOnTimeout();
10428                 }
10429             }
10430
10431             if (TAtimeout != INFINITE || (s_WorkType & WT_ThreadAbort) != 0)
10432             {
10433                 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for thread abort\n");
10434                 FastInterlockAnd(&s_WorkType, ~WT_ThreadAbort);
10435                 GCX_COOP();
10436                 Thread::ThreadAbortWatchDog();
10437             }
10438
10439             if ((s_WorkType & WT_UnloadDomain) != 0 && !AppDomain::HasWorkForFinalizerThread())
10440             {
10441                 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD unload\n");
10442                 FastInterlockAnd(&s_WorkType, ~WT_UnloadDomain);
10443                 GCX_COOP();
10444                 DoADUnloadWorkHelper();
10445             }
10446
10447             if ((s_WorkType & WT_ClearCollectedDomains) != 0)
10448             {
10449                 STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "ADUnloadThreadStart work for AD cleanup\n");
10450                 FastInterlockAnd(&s_WorkType, ~WT_ClearCollectedDomains);
10451                 GCX_COOP();
10452                 SystemDomain::System()->ClearCollectedDomains();
10453             }
10454
10455         }
10456 Exit:;
10457     }
10458
10459     END_ENTRYPOINT_NOTHROW;
10460
10461     return 0;
10462 }
10463
10464 void AppDomain::EnableADUnloadWorker()
10465 {
10466     CONTRACTL
10467     {
10468         NOTHROW;
10469         GC_NOTRIGGER;
10470         SO_TOLERANT; // Called during a SO
10471     }
10472     CONTRACTL_END;
10473
10474     EEPolicy::AppDomainUnloadTypes type = EEPolicy::ADU_Safe;
10475
10476 #ifdef _DEBUG
10477     DWORD hostTestADUnload = g_pConfig->GetHostTestADUnload();
10478     if (hostTestADUnload == 2) {
10479         type = EEPolicy::ADU_Rude;
10480     }
10481 #endif // _DEBUG
10482
10483     EnableADUnloadWorker(type);
10484 }
10485
10486 void AppDomain::EnableADUnloadWorker(EEPolicy::AppDomainUnloadTypes type, BOOL fHasStack)
10487 {
10488     CONTRACTL
10489     {
10490         NOTHROW;
10491         GC_NOTRIGGER;
10492         SO_TOLERANT; // Called during a SO
10493     }
10494     CONTRACTL_END;
10495
10496     FastInterlockOr (&s_WorkType, WT_UnloadDomain);
10497
10498     LONG stage = m_Stage;
10499     static_assert_no_msg(sizeof(m_Stage) == sizeof(int));
10500
10501     _ASSERTE(!IsDefaultDomain());
10502
10503     // Mark unload requested.
10504     if (type == EEPolicy::ADU_Rude) {
10505         SetRudeUnload();
10506     }
10507     while (stage < STAGE_UNLOAD_REQUESTED) {
10508         stage = FastInterlockCompareExchange((LONG*)&m_Stage,STAGE_UNLOAD_REQUESTED,stage);
10509     }
10510
10511     if (!fHasStack)
10512     {
10513         // Can not call Set due to limited stack.
10514         return;
10515     }
10516     LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker\n"));
10517     g_pUnloadStartEvent->Set();
10518 }
10519
10520 void AppDomain::EnableADUnloadWorkerForThreadAbort()
10521 {
10522     LIMITED_METHOD_CONTRACT;
10523     STRESS_LOG0(LF_ALWAYS, LL_ALWAYS, "Enabling unload worker for thread abort\n");
10524     LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for thread abort\n"));
10525     FastInterlockOr (&s_WorkType, WT_ThreadAbort);
10526     g_pUnloadStartEvent->Set();
10527 }
10528
10529
10530 void AppDomain::EnableADUnloadWorkerForFinalizer()
10531 {
10532     LIMITED_METHOD_CONTRACT;
10533     if (GetEEPolicy()->GetTimeout(OPR_FinalizerRun) != INFINITE)
10534     {
10535         LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for Finalizer Thread\n"));
10536         FastInterlockOr (&s_WorkType, WT_FinalizerThread);
10537         g_pUnloadStartEvent->Set();
10538     }
10539 }
10540
10541 void AppDomain::EnableADUnloadWorkerForCollectedADCleanup()
10542 {
10543     LIMITED_METHOD_CONTRACT;
10544     LOG((LF_APPDOMAIN, LL_INFO10, "Enabling unload worker for collected domains\n"));
10545     FastInterlockOr (&s_WorkType, WT_ClearCollectedDomains);
10546     g_pUnloadStartEvent->Set();
10547 }
10548
10549
10550 void SystemDomain::ClearCollectedDomains()
10551 {
10552     CONTRACTL
10553     {
10554         GC_TRIGGERS;
10555         NOTHROW;
10556         MODE_COOPERATIVE;
10557     }
10558     CONTRACTL_END;
10559         
10560     AppDomain* pDomainsToClear=NULL;
10561     {
10562         CrstHolder lh(&m_DelayedUnloadCrst); 
10563         for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
10564         {
10565             if ((*ppDomain)->m_Stage==AppDomain::STAGE_COLLECTED)
10566             {
10567                 AppDomain* pAppDomain=*ppDomain;
10568                 *ppDomain=(*ppDomain)->m_pNextInDelayedUnloadList;
10569                 pAppDomain->m_pNextInDelayedUnloadList=pDomainsToClear;
10570                 pDomainsToClear=pAppDomain;
10571             }
10572             else
10573                 ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
10574         }
10575     }
10576         
10577     for (AppDomain* pDomain=pDomainsToClear;pDomain!=NULL;)
10578     {
10579         AppDomain* pNext=pDomain->m_pNextInDelayedUnloadList;
10580         pDomain->Close(); //NOTHROW!
10581         pDomain->Release();
10582         pDomain=pNext;
10583     }
10584 }
10585  
10586 void SystemDomain::ProcessClearingDomains()
10587 {
10588     CONTRACTL
10589     {
10590         NOTHROW;
10591         GC_NOTRIGGER;
10592         MODE_ANY;           
10593     }
10594     CONTRACTL_END;
10595     CrstHolder lh(&m_DelayedUnloadCrst); 
10596
10597     for (AppDomain** ppDomain=&m_pDelayedUnloadList;(*ppDomain)!=NULL; )
10598     {
10599         if ((*ppDomain)->m_Stage==AppDomain::STAGE_HANDLETABLE_NOACCESS)
10600         {
10601             AppDomain* pAppDomain=*ppDomain;
10602             pAppDomain->SetStage(AppDomain::STAGE_CLEARED);
10603         }
10604         ppDomain=&((*ppDomain)->m_pNextInDelayedUnloadList);
10605     }
10606         
10607     if (!m_UnloadIsAsync)
10608     {
10609         // For synchronous mode, we are now done with the list.
10610         m_pDelayedUnloadList = NULL;    
10611     }
10612 }
10613
10614 void SystemDomain::ProcessDelayedUnloadDomains()
10615 {
10616     CONTRACTL
10617     {
10618         NOTHROW;
10619         GC_TRIGGERS;
10620         MODE_COOPERATIVE;
10621     }
10622     CONTRACTL_END;    
10623
10624     int iGCRefPoint=GCHeapUtilities::GetGCHeap()->CollectionCount(GCHeapUtilities::GetGCHeap()->GetMaxGeneration());
10625     if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCInProgress())
10626         iGCRefPoint--;
10627
10628     BOOL bAppDomainToCleanup = FALSE;
10629     LoaderAllocator * pAllocatorsToDelete = NULL;
10630
10631     {
10632         CrstHolder lh(&m_DelayedUnloadCrst); 
10633
10634         for (AppDomain* pDomain=m_pDelayedUnloadList; pDomain!=NULL; pDomain=pDomain->m_pNextInDelayedUnloadList)
10635         {
10636             if (pDomain->m_Stage==AppDomain::STAGE_CLEARED)
10637             {
10638                 // Compare with 0 to handle overflows gracefully
10639                 if (0 < iGCRefPoint - pDomain->GetGCRefPoint())
10640                 {
10641                     bAppDomainToCleanup=TRUE;
10642                     pDomain->SetStage(AppDomain::STAGE_COLLECTED);
10643                 }
10644             }
10645         }
10646
10647         LoaderAllocator ** ppAllocator=&m_pDelayedUnloadListOfLoaderAllocators;
10648         while (*ppAllocator!= NULL)
10649         {
10650             LoaderAllocator * pAllocator = *ppAllocator;
10651             if (0 < iGCRefPoint - pAllocator->GetGCRefPoint())
10652             {
10653                 *ppAllocator = pAllocator->m_pLoaderAllocatorDestroyNext;
10654
10655                 pAllocator->m_pLoaderAllocatorDestroyNext = pAllocatorsToDelete;
10656                 pAllocatorsToDelete = pAllocator;
10657             }
10658             else
10659             {
10660                 ppAllocator = &pAllocator->m_pLoaderAllocatorDestroyNext;
10661             }
10662         }
10663     }
10664
10665     if (bAppDomainToCleanup)
10666         AppDomain::EnableADUnloadWorkerForCollectedADCleanup();
10667
10668     // Delete collected loader allocators on the finalizer thread. We cannot offload it to appdomain unload thread because of 
10669     // there is not guaranteed to be one, and it is not that expensive operation anyway.
10670     while (pAllocatorsToDelete != NULL)
10671     {
10672         LoaderAllocator * pAllocator = pAllocatorsToDelete;
10673         pAllocatorsToDelete = pAllocator->m_pLoaderAllocatorDestroyNext;
10674         delete pAllocator;
10675     }
10676 }
10677
10678 #endif // CROSSGEN_COMPILE
10679
10680 AppDomainFromIDHolder::AppDomainFromIDHolder(ADID adId, BOOL bUnsafePoint, SyncType synctype)
10681 {
10682     WRAPPER_NO_CONTRACT;
10683     ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
10684 #ifdef _DEBUG
10685     m_bAcquired=false;   
10686     m_bChecked=false;
10687     m_type=synctype;
10688     
10689 #endif
10690     Assign(adId, bUnsafePoint);
10691 }
10692
10693 AppDomainFromIDHolder::AppDomainFromIDHolder(SyncType synctype)
10694 {
10695     LIMITED_METHOD_CONTRACT;
10696     ANNOTATION_SPECIAL_HOLDER_CALLER_NEEDS_DYNAMIC_CONTRACT;
10697     m_pDomain=NULL;
10698 #ifdef _DEBUG
10699     m_bAcquired=false;
10700     m_bChecked=false;
10701     m_type=synctype;
10702 #endif
10703 }
10704
10705 #ifndef CROSSGEN_COMPILE
10706 void ADUnloadSink::ReportUnloadResult (HRESULT hr, OBJECTREF* pException)
10707 {
10708     CONTRACTL
10709     {
10710         NOTHROW;
10711         GC_NOTRIGGER;
10712         PRECONDITION(CheckPointer(this));
10713         PRECONDITION(m_UnloadCompleteEvent.IsValid());
10714     }
10715     CONTRACTL_END;
10716
10717     //pException is unused;
10718     m_UnloadResult=hr;
10719     m_UnloadCompleteEvent.Set();
10720 };
10721
10722 void ADUnloadSink::WaitUnloadCompletion()
10723 {
10724     CONTRACTL
10725     {
10726         THROWS;
10727         GC_TRIGGERS;
10728         PRECONDITION(CheckPointer(this));
10729         PRECONDITION(m_UnloadCompleteEvent.IsValid());
10730     }
10731     CONTRACTL_END;
10732
10733     CONTRACT_VIOLATION(FaultViolation);
10734     m_UnloadCompleteEvent.WaitEx(INFINITE, (WaitMode)(WaitMode_Alertable | WaitMode_ADUnload));
10735 };
10736
10737 ADUnloadSink* AppDomain::PrepareForWaitUnloadCompletion()
10738 {
10739     CONTRACTL
10740     {
10741         NOTHROW;
10742         GC_NOTRIGGER;
10743         PRECONDITION(SystemDomain::IsUnderDomainLock());
10744         FORBID_FAULT;
10745     }
10746     CONTRACTL_END;
10747
10748     ADUnloadSink* pADSink=GetADUnloadSink();
10749     PREFIX_ASSUME(pADSink!=NULL);
10750     if (m_Stage < AppDomain::STAGE_UNLOAD_REQUESTED) //we're first
10751     {
10752         pADSink->Reset();
10753         SetUnloadRequestThread(GetThread());
10754     }
10755     return pADSink;
10756 };
10757
10758 ADUnloadSink::ADUnloadSink()
10759 {
10760     CONTRACTL
10761     {
10762         CONSTRUCTOR_CHECK;
10763         THROWS;
10764         GC_NOTRIGGER;
10765         MODE_ANY;
10766         INJECT_FAULT(COMPlusThrowOM(););
10767     }
10768     CONTRACTL_END;
10769
10770     m_cRef=1;
10771     m_UnloadCompleteEvent.CreateManualEvent(FALSE);
10772     m_UnloadResult=S_OK;
10773 };
10774
10775 ADUnloadSink::~ADUnloadSink()
10776 {
10777     CONTRACTL
10778     {
10779         DESTRUCTOR_CHECK;
10780         NOTHROW;
10781         GC_NOTRIGGER;
10782         MODE_ANY;
10783     }
10784     CONTRACTL_END;
10785     m_UnloadCompleteEvent.CloseEvent();
10786
10787 };
10788
10789
10790 ULONG ADUnloadSink::AddRef()
10791 {
10792     LIMITED_METHOD_CONTRACT;
10793     return InterlockedIncrement(&m_cRef);
10794 };
10795
10796 ULONG ADUnloadSink::Release()
10797 {
10798     LIMITED_METHOD_CONTRACT;
10799     ULONG ulRef = InterlockedDecrement(&m_cRef);
10800     if (ulRef == 0)
10801     {
10802         delete this;
10803     }
10804     return ulRef;
10805 };
10806
10807 void ADUnloadSink::Reset()
10808 {
10809     LIMITED_METHOD_CONTRACT;
10810     m_UnloadResult=S_OK;
10811     m_UnloadCompleteEvent.Reset();
10812 }
10813
10814 ADUnloadSink* AppDomain::GetADUnloadSink()
10815 {
10816     LIMITED_METHOD_CONTRACT;
10817     _ASSERTE(SystemDomain::IsUnderDomainLock());
10818     if(m_ADUnloadSink)
10819         m_ADUnloadSink->AddRef();
10820     return m_ADUnloadSink;
10821 };
10822
10823 ADUnloadSink* AppDomain::GetADUnloadSinkForUnload()
10824 {
10825     // unload thread only. Doesn't need to have AD lock
10826     LIMITED_METHOD_CONTRACT;
10827     if(m_ADUnloadSink)
10828         m_ADUnloadSink->AddRef();
10829     return m_ADUnloadSink;
10830 }
10831 #endif // CROSSGEN_COMPILE
10832
10833 void AppDomain::EnumStaticGCRefs(promote_func* fn, ScanContext* sc)
10834 {
10835     CONTRACT_VOID
10836     {
10837         NOTHROW;
10838         GC_NOTRIGGER;
10839     }
10840     CONTRACT_END;
10841
10842     _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
10843              GCHeapUtilities::IsServerHeap()   &&
10844              IsGCSpecialThread());
10845
10846     AppDomain::AssemblyIterator asmIterator = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution));
10847     CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
10848     while (asmIterator.Next(pDomainAssembly.This()))
10849     {
10850         // @TODO: Review when DomainAssemblies get added.
10851         _ASSERTE(pDomainAssembly != NULL);
10852         pDomainAssembly->EnumStaticGCRefs(fn, sc);
10853     }
10854
10855     RETURN;
10856 }
10857
10858 #endif // !DACCESS_COMPILE
10859
10860 //------------------------------------------------------------------------
10861 UINT32 BaseDomain::GetTypeID(PTR_MethodTable pMT) {
10862     CONTRACTL {
10863         THROWS;
10864         GC_TRIGGERS;
10865         PRECONDITION(pMT->GetDomain() == this);
10866     } CONTRACTL_END;
10867
10868     return m_typeIDMap.GetTypeID(pMT);
10869 }
10870
10871 //------------------------------------------------------------------------
10872 // Returns the ID of the type if found. If not found, returns INVALID_TYPE_ID
10873 UINT32 BaseDomain::LookupTypeID(PTR_MethodTable pMT)
10874 {
10875     CONTRACTL {
10876         NOTHROW;
10877         SO_TOLERANT;
10878         WRAPPER(GC_TRIGGERS);
10879         PRECONDITION(pMT->GetDomain() == this);
10880     } CONTRACTL_END;
10881
10882     return m_typeIDMap.LookupTypeID(pMT);
10883 }
10884
10885 //------------------------------------------------------------------------
10886 PTR_MethodTable BaseDomain::LookupType(UINT32 id) {
10887     CONTRACTL {
10888         NOTHROW;
10889         SO_TOLERANT;
10890         WRAPPER(GC_TRIGGERS);
10891         CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS);
10892     } CONTRACTL_END;
10893
10894     PTR_MethodTable pMT = m_typeIDMap.LookupType(id);
10895     if (pMT == NULL && !IsSharedDomain()) {
10896         pMT = SharedDomain::GetDomain()->LookupType(id);
10897     }
10898
10899     CONSISTENCY_CHECK(CheckPointer(pMT));
10900     CONSISTENCY_CHECK(pMT->IsInterface());
10901     return pMT;
10902 }
10903
10904 //---------------------------------------------------------------------------------------
10905 // 
10906 BOOL 
10907 AppDomain::AssemblyIterator::Next(
10908     CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
10909 {
10910     CONTRACTL {
10911         NOTHROW;
10912         WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
10913         MODE_ANY;
10914     } CONTRACTL_END;
10915     
10916     CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
10917     return Next_Unlocked(pDomainAssemblyHolder);
10918 }
10919
10920 //---------------------------------------------------------------------------------------
10921 // 
10922 // Note: Does not lock the assembly list, but locks collectible assemblies for adding references.
10923 // 
10924 BOOL 
10925 AppDomain::AssemblyIterator::Next_Unlocked(
10926     CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
10927 {
10928     CONTRACTL {
10929         NOTHROW;
10930         GC_NOTRIGGER;
10931         MODE_ANY;
10932     } CONTRACTL_END;
10933     
10934 #ifndef DACCESS_COMPILE
10935     _ASSERTE(m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
10936 #endif
10937     
10938     while (m_Iterator.Next())
10939     {
10940         // Get element from the list/iterator (without adding reference to the assembly)
10941         DomainAssembly * pDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
10942         if (pDomainAssembly == NULL)
10943         {
10944             continue;
10945         }
10946
10947         if (pDomainAssembly->IsError())
10948         {
10949             if (m_assemblyIterationFlags & kIncludeFailedToLoad)
10950             {
10951                 *pDomainAssemblyHolder = pDomainAssembly;
10952                 return TRUE;
10953             }
10954             continue; // reject
10955         }
10956
10957         // First, reject DomainAssemblies whose load status is not to be included in
10958         // the enumeration
10959         
10960         if (pDomainAssembly->IsAvailableToProfilers() && 
10961             (m_assemblyIterationFlags & kIncludeAvailableToProfilers))
10962         {
10963             // The assembly has reached the state at which we would notify profilers,
10964             // and we're supposed to include such assemblies in the enumeration. So
10965             // don't reject it (i.e., noop here, and don't bother with the rest of
10966             // the load status checks). Check for this first, since
10967             // kIncludeAvailableToProfilers contains some loaded AND loading
10968             // assemblies.
10969         }
10970         else if (pDomainAssembly->IsLoaded())
10971         {
10972             // A loaded assembly
10973             if (!(m_assemblyIterationFlags & kIncludeLoaded))
10974             {
10975                 continue; // reject
10976             }
10977         }
10978         else
10979         {
10980             // A loading assembly
10981             if (!(m_assemblyIterationFlags & kIncludeLoading))
10982             {
10983                 continue; // reject
10984             }
10985         }
10986
10987         // Next, reject DomainAssemblies whose execution / introspection status is
10988         // not to be included in the enumeration
10989         
10990         if (pDomainAssembly->IsIntrospectionOnly())
10991         {
10992             // introspection assembly
10993             if (!(m_assemblyIterationFlags & kIncludeIntrospection))
10994             {
10995                 continue; // reject
10996             }
10997         }
10998         else
10999         {
11000             // execution assembly
11001             if (!(m_assemblyIterationFlags & kIncludeExecution))
11002             {
11003                 continue; // reject
11004             }
11005         }
11006
11007         // Next, reject collectible assemblies
11008         if (pDomainAssembly->IsCollectible())
11009         {
11010             if (m_assemblyIterationFlags & kExcludeCollectible)
11011             {
11012                 _ASSERTE(!(m_assemblyIterationFlags & kIncludeCollected));
11013                 continue; // reject
11014             }
11015             
11016             // Un-tenured collectible assemblies should not be returned. (This can only happen in a brief
11017             // window during collectible assembly creation. No thread should need to have a pointer
11018             // to the just allocated DomainAssembly at this stage.)
11019             if (!pDomainAssembly->GetAssembly()->GetManifestModule()->IsTenured())
11020             {
11021                 continue; // reject
11022             }
11023
11024             if (pDomainAssembly->GetLoaderAllocator()->AddReferenceIfAlive())
11025             {   // The assembly is alive
11026                 
11027                 // Set the holder value (incl. increasing ref-count)
11028                 *pDomainAssemblyHolder = pDomainAssembly;
11029                 
11030                 // Now release the reference we took in the if-condition
11031                 pDomainAssembly->GetLoaderAllocator()->Release();
11032                 return TRUE;
11033             }
11034             // The assembly is not alive anymore (and we didn't increase its ref-count in the 
11035             // if-condition)
11036             
11037             if (!(m_assemblyIterationFlags & kIncludeCollected))
11038             {
11039                 continue; // reject
11040             }
11041             // Set the holder value to assembly with 0 ref-count without increasing the ref-count (won't 
11042             // call Release either)
11043             pDomainAssemblyHolder->Assign(pDomainAssembly, FALSE);
11044             return TRUE;
11045         }
11046
11047         *pDomainAssemblyHolder = pDomainAssembly;
11048         return TRUE;
11049     }
11050
11051     *pDomainAssemblyHolder = NULL;
11052     return FALSE;
11053 } // AppDomain::AssemblyIterator::Next_Unlocked
11054
11055 #ifndef DACCESS_COMPILE
11056
11057 //---------------------------------------------------------------------------------------
11058 // 
11059 // Can be called only from AppDomain shutdown code:AppDomain::ShutdownAssemblies.
11060 // Does not add-ref collectible assemblies (as the LoaderAllocator might not be reachable from the 
11061 // DomainAssembly anymore).
11062 // 
11063 BOOL 
11064 AppDomain::AssemblyIterator::Next_UnsafeNoAddRef(
11065     DomainAssembly ** ppDomainAssembly)
11066 {
11067     CONTRACTL {
11068         NOTHROW;
11069         GC_TRIGGERS;
11070         MODE_ANY;
11071     } CONTRACTL_END;
11072     
11073     // Make sure we are iterating all assemblies (see the only caller code:AppDomain::ShutdownAssemblies)
11074     _ASSERTE(m_assemblyIterationFlags == 
11075         (kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeIntrospection | kIncludeFailedToLoad | kIncludeCollected));
11076     // It also means that we do not exclude anything
11077     _ASSERTE((m_assemblyIterationFlags & kExcludeCollectible) == 0);
11078     
11079     // We are on shutdown path, so lock shouldn't be neccessary, but all _Unlocked methods on AssemblyList 
11080     // have asserts that the lock is held, so why not to take it ...
11081     CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
11082     
11083     while (m_Iterator.Next())
11084     {
11085         // Get element from the list/iterator (without adding reference to the assembly)
11086         *ppDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
11087         if (*ppDomainAssembly == NULL)
11088         {
11089             continue;
11090         }
11091         
11092         return TRUE;
11093     }
11094     
11095     *ppDomainAssembly = NULL;
11096     return FALSE;
11097 } // AppDomain::AssemblyIterator::Next_UnsafeNoAddRef
11098
11099
11100 //---------------------------------------------------------------------------------------
11101 // 
11102 BOOL AppDomain::IsImageFromTrustedPath(PEImage* pPEImage)
11103 {
11104     CONTRACTL
11105     {
11106         MODE_ANY;
11107         GC_TRIGGERS;
11108         THROWS;
11109         PRECONDITION(CheckPointer(pPEImage));
11110     }
11111     CONTRACTL_END;
11112
11113     const SString &sImagePath = pPEImage->GetPath();
11114
11115     return !sImagePath.IsEmpty();
11116 }
11117
11118 #endif //!DACCESS_COMPILE
11119
11120 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
11121
11122 // Returns a BOOL indicating if the binding model has been locked for the AppDomain
11123 BOOL AppDomain::IsBindingModelLocked()
11124 {
11125     CONTRACTL
11126     {
11127         NOTHROW;
11128         GC_NOTRIGGER;
11129         MODE_ANY;
11130     }
11131     CONTRACTL_END;
11132     
11133     return m_fIsBindingModelLocked.Load();
11134 }
11135
11136 // Marks the binding model locked for AppDomain
11137 BOOL AppDomain::LockBindingModel()
11138 {
11139     LIMITED_METHOD_CONTRACT;
11140     
11141     BOOL fDidWeLockBindingModel = FALSE;
11142     
11143     if (InterlockedCompareExchangeT<BOOL>(&m_fIsBindingModelLocked, TRUE, FALSE) == FALSE)
11144     {
11145         fDidWeLockBindingModel = TRUE;
11146     }
11147     
11148     return fDidWeLockBindingModel;
11149 }
11150
11151 BOOL AppDomain::IsHostAssemblyResolverInUse()
11152 {
11153     LIMITED_METHOD_CONTRACT;
11154     
11155     return (GetFusionContext() != GetTPABinderContext());
11156 }
11157
11158 // Helper used by the assembly binder to check if the specified AppDomain can use apppath assembly resolver
11159 BOOL RuntimeCanUseAppPathAssemblyResolver(DWORD adid)
11160 {
11161     CONTRACTL
11162     {
11163         NOTHROW; // Cannot throw since it is invoked by the Binder that expects to get a hresult
11164         GC_TRIGGERS;
11165         MODE_ANY;
11166     }
11167     CONTRACTL_END;
11168
11169     ADID id(adid);
11170
11171     // We need to be in COOP mode to get the AppDomain*
11172     GCX_COOP();
11173         
11174     AppDomain *pTargetDomain = SystemDomain::GetAppDomainFromId(id, ADV_CURRENTAD);
11175     _ASSERTE(pTargetDomain != NULL);
11176
11177     pTargetDomain->LockBindingModel();
11178         
11179     return !pTargetDomain->IsHostAssemblyResolverInUse();
11180 }
11181
11182 // Returns S_OK if the assembly was successfully loaded
11183 HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, IAssemblyName *pIAssemblyName, CLRPrivBinderCoreCLR *pTPABinder, BINDER_SPACE::AssemblyName *pAssemblyName, ICLRPrivAssembly **ppLoadedAssembly)
11184 {
11185     CONTRACTL
11186     {
11187         THROWS;
11188         GC_TRIGGERS;
11189         MODE_ANY;
11190         PRECONDITION(ppLoadedAssembly != NULL);
11191     }
11192     CONTRACTL_END;
11193     
11194     HRESULT hr = E_FAIL;
11195
11196     // DevDiv #933506: Exceptions thrown during AssemblyLoadContext.Load should propagate
11197     // EX_TRY
11198     {
11199         // Switch to COOP mode since we are going to work with managed references
11200         GCX_COOP();
11201         
11202         struct 
11203         {
11204             ASSEMBLYNAMEREF oRefAssemblyName;
11205             ASSEMBLYREF oRefLoadedAssembly;
11206         } _gcRefs;
11207         
11208         ZeroMemory(&_gcRefs, sizeof(_gcRefs));
11209         
11210         GCPROTECT_BEGIN(_gcRefs);
11211         
11212         ICLRPrivAssembly *pAssemblyBindingContext = NULL;
11213
11214         bool fInvokedForTPABinder = (pTPABinder == NULL)?true:false;
11215         
11216         // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.Resolve method.
11217         //
11218         // First, initialize an assembly spec for the requested assembly
11219         //
11220         AssemblySpec spec;
11221         hr = spec.Init(pIAssemblyName);
11222         if (SUCCEEDED(hr))
11223         {
11224             bool fResolvedAssembly = false;
11225             bool fResolvedAssemblyViaTPALoadContext = false;
11226
11227             // Allocate an AssemblyName managed object
11228             _gcRefs.oRefAssemblyName = (ASSEMBLYNAMEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME));
11229             
11230             // Initialize the AssemblyName object from the AssemblySpec
11231             spec.AssemblyNameInit(&_gcRefs.oRefAssemblyName, NULL);
11232                 
11233             if (!fInvokedForTPABinder)
11234             {
11235                 // Step 2 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName) - Invoke Load method
11236                 // This is not invoked for TPA Binder since it always returns NULL.
11237
11238                 // Finally, setup arguments for invocation
11239                 BinderMethodID idHAR_Resolve = METHOD__ASSEMBLYLOADCONTEXT__RESOLVE;
11240                 MethodDescCallSite methLoadAssembly(idHAR_Resolve);
11241                 
11242                 // Setup the arguments for the call
11243                 ARG_SLOT args[2] =
11244                 {
11245                     PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
11246                     ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
11247                 };
11248
11249                 // Make the call
11250                 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
11251                 if (_gcRefs.oRefLoadedAssembly != NULL)
11252                 {
11253                     fResolvedAssembly = true;
11254                 }
11255             
11256                 // Step 3 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
11257                 if (!fResolvedAssembly)
11258                 {
11259                     // If we could not resolve the assembly using Load method, then attempt fallback with TPA Binder.
11260                     // Since TPA binder cannot fallback to itself, this fallback does not happen for binds within TPA binder.
11261                     //
11262                     // Switch to pre-emp mode before calling into the binder
11263                     GCX_PREEMP();
11264                     ICLRPrivAssembly *pCoreCLRFoundAssembly = NULL;
11265                     hr = pTPABinder->BindAssemblyByName(pIAssemblyName, &pCoreCLRFoundAssembly);
11266                     if (SUCCEEDED(hr))
11267                     {
11268                         pAssemblyBindingContext = pCoreCLRFoundAssembly;
11269                         fResolvedAssembly = true;
11270                         fResolvedAssemblyViaTPALoadContext = true;
11271                     }
11272                 }
11273             }
11274             
11275             if (!fResolvedAssembly)
11276             {
11277                 // Step 4 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
11278                 //
11279                 // If we couldnt resolve the assembly using TPA LoadContext as well, then
11280                 // attempt to resolve it using the Resolving event.
11281                 // Finally, setup arguments for invocation
11282                 BinderMethodID idHAR_ResolveUsingEvent = METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUSINGEVENT;
11283                 MethodDescCallSite methLoadAssembly(idHAR_ResolveUsingEvent);
11284                 
11285                 // Setup the arguments for the call
11286                 ARG_SLOT args[2] =
11287                 {
11288                     PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
11289                     ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
11290                 };
11291
11292                 // Make the call
11293                 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
11294                 if (_gcRefs.oRefLoadedAssembly != NULL)
11295                 {
11296                     // Set the flag indicating we found the assembly
11297                     fResolvedAssembly = true;
11298                 }
11299             }
11300             
11301             if (fResolvedAssembly && !fResolvedAssemblyViaTPALoadContext)
11302             {
11303                 // If we are here, assembly was successfully resolved via Load or Resolving events.
11304                 _ASSERTE(_gcRefs.oRefLoadedAssembly != NULL);
11305                     
11306                 // We were able to get the assembly loaded. Now, get its name since the host could have
11307                 // performed the resolution using an assembly with different name.
11308                 DomainAssembly *pDomainAssembly = _gcRefs.oRefLoadedAssembly->GetDomainAssembly();
11309                 PEAssembly *pLoadedPEAssembly = NULL;
11310                 bool fFailLoad = false;
11311                 if (!pDomainAssembly)
11312                 {
11313                     // Reflection emitted assemblies will not have a domain assembly.
11314                     fFailLoad = true;
11315                 }
11316                 else
11317                 {
11318                     pLoadedPEAssembly = pDomainAssembly->GetFile();
11319                     if (pLoadedPEAssembly->HasHostAssembly() != true)
11320                     {
11321                         // Reflection emitted assemblies will not have a domain assembly.
11322                         fFailLoad = true;
11323                     }
11324                 }
11325                 
11326                 // The loaded assembly's ICLRPrivAssembly* is saved as HostAssembly in PEAssembly
11327                 if (fFailLoad)
11328                 {
11329                     SString name;
11330                     spec.GetFileOrDisplayName(0, name);
11331                     COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_DYNAMICALLY_EMITTED_ASSEMBLIES_UNSUPPORTED, name);
11332                 }
11333                 
11334                 // Is the assembly already bound using a binding context that will be incompatible?
11335                 // An example is attempting to consume an assembly bound to WinRT binder.
11336                 pAssemblyBindingContext = pLoadedPEAssembly->GetHostAssembly();
11337             }
11338             
11339 #ifdef FEATURE_COMINTEROP
11340             if (AreSameBinderInstance(pAssemblyBindingContext, GetAppDomain()->GetWinRtBinder()))
11341             {
11342                 // It is invalid to return an assembly bound to an incompatible binder
11343                 *ppLoadedAssembly = NULL;
11344                 SString name;
11345                 spec.GetFileOrDisplayName(0, name);
11346                 COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_BINDING_CONTEXT, name);
11347             }
11348 #endif // FEATURE_COMINTEROP
11349
11350             // Get the ICLRPrivAssembly reference to return back to.
11351             *ppLoadedAssembly = clr::SafeAddRef(pAssemblyBindingContext);
11352             hr = S_OK;
11353         }
11354         
11355         GCPROTECT_END();
11356     }
11357     // EX_CATCH_HRESULT(hr);
11358     
11359     return hr;
11360     
11361 }
11362 #endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
11363
11364 //approximate size of loader data
11365 //maintained for each assembly
11366 #define APPROX_LOADER_DATA_PER_ASSEMBLY 8196
11367
11368 size_t AppDomain::EstimateSize()
11369 {
11370     CONTRACTL
11371     {
11372         NOTHROW;
11373         GC_TRIGGERS;
11374         MODE_ANY;
11375     }
11376     CONTRACTL_END;
11377     
11378     size_t retval = sizeof(AppDomain);
11379     retval += GetLoaderAllocator()->EstimateSize();
11380     //very rough estimate
11381     retval += GetAssemblyCount() * APPROX_LOADER_DATA_PER_ASSEMBLY;
11382     return retval;
11383 }
11384
11385 #ifdef DACCESS_COMPILE
11386
11387 void
11388 DomainLocalModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
11389 {
11390     SUPPORTS_DAC;
11391
11392     // Enumerate the DomainLocalModule itself. DLMs are allocated to be larger than
11393     // sizeof(DomainLocalModule) to make room for ClassInit flags and non-GC statics.
11394     // "DAC_ENUM_DTHIS()" probably does not account for this, so we might not enumerate
11395     // all of the ClassInit flags and non-GC statics.
11396     // sizeof(DomainLocalModule) == 0x28
11397     DAC_ENUM_DTHIS();
11398
11399     if (m_pDomainFile.IsValid())
11400     {
11401         m_pDomainFile->EnumMemoryRegions(flags);
11402     }
11403
11404     if (m_pDynamicClassTable.Load().IsValid())
11405     {
11406         DacEnumMemoryRegion(dac_cast<TADDR>(m_pDynamicClassTable.Load()),
11407                             m_aDynamicEntries * sizeof(DynamicClassInfo));
11408
11409         for (SIZE_T i = 0; i < m_aDynamicEntries; i++)
11410         {
11411             PTR_DynamicEntry entry = dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[i].m_pDynamicEntry.Load());
11412             if (entry.IsValid())
11413             {
11414                 // sizeof(DomainLocalModule::DynamicEntry) == 8
11415                 entry.EnumMem();
11416             }
11417         }
11418     }
11419 }
11420
11421 void
11422 DomainLocalBlock::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
11423 {
11424     SUPPORTS_DAC;
11425     // Block is contained in AppDomain, don't enum this.
11426
11427     if (m_pModuleSlots.IsValid())
11428     {
11429         DacEnumMemoryRegion(dac_cast<TADDR>(m_pModuleSlots),
11430                             m_aModuleIndices * sizeof(TADDR));
11431
11432         for (SIZE_T i = 0; i < m_aModuleIndices; i++)
11433         {
11434             PTR_DomainLocalModule domMod = m_pModuleSlots[i];
11435             if (domMod.IsValid())
11436             {
11437                 domMod->EnumMemoryRegions(flags);
11438             }
11439         }
11440     }
11441 }
11442
11443 void
11444 BaseDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11445                               bool enumThis)
11446 {
11447     SUPPORTS_DAC;
11448     if (enumThis)
11449     {
11450         // This is wrong.  Don't do it.
11451         // BaseDomain cannot be instantiated.
11452         // The only thing this code can hope to accomplish is to potentially break
11453         // memory enumeration walking through the derived class if we
11454         // explicitly call the base class enum first.
11455 //        DAC_ENUM_VTHIS();
11456     }
11457
11458     EMEM_OUT(("MEM: %p BaseDomain\n", dac_cast<TADDR>(this)));
11459 }
11460
11461 void
11462 AppDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11463                              bool enumThis)
11464 {
11465     SUPPORTS_DAC;
11466
11467     if (enumThis)
11468     {
11469         //sizeof(AppDomain) == 0xeb0
11470         DAC_ENUM_VTHIS();
11471     }
11472     BaseDomain::EnumMemoryRegions(flags, false);
11473
11474     // We don't need AppDomain name in triage dumps.
11475     if (flags != CLRDATA_ENUM_MEM_TRIAGE)
11476     {
11477         m_friendlyName.EnumMemoryRegions(flags);
11478     }
11479
11480     m_Assemblies.EnumMemoryRegions(flags);
11481     AssemblyIterator assem = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution | kIncludeIntrospection));
11482     CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
11483     
11484     while (assem.Next(pDomainAssembly.This()))
11485     {
11486         pDomainAssembly->EnumMemoryRegions(flags);
11487     }
11488
11489     m_sDomainLocalBlock.EnumMemoryRegions(flags);
11490
11491     m_LoaderAllocator.EnumMemoryRegions(flags);
11492 }
11493
11494 void
11495 SystemDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11496                                 bool enumThis)
11497 {
11498     SUPPORTS_DAC;
11499     if (enumThis)
11500     {
11501         DAC_ENUM_VTHIS();
11502     }
11503     BaseDomain::EnumMemoryRegions(flags, false);
11504
11505     if (m_pSystemFile.IsValid())
11506     {
11507         m_pSystemFile->EnumMemoryRegions(flags);
11508     }
11509     if (m_pSystemAssembly.IsValid())
11510     {
11511         m_pSystemAssembly->EnumMemoryRegions(flags);
11512     }
11513     if (m_pDefaultDomain.IsValid())
11514     {
11515         m_pDefaultDomain->EnumMemoryRegions(flags, true);
11516     }
11517
11518     m_appDomainIndexList.EnumMem();
11519     (&m_appDomainIndexList)->EnumMemoryRegions(flags);
11520 }
11521
11522 void
11523 SharedDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
11524                                 bool enumThis)
11525 {
11526     SUPPORTS_DAC;
11527     if (enumThis)
11528     {
11529         DAC_ENUM_VTHIS();
11530     }
11531     BaseDomain::EnumMemoryRegions(flags, false);
11532 #ifdef FEATURE_LOADER_OPTIMIZATION
11533     m_assemblyMap.EnumMemoryRegions(flags);
11534     SharedAssemblyIterator assem;
11535     while (assem.Next())
11536     {
11537         assem.GetAssembly()->EnumMemoryRegions(flags);
11538     }
11539 #endif    
11540 }
11541
11542 #endif //DACCESS_COMPILE
11543
11544
11545 PTR_LoaderAllocator SystemDomain::GetGlobalLoaderAllocator()
11546 {
11547     return PTR_LoaderAllocator(PTR_HOST_MEMBER_TADDR(SystemDomain,System(),m_GlobalAllocator));
11548 }
11549
11550 #ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
11551
11552 #ifndef CROSSGEN_COMPILE
11553 // Return the total processor time (user and kernel) used by threads executing in this AppDomain so far. The
11554 // result is in 100ns units.
11555 ULONGLONG AppDomain::QueryProcessorUsage()
11556 {
11557     CONTRACTL
11558     {
11559         NOTHROW;
11560         GC_TRIGGERS;
11561         MODE_ANY;
11562     }
11563     CONTRACTL_END;
11564
11565 #ifndef DACCESS_COMPILE
11566     Thread *pThread = NULL;
11567
11568     // Need to update our accumulated processor time count with current values from each thread that is
11569     // currently executing in this domain.
11570
11571     // Take the thread store lock while we enumerate threads.
11572     ThreadStoreLockHolder tsl;
11573     while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
11574     {
11575         // Skip unstarted and dead threads and those that are currently executing in a different AppDomain.
11576         if (pThread->IsUnstarted() || pThread->IsDead() || pThread->GetDomain(INDEBUG(TRUE)) != this)
11577             continue;
11578
11579         // Add the amount of time spent by the thread in the AppDomain since the last time we asked (calling
11580         // Thread::QueryThreadProcessorUsage() will reset the thread's counter).
11581         UpdateProcessorUsage(pThread->QueryThreadProcessorUsage());
11582     }
11583 #endif // !DACCESS_COMPILE
11584
11585     // Return the updated total.
11586     return m_ullTotalProcessorUsage;
11587 }
11588
11589 // Add to the current count of processor time used by threads within this AppDomain. This API is called by
11590 // threads transitioning between AppDomains.
11591 void AppDomain::UpdateProcessorUsage(ULONGLONG ullAdditionalUsage)
11592 {
11593     LIMITED_METHOD_CONTRACT;
11594
11595     // Need to be careful to synchronize here, multiple threads could be racing to update this count.
11596     ULONGLONG ullOldValue;
11597     ULONGLONG ullNewValue;
11598     do
11599     {
11600         ullOldValue = m_ullTotalProcessorUsage;
11601         ullNewValue = ullOldValue + ullAdditionalUsage;
11602     } while (InterlockedCompareExchange64((LONGLONG*)&m_ullTotalProcessorUsage,
11603                                           (LONGLONG)ullNewValue,
11604                                           (LONGLONG)ullOldValue) != (LONGLONG)ullOldValue);
11605 }
11606 #endif // CROSSGEN_COMPILE
11607
11608 #endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
11609
11610 #if defined(FEATURE_TYPEEQUIVALENCE)
11611
11612 #ifndef DACCESS_COMPILE
11613 TypeEquivalenceHashTable * AppDomain::GetTypeEquivalenceCache()
11614 {
11615     CONTRACTL
11616     {
11617         THROWS;
11618         GC_TRIGGERS;
11619         INJECT_FAULT(COMPlusThrowOM());
11620         MODE_ANY;
11621     }
11622     CONTRACTL_END;
11623
11624     // Take the critical section all of the time in debug builds to ensure that it is safe to take
11625     // the critical section in the unusual times when it may actually be needed in retail builds
11626 #ifdef _DEBUG
11627     CrstHolder ch(&m_TypeEquivalenceCrst);
11628 #endif
11629
11630     if (m_pTypeEquivalenceTable.Load() == NULL)
11631     {
11632 #ifndef _DEBUG
11633         CrstHolder ch(&m_TypeEquivalenceCrst);
11634 #endif
11635         if (m_pTypeEquivalenceTable.Load() == NULL)
11636         {
11637             m_pTypeEquivalenceTable = TypeEquivalenceHashTable::Create(this, 12, &m_TypeEquivalenceCrst);
11638         }
11639     }
11640     return m_pTypeEquivalenceTable;
11641 }
11642 #endif //!DACCESS_COMPILE
11643
11644 #endif //FEATURE_TYPEEQUIVALENCE
11645
11646 #if !defined(DACCESS_COMPILE)
11647
11648 //---------------------------------------------------------------------------------------------------------------------
11649 void AppDomain::PublishHostedAssembly(
11650     DomainAssembly * pDomainAssembly)
11651 {
11652     CONTRACTL
11653     {
11654         THROWS;
11655         GC_NOTRIGGER;
11656         MODE_ANY;
11657     }
11658     CONTRACTL_END
11659
11660     if (pDomainAssembly->GetFile()->HasHostAssembly())
11661     {
11662         // We have to serialize all Add operations
11663         CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
11664         _ASSERTE(m_hostAssemblyMap.Lookup(pDomainAssembly->GetFile()->GetHostAssembly()) == nullptr);
11665         
11666         // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
11667         HostAssemblyMap::AddPhases addCall;
11668         
11669         // 1. Preallocate one element
11670         addCall.PreallocateForAdd(&m_hostAssemblyMap);
11671         {
11672             // 2. Take the reader lock which can be taken during stack walking
11673             // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
11674             ForbidSuspendThreadHolder suspend;
11675             {
11676                 CrstHolder lock(&m_crstHostAssemblyMap);
11677                 // 3. Add the element to the hash table (no call out into host)
11678                 addCall.Add(pDomainAssembly);
11679             }
11680         }
11681         // 4. Cleanup the old memory (if any)
11682         addCall.DeleteOldTable();
11683     }
11684     else
11685     {
11686     }
11687 }
11688
11689 //---------------------------------------------------------------------------------------------------------------------
11690 void AppDomain::UpdatePublishHostedAssembly(
11691     DomainAssembly * pAssembly, 
11692     PTR_PEFile       pFile)
11693 {
11694     CONTRACTL
11695     {
11696         THROWS;
11697         GC_NOTRIGGER;
11698         MODE_ANY;
11699         CAN_TAKE_LOCK;
11700     }
11701     CONTRACTL_END
11702
11703     if (pAssembly->GetFile()->HasHostAssembly())
11704     {
11705         // We have to serialize all Add operations
11706         CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
11707         {
11708             // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
11709             OriginalFileHostAssemblyMap::AddPhases addCall;
11710             bool fAddOrigFile = false;
11711         
11712             // For cases where the pefile is being updated 
11713             // 1. Preallocate one element
11714             if (pFile != pAssembly->GetFile())
11715             {
11716                 addCall.PreallocateForAdd(&m_hostAssemblyMapForOrigFile);
11717                 fAddOrigFile = true;
11718             }
11719
11720             {
11721                 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
11722                 ForbidSuspendThreadHolder suspend;
11723                 {
11724                     CrstHolder lock(&m_crstHostAssemblyMap);
11725                 
11726                     // Remove from hash table.
11727                     _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
11728                     m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
11729                 
11730                     // Update PEFile on DomainAssembly. (This may cause the key for the hash to change, which is why we need this function)
11731                     pAssembly->UpdatePEFileWorker(pFile);
11732                 
11733                     _ASSERTE(fAddOrigFile == (pAssembly->GetOriginalFile() != pAssembly->GetFile()));
11734                     if (fAddOrigFile)
11735                     {
11736                         // Add to the orig file hash table if we might be in a case where we've cached the original pefile and not the final pe file (for use during GetAssemblyIfLoaded)
11737                         addCall.Add(pAssembly);
11738                     }
11739
11740                     // Add back to the hashtable (the call to Remove above guarantees that we will not call into host for table reallocation)
11741                     _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) == nullptr);
11742                     m_hostAssemblyMap.Add(pAssembly);
11743                 }
11744             }
11745
11746             // 4. Cleanup the old memory (if any)
11747             if (fAddOrigFile)
11748                 addCall.DeleteOldTable();
11749         }
11750     }
11751     else
11752     {
11753
11754         pAssembly->UpdatePEFileWorker(pFile);
11755     }
11756 }
11757
11758 //---------------------------------------------------------------------------------------------------------------------
11759 void AppDomain::UnPublishHostedAssembly(
11760     DomainAssembly * pAssembly)
11761 {
11762     CONTRACTL
11763     {
11764         NOTHROW;
11765         GC_NOTRIGGER;
11766         MODE_ANY;
11767         CAN_TAKE_LOCK;
11768     }
11769     CONTRACTL_END
11770
11771     if (pAssembly->GetFile()->HasHostAssembly())
11772     {
11773         ForbidSuspendThreadHolder suspend;
11774         {
11775             CrstHolder lock(&m_crstHostAssemblyMap);
11776             _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
11777             m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
11778
11779             // We also have an entry in m_hostAssemblyMapForOrigFile. Handle that case.
11780             if (pAssembly->GetOriginalFile() != pAssembly->GetFile())
11781             {
11782                 m_hostAssemblyMapForOrigFile.Remove(pAssembly->GetOriginalFile()->GetHostAssembly());
11783             }
11784         }
11785     }
11786     else
11787     {
11788         // In AppX processes, all PEAssemblies that are reach this stage should have host binders.
11789         _ASSERTE(!AppX::IsAppXProcess());
11790     }
11791 }
11792
11793 #if defined(FEATURE_COMINTEROP)
11794 HRESULT AppDomain::SetWinrtApplicationContext(SString &appLocalWinMD)
11795 {
11796     STANDARD_VM_CONTRACT;
11797     
11798     _ASSERTE(WinRTSupported());
11799     _ASSERTE(m_pWinRtBinder != nullptr);
11800
11801     _ASSERTE(GetTPABinderContext() != NULL);
11802     BINDER_SPACE::ApplicationContext *pApplicationContext = GetTPABinderContext()->GetAppContext();
11803     _ASSERTE(pApplicationContext != NULL);
11804     
11805     return m_pWinRtBinder->SetApplicationContext(pApplicationContext, appLocalWinMD);
11806 }
11807
11808 #endif // FEATURE_COMINTEROP
11809
11810 #endif //!DACCESS_COMPILE
11811
11812 //---------------------------------------------------------------------------------------------------------------------
11813 PTR_DomainAssembly AppDomain::FindAssembly(PTR_ICLRPrivAssembly pHostAssembly)
11814 {
11815     CONTRACTL
11816     {
11817         NOTHROW;
11818         GC_NOTRIGGER;
11819         MODE_ANY;
11820         SUPPORTS_DAC;
11821     }
11822     CONTRACTL_END
11823     
11824     if (pHostAssembly == nullptr)
11825         return NULL;
11826     
11827     {
11828         ForbidSuspendThreadHolder suspend;
11829         {
11830             CrstHolder lock(&m_crstHostAssemblyMap);
11831             PTR_DomainAssembly returnValue = m_hostAssemblyMap.Lookup(pHostAssembly);
11832             if (returnValue == NULL)
11833             {
11834                 // If not found in the m_hostAssemblyMap, look in the m_hostAssemblyMapForOrigFile
11835                 // This is necessary as it may happen during in a second AppDomain that the PEFile 
11836                 // first discovered in the AppDomain may not be used by the DomainFile, but the CLRPrivBinderFusion
11837                 // will in some cases find the pHostAssembly associated with this no longer used PEFile
11838                 // instead of the PEFile that was finally decided upon.
11839                 returnValue = m_hostAssemblyMapForOrigFile.Lookup(pHostAssembly);
11840             }
11841
11842             return returnValue;
11843         }
11844     }
11845 }
11846
11847 #if !defined(DACCESS_COMPILE) && defined(FEATURE_NATIVE_IMAGE_GENERATION)
11848
11849 void ZapperSetBindingPaths(ICorCompilationDomain *pDomain, SString &trustedPlatformAssemblies, SString &platformResourceRoots, SString &appPaths, SString &appNiPaths)
11850 {
11851     CLRPrivBinderCoreCLR *pBinder = static_cast<CLRPrivBinderCoreCLR*>(((CompilationDomain *)pDomain)->GetFusionContext());
11852     _ASSERTE(pBinder != NULL);
11853     pBinder->SetupBindingPaths(trustedPlatformAssemblies, platformResourceRoots, appPaths, appNiPaths);
11854 #ifdef FEATURE_COMINTEROP
11855     SString emptString;
11856     ((CompilationDomain*)pDomain)->SetWinrtApplicationContext(emptString);
11857 #endif
11858 }
11859
11860 #endif