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