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