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
56#include "typeequivalencehash.hpp"
57
58#include "appdomain.inl"
59#include "typeparse.h"
60#include "mdaassistants.h"
61#include "threadpoolrequest.h"
62
63#include "nativeoverlapped.h"
64
65#ifndef FEATURE_PAL
66#include "dwreport.h"
67#endif // !FEATURE_PAL
68
69#include "stringarraylist.h"
70
71#include "../binder/inc/clrprivbindercoreclr.h"
72
73
74#include "clrprivtypecachewinrt.h"
75
76// this file handles string conversion errors for itself
77#undef MAKE_TRANSLATIONFAILED
78
79// Define these macro's to do strict validation for jit lock and class
80// init entry leaks. This defines determine if the asserts that
81// verify for these leaks are defined or not. These asserts can
82// sometimes go off even if no entries have been leaked so this
83// defines should be used with caution.
84//
85// If we are inside a .cctor when the application shut's down then the
86// class init lock's head will be set and this will cause the assert
87// to go off.
88//
89// If we are jitting a method when the application shut's down then
90// the jit lock's head will be set causing the assert to go off.
91
92//#define STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
93
94static const WCHAR DEFAULT_DOMAIN_FRIENDLY_NAME[] = W("DefaultDomain");
95static const WCHAR OTHER_DOMAIN_FRIENDLY_NAME_PREFIX[] = W("Domain");
96
97#define STATIC_OBJECT_TABLE_BUCKET_SIZE 1020
98
99//#define _DEBUG_ADUNLOAD 1
100
101// Statics
102
103SPTR_IMPL(AppDomain, AppDomain, m_pTheAppDomain);
104SPTR_IMPL(SystemDomain, SystemDomain, m_pSystemDomain);
105SVAL_IMPL(ArrayListStatic, SystemDomain, m_appDomainIndexList);
106SVAL_IMPL(BOOL, SystemDomain, s_fForceDebug);
107SVAL_IMPL(BOOL, SystemDomain, s_fForceProfiling);
108SVAL_IMPL(BOOL, SystemDomain, s_fForceInstrument);
109
110#ifndef DACCESS_COMPILE
111
112// Base Domain Statics
113CrstStatic BaseDomain::m_SpecialStaticsCrst;
114
115int BaseDomain::m_iNumberOfProcessors = 0;
116
117// System Domain Statics
118GlobalStringLiteralMap* SystemDomain::m_pGlobalStringLiteralMap = NULL;
119
120DECLSPEC_ALIGN(16)
121static BYTE g_pSystemDomainMemory[sizeof(SystemDomain)];
122
123#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
124size_t SystemDomain::m_totalSurvivedBytes = 0;
125#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
126
127CrstStatic SystemDomain::m_SystemDomainCrst;
128CrstStatic SystemDomain::m_DelayedUnloadCrst;
129
130ULONG SystemDomain::s_dNumAppDomains = 0;
131
132ArrayListStatic SystemDomain::m_appDomainIdList;
133
134DWORD SystemDomain::m_dwLowestFreeIndex = 0;
135
136
137
138// comparison function to be used for matching clsids in our clsid hash table
139BOOL CompareCLSID(UPTR u1, UPTR u2)
140{
141 CONTRACTL
142 {
143 THROWS;
144 GC_TRIGGERS;
145 MODE_ANY;
146 SO_INTOLERANT;
147 INJECT_FAULT(COMPlusThrowOM(););
148 }
149 CONTRACTL_END;
150
151 GUID *pguid = (GUID *)(u1 << 1);
152 _ASSERTE(pguid != NULL);
153
154 MethodTable *pMT= (MethodTable *)u2;
155 _ASSERTE(pMT!= NULL);
156
157 GUID guid;
158 pMT->GetGuid(&guid, TRUE);
159 if (!IsEqualIID(guid, *pguid))
160 return FALSE;
161
162 return TRUE;
163}
164
165#ifndef CROSSGEN_COMPILE
166// Constructor for the LargeHeapHandleBucket class.
167LargeHeapHandleBucket::LargeHeapHandleBucket(LargeHeapHandleBucket *pNext, DWORD Size, BaseDomain *pDomain, BOOL bCrossAD)
168: m_pNext(pNext)
169, m_ArraySize(Size)
170, m_CurrentPos(0)
171, m_CurrentEmbeddedFreePos(0) // hint for where to start a search for an embedded free item
172{
173 CONTRACTL
174 {
175 THROWS;
176 GC_TRIGGERS;
177 MODE_COOPERATIVE;
178 PRECONDITION(CheckPointer(pDomain));
179 INJECT_FAULT(COMPlusThrowOM(););
180 }
181 CONTRACTL_END;
182
183 PTRARRAYREF HandleArrayObj;
184
185 // Allocate the array in the large object heap.
186 if (!bCrossAD)
187 {
188 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
189 HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, TRUE);
190 }
191 else
192 {
193 // During AD creation we don't want to assign the handle array to the currently running AD but
194 // to the AD being created. Ensure that AllocateArrayEx doesn't set the AD and then set it here.
195 AppDomain *pAD = pDomain->AsAppDomain();
196 _ASSERTE(pAD);
197 _ASSERTE(pAD->IsBeingCreated());
198
199 OBJECTREF array;
200 {
201 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
202 array = AllocateArrayEx(
203 ClassLoader::LoadArrayTypeThrowing(g_pObjectClass),
204 (INT32 *)(&Size),
205 1,
206 TRUE
207 DEBUG_ARG(TRUE));
208 }
209
210 array->SetAppDomain(pAD);
211
212 HandleArrayObj = (PTRARRAYREF)array;
213 }
214
215 // Retrieve the pointer to the data inside the array. This is legal since the array
216 // is located in the large object heap and is guaranteed not to move.
217 m_pArrayDataPtr = (OBJECTREF *)HandleArrayObj->GetDataPtr();
218
219 // Store the array in a strong handle to keep it alive.
220 m_hndHandleArray = pDomain->CreatePinningHandle((OBJECTREF)HandleArrayObj);
221}
222
223
224// Destructor for the LargeHeapHandleBucket class.
225LargeHeapHandleBucket::~LargeHeapHandleBucket()
226{
227 CONTRACTL
228 {
229 NOTHROW;
230 GC_NOTRIGGER;
231 }
232 CONTRACTL_END;
233
234 if (m_hndHandleArray)
235 {
236 DestroyPinningHandle(m_hndHandleArray);
237 m_hndHandleArray = NULL;
238 }
239}
240
241
242// Allocate handles from the bucket.
243OBJECTREF *LargeHeapHandleBucket::AllocateHandles(DWORD nRequested)
244{
245 CONTRACTL
246 {
247 NOTHROW;
248 GC_NOTRIGGER;
249 MODE_COOPERATIVE;
250 }
251 CONTRACTL_END;
252
253 _ASSERTE(nRequested > 0 && nRequested <= GetNumRemainingHandles());
254 _ASSERTE(m_pArrayDataPtr == (OBJECTREF*)((PTRARRAYREF)ObjectFromHandle(m_hndHandleArray))->GetDataPtr());
255
256 // Store the handles in the buffer that was passed in
257 OBJECTREF* ret = &m_pArrayDataPtr[m_CurrentPos];
258 m_CurrentPos += nRequested;
259
260 return ret;
261}
262
263// look for a free item embedded in the table
264OBJECTREF *LargeHeapHandleBucket::TryAllocateEmbeddedFreeHandle()
265{
266 CONTRACTL
267 {
268 NOTHROW;
269 GC_NOTRIGGER;
270 MODE_COOPERATIVE;
271 }
272 CONTRACTL_END;
273
274 OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
275 _ASSERTE(pPreallocatedSentinalObject != NULL);
276
277 for (int i = m_CurrentEmbeddedFreePos; i < m_CurrentPos; i++)
278 {
279 if (m_pArrayDataPtr[i] == pPreallocatedSentinalObject)
280 {
281 m_CurrentEmbeddedFreePos = i;
282 m_pArrayDataPtr[i] = NULL;
283 return &m_pArrayDataPtr[i];
284 }
285 }
286
287 // 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)
288
289 m_CurrentEmbeddedFreePos = 0;
290 return NULL;
291}
292
293
294// Maximum bucket size will be 64K on 32-bit and 128K on 64-bit.
295// We subtract out a small amount to leave room for the object
296// header and length of the array.
297
298#define MAX_BUCKETSIZE (16384 - 4)
299
300// Constructor for the LargeHeapHandleTable class.
301LargeHeapHandleTable::LargeHeapHandleTable(BaseDomain *pDomain, DWORD InitialBucketSize)
302: m_pHead(NULL)
303, m_pDomain(pDomain)
304, m_NextBucketSize(InitialBucketSize)
305, m_pFreeSearchHint(NULL)
306, m_cEmbeddedFree(0)
307{
308 CONTRACTL
309 {
310 THROWS;
311 GC_TRIGGERS;
312 MODE_COOPERATIVE;
313 PRECONDITION(CheckPointer(pDomain));
314 INJECT_FAULT(COMPlusThrowOM(););
315 }
316 CONTRACTL_END;
317
318#ifdef _DEBUG
319 m_pCrstDebug = NULL;
320#endif
321}
322
323
324// Destructor for the LargeHeapHandleTable class.
325LargeHeapHandleTable::~LargeHeapHandleTable()
326{
327 CONTRACTL
328 {
329 NOTHROW;
330 GC_NOTRIGGER;
331 }
332 CONTRACTL_END;
333
334 // Delete the buckets.
335 while (m_pHead)
336 {
337 LargeHeapHandleBucket *pOld = m_pHead;
338 m_pHead = pOld->GetNext();
339 delete pOld;
340 }
341}
342
343//*****************************************************************************
344//
345// LOCKING RULES FOR AllocateHandles() and ReleaseHandles() 12/08/2004
346//
347//
348// These functions are not protected by any locking in this location but rather the callers are
349// assumed to be doing suitable locking for the handle table. The handle table itself is
350// behaving rather like a thread-agnostic collection class -- it doesn't want to know
351// much about the outside world and so it is just doing its job with no awareness of
352// thread notions.
353//
354// The instance in question is
355// There are two locations you can find a LargeHeapHandleTable
356// 1) there is one in every BaseDomain, it is used to keep track of the static members
357// in that domain
358// 2) there is one in the System Domain that is used for the GlobalStringLiteralMap
359//
360// the one in (2) is not the same as the one that is in the BaseDomain object that corresponds
361// to the SystemDomain -- that one is basically stilborn because the string literals don't go
362// there and of course the System Domain has no code loaded into it -- only regular
363// AppDomains (like Domain 0) actually execute code. As a result handle tables are in
364// practice used either for string literals or for static members but never for both.
365// At least not at this writing.
366//
367// Now it's useful to consider what the locking discipline is for these classes.
368//
369// ---------
370//
371// First case: (easiest) is the statics members
372//
373// Each BaseDomain has its own critical section
374//
375// BaseDomain::AllocateObjRefPtrsInLargeTable takes a lock with
376// CrstHolder ch(&m_LargeHeapHandleTableCrst);
377//
378// it does this before it calls AllocateHandles which suffices. It does not call ReleaseHandles
379// at any time (although ReleaseHandles may be called via AllocateHandles if the request
380// doesn't fit in the current block, the remaining handles at the end of the block are released
381// automatically as part of allocation/recycling)
382//
383// note: Recycled handles are only used during String Literal allocation because we only try
384// to recycle handles if the allocation request is for exactly one handle.
385//
386// The handles in the BaseDomain handle table are released when the Domain is unloaded
387// as the GC objects become rootless at that time.
388//
389// This dispenses with all of the Handle tables except the one that is used for string literals
390//
391// ---------
392//
393// Second case: Allocation for use in a string literal
394//
395// AppDomainStringLiteralMap::GetStringLiteral
396// leads to calls to
397// LargeHeapHandleBlockHolder constructor
398// leads to calls to
399// m_Data = pOwner->AllocateHandles(nCount);
400//
401// before doing this AppDomainStringLiteralMap::GetStringLiteral takes this lock
402//
403// CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
404//
405// which is the lock for the hash table that it owns
406//
407// STRINGREF *AppDomainStringLiteralMap::GetInternedString
408//
409// has a similar call path and uses the same approach and the same lock
410// this covers all the paths which allocate
411//
412// ---------
413//
414// Third case: Releases for use in a string literal entry
415//
416// CrstHolder gch(&(SystemDomain::GetGlobalStringLiteralMap()->m_HashTableCrstGlobal));
417// taken in the AppDomainStringLiteralMap functions below protects the 4 ways that this can happen
418//
419// case 3a)
420//
421// in an appdomain unload case
422//
423// AppDomainStringLiteralMap::~AppDomainStringLiteralMap() takes the lock then
424// leads to calls to
425// StringLiteralEntry::Release
426// which leads to
427// SystemDomain::GetGlobalStringLiteralMapNoCreate()->RemoveStringLiteralEntry(this)
428// which leads to
429// m_LargeHeapHandleTable.ReleaseHandles((OBJECTREF*)pObjRef, 1);
430//
431// case 3b)
432//
433// AppDomainStringLiteralMap::GetStringLiteral() can call StringLiteralEntry::Release in some
434// error cases, leading to the same stack as above
435//
436// case 3c)
437//
438// AppDomainStringLiteralMap::GetInternedString() can call StringLiteralEntry::Release in some
439// error cases, leading to the same stack as above
440//
441// case 3d)
442//
443// The same code paths in 3b and 3c and also end up releasing if an exception is thrown
444// during their processing. Both these paths use a StringLiteralEntryHolder to assist in cleanup,
445// the StaticRelease method of the StringLiteralEntry gets called, which in turn calls the
446// Release method.
447
448
449// Allocate handles from the large heap handle table.
450OBJECTREF* LargeHeapHandleTable::AllocateHandles(DWORD nRequested, BOOL bCrossAD)
451{
452 CONTRACTL
453 {
454 THROWS;
455 GC_TRIGGERS;
456 MODE_COOPERATIVE;
457 PRECONDITION(nRequested > 0);
458 INJECT_FAULT(COMPlusThrowOM(););
459 }
460 CONTRACTL_END;
461
462 // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
463
464 // the lock must be registered and already held by the caller per contract
465#ifdef _DEBUG
466 _ASSERTE(m_pCrstDebug != NULL);
467 _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
468#endif
469
470 if (nRequested == 1 && m_cEmbeddedFree != 0)
471 {
472 // special casing singleton requests to look for slots that can be re-used
473
474 // we need to do this because string literals are allocated one at a time and then sometimes
475 // released. we do not wish for the number of handles consumed by string literals to
476 // increase forever as assemblies are loaded and unloaded
477
478 if (m_pFreeSearchHint == NULL)
479 m_pFreeSearchHint = m_pHead;
480
481 while (m_pFreeSearchHint)
482 {
483 OBJECTREF* pObjRef = m_pFreeSearchHint->TryAllocateEmbeddedFreeHandle();
484 if (pObjRef != NULL)
485 {
486 // the slot is to have been prepared with a null ready to go
487 _ASSERTE(*pObjRef == NULL);
488 m_cEmbeddedFree--;
489 return pObjRef;
490 }
491 m_pFreeSearchHint = m_pFreeSearchHint->GetNext();
492 }
493
494 // the search doesn't wrap around so it's possible that we might have embedded free items
495 // and not find them but that's ok, we'll get them on the next alloc... all we're trying to do
496 // is to not have big leaks over time.
497 }
498
499
500 // Retrieve the remaining number of handles in the bucket.
501 DWORD NumRemainingHandlesInBucket = (m_pHead != NULL) ? m_pHead->GetNumRemainingHandles() : 0;
502
503 // create a new block if this request doesn't fit in the current block
504 if (nRequested > NumRemainingHandlesInBucket)
505 {
506 if (m_pHead != NULL)
507 {
508 // mark the handles in that remaining region as available for re-use
509 ReleaseHandles(m_pHead->CurrentPos(), NumRemainingHandlesInBucket);
510
511 // mark what's left as having been used
512 m_pHead->ConsumeRemaining();
513 }
514
515 // create a new bucket for this allocation
516
517 // We need a block big enough to hold the requested handles
518 DWORD NewBucketSize = max(m_NextBucketSize, nRequested);
519
520 m_pHead = new LargeHeapHandleBucket(m_pHead, NewBucketSize, m_pDomain, bCrossAD);
521
522 m_NextBucketSize = min(m_NextBucketSize * 2, MAX_BUCKETSIZE);
523 }
524
525 return m_pHead->AllocateHandles(nRequested);
526}
527
528//*****************************************************************************
529// Release object handles allocated using AllocateHandles().
530void LargeHeapHandleTable::ReleaseHandles(OBJECTREF *pObjRef, DWORD nReleased)
531{
532 CONTRACTL
533 {
534 NOTHROW;
535 GC_NOTRIGGER;
536 MODE_COOPERATIVE;
537 PRECONDITION(CheckPointer(pObjRef));
538 }
539 CONTRACTL_END;
540
541 // SEE "LOCKING RULES FOR AllocateHandles() and ReleaseHandles()" above
542
543 // the lock must be registered and already held by the caller per contract
544#ifdef _DEBUG
545 _ASSERTE(m_pCrstDebug != NULL);
546 _ASSERTE(m_pCrstDebug->OwnedByCurrentThread());
547#endif
548
549 OBJECTREF pPreallocatedSentinalObject = ObjectFromHandle(g_pPreallocatedSentinelObject);
550 _ASSERTE(pPreallocatedSentinalObject != NULL);
551
552
553 // Add the released handles to the list of available handles.
554 for (DWORD i = 0; i < nReleased; i++)
555 {
556 SetObjectReference(&pObjRef[i], pPreallocatedSentinalObject, NULL);
557 }
558
559 m_cEmbeddedFree += nReleased;
560}
561
562
563
564
565// Constructor for the ThreadStaticHandleBucket class.
566ThreadStaticHandleBucket::ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain)
567: m_pNext(pNext)
568, m_ArraySize(Size)
569{
570 CONTRACTL
571 {
572 THROWS;
573 GC_TRIGGERS;
574 MODE_COOPERATIVE;
575 PRECONDITION(CheckPointer(pDomain));
576 INJECT_FAULT(COMPlusThrowOM(););
577 }
578 CONTRACTL_END;
579
580 PTRARRAYREF HandleArrayObj;
581
582 // Allocate the array on the GC heap.
583 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
584 HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass, FALSE);
585
586 // Store the array in a strong handle to keep it alive.
587 m_hndHandleArray = pDomain->CreateStrongHandle((OBJECTREF)HandleArrayObj);
588}
589
590// Destructor for the ThreadStaticHandleBucket class.
591ThreadStaticHandleBucket::~ThreadStaticHandleBucket()
592{
593 CONTRACTL
594 {
595 NOTHROW;
596 GC_NOTRIGGER;
597 MODE_COOPERATIVE;
598 }
599 CONTRACTL_END;
600
601 if (m_hndHandleArray)
602 {
603 DestroyStrongHandle(m_hndHandleArray);
604 m_hndHandleArray = NULL;
605 }
606}
607
608// Allocate handles from the bucket.
609OBJECTHANDLE ThreadStaticHandleBucket::GetHandles()
610{
611 CONTRACTL
612 {
613 NOTHROW;
614 GC_NOTRIGGER;
615 MODE_COOPERATIVE;
616 }
617 CONTRACTL_END;
618
619 return m_hndHandleArray;
620}
621
622// Constructor for the ThreadStaticHandleTable class.
623ThreadStaticHandleTable::ThreadStaticHandleTable(BaseDomain *pDomain)
624: m_pHead(NULL)
625, m_pDomain(pDomain)
626{
627 CONTRACTL
628 {
629 NOTHROW;
630 GC_NOTRIGGER;
631 MODE_ANY;
632 PRECONDITION(CheckPointer(pDomain));
633 }
634 CONTRACTL_END;
635}
636
637// Destructor for the ThreadStaticHandleTable class.
638ThreadStaticHandleTable::~ThreadStaticHandleTable()
639{
640 CONTRACTL
641 {
642 NOTHROW;
643 GC_NOTRIGGER;
644 }
645 CONTRACTL_END;
646
647 // Delete the buckets.
648 while (m_pHead)
649 {
650 ThreadStaticHandleBucket *pOld = m_pHead;
651 m_pHead = pOld->GetNext();
652 delete pOld;
653 }
654}
655
656// Allocate handles from the large heap handle table.
657OBJECTHANDLE ThreadStaticHandleTable::AllocateHandles(DWORD nRequested)
658{
659 CONTRACTL
660 {
661 THROWS;
662 GC_TRIGGERS;
663 MODE_COOPERATIVE;
664 PRECONDITION(nRequested > 0);
665 INJECT_FAULT(COMPlusThrowOM(););
666 }
667 CONTRACTL_END;
668
669 // create a new bucket for this allocation
670 m_pHead = new ThreadStaticHandleBucket(m_pHead, nRequested, m_pDomain);
671
672 return m_pHead->GetHandles();
673}
674
675#endif // CROSSGEN_COMPILE
676
677
678//*****************************************************************************
679// BaseDomain
680//*****************************************************************************
681void BaseDomain::Attach()
682{
683 m_SpecialStaticsCrst.Init(CrstSpecialStatics);
684}
685
686BaseDomain::BaseDomain()
687{
688 // initialize fields so the domain can be safely destructed
689 // shouldn't call anything that can fail here - use ::Init instead
690 CONTRACTL
691 {
692 THROWS;
693 GC_TRIGGERS;
694 MODE_ANY;
695 FORBID_FAULT;
696 }
697 CONTRACTL_END;
698
699 m_fDisableInterfaceCache = FALSE;
700
701 m_pFusionContext = NULL;
702 m_pTPABinderContext = NULL;
703
704 // Make sure the container is set to NULL so that it gets loaded when it is used.
705 m_pLargeHeapHandleTable = NULL;
706
707#ifndef CROSSGEN_COMPILE
708 // Note that m_handleStore is overridden by app domains
709 m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
710#else
711 m_handleStore = NULL;
712#endif
713
714 m_pMarshalingData = NULL;
715
716#ifdef FEATURE_COMINTEROP
717 m_pMngStdInterfacesInfo = NULL;
718 m_pWinRtBinder = NULL;
719#endif
720 m_FileLoadLock.PreInit();
721 m_JITLock.PreInit();
722 m_ClassInitLock.PreInit();
723 m_ILStubGenLock.PreInit();
724
725#ifdef FEATURE_CODE_VERSIONING
726 m_codeVersionManager.PreInit();
727#endif
728
729} //BaseDomain::BaseDomain
730
731//*****************************************************************************
732void BaseDomain::Init()
733{
734 CONTRACTL
735 {
736 THROWS;
737 GC_TRIGGERS;
738 MODE_ANY;
739 INJECT_FAULT(COMPlusThrowOM(););
740 }
741 CONTRACTL_END;
742
743 //
744 // Initialize the domain locks
745 //
746
747 if (this == reinterpret_cast<BaseDomain*>(&g_pSystemDomainMemory[0]))
748 m_DomainCrst.Init(CrstSystemBaseDomain);
749 else
750 m_DomainCrst.Init(CrstBaseDomain);
751
752 m_DomainCacheCrst.Init(CrstAppDomainCache);
753 m_DomainLocalBlockCrst.Init(CrstDomainLocalBlock);
754
755 m_InteropDataCrst.Init(CrstInteropData, CRST_REENTRANCY);
756
757 m_WinRTFactoryCacheCrst.Init(CrstWinRTFactoryCache, CRST_UNSAFE_COOPGC);
758
759 // NOTE: CRST_UNSAFE_COOPGC prevents a GC mode switch to preemptive when entering this crst.
760 // If you remove this flag, we will switch to preemptive mode when entering
761 // m_FileLoadLock, which means all functions that enter it will become
762 // GC_TRIGGERS. (This includes all uses of PEFileListLockHolder, LoadLockHolder, etc.) So be sure
763 // to update the contracts if you remove this flag.
764 m_FileLoadLock.Init(CrstAssemblyLoader,
765 CrstFlags(CRST_HOST_BREAKABLE), TRUE);
766
767 //
768 // The JIT lock and the CCtor locks are at the same level (and marked as
769 // UNSAFE_SAME_LEVEL) because they are all part of the same deadlock detection mechanism. We
770 // see through cycles of JITting and .cctor execution and then explicitly allow the cycle to
771 // be broken by giving access to uninitialized classes. If there is no cycle or if the cycle
772 // involves other locks that arent part of this special deadlock-breaking semantics, then
773 // we continue to block.
774 //
775 m_JITLock.Init(CrstJit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
776 m_ClassInitLock.Init(CrstClassInit, CrstFlags(CRST_REENTRANCY | CRST_UNSAFE_SAMELEVEL), TRUE);
777
778 m_ILStubGenLock.Init(CrstILStubGen, CrstFlags(CRST_REENTRANCY), TRUE);
779
780 // Large heap handle table CRST.
781 m_LargeHeapHandleTableCrst.Init(CrstAppDomainHandleTable);
782
783 m_crstLoaderAllocatorReferences.Init(CrstLoaderAllocatorReferences);
784 // Has to switch thread to GC_NOTRIGGER while being held (see code:BaseDomain#AssemblyListLock)
785 m_crstAssemblyList.Init(CrstAssemblyList, CrstFlags(
786 CRST_GC_NOTRIGGER_WHEN_TAKEN | CRST_DEBUGGER_THREAD | CRST_TAKEN_DURING_SHUTDOWN));
787
788 // Initialize the EE marshaling data to NULL.
789 m_pMarshalingData = NULL;
790
791#ifdef FEATURE_COMINTEROP
792 // Allocate the managed standard interfaces information.
793 m_pMngStdInterfacesInfo = new MngStdInterfacesInfo();
794
795 {
796 CLRPrivBinderWinRT::NamespaceResolutionKind fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_WindowsAPI;
797 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DesignerNamespaceResolutionEnabled) != FALSE)
798 {
799 fNamespaceResolutionKind = CLRPrivBinderWinRT::NamespaceResolutionKind_DesignerResolveEvent;
800 }
801 CLRPrivTypeCacheWinRT * pWinRtTypeCache = CLRPrivTypeCacheWinRT::GetOrCreateTypeCache();
802 m_pWinRtBinder = CLRPrivBinderWinRT::GetOrCreateBinder(pWinRtTypeCache, fNamespaceResolutionKind);
803 }
804#endif // FEATURE_COMINTEROP
805
806 // Init the COM Interop data hash
807 {
808 LockOwner lock = {&m_InteropDataCrst, IsOwnerOfCrst};
809 m_interopDataHash.Init(0, NULL, false, &lock);
810 }
811
812 m_dwSizedRefHandles = 0;
813 if (!m_iNumberOfProcessors)
814 {
815 m_iNumberOfProcessors = GetCurrentProcessCpuCount();
816 }
817}
818
819#undef LOADERHEAP_PROFILE_COUNTER
820
821#ifndef CROSSGEN_COMPILE
822//*****************************************************************************
823void BaseDomain::Terminate()
824{
825 CONTRACTL
826 {
827 NOTHROW;
828 GC_TRIGGERS;
829 MODE_ANY;
830 }
831 CONTRACTL_END;
832
833 m_crstLoaderAllocatorReferences.Destroy();
834 m_DomainCrst.Destroy();
835 m_DomainCacheCrst.Destroy();
836 m_DomainLocalBlockCrst.Destroy();
837 m_InteropDataCrst.Destroy();
838
839 JitListLockEntry* pJitElement;
840 ListLockEntry* pElement;
841
842 // All the threads that are in this domain had better be stopped by this
843 // point.
844 //
845 // We might be jitting or running a .cctor so we need to empty that queue.
846 pJitElement = m_JITLock.Pop(TRUE);
847 while (pJitElement)
848 {
849#ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
850 _ASSERTE ((m_JITLock.m_pHead->m_dwRefCount == 1
851 && m_JITLock.m_pHead->m_hrResultCode == E_FAIL) ||
852 dbg_fDrasticShutdown || g_fInControlC);
853#endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
854 delete(pJitElement);
855 pJitElement = m_JITLock.Pop(TRUE);
856
857 }
858 m_JITLock.Destroy();
859
860 pElement = m_ClassInitLock.Pop(TRUE);
861 while (pElement)
862 {
863#ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
864 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
865#endif
866 delete(pElement);
867 pElement = m_ClassInitLock.Pop(TRUE);
868 }
869 m_ClassInitLock.Destroy();
870
871 FileLoadLock* pFileElement;
872 pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
873 while (pFileElement)
874 {
875#ifdef STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
876 _ASSERTE (dbg_fDrasticShutdown || g_fInControlC);
877#endif
878 pFileElement->Release();
879 pFileElement = (FileLoadLock*) m_FileLoadLock.Pop(TRUE);
880 }
881 m_FileLoadLock.Destroy();
882
883 pElement = m_ILStubGenLock.Pop(TRUE);
884 while (pElement)
885 {
886#ifdef STRICT_JITLOCK_ENTRY_LEAK_DETECTION
887 _ASSERTE ((m_ILStubGenLock.m_pHead->m_dwRefCount == 1
888 && m_ILStubGenLock.m_pHead->m_hrResultCode == E_FAIL) ||
889 dbg_fDrasticShutdown || g_fInControlC);
890#endif // STRICT_JITLOCK_ENTRY_LEAK_DETECTION
891 delete(pElement);
892 pElement = m_ILStubGenLock.Pop(TRUE);
893 }
894 m_ILStubGenLock.Destroy();
895
896 m_LargeHeapHandleTableCrst.Destroy();
897
898 if (m_pLargeHeapHandleTable != NULL)
899 {
900 delete m_pLargeHeapHandleTable;
901 m_pLargeHeapHandleTable = NULL;
902 }
903
904 if (!IsAppDomain())
905 {
906 // Kind of a workaround - during unloading, we need to have an EE halt
907 // around deleting this stuff. So it gets deleted in AppDomain::Terminate()
908 // for those things (because there is a convenient place there.)
909 GetLoaderAllocator()->CleanupStringLiteralMap();
910 }
911
912#ifdef FEATURE_COMINTEROP
913 if (m_pMngStdInterfacesInfo)
914 {
915 delete m_pMngStdInterfacesInfo;
916 m_pMngStdInterfacesInfo = NULL;
917 }
918
919 if (m_pWinRtBinder != NULL)
920 {
921 m_pWinRtBinder->Release();
922 }
923#endif // FEATURE_COMINTEROP
924
925 ClearFusionContext();
926
927 m_dwSizedRefHandles = 0;
928}
929#endif // CROSSGEN_COMPILE
930
931void BaseDomain::InitVSD()
932{
933 STANDARD_VM_CONTRACT;
934
935 // This is a workaround for gcc, since it fails to successfully resolve
936 // "TypeIDMap::STARTING_SHARED_DOMAIN_ID" when used within the ?: operator.
937 UINT32 startingId;
938 if (IsSharedDomain())
939 {
940 startingId = TypeIDMap::STARTING_SHARED_DOMAIN_ID;
941 }
942 else
943 {
944 startingId = TypeIDMap::STARTING_UNSHARED_DOMAIN_ID;
945 }
946
947 // By passing false as the last parameter, interfaces loaded in the
948 // shared domain will not be given fat type ids if RequiresFatDispatchTokens
949 // is set. This is correct, as the fat dispatch tokens are only needed to solve
950 // uniqueness problems involving domain specific types.
951 m_typeIDMap.Init(startingId, 2, !IsSharedDomain());
952
953#ifndef CROSSGEN_COMPILE
954 GetLoaderAllocator()->InitVirtualCallStubManager(this);
955#endif
956}
957
958#ifndef CROSSGEN_COMPILE
959
960void BaseDomain::ClearFusionContext()
961{
962 CONTRACTL
963 {
964 NOTHROW;
965 GC_TRIGGERS;
966 MODE_PREEMPTIVE;
967 }
968 CONTRACTL_END;
969
970 if(m_pFusionContext) {
971 m_pFusionContext->Release();
972 m_pFusionContext = NULL;
973 }
974 if (m_pTPABinderContext) {
975 m_pTPABinderContext->Release();
976 m_pTPABinderContext = NULL;
977 }
978}
979
980#ifdef FEATURE_PREJIT
981void AppDomain::DeleteNativeCodeRanges()
982{
983 CONTRACTL
984 {
985 NOTHROW;
986 GC_NOTRIGGER;
987 MODE_PREEMPTIVE;
988 FORBID_FAULT;
989 }
990 CONTRACTL_END;
991
992 // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized
993 // and yet we are destroying it. (This is the case if we OOM during AppDomain creation.)
994 if (m_Assemblies.IsEmpty())
995 return;
996
997 // Shutdown assemblies
998 AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeFailedToLoad) );
999 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1000
1001 while (i.Next(pDomainAssembly.This()))
1002 {
1003 Assembly * assembly = pDomainAssembly->m_pAssembly;
1004 if ((assembly != NULL))
1005 assembly->DeleteNativeCodeRanges();
1006 }
1007}
1008#endif
1009
1010void AppDomain::ShutdownAssemblies()
1011{
1012 CONTRACTL
1013 {
1014 NOTHROW;
1015 GC_TRIGGERS;
1016 MODE_ANY;
1017 }
1018 CONTRACTL_END;
1019
1020 // Fast path to skip using the assembly iterator when the appdomain has not yet completely been initialized
1021 // and yet we are destroying it. (This is the case if we OOM during AppDomain creation.)
1022 if (m_Assemblies.IsEmpty())
1023 return;
1024
1025 // Shutdown assemblies
1026 // has two stages because Terminate needs info from the Assembly's dependencies
1027
1028 // Stage 1: call code:Assembly::Terminate
1029 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1030 kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeFailedToLoad | kIncludeCollected));
1031 DomainAssembly * pDomainAssembly = NULL;
1032
1033 while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1034 {
1035 // Note: cannot use DomainAssembly::GetAssembly() here as it asserts that the assembly has been
1036 // loaded to at least the FILE_LOAD_ALLOCATE level. Since domain shutdown can take place
1037 // asynchronously this property cannot be guaranteed. Access the m_pAssembly field directly instead.
1038 Assembly * assembly = pDomainAssembly->m_pAssembly;
1039 if (assembly)
1040 assembly->Terminate();
1041 }
1042
1043 // Stage 2: Clear the list of assemblies
1044 i = IterateAssembliesEx((AssemblyIterationFlags)(
1045 kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeFailedToLoad | kIncludeCollected));
1046 while (i.Next_UnsafeNoAddRef(&pDomainAssembly))
1047 {
1048 // We are in shutdown path, no one else can get to the list anymore
1049 delete pDomainAssembly;
1050 }
1051 m_Assemblies.Clear(this);
1052
1053 // Stage 2: Clear the loader allocators registered for deletion from code:Assembly:Terminate calls in
1054 // stage 1
1055 // Note: It is not clear to me why we cannot delete the loader allocator from within
1056 // code:DomainAssembly::~DomainAssembly
1057 ShutdownFreeLoaderAllocators(FALSE);
1058} // AppDomain::ShutdownAssemblies
1059
1060void AppDomain::ShutdownFreeLoaderAllocators(BOOL bFromManagedCode)
1061{
1062 // If we're called from managed code (i.e. the finalizer thread) we take a lock in
1063 // LoaderAllocator::CleanupFailedTypeInit, which may throw. Otherwise we're called
1064 // from the app-domain shutdown path in which we can avoid taking the lock.
1065 CONTRACTL
1066 {
1067 GC_TRIGGERS;
1068 if (bFromManagedCode) THROWS; else NOTHROW;
1069 MODE_ANY;
1070 CAN_TAKE_LOCK;
1071 }
1072 CONTRACTL_END;
1073
1074 CrstHolder ch(GetLoaderAllocatorReferencesLock());
1075
1076 // Shutdown the LoaderAllocators associated with collectible assemblies
1077 while (m_pDelayedLoaderAllocatorUnloadList != NULL)
1078 {
1079 LoaderAllocator * pCurrentLoaderAllocator = m_pDelayedLoaderAllocatorUnloadList;
1080 // Remove next loader allocator from the list
1081 m_pDelayedLoaderAllocatorUnloadList = m_pDelayedLoaderAllocatorUnloadList->m_pLoaderAllocatorDestroyNext;
1082
1083 if (bFromManagedCode)
1084 {
1085 // For loader allocator finalization, we need to be careful about cleaning up per-appdomain allocations
1086 // and synchronizing with GC using delay unload list. We need to wait for next Gen2 GC to finish to ensure
1087 // that GC heap does not have any references to the MethodTables being unloaded.
1088
1089 pCurrentLoaderAllocator->CleanupFailedTypeInit();
1090
1091 pCurrentLoaderAllocator->CleanupHandles();
1092
1093 GCX_COOP();
1094 SystemDomain::System()->AddToDelayedUnloadList(pCurrentLoaderAllocator);
1095 }
1096 else
1097 {
1098 // For appdomain unload, delete the loader allocator right away
1099 delete pCurrentLoaderAllocator;
1100 }
1101 }
1102} // AppDomain::ShutdownFreeLoaderAllocators
1103
1104//---------------------------------------------------------------------------------------
1105//
1106// Register the loader allocator for deletion in code:AppDomain::ShutdownFreeLoaderAllocators.
1107//
1108void AppDomain::RegisterLoaderAllocatorForDeletion(LoaderAllocator * pLoaderAllocator)
1109{
1110 CONTRACTL
1111 {
1112 GC_TRIGGERS;
1113 NOTHROW;
1114 MODE_ANY;
1115 CAN_TAKE_LOCK;
1116 }
1117 CONTRACTL_END;
1118
1119 CrstHolder ch(GetLoaderAllocatorReferencesLock());
1120
1121 pLoaderAllocator->m_pLoaderAllocatorDestroyNext = m_pDelayedLoaderAllocatorUnloadList;
1122 m_pDelayedLoaderAllocatorUnloadList = pLoaderAllocator;
1123}
1124
1125void AppDomain::SetNativeDllSearchDirectories(LPCWSTR wszNativeDllSearchDirectories)
1126{
1127 STANDARD_VM_CONTRACT;
1128
1129 SString sDirectories(wszNativeDllSearchDirectories);
1130
1131 if (sDirectories.GetCount() > 0)
1132 {
1133 SString::CIterator start = sDirectories.Begin();
1134 SString::CIterator itr = sDirectories.Begin();
1135 SString::CIterator end = sDirectories.End();
1136 SString qualifiedPath;
1137
1138 while (itr != end)
1139 {
1140 start = itr;
1141 BOOL found = sDirectories.Find(itr, PATH_SEPARATOR_CHAR_W);
1142 if (!found)
1143 {
1144 itr = end;
1145 }
1146
1147 SString qualifiedPath(sDirectories, start, itr);
1148
1149 if (found)
1150 {
1151 itr++;
1152 }
1153
1154 unsigned len = qualifiedPath.GetCount();
1155
1156 if (len > 0)
1157 {
1158 if (qualifiedPath[len - 1] != DIRECTORY_SEPARATOR_CHAR_W)
1159 {
1160 qualifiedPath.Append(DIRECTORY_SEPARATOR_CHAR_W);
1161 }
1162
1163 NewHolder<SString> stringHolder(new SString(qualifiedPath));
1164 IfFailThrow(m_NativeDllSearchDirectories.Append(stringHolder.GetValue()));
1165 stringHolder.SuppressRelease();
1166 }
1167 }
1168 }
1169}
1170
1171void AppDomain::ShutdownNativeDllSearchDirectories()
1172{
1173 LIMITED_METHOD_CONTRACT;
1174 // Shutdown assemblies
1175 PathIterator i = IterateNativeDllSearchDirectories();
1176
1177 while (i.Next())
1178 {
1179 delete i.GetPath();
1180 }
1181
1182 m_NativeDllSearchDirectories.Clear();
1183}
1184
1185void AppDomain::ReleaseDomainBoundInfo()
1186{
1187 CONTRACTL
1188 {
1189 NOTHROW;
1190 GC_TRIGGERS;
1191 MODE_ANY;
1192 }
1193 CONTRACTL_END;;
1194 // Shutdown assemblies
1195 m_AssemblyCache.OnAppDomainUnload();
1196
1197 AssemblyIterator i = IterateAssembliesEx( (AssemblyIterationFlags)(kIncludeFailedToLoad) );
1198 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1199
1200 while (i.Next(pDomainAssembly.This()))
1201 {
1202 pDomainAssembly->ReleaseManagedData();
1203 }
1204}
1205
1206void AppDomain::ReleaseFiles()
1207{
1208 STANDARD_VM_CONTRACT;
1209
1210 // Shutdown assemblies
1211 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
1212 kIncludeLoaded | kIncludeExecution | kIncludeFailedToLoad | kIncludeLoading));
1213 CollectibleAssemblyHolder<DomainAssembly *> pAsm;
1214
1215 while (i.Next(pAsm.This()))
1216 {
1217 if (pAsm->GetCurrentAssembly() == NULL)
1218 {
1219 // Might be domain neutral or not, but should have no live objects as it has not been
1220 // really loaded yet. Just reset it.
1221 _ASSERTE(FitsIn<DWORD>(i.GetIndex()));
1222 m_Assemblies.Set(this, static_cast<DWORD>(i.GetIndex()), NULL);
1223 delete pAsm.Extract();
1224 }
1225 else
1226 {
1227 pAsm->ReleaseFiles();
1228 }
1229 }
1230} // AppDomain::ReleaseFiles
1231
1232
1233OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate, BOOL bCrossAD)
1234{
1235 CONTRACTL
1236 {
1237 THROWS;
1238 GC_TRIGGERS;
1239 MODE_ANY;
1240 PRECONDITION((nRequested > 0));
1241 INJECT_FAULT(COMPlusThrowOM(););
1242 }
1243 CONTRACTL_END;
1244
1245 if (ppLazyAllocate && *ppLazyAllocate)
1246 {
1247 // Allocation already happened
1248 return *ppLazyAllocate;
1249 }
1250
1251 // Enter preemptive state, take the lock and go back to cooperative mode.
1252 {
1253 CrstHolder ch(&m_LargeHeapHandleTableCrst);
1254 GCX_COOP();
1255
1256 if (ppLazyAllocate && *ppLazyAllocate)
1257 {
1258 // Allocation already happened
1259 return *ppLazyAllocate;
1260 }
1261
1262 // Make sure the large heap handle table is initialized.
1263 if (!m_pLargeHeapHandleTable)
1264 InitLargeHeapHandleTable();
1265
1266 // Allocate the handles.
1267 OBJECTREF* result = m_pLargeHeapHandleTable->AllocateHandles(nRequested, bCrossAD);
1268
1269 if (ppLazyAllocate)
1270 {
1271 *ppLazyAllocate = result;
1272 }
1273
1274 return result;
1275 }
1276}
1277#endif // CROSSGEN_COMPILE
1278
1279#endif // !DACCESS_COMPILE
1280
1281#ifndef DACCESS_COMPILE
1282
1283// Insert class in the hash table
1284void AppDomain::InsertClassForCLSID(MethodTable* pMT, BOOL fForceInsert /*=FALSE*/)
1285{
1286 CONTRACTL
1287 {
1288 GC_TRIGGERS;
1289 MODE_ANY;
1290 THROWS;
1291 INJECT_FAULT(COMPlusThrowOM(););
1292 }
1293 CONTRACTL_END;
1294
1295 CVID cvid;
1296
1297 // Ensure that registered classes are activated for allocation
1298 pMT->EnsureInstanceActive();
1299
1300 // Note that it is possible for multiple classes to claim the same CLSID, and in such a
1301 // case it is arbitrary which one we will return for a future query for a given app domain.
1302
1303 pMT->GetGuid(&cvid, fForceInsert);
1304
1305 if (!IsEqualIID(cvid, GUID_NULL))
1306 {
1307 //<TODO>@todo get a better key</TODO>
1308 LPVOID val = (LPVOID)pMT;
1309 {
1310 LockHolder lh(this);
1311
1312 if (LookupClass(cvid) != pMT)
1313 {
1314 m_clsidHash.InsertValue(GetKeyFromGUID(&cvid), val);
1315 }
1316 }
1317 }
1318}
1319
1320void AppDomain::InsertClassForCLSID(MethodTable* pMT, GUID *pGuid)
1321{
1322 CONTRACT_VOID
1323 {
1324 NOTHROW;
1325 PRECONDITION(CheckPointer(pMT));
1326 PRECONDITION(CheckPointer(pGuid));
1327 }
1328 CONTRACT_END;
1329
1330 LPVOID val = (LPVOID)pMT;
1331 {
1332 LockHolder lh(this);
1333
1334 CVID* cvid = pGuid;
1335 if (LookupClass(*cvid) != pMT)
1336 {
1337 m_clsidHash.InsertValue(GetKeyFromGUID(pGuid), val);
1338 }
1339 }
1340
1341 RETURN;
1342}
1343#endif // DACCESS_COMPILE
1344
1345#ifdef FEATURE_COMINTEROP
1346
1347#ifndef DACCESS_COMPILE
1348void AppDomain::CacheTypeByName(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1349{
1350 WRAPPER_NO_CONTRACT;
1351 LockHolder lh(this);
1352 CacheTypeByNameWorker(ssClassName, vCacheVersion, typeHandle, bFlags, bReplaceExisting);
1353}
1354
1355void AppDomain::CacheTypeByNameWorker(const SString &ssClassName, const UINT vCacheVersion, TypeHandle typeHandle, BYTE bFlags, BOOL bReplaceExisting /*= FALSE*/)
1356{
1357 CONTRACTL
1358 {
1359 THROWS;
1360 GC_TRIGGERS;
1361 PRECONDITION(!typeHandle.IsNull());
1362 }
1363 CONTRACTL_END;
1364
1365 NewArrayHolder<WCHAR> wzClassName(DuplicateStringThrowing(ssClassName.GetUnicode()));
1366
1367 if (m_vNameToTypeMapVersion != vCacheVersion)
1368 return;
1369
1370 if (m_pNameToTypeMap == nullptr)
1371 {
1372 m_pNameToTypeMap = new NameToTypeMapTable();
1373 }
1374
1375 NameToTypeMapEntry e;
1376 e.m_key.m_wzName = wzClassName;
1377 e.m_key.m_cchName = ssClassName.GetCount();
1378 e.m_typeHandle = typeHandle;
1379 e.m_nEpoch = this->m_nEpoch;
1380 e.m_bFlags = bFlags;
1381 if (!bReplaceExisting)
1382 m_pNameToTypeMap->Add(e);
1383 else
1384 m_pNameToTypeMap->AddOrReplace(e);
1385
1386 wzClassName.SuppressRelease();
1387}
1388#endif // DACCESS_COMPILE
1389
1390TypeHandle AppDomain::LookupTypeByName(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1391{
1392 WRAPPER_NO_CONTRACT;
1393 LockHolder lh(this);
1394 return LookupTypeByNameWorker(ssClassName, pvCacheVersion, pbFlags);
1395}
1396
1397TypeHandle AppDomain::LookupTypeByNameWorker(const SString &ssClassName, UINT* pvCacheVersion, BYTE *pbFlags)
1398{
1399 CONTRACTL
1400 {
1401 THROWS;
1402 GC_TRIGGERS;
1403 SUPPORTS_DAC;
1404 PRECONDITION(CheckPointer(pbFlags, NULL_OK));
1405 }
1406 CONTRACTL_END;
1407
1408 *pvCacheVersion = m_vNameToTypeMapVersion;
1409
1410 if (m_pNameToTypeMap == nullptr)
1411 return TypeHandle(); // a null TypeHandle
1412
1413 NameToTypeMapEntry::Key key;
1414 key.m_cchName = ssClassName.GetCount();
1415 key.m_wzName = ssClassName.GetUnicode();
1416
1417 const NameToTypeMapEntry * pEntry = m_pNameToTypeMap->LookupPtr(key);
1418 if (pEntry == NULL)
1419 return TypeHandle(); // a null TypeHandle
1420
1421 if (pbFlags != NULL)
1422 *pbFlags = pEntry->m_bFlags;
1423
1424 return pEntry->m_typeHandle;
1425}
1426
1427PTR_MethodTable AppDomain::LookupTypeByGuid(const GUID & guid)
1428{
1429 CONTRACTL
1430 {
1431 THROWS;
1432 GC_TRIGGERS;
1433 MODE_ANY;
1434 SUPPORTS_DAC;
1435 }
1436 CONTRACTL_END;
1437
1438 SString sGuid;
1439 {
1440 WCHAR wszGuid[64];
1441 GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1442 sGuid.Append(wszGuid);
1443 }
1444 UINT ver;
1445 TypeHandle th = LookupTypeByName(sGuid, &ver, NULL);
1446
1447 if (!th.IsNull())
1448 {
1449 _ASSERTE(!th.IsTypeDesc());
1450 return th.AsMethodTable();
1451 }
1452
1453#ifdef FEATURE_PREJIT
1454 else
1455 {
1456 // Next look in each ngen'ed image in turn
1457 AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1458 kIncludeLoaded | kIncludeExecution));
1459 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1460 while (assemblyIterator.Next(pDomainAssembly.This()))
1461 {
1462 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1463
1464 DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1465 while (i.Next())
1466 {
1467 Module * pModule = i.GetLoadedModule();
1468 if (!pModule->HasNativeImage())
1469 continue;
1470 _ASSERTE(!pModule->IsCollectible());
1471 PTR_MethodTable pMT = pModule->LookupTypeByGuid(guid);
1472 if (pMT != NULL)
1473 {
1474 return pMT;
1475 }
1476 }
1477 }
1478 }
1479#endif // FEATURE_PREJIT
1480 return NULL;
1481}
1482
1483#ifndef DACCESS_COMPILE
1484void AppDomain::CacheWinRTTypeByGuid(TypeHandle typeHandle)
1485{
1486 CONTRACTL
1487 {
1488 THROWS;
1489 GC_TRIGGERS;
1490 MODE_ANY;
1491 PRECONDITION(!typeHandle.IsTypeDesc());
1492 PRECONDITION(CanCacheWinRTTypeByGuid(typeHandle));
1493 }
1494 CONTRACTL_END;
1495
1496 PTR_MethodTable pMT = typeHandle.AsMethodTable();
1497
1498 GUID guid;
1499 if (pMT->GetGuidForWinRT(&guid))
1500 {
1501 SString sGuid;
1502
1503 {
1504 WCHAR wszGuid[64];
1505 GuidToLPWSTR(guid, wszGuid, _countof(wszGuid));
1506 sGuid.Append(wszGuid);
1507 }
1508
1509 BYTE bFlags = 0x80;
1510 TypeHandle th;
1511 UINT vCacheVersion;
1512 {
1513 LockHolder lh(this);
1514 th = LookupTypeByNameWorker(sGuid, &vCacheVersion, &bFlags);
1515
1516 if (th.IsNull())
1517 {
1518 // no other entry with the same GUID exists in the cache
1519 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags);
1520 }
1521 else if (typeHandle.AsMethodTable() != th.AsMethodTable() && th.IsProjectedFromWinRT())
1522 {
1523 // If we found a native WinRT type cached with the same GUID, replace it.
1524 // Otherwise simply add the new mapping to the cache.
1525 CacheTypeByNameWorker(sGuid, vCacheVersion, typeHandle, bFlags, TRUE);
1526 }
1527 }
1528 }
1529}
1530#endif // DACCESS_COMPILE
1531
1532void AppDomain::GetCachedWinRTTypes(
1533 SArray<PTR_MethodTable> * pTypes,
1534 SArray<GUID> * pGuids,
1535 UINT minEpoch,
1536 UINT * pCurEpoch)
1537{
1538 CONTRACTL
1539 {
1540 THROWS;
1541 GC_TRIGGERS;
1542 MODE_ANY;
1543 SUPPORTS_DAC;
1544 }
1545 CONTRACTL_END;
1546
1547 LockHolder lh(this);
1548
1549 for (auto it = m_pNameToTypeMap->Begin(), end = m_pNameToTypeMap->End();
1550 it != end;
1551 ++it)
1552 {
1553 NameToTypeMapEntry entry = (NameToTypeMapEntry)(*it);
1554 TypeHandle th = entry.m_typeHandle;
1555 if (th.AsMethodTable() != NULL &&
1556 entry.m_key.m_wzName[0] == W('{') &&
1557 entry.m_nEpoch >= minEpoch)
1558 {
1559 _ASSERTE(!th.IsTypeDesc());
1560 PTR_MethodTable pMT = th.AsMethodTable();
1561 // we're parsing the GUID value from the cache, because projected types do not cache the
1562 // COM GUID in their GetGuid() but rather the legacy GUID
1563 GUID iid;
1564 if (LPWSTRToGuid(&iid, entry.m_key.m_wzName, 38) && iid != GUID_NULL)
1565 {
1566 pTypes->Append(pMT);
1567 pGuids->Append(iid);
1568 }
1569 }
1570 }
1571
1572#ifdef FEATURE_PREJIT
1573 // Next look in each ngen'ed image in turn
1574 AssemblyIterator assemblyIterator = IterateAssembliesEx((AssemblyIterationFlags)(
1575 kIncludeLoaded | kIncludeExecution));
1576 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
1577 while (assemblyIterator.Next(pDomainAssembly.This()))
1578 {
1579 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
1580
1581 DomainAssembly::ModuleIterator i = pDomainAssembly->IterateModules(kModIterIncludeLoaded);
1582 while (i.Next())
1583 {
1584 Module * pModule = i.GetLoadedModule();
1585 if (!pModule->HasNativeImage())
1586 continue;
1587 _ASSERTE(!pModule->IsCollectible());
1588
1589 pModule->GetCachedWinRTTypes(pTypes, pGuids);
1590 }
1591 }
1592#endif // FEATURE_PREJIT
1593
1594 if (pCurEpoch != NULL)
1595 *pCurEpoch = m_nEpoch;
1596 ++m_nEpoch;
1597}
1598
1599#ifndef CROSSGEN_COMPILE
1600#ifndef DACCESS_COMPILE
1601// static
1602void WinRTFactoryCacheTraits::OnDestructPerEntryCleanupAction(const WinRTFactoryCacheEntry& e)
1603{
1604 WRAPPER_NO_CONTRACT;
1605 if (e.m_pCtxEntry != NULL)
1606 {
1607 e.m_pCtxEntry->Release();
1608 }
1609 // the AD is going away, no need to destroy the OBJECTHANDLE
1610}
1611
1612void AppDomain::CacheWinRTFactoryObject(MethodTable *pClassMT, OBJECTREF *refFactory, LPVOID lpCtxCookie)
1613{
1614 CONTRACTL
1615 {
1616 THROWS;
1617 GC_TRIGGERS;
1618 MODE_COOPERATIVE;
1619 PRECONDITION(CheckPointer(pClassMT));
1620 }
1621 CONTRACTL_END;
1622
1623 CtxEntryHolder pNewCtxEntry;
1624 if (lpCtxCookie != NULL)
1625 {
1626 // We don't want to insert the context cookie in the cache because it's just an address
1627 // of an internal COM data structure which will be freed when the apartment is torn down.
1628 // What's worse, if another apartment is later created, its context cookie may have exactly
1629 // the same value leading to incorrect cache hits. We'll use our CtxEntry instead which
1630 // is ref-counted and keeps the COM data structure alive even after the apartment ceases
1631 // to exist.
1632 pNewCtxEntry = CtxEntryCache::GetCtxEntryCache()->FindCtxEntry(lpCtxCookie, GetThread());
1633 }
1634
1635 WinRTFactoryCacheLockHolder lh(this);
1636
1637 if (m_pWinRTFactoryCache == nullptr)
1638 {
1639 m_pWinRTFactoryCache = new WinRTFactoryCache();
1640 }
1641
1642 WinRTFactoryCacheEntry *pEntry = const_cast<WinRTFactoryCacheEntry*>(m_pWinRTFactoryCache->LookupPtr(pClassMT));
1643 if (!pEntry)
1644 {
1645 //
1646 // No existing entry for this cache
1647 // Create a new one
1648 //
1649 WinRTFactoryCacheEntry e;
1650
1651 OBJECTHANDLEHolder ohNewHandle(CreateHandle(*refFactory));
1652
1653 e.key = pClassMT;
1654 e.m_pCtxEntry = pNewCtxEntry;
1655 e.m_ohFactoryObject = ohNewHandle;
1656
1657 m_pWinRTFactoryCache->Add(e);
1658
1659 // suppress release of the CtxEntry and handle after we successfully inserted the new entry
1660 pNewCtxEntry.SuppressRelease();
1661 ohNewHandle.SuppressRelease();
1662 }
1663 else
1664 {
1665 //
1666 // Existing entry
1667 //
1668 // release the old CtxEntry and update the entry
1669 CtxEntry *pTemp = pNewCtxEntry.Extract();
1670 pNewCtxEntry = pEntry->m_pCtxEntry;
1671 pEntry->m_pCtxEntry = pTemp;
1672
1673 IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
1674 mgr->StoreObjectInHandle(pEntry->m_ohFactoryObject, OBJECTREFToObject(*refFactory));
1675 }
1676}
1677
1678OBJECTREF AppDomain::LookupWinRTFactoryObject(MethodTable *pClassMT, LPVOID lpCtxCookie)
1679{
1680 CONTRACTL
1681 {
1682 THROWS;
1683 GC_NOTRIGGER;
1684 MODE_COOPERATIVE;
1685 PRECONDITION(CheckPointer(pClassMT));
1686 PRECONDITION(CheckPointer(m_pWinRTFactoryCache, NULL_OK));
1687 }
1688 CONTRACTL_END;
1689
1690
1691 if (m_pWinRTFactoryCache == nullptr)
1692 return NULL;
1693
1694 //
1695 // Retrieve cached factory
1696 //
1697 WinRTFactoryCacheLockHolder lh(this);
1698
1699 const WinRTFactoryCacheEntry *pEntry = m_pWinRTFactoryCache->LookupPtr(pClassMT);
1700 if (pEntry == NULL)
1701 return NULL;
1702
1703 //
1704 // Ignore factories from a different context, unless lpCtxCookie == NULL,
1705 // which means the factory is free-threaded
1706 // Note that we cannot touch the RCW to retrieve cookie at this point
1707 // because the RCW might belong to a STA thread and that STA thread might die
1708 // and take the RCW with it. Therefore we have to save cookie in this cache
1709 //
1710 if (pEntry->m_pCtxEntry == NULL || pEntry->m_pCtxEntry->GetCtxCookie() == lpCtxCookie)
1711 return ObjectFromHandle(pEntry->m_ohFactoryObject);
1712
1713 return NULL;
1714}
1715
1716void AppDomain::RemoveWinRTFactoryObjects(LPVOID pCtxCookie)
1717{
1718 CONTRACTL
1719 {
1720 THROWS;
1721 GC_TRIGGERS;
1722 MODE_ANY;
1723 }
1724 CONTRACTL_END;
1725
1726 if (m_pWinRTFactoryCache == nullptr)
1727 return;
1728
1729 // helper class for delayed CtxEntry cleanup
1730 class CtxEntryListReleaseHolder
1731 {
1732 public:
1733 CQuickArrayList<CtxEntry *> m_list;
1734
1735 ~CtxEntryListReleaseHolder()
1736 {
1737 CONTRACTL
1738 {
1739 NOTHROW;
1740 GC_TRIGGERS;
1741 MODE_ANY;
1742 }
1743 CONTRACTL_END;
1744
1745 for (SIZE_T i = 0; i < m_list.Size(); i++)
1746 {
1747 m_list[i]->Release();
1748 }
1749 }
1750 } ctxEntryListReleaseHolder;
1751
1752 GCX_COOP();
1753 {
1754 WinRTFactoryCacheLockHolder lh(this);
1755
1756 // Go through the hash table and remove items in the given context
1757 for (WinRTFactoryCache::Iterator it = m_pWinRTFactoryCache->Begin(); it != m_pWinRTFactoryCache->End(); it++)
1758 {
1759 if (it->m_pCtxEntry != NULL && it->m_pCtxEntry->GetCtxCookie() == pCtxCookie)
1760 {
1761 // Releasing the CtxEntry may trigger GC which we can't do under the lock so we push
1762 // it on our local list and release them all after we're done iterating the hashtable.
1763 ctxEntryListReleaseHolder.m_list.Push(it->m_pCtxEntry);
1764
1765 DestroyHandle(it->m_ohFactoryObject);
1766 m_pWinRTFactoryCache->Remove(it);
1767 }
1768 }
1769 }
1770}
1771
1772OBJECTREF AppDomain::GetMissingObject()
1773{
1774 CONTRACTL
1775 {
1776 THROWS;
1777 GC_TRIGGERS;
1778 MODE_COOPERATIVE;
1779 }
1780 CONTRACTL_END;
1781
1782 if (!m_hndMissing)
1783 {
1784 // Get the field
1785 FieldDesc *pValueFD = MscorlibBinder::GetField(FIELD__MISSING__VALUE);
1786
1787 pValueFD->CheckRunClassInitThrowing();
1788
1789 // Retrieve the value static field and store it.
1790 OBJECTHANDLE hndMissing = CreateHandle(pValueFD->GetStaticOBJECTREF());
1791
1792 if (FastInterlockCompareExchangePointer(&m_hndMissing, hndMissing, NULL) != NULL)
1793 {
1794 // Exchanged failed. The m_hndMissing did not equal NULL and was returned.
1795 DestroyHandle(hndMissing);
1796 }
1797 }
1798
1799 return ObjectFromHandle(m_hndMissing);
1800}
1801
1802#endif // DACCESS_COMPILE
1803#endif //CROSSGEN_COMPILE
1804#endif // FEATURE_COMINTEROP
1805
1806#ifndef DACCESS_COMPILE
1807
1808EEMarshalingData *BaseDomain::GetMarshalingData()
1809{
1810 CONTRACT (EEMarshalingData*)
1811 {
1812 THROWS;
1813 GC_TRIGGERS;
1814 MODE_ANY;
1815 INJECT_FAULT(COMPlusThrowOM());
1816 POSTCONDITION(CheckPointer(m_pMarshalingData));
1817 }
1818 CONTRACT_END;
1819
1820 if (!m_pMarshalingData)
1821 {
1822 // Take the lock
1823 CrstHolder holder(&m_InteropDataCrst);
1824
1825 if (!m_pMarshalingData)
1826 {
1827 LoaderHeap* pHeap = GetLoaderAllocator()->GetLowFrequencyHeap();
1828 m_pMarshalingData = new (pHeap) EEMarshalingData(this, pHeap, &m_DomainCrst);
1829 }
1830 }
1831
1832 RETURN m_pMarshalingData;
1833}
1834
1835void BaseDomain::DeleteMarshalingData()
1836{
1837 CONTRACTL
1838 {
1839 NOTHROW;
1840 GC_TRIGGERS;
1841 MODE_ANY;
1842 }
1843 CONTRACTL_END;
1844
1845 // We are in shutdown - no need to take any lock
1846 if (m_pMarshalingData)
1847 {
1848 delete m_pMarshalingData;
1849 m_pMarshalingData = NULL;
1850 }
1851}
1852
1853#ifndef CROSSGEN_COMPILE
1854
1855STRINGREF *BaseDomain::IsStringInterned(STRINGREF *pString)
1856{
1857 CONTRACTL
1858 {
1859 GC_TRIGGERS;
1860 THROWS;
1861 MODE_COOPERATIVE;
1862 PRECONDITION(CheckPointer(pString));
1863 INJECT_FAULT(COMPlusThrowOM(););
1864 }
1865 CONTRACTL_END;
1866
1867 return GetLoaderAllocator()->IsStringInterned(pString);
1868}
1869
1870STRINGREF *BaseDomain::GetOrInternString(STRINGREF *pString)
1871{
1872 CONTRACTL
1873 {
1874 GC_TRIGGERS;
1875 THROWS;
1876 MODE_COOPERATIVE;
1877 PRECONDITION(CheckPointer(pString));
1878 INJECT_FAULT(COMPlusThrowOM(););
1879 }
1880 CONTRACTL_END;
1881
1882 return GetLoaderAllocator()->GetOrInternString(pString);
1883}
1884
1885void BaseDomain::InitLargeHeapHandleTable()
1886{
1887 CONTRACTL
1888 {
1889 THROWS;
1890 GC_TRIGGERS;
1891 MODE_ANY;
1892 PRECONDITION(m_pLargeHeapHandleTable==NULL);
1893 INJECT_FAULT(COMPlusThrowOM(););
1894 }
1895 CONTRACTL_END;
1896
1897 m_pLargeHeapHandleTable = new LargeHeapHandleTable(this, STATIC_OBJECT_TABLE_BUCKET_SIZE);
1898
1899#ifdef _DEBUG
1900 m_pLargeHeapHandleTable->RegisterCrstDebug(&m_LargeHeapHandleTableCrst);
1901#endif
1902}
1903
1904#ifdef FEATURE_COMINTEROP
1905MethodTable* AppDomain::GetLicenseInteropHelperMethodTable()
1906{
1907 CONTRACTL
1908 {
1909 THROWS;
1910 GC_TRIGGERS;
1911 }
1912 CONTRACTL_END;
1913
1914 if(m_pLicenseInteropHelperMT == NULL)
1915 {
1916 // Do this work outside of the lock so we don't have an unbreakable lock condition
1917
1918 TypeHandle licenseMgrTypeHnd;
1919 MethodDescCallSite loadLM(METHOD__MARSHAL__LOAD_LICENSE_MANAGER);
1920
1921 licenseMgrTypeHnd = (MethodTable*) loadLM.Call_RetLPVOID((ARG_SLOT*)NULL);
1922
1923 //
1924 // Look up this method by name, because the type is actually declared in System.dll. <TODO>@todo: why?</TODO>
1925 //
1926
1927 MethodDesc *pGetLIHMD = MemberLoader::FindMethod(licenseMgrTypeHnd.AsMethodTable(),
1928 "GetLicenseInteropHelperType", &gsig_SM_Void_RetIntPtr);
1929 _ASSERTE(pGetLIHMD);
1930
1931 TypeHandle lihTypeHnd;
1932
1933 MethodDescCallSite getLIH(pGetLIHMD);
1934 lihTypeHnd = (MethodTable*) getLIH.Call_RetLPVOID((ARG_SLOT*)NULL);
1935
1936 BaseDomain::LockHolder lh(this);
1937
1938 if(m_pLicenseInteropHelperMT == NULL)
1939 m_pLicenseInteropHelperMT = lihTypeHnd.AsMethodTable();
1940 }
1941 return m_pLicenseInteropHelperMT;
1942}
1943#endif // FEATURE_COMINTEROP
1944
1945#endif // CROSSGEN_COMPILE
1946
1947//*****************************************************************************
1948//*****************************************************************************
1949//*****************************************************************************
1950
1951void *SystemDomain::operator new(size_t size, void *pInPlace)
1952{
1953 LIMITED_METHOD_CONTRACT;
1954 return pInPlace;
1955}
1956
1957
1958void SystemDomain::operator delete(void *pMem)
1959{
1960 LIMITED_METHOD_CONTRACT;
1961 // Do nothing - new() was in-place
1962}
1963
1964
1965void SystemDomain::SetCompilationOverrides(BOOL fForceDebug,
1966 BOOL fForceProfiling,
1967 BOOL fForceInstrument)
1968{
1969 LIMITED_METHOD_CONTRACT;
1970 s_fForceDebug = fForceDebug;
1971 s_fForceProfiling = fForceProfiling;
1972 s_fForceInstrument = fForceInstrument;
1973}
1974
1975#endif //!DACCESS_COMPILE
1976
1977void SystemDomain::GetCompilationOverrides(BOOL * fForceDebug,
1978 BOOL * fForceProfiling,
1979 BOOL * fForceInstrument)
1980{
1981 LIMITED_METHOD_DAC_CONTRACT;
1982 *fForceDebug = s_fForceDebug;
1983 *fForceProfiling = s_fForceProfiling;
1984 *fForceInstrument = s_fForceInstrument;
1985}
1986
1987#ifndef DACCESS_COMPILE
1988
1989void SystemDomain::Attach()
1990{
1991 CONTRACTL
1992 {
1993 THROWS;
1994 GC_TRIGGERS;
1995 MODE_ANY;
1996 PRECONDITION(m_pSystemDomain == NULL);
1997 INJECT_FAULT(COMPlusThrowOM(););
1998 }
1999 CONTRACTL_END;
2000
2001#ifndef CROSSGEN_COMPILE
2002 // Initialize stub managers
2003 PrecodeStubManager::Init();
2004 DelegateInvokeStubManager::Init();
2005 JumpStubStubManager::Init();
2006 RangeSectionStubManager::Init();
2007 ILStubManager::Init();
2008 InteropDispatchStubManager::Init();
2009 StubLinkStubManager::Init();
2010
2011 ThunkHeapStubManager::Init();
2012
2013 TailCallStubManager::Init();
2014
2015 PerAppDomainTPCountList::InitAppDomainIndexList();
2016#endif // CROSSGEN_COMPILE
2017
2018 m_appDomainIndexList.Init();
2019 m_appDomainIdList.Init();
2020
2021 m_SystemDomainCrst.Init(CrstSystemDomain, (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN));
2022 m_DelayedUnloadCrst.Init(CrstSystemDomainDelayedUnloadList, CRST_UNSAFE_COOPGC);
2023
2024 // Initialize the ID dispenser that is used for domain neutral module IDs
2025 g_pModuleIndexDispenser = new IdDispenser();
2026
2027 // Create the global SystemDomain and initialize it.
2028 m_pSystemDomain = new (&g_pSystemDomainMemory[0]) SystemDomain();
2029 // No way it can fail since g_pSystemDomainMemory is a static array.
2030 CONSISTENCY_CHECK(CheckPointer(m_pSystemDomain));
2031
2032 LOG((LF_CLASSLOADER,
2033 LL_INFO10,
2034 "Created system domain at %p\n",
2035 m_pSystemDomain));
2036
2037 // We need to initialize the memory pools etc. for the system domain.
2038 m_pSystemDomain->BaseDomain::Init(); // Setup the memory heaps
2039
2040 // Create the one and only app domain
2041 AppDomain::Create();
2042
2043 // Each domain gets its own ReJitManager, and ReJitManager has its own static
2044 // initialization to run
2045 ReJitManager::InitStatic();
2046}
2047
2048#ifndef CROSSGEN_COMPILE
2049
2050void SystemDomain::DetachBegin()
2051{
2052 WRAPPER_NO_CONTRACT;
2053 // Shut down the domain and its children (but don't deallocate anything just
2054 // yet).
2055
2056 // TODO: we should really not running managed DLLMain during process detach.
2057 if (GetThread() == NULL)
2058 {
2059 return;
2060 }
2061
2062 if(m_pSystemDomain)
2063 m_pSystemDomain->Stop();
2064}
2065
2066void SystemDomain::DetachEnd()
2067{
2068 CONTRACTL
2069 {
2070 NOTHROW;
2071 GC_TRIGGERS;
2072 MODE_ANY;
2073 }
2074 CONTRACTL_END;
2075 // Shut down the domain and its children (but don't deallocate anything just
2076 // yet).
2077 if(m_pSystemDomain)
2078 {
2079 GCX_PREEMP();
2080 m_pSystemDomain->ClearFusionContext();
2081 AppDomain* pAppDomain = GetAppDomain();
2082 if (pAppDomain)
2083 pAppDomain->ClearFusionContext();
2084 }
2085}
2086
2087void SystemDomain::Stop()
2088{
2089 WRAPPER_NO_CONTRACT;
2090 AppDomainIterator i(TRUE);
2091
2092 while (i.Next())
2093 i.GetDomain()->Stop();
2094}
2095
2096
2097void SystemDomain::Terminate() // bNotifyProfiler is ignored
2098{
2099 CONTRACTL
2100 {
2101 NOTHROW;
2102 GC_TRIGGERS;
2103 MODE_ANY;
2104 }
2105 CONTRACTL_END;
2106
2107 // This ignores the refences and terminates the appdomains
2108 AppDomainIterator i(FALSE);
2109
2110 while (i.Next())
2111 {
2112 delete i.GetDomain();
2113 // Keep the iterator from Releasing the current domain
2114 i.m_pCurrent = NULL;
2115 }
2116
2117 if (m_pSystemFile != NULL) {
2118 m_pSystemFile->Release();
2119 m_pSystemFile = NULL;
2120 }
2121
2122 m_pSystemAssembly = NULL;
2123
2124 if (m_pGlobalStringLiteralMap) {
2125 delete m_pGlobalStringLiteralMap;
2126 m_pGlobalStringLiteralMap = NULL;
2127 }
2128
2129 BaseDomain::Terminate();
2130
2131#ifdef FEATURE_COMINTEROP
2132 if (g_pRCWCleanupList != NULL)
2133 delete g_pRCWCleanupList;
2134#endif // FEATURE_COMINTEROP
2135 m_GlobalAllocator.Terminate();
2136}
2137
2138
2139void SystemDomain::PreallocateSpecialObjects()
2140{
2141 CONTRACTL
2142 {
2143 THROWS;
2144 GC_TRIGGERS;
2145 MODE_COOPERATIVE;
2146 INJECT_FAULT(COMPlusThrowOM(););
2147 }
2148 CONTRACTL_END;
2149
2150 _ASSERTE(g_pPreallocatedSentinelObject == NULL);
2151
2152 OBJECTREF pPreallocatedSentinalObject = AllocateObject(g_pObjectClass);
2153 g_pPreallocatedSentinelObject = CreatePinningHandle( pPreallocatedSentinalObject );
2154
2155#ifdef FEATURE_PREJIT
2156 if (SystemModule()->HasNativeImage())
2157 {
2158 CORCOMPILE_EE_INFO_TABLE *pEEInfo = SystemModule()->GetNativeImage()->GetNativeEEInfoTable();
2159 pEEInfo->emptyString = (CORINFO_Object **)StringObject::GetEmptyStringRefPtr();
2160 }
2161#endif
2162}
2163
2164void SystemDomain::CreatePreallocatedExceptions()
2165{
2166 CONTRACTL
2167 {
2168 THROWS;
2169 GC_TRIGGERS;
2170 MODE_COOPERATIVE;
2171 INJECT_FAULT(COMPlusThrowOM(););
2172 }
2173 CONTRACTL_END;
2174
2175 EXCEPTIONREF pBaseException = (EXCEPTIONREF)AllocateObject(g_pExceptionClass);
2176 pBaseException->SetHResult(COR_E_EXCEPTION);
2177 pBaseException->SetXCode(EXCEPTION_COMPLUS);
2178 _ASSERTE(g_pPreallocatedBaseException == NULL);
2179 g_pPreallocatedBaseException = CreateHandle(pBaseException);
2180
2181
2182 EXCEPTIONREF pOutOfMemory = (EXCEPTIONREF)AllocateObject(g_pOutOfMemoryExceptionClass);
2183 pOutOfMemory->SetHResult(COR_E_OUTOFMEMORY);
2184 pOutOfMemory->SetXCode(EXCEPTION_COMPLUS);
2185 _ASSERTE(g_pPreallocatedOutOfMemoryException == NULL);
2186 g_pPreallocatedOutOfMemoryException = CreateHandle(pOutOfMemory);
2187
2188
2189 EXCEPTIONREF pStackOverflow = (EXCEPTIONREF)AllocateObject(g_pStackOverflowExceptionClass);
2190 pStackOverflow->SetHResult(COR_E_STACKOVERFLOW);
2191 pStackOverflow->SetXCode(EXCEPTION_COMPLUS);
2192 _ASSERTE(g_pPreallocatedStackOverflowException == NULL);
2193 g_pPreallocatedStackOverflowException = CreateHandle(pStackOverflow);
2194
2195
2196 EXCEPTIONREF pExecutionEngine = (EXCEPTIONREF)AllocateObject(g_pExecutionEngineExceptionClass);
2197 pExecutionEngine->SetHResult(COR_E_EXECUTIONENGINE);
2198 pExecutionEngine->SetXCode(EXCEPTION_COMPLUS);
2199 _ASSERTE(g_pPreallocatedExecutionEngineException == NULL);
2200 g_pPreallocatedExecutionEngineException = CreateHandle(pExecutionEngine);
2201
2202
2203 EXCEPTIONREF pRudeAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2204 pRudeAbortException->SetHResult(COR_E_THREADABORTED);
2205 pRudeAbortException->SetXCode(EXCEPTION_COMPLUS);
2206 _ASSERTE(g_pPreallocatedRudeThreadAbortException == NULL);
2207 g_pPreallocatedRudeThreadAbortException = CreateHandle(pRudeAbortException);
2208
2209
2210 EXCEPTIONREF pAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
2211 pAbortException->SetHResult(COR_E_THREADABORTED);
2212 pAbortException->SetXCode(EXCEPTION_COMPLUS);
2213 _ASSERTE(g_pPreallocatedThreadAbortException == NULL);
2214 g_pPreallocatedThreadAbortException = CreateHandle( pAbortException );
2215}
2216#endif // CROSSGEN_COMPILE
2217
2218void SystemDomain::Init()
2219{
2220 STANDARD_VM_CONTRACT;
2221
2222 HRESULT hr = S_OK;
2223
2224#ifdef _DEBUG
2225 LOG((
2226 LF_EEMEM,
2227 LL_INFO10,
2228 "sizeof(EEClass) = %d\n"
2229 "sizeof(MethodTable) = %d\n"
2230 "sizeof(MethodDesc)= %d\n"
2231 "sizeof(FieldDesc) = %d\n"
2232 "sizeof(Module) = %d\n",
2233 sizeof(EEClass),
2234 sizeof(MethodTable),
2235 sizeof(MethodDesc),
2236 sizeof(FieldDesc),
2237 sizeof(Module)
2238 ));
2239#endif // _DEBUG
2240
2241 // The base domain is initialized in SystemDomain::Attach()
2242 // to allow stub caches to use the memory pool. Do not
2243 // initialze it here!
2244
2245#ifdef FEATURE_PREJIT
2246 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapDisable) != 0)
2247 g_fAllowNativeImages = false;
2248#endif
2249
2250 m_pSystemFile = NULL;
2251 m_pSystemAssembly = NULL;
2252
2253 DWORD size = 0;
2254
2255
2256 // Get the install directory so we can find mscorlib
2257 hr = GetInternalSystemDirectory(NULL, &size);
2258 if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
2259 ThrowHR(hr);
2260
2261 // GetInternalSystemDirectory returns a size, including the null!
2262 WCHAR *buffer = m_SystemDirectory.OpenUnicodeBuffer(size-1);
2263 IfFailThrow(GetInternalSystemDirectory(buffer, &size));
2264 m_SystemDirectory.CloseBuffer();
2265 m_SystemDirectory.Normalize();
2266
2267 // At this point m_SystemDirectory should already be canonicalized
2268
2269
2270 m_BaseLibrary.Append(m_SystemDirectory);
2271 if (!m_BaseLibrary.EndsWith(DIRECTORY_SEPARATOR_CHAR_W))
2272 {
2273 m_BaseLibrary.Append(DIRECTORY_SEPARATOR_CHAR_W);
2274 }
2275 m_BaseLibrary.Append(g_pwBaseLibrary);
2276 m_BaseLibrary.Normalize();
2277
2278 LoadBaseSystemClasses();
2279
2280 {
2281 // We are about to start allocating objects, so we must be in cooperative mode.
2282 // However, many of the entrypoints to the system (DllGetClassObject and all
2283 // N/Direct exports) get called multiple times. Sometimes they initialize the EE,
2284 // but generally they remain in preemptive mode. So we really want to push/pop
2285 // the state here:
2286 GCX_COOP();
2287
2288#ifndef CROSSGEN_COMPILE
2289 if (!NingenEnabled())
2290 {
2291 CreatePreallocatedExceptions();
2292
2293 PreallocateSpecialObjects();
2294 }
2295#endif
2296
2297 // Finish loading mscorlib now.
2298 m_pSystemAssembly->GetDomainAssembly()->EnsureActive();
2299 }
2300
2301#ifdef _DEBUG
2302 BOOL fPause = EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_PauseOnLoad, FALSE);
2303
2304 while(fPause)
2305 {
2306 ClrSleepEx(20, TRUE);
2307 }
2308#endif // _DEBUG
2309}
2310
2311#ifndef CROSSGEN_COMPILE
2312void SystemDomain::LazyInitGlobalStringLiteralMap()
2313{
2314 CONTRACTL
2315 {
2316 THROWS;
2317 GC_TRIGGERS;
2318 MODE_ANY;
2319 INJECT_FAULT(COMPlusThrowOM(););
2320 }
2321 CONTRACTL_END;
2322
2323 // Allocate the global string literal map.
2324 NewHolder<GlobalStringLiteralMap> pGlobalStringLiteralMap(new GlobalStringLiteralMap());
2325
2326 // Initialize the global string literal map.
2327 pGlobalStringLiteralMap->Init();
2328
2329 if (InterlockedCompareExchangeT<GlobalStringLiteralMap *>(&m_pGlobalStringLiteralMap, pGlobalStringLiteralMap, NULL) == NULL)
2330 {
2331 pGlobalStringLiteralMap.SuppressRelease();
2332 }
2333}
2334
2335/*static*/ void SystemDomain::EnumAllStaticGCRefs(promote_func* fn, ScanContext* sc)
2336{
2337 CONTRACT_VOID
2338 {
2339 NOTHROW;
2340 GC_NOTRIGGER;
2341 MODE_COOPERATIVE;
2342 }
2343 CONTRACT_END;
2344
2345 // We don't do a normal AppDomainIterator because we can't take the SystemDomain lock from
2346 // here.
2347 // We're only supposed to call this from a Server GC. We're walking here m_appDomainIdList
2348 // m_appDomainIdList will have an AppDomain* or will be NULL. So the only danger is if we
2349 // Fetch an AppDomain and then in some other thread the AppDomain is deleted.
2350 //
2351 // If the thread deleting the AppDomain (AppDomain::~AppDomain)was in Preemptive mode
2352 // while doing SystemDomain::EnumAllStaticGCRefs we will issue a GCX_COOP(), which will wait
2353 // for the GC to finish, so we are safe
2354 //
2355 // If the thread is in cooperative mode, it must have been suspended for the GC so a delete
2356 // can't happen.
2357
2358 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
2359 GCHeapUtilities::IsServerHeap() &&
2360 IsGCSpecialThread());
2361
2362 SystemDomain* sysDomain = SystemDomain::System();
2363 if (sysDomain)
2364 {
2365 DWORD i;
2366 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2367 for (i = 0 ; i < count ; i++)
2368 {
2369 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2370 if (pAppDomain && pAppDomain->IsActive())
2371 {
2372#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2373 if (g_fEnableARM)
2374 {
2375 sc->pCurrentDomain = pAppDomain;
2376 }
2377#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2378 pAppDomain->EnumStaticGCRefs(fn, sc);
2379 }
2380 }
2381 }
2382
2383 RETURN;
2384}
2385
2386#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
2387void SystemDomain::ResetADSurvivedBytes()
2388{
2389 CONTRACT_VOID
2390 {
2391 NOTHROW;
2392 GC_NOTRIGGER;
2393 MODE_ANY;
2394 }
2395 CONTRACT_END;
2396
2397 _ASSERTE(GCHeapUtilities::IsGCInProgress());
2398
2399 SystemDomain* sysDomain = SystemDomain::System();
2400 if (sysDomain)
2401 {
2402 DWORD i;
2403 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2404 for (i = 0 ; i < count ; i++)
2405 {
2406 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2407 if (pAppDomain && pAppDomain->IsUserActive())
2408 {
2409 pAppDomain->ResetSurvivedBytes();
2410 }
2411 }
2412 }
2413
2414 RETURN;
2415}
2416
2417ULONGLONG SystemDomain::GetADSurvivedBytes()
2418{
2419 CONTRACTL
2420 {
2421 NOTHROW;
2422 GC_NOTRIGGER;
2423 MODE_ANY;
2424 }
2425 CONTRACTL_END;
2426
2427 SystemDomain* sysDomain = SystemDomain::System();
2428 ULONGLONG ullTotalADSurvived = 0;
2429 if (sysDomain)
2430 {
2431 DWORD i;
2432 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2433 for (i = 0 ; i < count ; i++)
2434 {
2435 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2436 if (pAppDomain && pAppDomain->IsUserActive())
2437 {
2438 ULONGLONG ullSurvived = pAppDomain->GetSurvivedBytes();
2439 ullTotalADSurvived += ullSurvived;
2440 }
2441 }
2442 }
2443
2444 return ullTotalADSurvived;
2445}
2446
2447void SystemDomain::RecordTotalSurvivedBytes(size_t totalSurvivedBytes)
2448{
2449 CONTRACT_VOID
2450 {
2451 NOTHROW;
2452 GC_NOTRIGGER;
2453 MODE_ANY;
2454 }
2455 CONTRACT_END;
2456
2457 m_totalSurvivedBytes = totalSurvivedBytes;
2458
2459 SystemDomain* sysDomain = SystemDomain::System();
2460 if (sysDomain)
2461 {
2462 DWORD i;
2463 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2464 for (i = 0 ; i < count ; i++)
2465 {
2466 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2467 if (pAppDomain && pAppDomain->IsUserActive())
2468 {
2469 FireEtwAppDomainMemSurvived((ULONGLONG)pAppDomain, pAppDomain->GetSurvivedBytes(), totalSurvivedBytes, GetClrInstanceId());
2470 }
2471 }
2472 }
2473
2474 RETURN;
2475}
2476#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
2477
2478// Only called when EE is suspended.
2479DWORD SystemDomain::GetTotalNumSizedRefHandles()
2480{
2481 CONTRACTL
2482 {
2483 NOTHROW;
2484 GC_NOTRIGGER;
2485 MODE_ANY;
2486 }
2487 CONTRACTL_END;
2488
2489 SystemDomain* sysDomain = SystemDomain::System();
2490 DWORD dwTotalNumSizedRefHandles = 0;
2491 if (sysDomain)
2492 {
2493 DWORD i;
2494 DWORD count = (DWORD) m_appDomainIdList.GetCount();
2495 for (i = 0 ; i < count ; i++)
2496 {
2497 AppDomain* pAppDomain = (AppDomain *)m_appDomainIdList.Get(i);
2498 if (pAppDomain && pAppDomain->IsActive())
2499 {
2500 dwTotalNumSizedRefHandles += pAppDomain->GetNumSizedRefHandles();
2501 }
2502 }
2503 }
2504
2505 return dwTotalNumSizedRefHandles;
2506}
2507#endif // CROSSGEN_COMPILE
2508
2509void SystemDomain::LoadBaseSystemClasses()
2510{
2511 STANDARD_VM_CONTRACT;
2512
2513 ETWOnStartup(LdSysBases_V1, LdSysBasesEnd_V1);
2514
2515 {
2516 m_pSystemFile = PEAssembly::OpenSystem(NULL);
2517 }
2518 // Only partially load the system assembly. Other parts of the code will want to access
2519 // the globals in this function before finishing the load.
2520 m_pSystemAssembly = DefaultDomain()->LoadDomainAssembly(NULL, m_pSystemFile, FILE_LOAD_POST_LOADLIBRARY)->GetCurrentAssembly();
2521
2522 // Set up binder for mscorlib
2523 MscorlibBinder::AttachModule(m_pSystemAssembly->GetManifestModule());
2524
2525 // Load Object
2526 g_pObjectClass = MscorlibBinder::GetClass(CLASS__OBJECT);
2527
2528 // Now that ObjectClass is loaded, we can set up
2529 // the system for finalizers. There is no point in deferring this, since we need
2530 // to know this before we allocate our first object.
2531 g_pObjectFinalizerMD = MscorlibBinder::GetMethod(METHOD__OBJECT__FINALIZE);
2532
2533
2534 g_pCanonMethodTableClass = MscorlibBinder::GetClass(CLASS____CANON);
2535
2536 // NOTE: !!!IMPORTANT!!! ValueType and Enum MUST be loaded one immediately after
2537 // the other, because we have coded MethodTable::IsChildValueType
2538 // in such a way that it depends on this behaviour.
2539 // Load the ValueType class
2540 g_pValueTypeClass = MscorlibBinder::GetClass(CLASS__VALUE_TYPE);
2541
2542 // Load the enum class
2543 g_pEnumClass = MscorlibBinder::GetClass(CLASS__ENUM);
2544 _ASSERTE(!g_pEnumClass->IsValueType());
2545
2546 // Load System.RuntimeType
2547 g_pRuntimeTypeClass = MscorlibBinder::GetClass(CLASS__CLASS);
2548 _ASSERTE(g_pRuntimeTypeClass->IsFullyLoaded());
2549
2550 // Load Array class
2551 g_pArrayClass = MscorlibBinder::GetClass(CLASS__ARRAY);
2552
2553 // Calling a method on IList<T> for an array requires redirection to a method on
2554 // the SZArrayHelper class. Retrieving such methods means calling
2555 // GetActualImplementationForArrayGenericIListMethod, which calls FetchMethod for
2556 // the corresponding method on SZArrayHelper. This basically results in a class
2557 // load due to a method call, which the debugger cannot handle, so we pre-load
2558 // the SZArrayHelper class here.
2559 g_pSZArrayHelperClass = MscorlibBinder::GetClass(CLASS__SZARRAYHELPER);
2560
2561 // Load ByReference class
2562 //
2563 // NOTE: ByReference<T> must be the first by-ref-like system type to be loaded,
2564 // because MethodTable::ClassifyEightBytesWithManagedLayout depends on it.
2565 g_pByReferenceClass = MscorlibBinder::GetClass(CLASS__BYREFERENCE);
2566
2567 // Load Nullable class
2568 g_pNullableClass = MscorlibBinder::GetClass(CLASS__NULLABLE);
2569
2570 // Load the Object array class.
2571 g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pObjectClass)).AsArray();
2572
2573 // We have delayed allocation of mscorlib's static handles until we load the object class
2574 MscorlibBinder::GetModule()->AllocateRegularStaticHandles(DefaultDomain());
2575
2576 g_TypedReferenceMT = MscorlibBinder::GetClass(CLASS__TYPED_REFERENCE);
2577
2578 // Make sure all primitive types are loaded
2579 for (int et = ELEMENT_TYPE_VOID; et <= ELEMENT_TYPE_R8; et++)
2580 MscorlibBinder::LoadPrimitiveType((CorElementType)et);
2581
2582 MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_I);
2583 MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_U);
2584
2585 // unfortunately, the following cannot be delay loaded since the jit
2586 // uses it to compute method attributes within a function that cannot
2587 // handle Complus exception and the following call goes through a path
2588 // where a complus exception can be thrown. It is unfortunate, because
2589 // we know that the delegate class and multidelegate class are always
2590 // guaranteed to be found.
2591 g_pDelegateClass = MscorlibBinder::GetClass(CLASS__DELEGATE);
2592 g_pMulticastDelegateClass = MscorlibBinder::GetClass(CLASS__MULTICAST_DELEGATE);
2593
2594 // used by IsImplicitInterfaceOfSZArray
2595 MscorlibBinder::GetClass(CLASS__IENUMERABLEGENERIC);
2596 MscorlibBinder::GetClass(CLASS__ICOLLECTIONGENERIC);
2597 MscorlibBinder::GetClass(CLASS__ILISTGENERIC);
2598 MscorlibBinder::GetClass(CLASS__IREADONLYCOLLECTIONGENERIC);
2599 MscorlibBinder::GetClass(CLASS__IREADONLYLISTGENERIC);
2600
2601 // Load String
2602 g_pStringClass = MscorlibBinder::LoadPrimitiveType(ELEMENT_TYPE_STRING);
2603
2604 // Used by Buffer::BlockCopy
2605 g_pByteArrayMT = ClassLoader::LoadArrayTypeThrowing(
2606 TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_U1))).AsArray()->GetMethodTable();
2607
2608#ifndef CROSSGEN_COMPILE
2609 ECall::PopulateManagedStringConstructors();
2610#endif // CROSSGEN_COMPILE
2611
2612 g_pExceptionClass = MscorlibBinder::GetClass(CLASS__EXCEPTION);
2613 g_pOutOfMemoryExceptionClass = MscorlibBinder::GetException(kOutOfMemoryException);
2614 g_pStackOverflowExceptionClass = MscorlibBinder::GetException(kStackOverflowException);
2615 g_pExecutionEngineExceptionClass = MscorlibBinder::GetException(kExecutionEngineException);
2616 g_pThreadAbortExceptionClass = MscorlibBinder::GetException(kThreadAbortException);
2617
2618 g_pThreadClass = MscorlibBinder::GetClass(CLASS__THREAD);
2619
2620#ifdef FEATURE_COMINTEROP
2621 g_pBaseCOMObject = MscorlibBinder::GetClass(CLASS__COM_OBJECT);
2622 g_pBaseRuntimeClass = MscorlibBinder::GetClass(CLASS__RUNTIME_CLASS);
2623
2624 MscorlibBinder::GetClass(CLASS__IDICTIONARYGENERIC);
2625 MscorlibBinder::GetClass(CLASS__IREADONLYDICTIONARYGENERIC);
2626 MscorlibBinder::GetClass(CLASS__ATTRIBUTE);
2627 MscorlibBinder::GetClass(CLASS__EVENT_HANDLERGENERIC);
2628
2629 MscorlibBinder::GetClass(CLASS__IENUMERABLE);
2630 MscorlibBinder::GetClass(CLASS__ICOLLECTION);
2631 MscorlibBinder::GetClass(CLASS__ILIST);
2632 MscorlibBinder::GetClass(CLASS__IDISPOSABLE);
2633
2634#ifdef _DEBUG
2635 WinRTInterfaceRedirector::VerifyRedirectedInterfaceStubs();
2636#endif // _DEBUG
2637#endif
2638
2639#ifdef FEATURE_ICASTABLE
2640 g_pICastableInterface = MscorlibBinder::GetClass(CLASS__ICASTABLE);
2641#endif // FEATURE_ICASTABLE
2642
2643 // Load a special marker method used to detect Constrained Execution Regions
2644 // at jit time.
2645 g_pExecuteBackoutCodeHelperMethod = MscorlibBinder::GetMethod(METHOD__RUNTIME_HELPERS__EXECUTE_BACKOUT_CODE_HELPER);
2646
2647 // Make sure that FCall mapping for Monitor.Enter is initialized. We need it in case Monitor.Enter is used only as JIT helper.
2648 // For more details, see comment in code:JITutil_MonEnterWorker around "__me = GetEEFuncEntryPointMacro(JIT_MonEnter)".
2649 ECall::GetFCallImpl(MscorlibBinder::GetMethod(METHOD__MONITOR__ENTER));
2650
2651#ifdef PROFILING_SUPPORTED
2652 // Note that g_profControlBlock.fBaseSystemClassesLoaded must be set to TRUE only after
2653 // all base system classes are loaded. Profilers are not allowed to call any type-loading
2654 // APIs until g_profControlBlock.fBaseSystemClassesLoaded is TRUE. It is important that
2655 // all base system classes need to be loaded before profilers can trigger the type loading.
2656 g_profControlBlock.fBaseSystemClassesLoaded = TRUE;
2657#endif // PROFILING_SUPPORTED
2658
2659#if defined(_DEBUG) && !defined(CROSSGEN_COMPILE)
2660 if (!NingenEnabled())
2661 {
2662 g_Mscorlib.Check();
2663 }
2664#endif
2665
2666#if defined(HAVE_GCCOVER) && defined(FEATURE_PREJIT)
2667 if (GCStress<cfg_instr_ngen>::IsEnabled())
2668 {
2669 // Setting up gc coverage requires the base system classes
2670 // to be initialized. So we have deferred it until now for mscorlib.
2671 Module *pModule = MscorlibBinder::GetModule();
2672 _ASSERTE(pModule->IsSystem());
2673 if(pModule->HasNativeImage())
2674 {
2675 SetupGcCoverageForNativeImage(pModule);
2676 }
2677 }
2678#endif // defined(HAVE_GCCOVER) && !defined(FEATURE_PREJIT)
2679}
2680
2681/*static*/
2682void SystemDomain::LoadDomain(AppDomain *pDomain)
2683{
2684 CONTRACTL
2685 {
2686 THROWS;
2687 GC_TRIGGERS;
2688 MODE_ANY;
2689 PRECONDITION(CheckPointer(System()));
2690 INJECT_FAULT(COMPlusThrowOM(););
2691 }
2692 CONTRACTL_END;
2693
2694 SystemDomain::System()->AddDomain(pDomain);
2695}
2696
2697ADIndex SystemDomain::GetNewAppDomainIndex(AppDomain *pAppDomain)
2698{
2699 STANDARD_VM_CONTRACT;
2700
2701 DWORD count = m_appDomainIndexList.GetCount();
2702 DWORD i;
2703
2704#ifdef _DEBUG
2705 if (count < 2000)
2706 {
2707 // So that we can keep AD index inside object header.
2708 // We do not want to create syncblock unless needed.
2709 i = count;
2710 }
2711 else
2712 {
2713#endif // _DEBUG
2714 //
2715 // Look for an unused index. Note that in a checked build,
2716 // we never reuse indexes - this makes it easier to tell
2717 // when we are looking at a stale app domain.
2718 //
2719
2720 i = m_appDomainIndexList.FindElement(m_dwLowestFreeIndex, NULL);
2721 if (i == (DWORD) ArrayList::NOT_FOUND)
2722 i = count;
2723 m_dwLowestFreeIndex = i+1;
2724#ifdef _DEBUG
2725 if (m_dwLowestFreeIndex >= 2000)
2726 {
2727 m_dwLowestFreeIndex = 0;
2728 }
2729 }
2730#endif // _DEBUG
2731
2732 if (i == count)
2733 IfFailThrow(m_appDomainIndexList.Append(pAppDomain));
2734 else
2735 m_appDomainIndexList.Set(i, pAppDomain);
2736
2737 _ASSERTE(i < m_appDomainIndexList.GetCount());
2738
2739 // Note that index 0 means domain agile.
2740 return ADIndex(i+1);
2741}
2742
2743void SystemDomain::ReleaseAppDomainIndex(ADIndex index)
2744{
2745 WRAPPER_NO_CONTRACT;
2746 SystemDomain::LockHolder lh;
2747 // Note that index 0 means domain agile.
2748 index.m_dwIndex--;
2749
2750 _ASSERTE(m_appDomainIndexList.Get(index.m_dwIndex) != NULL);
2751
2752 m_appDomainIndexList.Set(index.m_dwIndex, NULL);
2753
2754#ifndef _DEBUG
2755 if (index.m_dwIndex < m_dwLowestFreeIndex)
2756 m_dwLowestFreeIndex = index.m_dwIndex;
2757#endif // !_DEBUG
2758}
2759
2760#endif // !DACCESS_COMPILE
2761
2762PTR_AppDomain SystemDomain::GetAppDomainAtIndex(ADIndex index)
2763{
2764 LIMITED_METHOD_CONTRACT;
2765 SUPPORTS_DAC;
2766 _ASSERTE(index.m_dwIndex != 0);
2767
2768 PTR_AppDomain pAppDomain = TestGetAppDomainAtIndex(index);
2769
2770 _ASSERTE(pAppDomain || !"Attempt to access unloaded app domain");
2771
2772 return pAppDomain;
2773}
2774
2775PTR_AppDomain SystemDomain::TestGetAppDomainAtIndex(ADIndex index)
2776{
2777 LIMITED_METHOD_CONTRACT;
2778 SUPPORTS_DAC;
2779 _ASSERTE(index.m_dwIndex != 0);
2780 index.m_dwIndex--;
2781
2782#ifndef DACCESS_COMPILE
2783 _ASSERTE(index.m_dwIndex < (DWORD)m_appDomainIndexList.GetCount());
2784 AppDomain *pAppDomain = (AppDomain*) m_appDomainIndexList.Get(index.m_dwIndex);
2785#else // DACCESS_COMPILE
2786 PTR_ArrayListStatic pList = &m_appDomainIndexList;
2787 AppDomain *pAppDomain = dac_cast<PTR_AppDomain>(pList->Get(index.m_dwIndex));
2788#endif // DACCESS_COMPILE
2789 return PTR_AppDomain(pAppDomain);
2790}
2791
2792#ifndef DACCESS_COMPILE
2793
2794// See also code:SystemDomain::ReleaseAppDomainId
2795ADID SystemDomain::GetNewAppDomainId(AppDomain *pAppDomain)
2796{
2797 CONTRACTL
2798 {
2799 THROWS;
2800 GC_TRIGGERS;
2801 MODE_ANY;
2802 INJECT_FAULT(COMPlusThrowOM(););
2803 }
2804 CONTRACTL_END;
2805
2806 DWORD i = m_appDomainIdList.GetCount();
2807
2808 IfFailThrow(m_appDomainIdList.Append(pAppDomain));
2809
2810 _ASSERTE(i < m_appDomainIdList.GetCount());
2811
2812 return ADID(i+1);
2813}
2814
2815AppDomain *SystemDomain::GetAppDomainAtId(ADID index)
2816{
2817 CONTRACTL
2818 {
2819#ifdef _DEBUG
2820 if (!SystemDomain::IsUnderDomainLock() && !IsGCThread()) { MODE_COOPERATIVE;} else { DISABLED(MODE_ANY);}
2821#endif
2822 GC_NOTRIGGER;
2823 SO_TOLERANT;
2824 NOTHROW;
2825 }
2826 CONTRACTL_END;
2827
2828 if(index.m_dwId == 0)
2829 return NULL;
2830 DWORD requestedID = index.m_dwId - 1;
2831
2832 if(requestedID >= (DWORD)m_appDomainIdList.GetCount())
2833 return NULL;
2834
2835 AppDomain * result = (AppDomain *)m_appDomainIdList.Get(requestedID);
2836
2837#ifndef CROSSGEN_COMPILE
2838 // If the current thread can't enter the AppDomain, then don't return it.
2839 if (!result)
2840 return NULL;
2841#endif // CROSSGEN_COMPILE
2842
2843 return result;
2844}
2845
2846// Releases an appdomain index. Note that today we have code that depends on these
2847// indexes not being recycled, so we don't actually shrink m_appDomainIdList, but
2848// simply zero out an entry. THus we 'leak' the memory associated the slot in
2849// m_appDomainIdList.
2850//
2851// TODO make this a sparse structure so that we avoid that leak.
2852//
2853void SystemDomain::ReleaseAppDomainId(ADID index)
2854{
2855 LIMITED_METHOD_CONTRACT;
2856 index.m_dwId--;
2857
2858 _ASSERTE(index.m_dwId < (DWORD)m_appDomainIdList.GetCount());
2859
2860 m_appDomainIdList.Set(index.m_dwId, NULL);
2861}
2862
2863#if defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
2864
2865Thread::ApartmentState SystemDomain::GetEntryPointThreadAptState(IMDInternalImport* pScope, mdMethodDef mdMethod)
2866{
2867 STANDARD_VM_CONTRACT;
2868
2869 HRESULT hr;
2870 IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
2871 DEFAULTDOMAIN_MTA_TYPE,
2872 NULL,
2873 NULL));
2874 BOOL fIsMTA = FALSE;
2875 if(hr == S_OK)
2876 fIsMTA = TRUE;
2877
2878 IfFailThrow(hr = pScope->GetCustomAttributeByName(mdMethod,
2879 DEFAULTDOMAIN_STA_TYPE,
2880 NULL,
2881 NULL));
2882 BOOL fIsSTA = FALSE;
2883 if (hr == S_OK)
2884 fIsSTA = TRUE;
2885
2886 if (fIsSTA && fIsMTA)
2887 COMPlusThrowHR(COR_E_CUSTOMATTRIBUTEFORMAT);
2888
2889 if (fIsSTA)
2890 return Thread::AS_InSTA;
2891 else if (fIsMTA)
2892 return Thread::AS_InMTA;
2893
2894 return Thread::AS_Unknown;
2895}
2896
2897void SystemDomain::SetThreadAptState (Thread::ApartmentState state)
2898{
2899 STANDARD_VM_CONTRACT;
2900
2901 Thread* pThread = GetThread();
2902 _ASSERTE(pThread);
2903
2904 if(state == Thread::AS_InSTA)
2905 {
2906 Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InSTA, TRUE);
2907 _ASSERTE(pState == Thread::AS_InSTA);
2908 }
2909 else
2910 {
2911 // If an apartment state was not explicitly requested, default to MTA
2912 Thread::ApartmentState pState = pThread->SetApartment(Thread::AS_InMTA, TRUE);
2913 _ASSERTE(pState == Thread::AS_InMTA);
2914 }
2915}
2916#endif // defined(FEATURE_COMINTEROP_APARTMENT_SUPPORT) && !defined(CROSSGEN_COMPILE)
2917
2918// Helper function to load an assembly. This is called from LoadCOMClass.
2919/* static */
2920
2921Assembly *AppDomain::LoadAssemblyHelper(LPCWSTR wszAssembly,
2922 LPCWSTR wszCodeBase)
2923{
2924 CONTRACT(Assembly *)
2925 {
2926 THROWS;
2927 POSTCONDITION(CheckPointer(RETVAL));
2928 PRECONDITION(wszAssembly || wszCodeBase);
2929 INJECT_FAULT(COMPlusThrowOM(););
2930 }
2931 CONTRACT_END;
2932
2933 AssemblySpec spec;
2934 if(wszAssembly) {
2935 #define MAKE_TRANSLATIONFAILED { ThrowOutOfMemory(); }
2936 MAKE_UTF8PTR_FROMWIDE(szAssembly,wszAssembly);
2937 #undef MAKE_TRANSLATIONFAILED
2938
2939 IfFailThrow(spec.Init(szAssembly));
2940 }
2941
2942 if (wszCodeBase) {
2943 spec.SetCodeBase(wszCodeBase);
2944 }
2945 RETURN spec.LoadAssembly(FILE_LOADED);
2946}
2947
2948#if defined(FEATURE_CLASSIC_COMINTEROP) && !defined(CROSSGEN_COMPILE)
2949
2950MethodTable *AppDomain::LoadCOMClass(GUID clsid,
2951 BOOL bLoadRecord/*=FALSE*/,
2952 BOOL* pfAssemblyInReg/*=NULL*/)
2953{
2954 // @CORESYSTODO: what to do here?
2955 return NULL;
2956}
2957
2958#endif // FEATURE_CLASSIC_COMINTEROP && !CROSSGEN_COMPILE
2959
2960
2961/*static*/
2962bool SystemDomain::IsReflectionInvocationMethod(MethodDesc* pMeth)
2963{
2964 CONTRACTL
2965 {
2966 THROWS;
2967 GC_TRIGGERS;
2968 MODE_ANY;
2969 }
2970 CONTRACTL_END;
2971
2972 MethodTable* pCaller = pMeth->GetMethodTable();
2973
2974 // All Reflection Invocation methods are defined in mscorlib.dll
2975 if (!pCaller->GetModule()->IsSystem())
2976 return false;
2977
2978 /* List of types that should be skipped to identify true caller */
2979 static const BinderClassID reflectionInvocationTypes[] = {
2980 CLASS__METHOD,
2981 CLASS__METHOD_BASE,
2982 CLASS__METHOD_INFO,
2983 CLASS__CONSTRUCTOR,
2984 CLASS__CONSTRUCTOR_INFO,
2985 CLASS__CLASS,
2986 CLASS__TYPE_HANDLE,
2987 CLASS__METHOD_HANDLE,
2988 CLASS__FIELD_HANDLE,
2989 CLASS__TYPE,
2990 CLASS__FIELD,
2991 CLASS__RT_FIELD_INFO,
2992 CLASS__FIELD_INFO,
2993 CLASS__EVENT,
2994 CLASS__EVENT_INFO,
2995 CLASS__PROPERTY,
2996 CLASS__PROPERTY_INFO,
2997 CLASS__ACTIVATOR,
2998 CLASS__ARRAY,
2999 CLASS__ASSEMBLYBASE,
3000 CLASS__ASSEMBLY,
3001 CLASS__TYPE_DELEGATOR,
3002 CLASS__RUNTIME_HELPERS,
3003 CLASS__LAZY_INITIALIZER,
3004 CLASS__DYNAMICMETHOD,
3005 CLASS__DELEGATE,
3006 CLASS__MULTICAST_DELEGATE
3007 };
3008
3009 static const BinderClassID genericReflectionInvocationTypes[] = {
3010 CLASS__LAZY
3011 };
3012
3013 static mdTypeDef genericReflectionInvocationTypeDefs[NumItems(genericReflectionInvocationTypes)];
3014
3015 static bool fInited = false;
3016
3017 if (!VolatileLoad(&fInited))
3018 {
3019 // Make sure all types are loaded so that we can use faster GetExistingClass()
3020 for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3021 {
3022 MscorlibBinder::GetClass(reflectionInvocationTypes[i]);
3023 }
3024
3025 // Make sure all types are loaded so that we can use faster GetExistingClass()
3026 for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypes); i++)
3027 {
3028 genericReflectionInvocationTypeDefs[i] = MscorlibBinder::GetClass(genericReflectionInvocationTypes[i])->GetCl();
3029 }
3030
3031 VolatileStore(&fInited, true);
3032 }
3033
3034 if (pCaller->HasInstantiation())
3035 {
3036 // For generic types, pCaller will be an instantiated type and never equal to the type definition.
3037 // So we compare their TypeDef tokens instead.
3038 for (unsigned i = 0; i < NumItems(genericReflectionInvocationTypeDefs); i++)
3039 {
3040 if (pCaller->GetCl() == genericReflectionInvocationTypeDefs[i])
3041 return true;
3042 }
3043 }
3044 else
3045 {
3046 for (unsigned i = 0; i < NumItems(reflectionInvocationTypes); i++)
3047 {
3048 if (MscorlibBinder::GetExistingClass(reflectionInvocationTypes[i]) == pCaller)
3049 return true;
3050 }
3051 }
3052
3053 return false;
3054}
3055
3056#ifndef CROSSGEN_COMPILE
3057struct CallersDataWithStackMark
3058{
3059 StackCrawlMark* stackMark;
3060 BOOL foundMe;
3061 MethodDesc* pFoundMethod;
3062 MethodDesc* pPrevMethod;
3063 AppDomain* pAppDomain;
3064};
3065
3066/*static*/
3067MethodDesc* SystemDomain::GetCallersMethod(StackCrawlMark* stackMark,
3068 AppDomain **ppAppDomain/*=NULL*/)
3069
3070{
3071 CONTRACTL
3072 {
3073 THROWS;
3074 GC_TRIGGERS;
3075 MODE_ANY;
3076 INJECT_FAULT(COMPlusThrowOM(););
3077 }
3078 CONTRACTL_END;
3079
3080 GCX_COOP();
3081
3082 CallersDataWithStackMark cdata;
3083 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3084 cdata.stackMark = stackMark;
3085
3086 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3087
3088 if(cdata.pFoundMethod) {
3089 if (ppAppDomain)
3090 *ppAppDomain = cdata.pAppDomain;
3091 return cdata.pFoundMethod;
3092 } else
3093 return NULL;
3094}
3095
3096/*static*/
3097MethodTable* SystemDomain::GetCallersType(StackCrawlMark* stackMark,
3098 AppDomain **ppAppDomain/*=NULL*/)
3099
3100{
3101 CONTRACTL
3102 {
3103 THROWS;
3104 GC_TRIGGERS;
3105 MODE_COOPERATIVE;
3106 INJECT_FAULT(COMPlusThrowOM(););
3107 }
3108 CONTRACTL_END;
3109
3110 CallersDataWithStackMark cdata;
3111 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3112 cdata.stackMark = stackMark;
3113
3114 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3115
3116 if(cdata.pFoundMethod) {
3117 if (ppAppDomain)
3118 *ppAppDomain = cdata.pAppDomain;
3119 return cdata.pFoundMethod->GetMethodTable();
3120 } else
3121 return NULL;
3122}
3123
3124/*static*/
3125Module* SystemDomain::GetCallersModule(StackCrawlMark* stackMark,
3126 AppDomain **ppAppDomain/*=NULL*/)
3127
3128{
3129 CONTRACTL
3130 {
3131 THROWS;
3132 GC_TRIGGERS;
3133 MODE_ANY;
3134 INJECT_FAULT(COMPlusThrowOM(););
3135 }
3136 CONTRACTL_END;
3137
3138 GCX_COOP();
3139
3140 CallersDataWithStackMark cdata;
3141 ZeroMemory(&cdata, sizeof(CallersDataWithStackMark));
3142 cdata.stackMark = stackMark;
3143
3144 GetThread()->StackWalkFrames(CallersMethodCallbackWithStackMark, &cdata, FUNCTIONSONLY | LIGHTUNWIND);
3145
3146 if(cdata.pFoundMethod) {
3147 if (ppAppDomain)
3148 *ppAppDomain = cdata.pAppDomain;
3149 return cdata.pFoundMethod->GetModule();
3150 } else
3151 return NULL;
3152}
3153
3154struct CallersData
3155{
3156 int skip;
3157 MethodDesc* pMethod;
3158};
3159
3160/*static*/
3161Assembly* SystemDomain::GetCallersAssembly(StackCrawlMark *stackMark,
3162 AppDomain **ppAppDomain/*=NULL*/)
3163{
3164 WRAPPER_NO_CONTRACT;
3165 Module* mod = GetCallersModule(stackMark, ppAppDomain);
3166 if (mod)
3167 return mod->GetAssembly();
3168 return NULL;
3169}
3170
3171/*static*/
3172Module* SystemDomain::GetCallersModule(int skip)
3173{
3174 CONTRACTL
3175 {
3176 THROWS;
3177 GC_TRIGGERS;
3178 MODE_ANY;
3179 INJECT_FAULT(COMPlusThrowOM(););
3180 }
3181 CONTRACTL_END;
3182
3183 GCX_COOP();
3184
3185 CallersData cdata;
3186 ZeroMemory(&cdata, sizeof(CallersData));
3187 cdata.skip = skip;
3188
3189 StackWalkFunctions(GetThread(), CallersMethodCallback, &cdata);
3190
3191 if(cdata.pMethod)
3192 return cdata.pMethod->GetModule();
3193 else
3194 return NULL;
3195}
3196
3197/*private static*/
3198StackWalkAction SystemDomain::CallersMethodCallbackWithStackMark(CrawlFrame* pCf, VOID* data)
3199{
3200 CONTRACTL
3201 {
3202 THROWS;
3203 GC_TRIGGERS;
3204 MODE_COOPERATIVE;
3205 SO_INTOLERANT;
3206 INJECT_FAULT(COMPlusThrowOM(););
3207 }
3208 CONTRACTL_END;
3209
3210
3211 MethodDesc *pFunc = pCf->GetFunction();
3212
3213 /* We asked to be called back only for functions */
3214 _ASSERTE(pFunc);
3215
3216 CallersDataWithStackMark* pCaller = (CallersDataWithStackMark*) data;
3217 if (pCaller->stackMark)
3218 {
3219 if (!pCf->IsInCalleesFrames(pCaller->stackMark))
3220 {
3221 // save the current in case it is the one we want
3222 pCaller->pPrevMethod = pFunc;
3223 pCaller->pAppDomain = pCf->GetAppDomain();
3224 return SWA_CONTINUE;
3225 }
3226
3227 // LookForMe stack crawl marks needn't worry about reflection or
3228 // remoting frames on the stack. Each frame above (newer than) the
3229 // target will be captured by the logic above. Once we transition to
3230 // finding the stack mark below the AofRA, we know that we hit the
3231 // target last time round and immediately exit with the cached result.
3232
3233 if (*(pCaller->stackMark) == LookForMe)
3234 {
3235 pCaller->pFoundMethod = pCaller->pPrevMethod;
3236 return SWA_ABORT;
3237 }
3238 }
3239
3240 // Skip reflection and remoting frames that could lie between a stack marked
3241 // method and its true caller (or that caller and its own caller). These
3242 // frames are infrastructure and logically transparent to the stack crawling
3243 // algorithm.
3244
3245 // Skipping remoting frames. We always skip entire client to server spans
3246 // (though we see them in the order server then client during a stack crawl
3247 // obviously).
3248
3249 // We spot the server dispatcher end because all calls are dispatched
3250 // through a single method: StackBuilderSink._PrivateProcessMessage.
3251
3252 Frame* frame = pCf->GetFrame();
3253 _ASSERTE(pCf->IsFrameless() || frame);
3254
3255
3256
3257 // Skipping reflection frames. We don't need to be quite as exhaustive here
3258 // as the security or reflection stack walking code since we know this logic
3259 // is only invoked for selected methods in mscorlib itself. So we're
3260 // reasonably sure we won't have any sensitive methods late bound invoked on
3261 // constructors, properties or events. This leaves being invoked via
3262 // MethodInfo, Type or Delegate (and depending on which invoke overload is
3263 // being used, several different reflection classes may be involved).
3264
3265 g_IBCLogger.LogMethodDescAccess(pFunc);
3266
3267 if (SystemDomain::IsReflectionInvocationMethod(pFunc))
3268 return SWA_CONTINUE;
3269
3270 if (frame && frame->GetFrameType() == Frame::TYPE_MULTICAST)
3271 {
3272 // This must be either a secure delegate frame or a true multicast delegate invocation.
3273
3274 _ASSERTE(pFunc->GetMethodTable()->IsDelegate());
3275
3276 DELEGATEREF del = (DELEGATEREF)((SecureDelegateFrame*)frame)->GetThis(); // This can throw.
3277
3278 if (COMDelegate::IsSecureDelegate(del))
3279 {
3280 if (del->IsWrapperDelegate())
3281 {
3282 // On ARM, we use secure delegate infrastructure to preserve R4 register.
3283 return SWA_CONTINUE;
3284 }
3285 // For a secure delegate frame, we should return the delegate creator instead
3286 // of the delegate method itself.
3287 pFunc = (MethodDesc*) del->GetMethodPtrAux();
3288 }
3289 else
3290 {
3291 _ASSERTE(COMDelegate::IsTrueMulticastDelegate(del));
3292 return SWA_CONTINUE;
3293 }
3294 }
3295
3296 // Return the first non-reflection/remoting frame if no stack mark was
3297 // supplied.
3298 if (!pCaller->stackMark)
3299 {
3300 pCaller->pFoundMethod = pFunc;
3301 pCaller->pAppDomain = pCf->GetAppDomain();
3302 return SWA_ABORT;
3303 }
3304
3305 // If we got here, we must already be in the frame containing the stack mark and we are not looking for "me".
3306 _ASSERTE(pCaller->stackMark &&
3307 pCf->IsInCalleesFrames(pCaller->stackMark) &&
3308 *(pCaller->stackMark) != LookForMe);
3309
3310 // When looking for caller's caller, we delay returning results for another
3311 // round (the way this is structured, we will still be able to skip
3312 // reflection and remoting frames between the caller and the caller's
3313 // caller).
3314
3315 if ((*(pCaller->stackMark) == LookForMyCallersCaller) &&
3316 (pCaller->pFoundMethod == NULL))
3317 {
3318 pCaller->pFoundMethod = pFunc;
3319 return SWA_CONTINUE;
3320 }
3321
3322 // If remoting is not available, we only set the caller if the crawlframe is from the same domain.
3323 // Why? Because if the callerdomain is different from current domain,
3324 // there have to be interop/native frames in between.
3325 // For example, in the CORECLR, if we find the caller to be in a different domain, then the
3326 // call into reflection is due to an unmanaged call into mscorlib. For that
3327 // case, the caller really is an INTEROP method.
3328 // In general, if the caller is INTEROP, we set the caller/callerdomain to be NULL
3329 // (To be precise: they are already NULL and we don't change them).
3330 if (pCf->GetAppDomain() == GetAppDomain())
3331 // We must either be looking for the caller, or the caller's caller when
3332 // we've already found the caller (we used a non-null value in pFoundMethod
3333 // simply as a flag, the correct method to return in both case is the
3334 // current method).
3335 {
3336 pCaller->pFoundMethod = pFunc;
3337 pCaller->pAppDomain = pCf->GetAppDomain();
3338 }
3339
3340 return SWA_ABORT;
3341}
3342
3343/*private static*/
3344StackWalkAction SystemDomain::CallersMethodCallback(CrawlFrame* pCf, VOID* data)
3345{
3346 LIMITED_METHOD_CONTRACT;
3347 STATIC_CONTRACT_SO_TOLERANT;
3348 MethodDesc *pFunc = pCf->GetFunction();
3349
3350 /* We asked to be called back only for functions */
3351 _ASSERTE(pFunc);
3352
3353 CallersData* pCaller = (CallersData*) data;
3354 if(pCaller->skip == 0) {
3355 pCaller->pMethod = pFunc;
3356 return SWA_ABORT;
3357 }
3358 else {
3359 pCaller->skip--;
3360 return SWA_CONTINUE;
3361 }
3362
3363}
3364#endif // CROSSGEN_COMPILE
3365
3366#ifdef CROSSGEN_COMPILE
3367// defined in compile.cpp
3368extern CompilationDomain * theDomain;
3369#endif
3370
3371void AppDomain::Create()
3372{
3373 STANDARD_VM_CONTRACT;
3374
3375#ifdef CROSSGEN_COMPILE
3376 AppDomainRefHolder pDomain(theDomain);
3377#else
3378 AppDomainRefHolder pDomain(new AppDomain());
3379#endif
3380
3381 pDomain->Init();
3382
3383 // need to make this assignment here since we'll be releasing
3384 // the lock before calling AddDomain. So any other thread
3385 // grabbing this lock after we release it will find that
3386 // the COM Domain has already been created
3387 _ASSERTE (pDomain->GetId().m_dwId == DefaultADID);
3388
3389 // allocate a Virtual Call Stub Manager for the default domain
3390 pDomain->InitVSD();
3391
3392 pDomain->SetStage(AppDomain::STAGE_OPEN);
3393 pDomain.SuppressRelease();
3394
3395 m_pTheAppDomain = pDomain;
3396
3397 LOG((LF_CLASSLOADER | LF_CORDB,
3398 LL_INFO10,
3399 "Created the app domain at %p\n", m_pTheAppDomain));
3400}
3401
3402#ifdef DEBUGGING_SUPPORTED
3403
3404void SystemDomain::PublishAppDomainAndInformDebugger (AppDomain *pDomain)
3405{
3406 CONTRACTL
3407 {
3408 if(!g_fEEInit) {THROWS;} else {DISABLED(NOTHROW);};
3409 if(!g_fEEInit) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);};
3410 MODE_ANY;
3411 }
3412 CONTRACTL_END;
3413
3414 LOG((LF_CORDB, LL_INFO100, "SD::PADAID: Adding 0x%x\n", pDomain));
3415
3416 // Call the publisher API to add this appdomain entry to the list
3417 // The publisher will handle failures, so we don't care if this succeeds or fails.
3418 if (g_pDebugInterface != NULL)
3419 {
3420 g_pDebugInterface->AddAppDomainToIPC(pDomain);
3421 }
3422}
3423
3424#endif // DEBUGGING_SUPPORTED
3425
3426void SystemDomain::AddDomain(AppDomain* pDomain)
3427{
3428 CONTRACTL
3429 {
3430 NOTHROW;
3431 MODE_ANY;
3432 GC_TRIGGERS;
3433 PRECONDITION(CheckPointer((pDomain)));
3434 }
3435 CONTRACTL_END;
3436
3437 {
3438 LockHolder lh;
3439
3440 _ASSERTE (pDomain->m_Stage != AppDomain::STAGE_CREATING);
3441 if (pDomain->m_Stage == AppDomain::STAGE_READYFORMANAGEDCODE ||
3442 pDomain->m_Stage == AppDomain::STAGE_ACTIVE)
3443 {
3444 pDomain->SetStage(AppDomain::STAGE_OPEN);
3445 IncrementNumAppDomains(); // Maintain a count of app domains added to the list.
3446 }
3447 }
3448
3449 // Note that if you add another path that can reach here without calling
3450 // PublishAppDomainAndInformDebugger, then you should go back & make sure
3451 // that PADAID gets called. Right after this call, if not sooner.
3452 LOG((LF_CORDB, LL_INFO1000, "SD::AD:Would have added domain here! 0x%x\n",
3453 pDomain));
3454}
3455
3456BOOL SystemDomain::RemoveDomain(AppDomain* pDomain)
3457{
3458 CONTRACTL
3459 {
3460 NOTHROW;
3461 GC_TRIGGERS;
3462 MODE_ANY;
3463 PRECONDITION(CheckPointer(pDomain));
3464 PRECONDITION(!pDomain->IsDefaultDomain());
3465 }
3466 CONTRACTL_END;
3467
3468 // You can not remove the default domain.
3469
3470
3471 if (!pDomain->IsActive())
3472 return FALSE;
3473
3474 pDomain->Release();
3475
3476 return TRUE;
3477}
3478
3479
3480#ifdef PROFILING_SUPPORTED
3481void SystemDomain::NotifyProfilerStartup()
3482{
3483 CONTRACTL
3484 {
3485 NOTHROW;
3486 GC_TRIGGERS;
3487 MODE_PREEMPTIVE;
3488 }
3489 CONTRACTL_END;
3490
3491 {
3492 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3493 _ASSERTE(System());
3494 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System());
3495 END_PIN_PROFILER();
3496 }
3497
3498 {
3499 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3500 _ASSERTE(System());
3501 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System(), S_OK);
3502 END_PIN_PROFILER();
3503 }
3504
3505 {
3506 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3507 _ASSERTE(System()->DefaultDomain());
3508 g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System()->DefaultDomain());
3509 END_PIN_PROFILER();
3510 }
3511
3512 {
3513 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3514 _ASSERTE(System()->DefaultDomain());
3515 g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3516 END_PIN_PROFILER();
3517 }
3518}
3519
3520HRESULT SystemDomain::NotifyProfilerShutdown()
3521{
3522 CONTRACTL
3523 {
3524 NOTHROW;
3525 GC_TRIGGERS;
3526 MODE_PREEMPTIVE;
3527 }
3528 CONTRACTL_END;
3529
3530 {
3531 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3532 _ASSERTE(System());
3533 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System());
3534 END_PIN_PROFILER();
3535 }
3536
3537 {
3538 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3539 _ASSERTE(System());
3540 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System(), S_OK);
3541 END_PIN_PROFILER();
3542 }
3543
3544 {
3545 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3546 _ASSERTE(System()->DefaultDomain());
3547 g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System()->DefaultDomain());
3548 END_PIN_PROFILER();
3549 }
3550
3551 {
3552 BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads());
3553 _ASSERTE(System()->DefaultDomain());
3554 g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System()->DefaultDomain(), S_OK);
3555 END_PIN_PROFILER();
3556 }
3557 return (S_OK);
3558}
3559#endif // PROFILING_SUPPORTED
3560
3561
3562#ifdef _DEBUG
3563struct AppDomain::ThreadTrackInfo {
3564 Thread *pThread;
3565 CDynArray<Frame *> frameStack;
3566};
3567#endif // _DEBUG
3568
3569AppDomain::AppDomain()
3570{
3571 // initialize fields so the appdomain can be safely destructed
3572 // shouldn't call anything that can fail here - use ::Init instead
3573 CONTRACTL
3574 {
3575 THROWS;
3576 GC_TRIGGERS;
3577 MODE_ANY;
3578 FORBID_FAULT;
3579 }
3580 CONTRACTL_END;
3581
3582 m_cRef=1;
3583
3584 m_pRootAssembly = NULL;
3585
3586 m_dwFlags = 0;
3587#ifdef FEATURE_COMINTEROP
3588 m_pRCWCache = NULL;
3589 m_pRCWRefCache = NULL;
3590 m_pLicenseInteropHelperMT = NULL;
3591 memset(m_rpCLRTypes, 0, sizeof(m_rpCLRTypes));
3592#endif // FEATURE_COMINTEROP
3593
3594 m_handleStore = NULL;
3595
3596 #ifdef _DEBUG
3597 m_pThreadTrackInfoList = NULL;
3598 m_TrackSpinLock = 0;
3599 m_Assemblies.Debug_SetAppDomain(this);
3600#endif // _DEBUG
3601
3602 m_dwThreadEnterCount = 0;
3603 m_dwThreadsStillInAppDomain = (ULONG)-1;
3604
3605#ifdef FEATURE_COMINTEROP
3606 m_pRefDispIDCache = NULL;
3607 m_hndMissing = NULL;
3608#endif
3609
3610 m_pRefClassFactHash = NULL;
3611
3612 m_ReversePInvokeCanEnter=TRUE;
3613 m_ForceTrivialWaitOperations = false;
3614 m_Stage=STAGE_CREATING;
3615
3616#ifdef _DEBUG
3617 m_dwIterHolders=0;
3618 m_dwRefTakers=0;
3619 m_dwCreationHolders=0;
3620#endif
3621
3622#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3623 m_ullTotalProcessorUsage = 0;
3624 m_pullAllocBytes = NULL;
3625 m_pullSurvivedBytes = NULL;
3626#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3627
3628#ifdef FEATURE_TYPEEQUIVALENCE
3629 m_pTypeEquivalenceTable = NULL;
3630#endif // FEATURE_TYPEEQUIVALENCE
3631
3632#ifdef FEATURE_COMINTEROP
3633 m_pNameToTypeMap = NULL;
3634 m_vNameToTypeMapVersion = 0;
3635 m_nEpoch = 0;
3636 m_pWinRTFactoryCache = NULL;
3637#endif // FEATURE_COMINTEROP
3638
3639#ifdef FEATURE_PREJIT
3640 m_pDomainFileWithNativeImageList = NULL;
3641#endif
3642
3643} // AppDomain::AppDomain
3644
3645AppDomain::~AppDomain()
3646{
3647 CONTRACTL
3648 {
3649 NOTHROW;
3650 GC_TRIGGERS;
3651 MODE_ANY;
3652 }
3653 CONTRACTL_END;
3654
3655#ifndef CROSSGEN_COMPILE
3656
3657 _ASSERTE(m_dwCreationHolders == 0);
3658
3659 // release the TPIndex. note that since TPIndex values are recycled the TPIndex
3660 // can only be released once all threads in the AppDomain have exited.
3661 if (GetTPIndex().m_dwIndex != 0)
3662 PerAppDomainTPCountList::ResetAppDomainIndex(GetTPIndex());
3663
3664 if (m_dwId.m_dwId!=0)
3665 SystemDomain::ReleaseAppDomainId(m_dwId);
3666
3667 m_AssemblyCache.Clear();
3668
3669 if(!g_fEEInit)
3670 Terminate();
3671
3672
3673
3674
3675#ifdef FEATURE_COMINTEROP
3676 if (m_pNameToTypeMap != nullptr)
3677 {
3678 delete m_pNameToTypeMap;
3679 m_pNameToTypeMap = nullptr;
3680 }
3681 if (m_pWinRTFactoryCache != nullptr)
3682 {
3683 delete m_pWinRTFactoryCache;
3684 m_pWinRTFactoryCache = nullptr;
3685 }
3686#endif //FEATURE_COMINTEROP
3687
3688#ifdef _DEBUG
3689 // If we were tracking thread AD transitions, cleanup the list on shutdown
3690 if (m_pThreadTrackInfoList)
3691 {
3692 while (m_pThreadTrackInfoList->Count() > 0)
3693 {
3694 // Get the very last element
3695 ThreadTrackInfo *pElem = *(m_pThreadTrackInfoList->Get(m_pThreadTrackInfoList->Count() - 1));
3696 _ASSERTE(pElem);
3697
3698 // Free the memory
3699 delete pElem;
3700
3701 // Remove pointer entry from the list
3702 m_pThreadTrackInfoList->Delete(m_pThreadTrackInfoList->Count() - 1);
3703 }
3704
3705 // Now delete the list itself
3706 delete m_pThreadTrackInfoList;
3707 m_pThreadTrackInfoList = NULL;
3708 }
3709#endif // _DEBUG
3710
3711#endif // CROSSGEN_COMPILE
3712}
3713
3714//*****************************************************************************
3715//*****************************************************************************
3716//*****************************************************************************
3717void AppDomain::Init()
3718{
3719 CONTRACTL
3720 {
3721 STANDARD_VM_CHECK;
3722 }
3723 CONTRACTL_END;
3724
3725 m_pDelayedLoaderAllocatorUnloadList = NULL;
3726
3727 SetStage( STAGE_CREATING);
3728
3729
3730 // The lock is taken also during stack walking (GC or profiler)
3731 // - To prevent deadlock with GC thread, we cannot trigger GC while holding the lock
3732 // - To prevent deadlock with profiler thread, we cannot allow thread suspension
3733 m_crstHostAssemblyMap.Init(
3734 CrstHostAssemblyMap,
3735 (CrstFlags)(CRST_GC_NOTRIGGER_WHEN_TAKEN
3736 | CRST_DEBUGGER_THREAD
3737 INDEBUG(| CRST_DEBUG_ONLY_CHECK_FORBID_SUSPEND_THREAD)));
3738 m_crstHostAssemblyMapAdd.Init(CrstHostAssemblyMapAdd);
3739
3740 m_dwId = SystemDomain::GetNewAppDomainId(this);
3741
3742#ifndef CROSSGEN_COMPILE
3743 //Allocate the threadpool entry before the appdomain id list. Otherwise,
3744 //the thread pool list will be out of sync if insertion of id in
3745 //the appdomain fails.
3746 m_tpIndex = PerAppDomainTPCountList::AddNewTPIndex();
3747#endif // CROSSGEN_COMPILE
3748
3749 m_dwIndex = SystemDomain::GetNewAppDomainIndex(this);
3750
3751#ifndef CROSSGEN_COMPILE
3752 PerAppDomainTPCountList::SetAppDomainId(m_tpIndex, m_dwId);
3753#endif
3754
3755 BaseDomain::Init();
3756
3757// Set up the binding caches
3758 m_AssemblyCache.Init(&m_DomainCacheCrst, GetHighFrequencyHeap());
3759 m_UnmanagedCache.InitializeTable(this, &m_DomainCacheCrst);
3760
3761 m_MemoryPressure = 0;
3762
3763 m_sDomainLocalBlock.Init(this);
3764
3765#ifndef CROSSGEN_COMPILE
3766
3767#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3768 // NOTE: it's important that we initialize ARM data structures before calling
3769 // IGCHandleManager::CreateHandleStore, this is because AD::Init() can race with GC
3770 // and once we add ourselves to the handle table map the GC can start walking
3771 // our handles and calling AD::RecordSurvivedBytes() which touches ARM data.
3772 if (GCHeapUtilities::IsServerHeap())
3773 m_dwNumHeaps = CPUGroupInfo::CanEnableGCCPUGroups() ?
3774 CPUGroupInfo::GetNumActiveProcessors() :
3775 GetCurrentProcessCpuCount();
3776 else
3777 m_dwNumHeaps = 1;
3778 m_pullAllocBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
3779 m_pullSurvivedBytes = new ULONGLONG [m_dwNumHeaps * ARM_CACHE_LINE_SIZE_ULL];
3780 for (DWORD i = 0; i < m_dwNumHeaps; i++)
3781 {
3782 m_pullAllocBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
3783 m_pullSurvivedBytes[i * ARM_CACHE_LINE_SIZE_ULL] = 0;
3784 }
3785 m_ullLastEtwAllocBytes = 0;
3786#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3787
3788 // Default domain reuses the handletablemap that was created during EEStartup since
3789 // default domain cannot be unloaded.
3790 if (GetId().m_dwId == DefaultADID)
3791 {
3792 m_handleStore = GCHandleUtilities::GetGCHandleManager()->GetGlobalHandleStore();
3793 }
3794 else
3795 {
3796 m_handleStore = GCHandleUtilities::GetGCHandleManager()->CreateHandleStore((void*)(uintptr_t)m_dwIndex.m_dwIndex);
3797 }
3798
3799 if (!m_handleStore)
3800 {
3801 COMPlusThrowOM();
3802 }
3803
3804#endif // CROSSGEN_COMPILE
3805
3806#ifdef FEATURE_TYPEEQUIVALENCE
3807 m_TypeEquivalenceCrst.Init(CrstTypeEquivalenceMap);
3808#endif
3809
3810 m_ReflectionCrst.Init(CrstReflection, CRST_UNSAFE_ANYMODE);
3811 m_RefClassFactCrst.Init(CrstClassFactInfoHash);
3812
3813 {
3814 LockOwner lock = {&m_DomainCrst, IsOwnerOfCrst};
3815 m_clsidHash.Init(0,&CompareCLSID,true, &lock); // init hash table
3816 }
3817
3818 SetStage(STAGE_READYFORMANAGEDCODE);
3819
3820#ifndef CROSSGEN_COMPILE
3821 COUNTER_ONLY(GetPerfCounters().m_Loading.cAppDomains++);
3822
3823#ifdef FEATURE_TIERED_COMPILATION
3824 m_tieredCompilationManager.Init(GetId());
3825#endif
3826#endif // CROSSGEN_COMPILE
3827} // AppDomain::Init
3828
3829
3830/*********************************************************************/
3831
3832BOOL AppDomain::IsCompilationDomain()
3833{
3834 LIMITED_METHOD_CONTRACT;
3835
3836 BOOL isCompilationDomain = (m_dwFlags & COMPILATION_DOMAIN) != 0;
3837#ifdef FEATURE_PREJIT
3838 _ASSERTE(!isCompilationDomain || IsCompilationProcess());
3839#endif // FEATURE_PREJIT
3840 return isCompilationDomain;
3841}
3842
3843#ifndef CROSSGEN_COMPILE
3844
3845void AppDomain::Stop()
3846{
3847 CONTRACTL
3848 {
3849 NOTHROW;
3850 MODE_ANY;
3851 GC_TRIGGERS;
3852 }
3853 CONTRACTL_END;
3854
3855#ifdef FEATURE_MULTICOREJIT
3856 GetMulticoreJitManager().StopProfile(true);
3857#endif
3858
3859 // Set the unloaded flag before notifying the debugger
3860 GetLoaderAllocator()->SetIsUnloaded();
3861
3862#ifdef DEBUGGING_SUPPORTED
3863 if (IsDebuggerAttached())
3864 NotifyDebuggerUnload();
3865#endif // DEBUGGING_SUPPORTED
3866
3867 m_pRootAssembly = NULL; // This assembly is in the assembly list;
3868
3869#ifdef DEBUGGING_SUPPORTED
3870 if (NULL != g_pDebugInterface)
3871 {
3872 // Call the publisher API to delete this appdomain entry from the list
3873 CONTRACT_VIOLATION(ThrowsViolation);
3874 g_pDebugInterface->RemoveAppDomainFromIPC (this);
3875 }
3876#endif // DEBUGGING_SUPPORTED
3877}
3878
3879void AppDomain::Terminate()
3880{
3881 CONTRACTL
3882 {
3883 NOTHROW;
3884 GC_TRIGGERS;
3885 MODE_ANY;
3886 }
3887 CONTRACTL_END;
3888
3889 GCX_PREEMP();
3890
3891 _ASSERTE(m_dwThreadEnterCount == 0 || IsDefaultDomain());
3892
3893#ifdef FEATURE_COMINTEROP
3894 if (m_pRCWCache)
3895 {
3896 delete m_pRCWCache;
3897 m_pRCWCache = NULL;
3898 }
3899
3900 if (m_pRCWRefCache)
3901 {
3902 delete m_pRCWRefCache;
3903 m_pRCWRefCache = NULL;
3904 }
3905#endif // FEATURE_COMINTEROP
3906
3907
3908 if (!IsAtProcessExit())
3909 {
3910 // if we're not shutting down everything then clean up the string literals associated
3911 // with this appdomain -- note that is no longer needs to happen while suspended
3912 // because the appropriate locks are taken in the GlobalStringLiteralMap
3913 // this is important as this locks have a higher lock number than does the
3914 // thread-store lock which is taken when we suspend.
3915 GetLoaderAllocator()->CleanupStringLiteralMap();
3916
3917 // Suspend the EE to do some clean up that can only occur
3918 // while no threads are running.
3919 GCX_COOP (); // SuspendEE may require current thread to be in Coop mode
3920 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
3921 }
3922
3923 // Note that this must be performed before restarting the EE. It will clean
3924 // the cache and prevent others from using stale cache entries.
3925 //@TODO: Would be nice to get this back to BaseDomain, but need larger fix for that.
3926 // NOTE: Must have the runtime suspended to unlink managers
3927 // NOTE: May be NULL due to OOM during initialization. Can skip in that case.
3928 GetLoaderAllocator()->UninitVirtualCallStubManager();
3929 MethodTable::ClearMethodDataCache();
3930 ClearJitGenericHandleCache(this);
3931
3932 // @TODO s_TPMethodTableCrst prevents us from from keeping the whole
3933 // assembly shutdown logic here. See if we can do better in the next milestone
3934#ifdef FEATURE_PREJIT
3935 DeleteNativeCodeRanges();
3936#endif
3937
3938 if (!IsAtProcessExit())
3939 {
3940 // Resume the EE.
3941 ThreadSuspend::RestartEE(FALSE, TRUE);
3942 }
3943
3944 ShutdownAssemblies();
3945 ShutdownNativeDllSearchDirectories();
3946
3947 if (m_pRefClassFactHash)
3948 {
3949 m_pRefClassFactHash->Destroy();
3950 // storage for m_pRefClassFactHash itself is allocated on the loader heap
3951 }
3952
3953#ifdef FEATURE_TYPEEQUIVALENCE
3954 m_TypeEquivalenceCrst.Destroy();
3955#endif
3956
3957 m_ReflectionCrst.Destroy();
3958 m_RefClassFactCrst.Destroy();
3959
3960 BaseDomain::Terminate();
3961
3962 if (m_handleStore)
3963 {
3964 GCHandleUtilities::GetGCHandleManager()->DestroyHandleStore(m_handleStore);
3965 m_handleStore = NULL;
3966 }
3967
3968#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3969 if (m_pullAllocBytes)
3970 {
3971 delete [] m_pullAllocBytes;
3972 }
3973 if (m_pullSurvivedBytes)
3974 {
3975 delete [] m_pullSurvivedBytes;
3976 }
3977#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
3978
3979 if(m_dwIndex.m_dwIndex != 0)
3980 SystemDomain::ReleaseAppDomainIndex(m_dwIndex);
3981} // AppDomain::Terminate
3982
3983void AppDomain::CloseDomain()
3984{
3985 CONTRACTL
3986 {
3987 NOTHROW;
3988 GC_TRIGGERS;
3989 MODE_ANY;
3990 }
3991 CONTRACTL_END;
3992
3993
3994 BOOL bADRemoved=FALSE;;
3995
3996 AddRef(); // Hold a reference
3997 AppDomainRefHolder AdHolder(this);
3998 {
3999 SystemDomain::LockHolder lh;
4000
4001 SystemDomain::System()->DecrementNumAppDomains(); // Maintain a count of app domains added to the list.
4002 bADRemoved = SystemDomain::System()->RemoveDomain(this);
4003 }
4004
4005 if(bADRemoved)
4006 Stop();
4007}
4008
4009#endif // !CROSSGEN_COMPILE
4010
4011#ifdef FEATURE_COMINTEROP
4012MethodTable *AppDomain::GetRedirectedType(WinMDAdapter::RedirectedTypeIndex index)
4013{
4014 CONTRACTL
4015 {
4016 THROWS;
4017 GC_TRIGGERS;
4018 MODE_ANY;
4019 }
4020 CONTRACTL_END;
4021
4022 // If we have the type loaded already, use that
4023 if (m_rpCLRTypes[index] != nullptr)
4024 {
4025 return m_rpCLRTypes[index];
4026 }
4027
4028 WinMDAdapter::FrameworkAssemblyIndex frameworkAssemblyIndex;
4029 WinMDAdapter::GetRedirectedTypeInfo(index, nullptr, nullptr, nullptr, &frameworkAssemblyIndex, nullptr, nullptr);
4030 MethodTable * pMT = LoadRedirectedType(index, frameworkAssemblyIndex);
4031 m_rpCLRTypes[index] = pMT;
4032 return pMT;
4033}
4034
4035MethodTable* AppDomain::LoadRedirectedType(WinMDAdapter::RedirectedTypeIndex index, WinMDAdapter::FrameworkAssemblyIndex assembly)
4036{
4037 CONTRACTL
4038 {
4039 THROWS;
4040 GC_TRIGGERS;
4041 MODE_ANY;
4042 PRECONDITION(index < WinMDAdapter::RedirectedTypeIndex_Count);
4043 }
4044 CONTRACTL_END;
4045
4046 LPCSTR szClrNamespace;
4047 LPCSTR szClrName;
4048 LPCSTR szFullWinRTName;
4049 WinMDAdapter::FrameworkAssemblyIndex nFrameworkAssemblyIndex;
4050
4051 WinMDAdapter::GetRedirectedTypeInfo(index, &szClrNamespace, &szClrName, &szFullWinRTName, &nFrameworkAssemblyIndex, nullptr, nullptr);
4052
4053 _ASSERTE(nFrameworkAssemblyIndex >= WinMDAdapter::FrameworkAssembly_Mscorlib &&
4054 nFrameworkAssemblyIndex < WinMDAdapter::FrameworkAssembly_Count);
4055
4056 if (assembly != nFrameworkAssemblyIndex)
4057 {
4058 // The framework type does not live in the assembly we were requested to load redirected types from
4059 return nullptr;
4060 }
4061 else if (nFrameworkAssemblyIndex == WinMDAdapter::FrameworkAssembly_Mscorlib)
4062 {
4063 return ClassLoader::LoadTypeByNameThrowing(MscorlibBinder::GetModule()->GetAssembly(),
4064 szClrNamespace,
4065 szClrName,
4066 ClassLoader::ThrowIfNotFound,
4067 ClassLoader::LoadTypes,
4068 CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4069 }
4070 else
4071 {
4072 LPCSTR pSimpleName;
4073 AssemblyMetaDataInternal context;
4074 const BYTE * pbKeyToken;
4075 DWORD cbKeyTokenLength;
4076 DWORD dwFlags;
4077
4078 WinMDAdapter::GetExtraAssemblyRefProps(nFrameworkAssemblyIndex,
4079 &pSimpleName,
4080 &context,
4081 &pbKeyToken,
4082 &cbKeyTokenLength,
4083 &dwFlags);
4084
4085 Assembly* pAssembly = AssemblySpec::LoadAssembly(pSimpleName,
4086 &context,
4087 pbKeyToken,
4088 cbKeyTokenLength,
4089 dwFlags);
4090
4091 return ClassLoader::LoadTypeByNameThrowing(
4092 pAssembly,
4093 szClrNamespace,
4094 szClrName,
4095 ClassLoader::ThrowIfNotFound,
4096 ClassLoader::LoadTypes,
4097 CLASS_LOAD_EXACTPARENTS).GetMethodTable();
4098 }
4099}
4100#endif //FEATURE_COMINTEROP
4101
4102#endif //!DACCESS_COMPILE
4103
4104#ifndef DACCESS_COMPILE
4105
4106bool IsPlatformAssembly(LPCSTR szName, DomainAssembly *pDomainAssembly)
4107{
4108 CONTRACTL
4109 {
4110 THROWS;
4111 GC_TRIGGERS;
4112 MODE_ANY;
4113 PRECONDITION(CheckPointer(szName));
4114 PRECONDITION(CheckPointer(pDomainAssembly));
4115 }
4116 CONTRACTL_END;
4117
4118 PEAssembly *pPEAssembly = pDomainAssembly->GetFile();
4119
4120 if (strcmp(szName, pPEAssembly->GetSimpleName()) != 0)
4121 {
4122 return false;
4123 }
4124
4125 DWORD cbPublicKey;
4126 const BYTE *pbPublicKey = static_cast<const BYTE *>(pPEAssembly->GetPublicKey(&cbPublicKey));
4127 if (pbPublicKey == nullptr)
4128 {
4129 return false;
4130 }
4131
4132 return StrongNameIsSilverlightPlatformKey(pbPublicKey, cbPublicKey);
4133}
4134
4135void AppDomain::AddAssembly(DomainAssembly * assem)
4136{
4137 CONTRACTL
4138 {
4139 THROWS;
4140 GC_TRIGGERS;
4141 MODE_ANY;
4142 INJECT_FAULT(COMPlusThrowOM(););
4143 }
4144 CONTRACTL_END;
4145
4146 {
4147 CrstHolder ch(GetAssemblyListLock());
4148
4149 // Attempt to find empty space in assemblies list
4150 DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4151 for (DWORD i = 0; i < asmCount; ++i)
4152 {
4153 if (m_Assemblies.Get_UnlockedNoReference(i) == NULL)
4154 {
4155 m_Assemblies.Set_Unlocked(i, assem);
4156 return;
4157 }
4158 }
4159
4160 // If empty space not found, simply add to end of list
4161 IfFailThrow(m_Assemblies.Append_Unlocked(assem));
4162 }
4163}
4164
4165void AppDomain::RemoveAssembly(DomainAssembly * pAsm)
4166{
4167 CONTRACTL
4168 {
4169 NOTHROW;
4170 GC_NOTRIGGER;
4171 }
4172 CONTRACTL_END;
4173
4174 CrstHolder ch(GetAssemblyListLock());
4175 DWORD asmCount = m_Assemblies.GetCount_Unlocked();
4176 for (DWORD i = 0; i < asmCount; ++i)
4177 {
4178 if (m_Assemblies.Get_UnlockedNoReference(i) == pAsm)
4179 {
4180 m_Assemblies.Set_Unlocked(i, NULL);
4181 return;
4182 }
4183 }
4184
4185 _ASSERTE(!"Unreachable");
4186}
4187
4188BOOL AppDomain::ContainsAssembly(Assembly * assem)
4189{
4190 WRAPPER_NO_CONTRACT;
4191 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
4192 kIncludeLoaded | kIncludeExecution));
4193 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
4194
4195 while (i.Next(pDomainAssembly.This()))
4196 {
4197 CollectibleAssemblyHolder<Assembly *> pAssembly = pDomainAssembly->GetLoadedAssembly();
4198 if (pAssembly == assem)
4199 return TRUE;
4200 }
4201
4202 return FALSE;
4203}
4204
4205EEClassFactoryInfoHashTable* AppDomain::SetupClassFactHash()
4206{
4207 CONTRACTL
4208 {
4209 THROWS;
4210 GC_TRIGGERS;
4211 MODE_ANY;
4212 INJECT_FAULT(COMPlusThrowOM(););
4213 }
4214 CONTRACTL_END;
4215
4216 CrstHolder ch(&m_ReflectionCrst);
4217
4218 if (m_pRefClassFactHash == NULL)
4219 {
4220 AllocMemHolder<void> pCache(GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (EEClassFactoryInfoHashTable))));
4221 EEClassFactoryInfoHashTable *tmp = new (pCache) EEClassFactoryInfoHashTable;
4222 LockOwner lock = {&m_RefClassFactCrst,IsOwnerOfCrst};
4223 if (!tmp->Init(20, &lock))
4224 COMPlusThrowOM();
4225 pCache.SuppressRelease();
4226 m_pRefClassFactHash = tmp;
4227 }
4228
4229 return m_pRefClassFactHash;
4230}
4231
4232#ifdef FEATURE_COMINTEROP
4233DispIDCache* AppDomain::SetupRefDispIDCache()
4234{
4235 CONTRACTL
4236 {
4237 THROWS;
4238 GC_TRIGGERS;
4239 MODE_ANY;
4240 INJECT_FAULT(COMPlusThrowOM(););
4241 }
4242 CONTRACTL_END;
4243
4244 CrstHolder ch(&m_ReflectionCrst);
4245
4246 if (m_pRefDispIDCache == NULL)
4247 {
4248 AllocMemHolder<void> pCache = GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof (DispIDCache)));
4249
4250 DispIDCache *tmp = new (pCache) DispIDCache;
4251 tmp->Init();
4252
4253 pCache.SuppressRelease();
4254 m_pRefDispIDCache = tmp;
4255 }
4256
4257 return m_pRefDispIDCache;
4258}
4259
4260#endif // FEATURE_COMINTEROP
4261
4262FileLoadLock *FileLoadLock::Create(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
4263{
4264 CONTRACTL
4265 {
4266 THROWS;
4267 GC_TRIGGERS;
4268 MODE_ANY;
4269 PRECONDITION(pLock->HasLock());
4270 PRECONDITION(pLock->FindFileLock(pFile) == NULL);
4271 INJECT_FAULT(COMPlusThrowOM(););
4272 }
4273 CONTRACTL_END;
4274
4275 NewHolder<FileLoadLock> result(new FileLoadLock(pLock, pFile, pDomainFile));
4276
4277 pLock->AddElement(result);
4278 result->AddRef(); // Add one ref on behalf of the ListLock's reference. The corresponding Release() happens in FileLoadLock::CompleteLoadLevel.
4279 return result.Extract();
4280}
4281
4282FileLoadLock::~FileLoadLock()
4283{
4284 CONTRACTL
4285 {
4286 DESTRUCTOR_CHECK;
4287 NOTHROW;
4288 GC_TRIGGERS;
4289 MODE_ANY;
4290 }
4291 CONTRACTL_END;
4292 ((PEFile *) m_data)->Release();
4293}
4294
4295DomainFile *FileLoadLock::GetDomainFile()
4296{
4297 LIMITED_METHOD_CONTRACT;
4298 return m_pDomainFile;
4299}
4300
4301FileLoadLevel FileLoadLock::GetLoadLevel()
4302{
4303 LIMITED_METHOD_CONTRACT;
4304 return m_level;
4305}
4306
4307ADID FileLoadLock::GetAppDomainId()
4308{
4309 LIMITED_METHOD_CONTRACT;
4310 return m_AppDomainId;
4311}
4312
4313// Acquire will return FALSE and not take the lock if the file
4314// has already been loaded to the target level. Otherwise,
4315// it will return TRUE and take the lock.
4316//
4317// Note that the taker must release the lock via IncrementLoadLevel.
4318
4319BOOL FileLoadLock::Acquire(FileLoadLevel targetLevel)
4320{
4321 WRAPPER_NO_CONTRACT;
4322
4323 // If we are already loaded to the desired level, the lock is "free".
4324 if (m_level >= targetLevel)
4325 return FALSE;
4326
4327 if (!DeadlockAwareEnter())
4328 {
4329 // We failed to get the lock due to a deadlock.
4330 return FALSE;
4331 }
4332
4333 if (m_level >= targetLevel)
4334 {
4335 Leave();
4336 return FALSE;
4337 }
4338
4339 return TRUE;
4340}
4341
4342BOOL FileLoadLock::CanAcquire(FileLoadLevel targetLevel)
4343{
4344 // If we are already loaded to the desired level, the lock is "free".
4345 if (m_level >= targetLevel)
4346 return FALSE;
4347
4348 return CanDeadlockAwareEnter();
4349}
4350
4351#if !defined(DACCESS_COMPILE) && (defined(LOGGING) || defined(STRESS_LOG))
4352static const char *fileLoadLevelName[] =
4353{
4354 "CREATE", // FILE_LOAD_CREATE
4355 "BEGIN", // FILE_LOAD_BEGIN
4356 "FIND_NATIVE_IMAGE", // FILE_LOAD_FIND_NATIVE_IMAGE
4357 "VERIFY_NATIVE_IMAGE_DEPENDENCIES", // FILE_LOAD_VERIFY_NATIVE_IMAGE_DEPENDENCIES
4358 "ALLOCATE", // FILE_LOAD_ALLOCATE
4359 "ADD_DEPENDENCIES", // FILE_LOAD_ADD_DEPENDENCIES
4360 "PRE_LOADLIBRARY", // FILE_LOAD_PRE_LOADLIBRARY
4361 "LOADLIBRARY", // FILE_LOAD_LOADLIBRARY
4362 "POST_LOADLIBRARY", // FILE_LOAD_POST_LOADLIBRARY
4363 "EAGER_FIXUPS", // FILE_LOAD_EAGER_FIXUPS
4364 "VTABLE FIXUPS", // FILE_LOAD_VTABLE_FIXUPS
4365 "DELIVER_EVENTS", // FILE_LOAD_DELIVER_EVENTS
4366 "LOADED", // FILE_LOADED
4367 "VERIFY_EXECUTION", // FILE_LOAD_VERIFY_EXECUTION
4368 "ACTIVE", // FILE_ACTIVE
4369};
4370#endif // !DACCESS_COMPILE && (LOGGING || STRESS_LOG)
4371
4372BOOL FileLoadLock::CompleteLoadLevel(FileLoadLevel level, BOOL success)
4373{
4374 CONTRACTL
4375 {
4376 MODE_ANY;
4377 GC_TRIGGERS;
4378 THROWS;
4379 PRECONDITION(HasLock());
4380 }
4381 CONTRACTL_END;
4382
4383 // Increment may happen more than once if reentrancy occurs (e.g. LoadLibrary)
4384 if (level > m_level)
4385 {
4386 // Must complete each level in turn, unless we have an error
4387 CONSISTENCY_CHECK(m_pDomainFile->IsError() || (level == (m_level+1)));
4388 // Remove the lock from the list if the load is completed
4389 if (level >= FILE_ACTIVE)
4390 {
4391 {
4392 GCX_COOP();
4393 PEFileListLockHolder lock((PEFileListLock*)m_pList);
4394
4395#if _DEBUG
4396 BOOL fDbgOnly_SuccessfulUnlink =
4397#endif
4398 m_pList->Unlink(this);
4399 _ASSERTE(fDbgOnly_SuccessfulUnlink);
4400
4401 m_pDomainFile->ClearLoading();
4402
4403 CONSISTENCY_CHECK(m_dwRefCount >= 2); // Caller (LoadDomainFile) should have 1 refcount and m_pList should have another which was acquired in FileLoadLock::Create.
4404
4405 m_level = (FileLoadLevel)level;
4406
4407 // Dev11 bug 236344
4408 // In AppDomain::IsLoading, if the lock is taken on m_pList and then FindFileLock returns NULL,
4409 // we depend on the DomainFile's load level being up to date. Hence we must update the load
4410 // level while the m_pList lock is held.
4411 if (success)
4412 m_pDomainFile->SetLoadLevel(level);
4413 }
4414
4415
4416 Release(); // Release m_pList's refcount on this lock, which was acquired in FileLoadLock::Create
4417
4418 }
4419 else
4420 {
4421 m_level = (FileLoadLevel)level;
4422
4423 if (success)
4424 m_pDomainFile->SetLoadLevel(level);
4425 }
4426
4427#ifndef DACCESS_COMPILE
4428 switch(level)
4429 {
4430 case FILE_LOAD_ALLOCATE:
4431 case FILE_LOAD_ADD_DEPENDENCIES:
4432 case FILE_LOAD_DELIVER_EVENTS:
4433 case FILE_LOADED:
4434 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.
4435 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);
4436 break;
4437 default:
4438 break;
4439 }
4440#endif
4441
4442 return TRUE;
4443 }
4444 else
4445 return FALSE;
4446}
4447
4448void FileLoadLock::SetError(Exception *ex)
4449{
4450 CONTRACTL
4451 {
4452 MODE_ANY;
4453 GC_TRIGGERS;
4454 THROWS;
4455 PRECONDITION(CheckPointer(ex));
4456 PRECONDITION(HasLock());
4457 INJECT_FAULT(COMPlusThrowOM(););
4458 }
4459 CONTRACTL_END;
4460
4461 m_cachedHR = ex->GetHR();
4462
4463 LOG((LF_LOADER, LL_WARNING, "LOADER: %x:***%s*\t!!!Non-transient error 0x%x\n",
4464 m_pDomainFile->GetAppDomain(), m_pDomainFile->GetSimpleName(), m_cachedHR));
4465
4466 m_pDomainFile->SetError(ex);
4467
4468 CompleteLoadLevel(FILE_ACTIVE, FALSE);
4469}
4470
4471void FileLoadLock::AddRef()
4472{
4473 LIMITED_METHOD_CONTRACT;
4474 FastInterlockIncrement((LONG *) &m_dwRefCount);
4475}
4476
4477UINT32 FileLoadLock::Release()
4478{
4479 CONTRACTL
4480 {
4481 NOTHROW;
4482 GC_TRIGGERS;
4483 MODE_ANY;
4484 }
4485 CONTRACTL_END;
4486
4487 LONG count = FastInterlockDecrement((LONG *) &m_dwRefCount);
4488 if (count == 0)
4489 delete this;
4490
4491 return count;
4492}
4493
4494FileLoadLock::FileLoadLock(PEFileListLock *pLock, PEFile *pFile, DomainFile *pDomainFile)
4495 : ListLockEntry(pLock, pFile, "File load lock"),
4496 m_level((FileLoadLevel) (FILE_LOAD_CREATE)),
4497 m_pDomainFile(pDomainFile),
4498 m_cachedHR(S_OK),
4499 m_AppDomainId(pDomainFile->GetAppDomain()->GetId())
4500{
4501 WRAPPER_NO_CONTRACT;
4502 pFile->AddRef();
4503}
4504
4505void FileLoadLock::HolderLeave(FileLoadLock *pThis)
4506{
4507 LIMITED_METHOD_CONTRACT;
4508 pThis->Leave();
4509}
4510
4511
4512
4513
4514
4515
4516//
4517// Assembly loading:
4518//
4519// Assembly loading is carefully layered to avoid deadlocks in the
4520// presence of circular loading dependencies.
4521// A LoadLevel is associated with each assembly as it is being loaded. During the
4522// act of loading (abstractly, increasing its load level), its lock is
4523// held, and the current load level is stored on the thread. Any
4524// recursive loads during that period are automatically restricted to
4525// only partially load the dependent assembly to the same level as the
4526// caller (or to one short of that level in the presence of a deadlock
4527// loop.)
4528//
4529// Each loading stage must be carfully constructed so that
4530// this constraint is expected and can be dealt with.
4531//
4532// Note that there is one case where this still doesn't handle recursion, and that is the
4533// security subsytem. The security system runs managed code, and thus must typically fully
4534// initialize assemblies of permission sets it is trying to use. (And of course, these may be used
4535// while those assemblies are initializing.) This is dealt with in the historical manner - namely
4536// the security system passes in a special flag which says that it will deal with null return values
4537// in the case where a load cannot be safely completed due to such issues.
4538//
4539
4540void AppDomain::LoadSystemAssemblies()
4541{
4542 STANDARD_VM_CONTRACT;
4543
4544 // The only reason to make an assembly a "system assembly" is if the EE is caching
4545 // pointers to stuff in the assembly. Because this is going on, we need to preserve
4546 // the invariant that the assembly is loaded into every app domain.
4547 //
4548 // Right now we have only one system assembly. We shouldn't need to add any more.
4549
4550 LoadAssembly(NULL, SystemDomain::System()->SystemFile(), FILE_ACTIVE);
4551}
4552
4553FileLoadLevel AppDomain::GetDomainFileLoadLevel(DomainFile *pFile)
4554{
4555 CONTRACTL
4556 {
4557 THROWS;
4558 GC_TRIGGERS;
4559 MODE_ANY;
4560 }
4561 CONTRACTL_END
4562
4563 LoadLockHolder lock(this);
4564
4565 FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
4566
4567 if (pLockEntry == NULL)
4568 return pFile->GetLoadLevel();
4569 else
4570 return pLockEntry->GetLoadLevel();
4571}
4572
4573// This checks if the thread has initiated (or completed) loading at the given level. A false guarantees that
4574// (a) The current thread (or a thread blocking on the current thread) has not started loading the file
4575// at the given level, and
4576// (b) No other thread had started loading the file at this level at the start of this function call.
4577
4578// Note that another thread may start loading the file at that level in a race with the completion of
4579// this function. However, the caller still has the guarantee that such a load started after this
4580// function was called (and e.g. any state in place before the function call will be seen by the other thread.)
4581//
4582// Conversely, a true guarantees that either the current thread has started the load step, or another
4583// thread has completed the load step.
4584//
4585
4586BOOL AppDomain::IsLoading(DomainFile *pFile, FileLoadLevel level)
4587{
4588 // Cheap out
4589 if (pFile->GetLoadLevel() < level)
4590 {
4591 FileLoadLock *pLock = NULL;
4592 {
4593 LoadLockHolder lock(this);
4594
4595 pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
4596
4597 if (pLock == NULL)
4598 {
4599 // No thread involved with loading
4600 return pFile->GetLoadLevel() >= level;
4601 }
4602
4603 pLock->AddRef();
4604 }
4605
4606 FileLoadLockRefHolder lockRef(pLock);
4607
4608 if (pLock->Acquire(level))
4609 {
4610 // We got the lock - therefore no other thread has started this loading step yet.
4611 pLock->Leave();
4612 return FALSE;
4613 }
4614
4615 // We didn't get the lock - either this thread is already doing the load,
4616 // or else the load has already finished.
4617 }
4618 return TRUE;
4619}
4620
4621// CheckLoading is a weaker form of IsLoading, which will not block on
4622// other threads waiting for their status. This is appropriate for asserts.
4623CHECK AppDomain::CheckLoading(DomainFile *pFile, FileLoadLevel level)
4624{
4625 // Cheap out
4626 if (pFile->GetLoadLevel() < level)
4627 {
4628 FileLoadLock *pLock = NULL;
4629
4630 LoadLockHolder lock(this);
4631
4632 pLock = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
4633
4634 if (pLock != NULL
4635 && pLock->CanAcquire(level))
4636 {
4637 // We can get the lock - therefore no other thread has started this loading step yet.
4638 CHECK_FAILF(("Loading step %d has not been initiated yet", level));
4639 }
4640
4641 // We didn't get the lock - either this thread is already doing the load,
4642 // or else the load has already finished.
4643 }
4644
4645 CHECK_OK;
4646}
4647
4648CHECK AppDomain::CheckCanLoadTypes(Assembly *pAssembly)
4649{
4650 CONTRACTL
4651 {
4652 THROWS;
4653 GC_TRIGGERS;
4654 MODE_ANY;
4655 }
4656 CONTRACTL_END;
4657 CHECK_MSG(CheckValidModule(pAssembly->GetManifestModule()),
4658 "Type loading can occur only when executing in the assembly's app domain");
4659 CHECK_OK;
4660}
4661
4662CHECK AppDomain::CheckCanExecuteManagedCode(MethodDesc* pMD)
4663{
4664 CONTRACTL
4665 {
4666 THROWS;
4667 GC_TRIGGERS;
4668 MODE_ANY;
4669 }
4670 CONTRACTL_END;
4671
4672 Module* pModule=pMD->GetModule();
4673
4674 CHECK_MSG(CheckValidModule(pModule),
4675 "Managed code can only run when executing in the module's app domain");
4676
4677 if (!pMD->IsInterface() || pMD->IsStatic()) //interfaces require no activation for instance methods
4678 {
4679 //cctor could have been interupted by ADU
4680 CHECK_MSG(pModule->CheckActivated(),
4681 "Managed code can only run when its module has been activated in the current app domain");
4682 }
4683
4684 CHECK_OK;
4685}
4686
4687#endif // !DACCESS_COMPILE
4688
4689void AppDomain::LoadDomainFile(DomainFile *pFile,
4690 FileLoadLevel targetLevel)
4691{
4692 CONTRACTL
4693 {
4694 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
4695 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
4696 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM();); }
4697 INJECT_FAULT(COMPlusThrowOM(););
4698 }
4699 CONTRACTL_END;
4700
4701 // Quick exit if finished
4702 if (pFile->GetLoadLevel() >= targetLevel)
4703 return;
4704
4705 // Handle the error case
4706 pFile->ThrowIfError(targetLevel);
4707
4708
4709#ifndef DACCESS_COMPILE
4710
4711 if (pFile->IsLoading())
4712 {
4713 GCX_PREEMP();
4714
4715 // Load some more if appropriate
4716 LoadLockHolder lock(this);
4717
4718 FileLoadLock* pLockEntry = (FileLoadLock *) lock->FindFileLock(pFile->GetFile());
4719 if (pLockEntry == NULL)
4720 {
4721 _ASSERTE (!pFile->IsLoading());
4722 return;
4723 }
4724
4725 pLockEntry->AddRef();
4726
4727 lock.Release();
4728
4729 LoadDomainFile(pLockEntry, targetLevel);
4730 }
4731
4732#else // DACCESS_COMPILE
4733 DacNotImpl();
4734#endif // DACCESS_COMPILE
4735}
4736
4737#ifndef DACCESS_COMPILE
4738
4739FileLoadLevel AppDomain::GetThreadFileLoadLevel()
4740{
4741 WRAPPER_NO_CONTRACT;
4742 if (GetThread()->GetLoadLevelLimiter() == NULL)
4743 return FILE_ACTIVE;
4744 else
4745 return (FileLoadLevel)(GetThread()->GetLoadLevelLimiter()->GetLoadLevel()-1);
4746}
4747
4748
4749Assembly *AppDomain::LoadAssembly(AssemblySpec* pIdentity,
4750 PEAssembly *pFile,
4751 FileLoadLevel targetLevel)
4752{
4753 CONTRACT(Assembly *)
4754 {
4755 GC_TRIGGERS;
4756 THROWS;
4757 MODE_ANY;
4758 PRECONDITION(CheckPointer(pFile));
4759 POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // May be NULL in recursive load case
4760 INJECT_FAULT(COMPlusThrowOM(););
4761 }
4762 CONTRACT_END;
4763
4764 DomainAssembly *pAssembly = LoadDomainAssembly(pIdentity, pFile, targetLevel);
4765 PREFIX_ASSUME(pAssembly != NULL);
4766
4767 RETURN pAssembly->GetAssembly();
4768}
4769
4770#ifndef CROSSGEN_COMPILE
4771// Thread stress
4772class LoadDomainAssemblyStress : APIThreadStress
4773{
4774public:
4775 AppDomain *pThis;
4776 AssemblySpec* pSpec;
4777 PEAssembly *pFile;
4778 FileLoadLevel targetLevel;
4779
4780 LoadDomainAssemblyStress(AppDomain *pThis, AssemblySpec* pSpec, PEAssembly *pFile, FileLoadLevel targetLevel)
4781 : pThis(pThis), pSpec(pSpec), pFile(pFile), targetLevel(targetLevel) {LIMITED_METHOD_CONTRACT;}
4782
4783 void Invoke()
4784 {
4785 WRAPPER_NO_CONTRACT;
4786 STATIC_CONTRACT_SO_INTOLERANT;
4787 SetupThread();
4788 pThis->LoadDomainAssembly(pSpec, pFile, targetLevel);
4789 }
4790};
4791#endif // CROSSGEN_COMPILE
4792
4793extern BOOL AreSameBinderInstance(ICLRPrivBinder *pBinderA, ICLRPrivBinder *pBinderB);
4794
4795DomainAssembly* AppDomain::LoadDomainAssembly( AssemblySpec* pSpec,
4796 PEAssembly *pFile,
4797 FileLoadLevel targetLevel)
4798{
4799 STATIC_CONTRACT_THROWS;
4800
4801 if (pSpec == nullptr)
4802 {
4803 // skip caching, since we don't have anything to base it on
4804 return LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
4805 }
4806
4807 DomainAssembly* pRetVal = NULL;
4808 EX_TRY
4809 {
4810 pRetVal = LoadDomainAssemblyInternal(pSpec, pFile, targetLevel);
4811 }
4812 EX_HOOK
4813 {
4814 Exception* pEx=GET_EXCEPTION();
4815 if (!pEx->IsTransient())
4816 {
4817 // Setup the binder reference in AssemblySpec from the PEAssembly if one is not already set.
4818 ICLRPrivBinder* pCurrentBindingContext = pSpec->GetBindingContext();
4819 ICLRPrivBinder* pBindingContextFromPEAssembly = pFile->GetBindingContext();
4820
4821 if (pCurrentBindingContext == NULL)
4822 {
4823 // Set the binding context we got from the PEAssembly if AssemblySpec does not
4824 // have that information
4825 _ASSERTE(pBindingContextFromPEAssembly != NULL);
4826 pSpec->SetBindingContext(pBindingContextFromPEAssembly);
4827 }
4828#if defined(_DEBUG)
4829 else
4830 {
4831 // Binding context in the spec should be the same as the binding context in the PEAssembly
4832 _ASSERTE(AreSameBinderInstance(pCurrentBindingContext, pBindingContextFromPEAssembly));
4833 }
4834#endif // _DEBUG
4835
4836 if (!EEFileLoadException::CheckType(pEx))
4837 {
4838 StackSString name;
4839 pSpec->GetFileOrDisplayName(0, name);
4840 pEx=new EEFileLoadException(name, pEx->GetHR(), NULL, pEx);
4841 AddExceptionToCache(pSpec, pEx);
4842 PAL_CPP_THROW(Exception *, pEx);
4843 }
4844 else
4845 AddExceptionToCache(pSpec, pEx);
4846 }
4847 }
4848 EX_END_HOOK;
4849
4850 return pRetVal;
4851}
4852
4853
4854DomainAssembly *AppDomain::LoadDomainAssemblyInternal(AssemblySpec* pIdentity,
4855 PEAssembly *pFile,
4856 FileLoadLevel targetLevel)
4857{
4858 CONTRACT(DomainAssembly *)
4859 {
4860 GC_TRIGGERS;
4861 THROWS;
4862 MODE_ANY;
4863 PRECONDITION(CheckPointer(pFile));
4864 PRECONDITION(pFile->IsSystem() || ::GetAppDomain()==this);
4865 POSTCONDITION(CheckPointer(RETVAL));
4866 POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
4867 || RETVAL->GetLoadLevel() >= targetLevel);
4868 POSTCONDITION(RETVAL->CheckNoError(targetLevel));
4869 INJECT_FAULT(COMPlusThrowOM(););
4870 }
4871 CONTRACT_END;
4872
4873
4874 DomainAssembly * result;
4875
4876#ifndef CROSSGEN_COMPILE
4877 LoadDomainAssemblyStress ts (this, pIdentity, pFile, targetLevel);
4878#endif
4879
4880 // Go into preemptive mode since this may take a while.
4881 GCX_PREEMP();
4882
4883 // Check for existing fully loaded assembly, or for an assembly which has failed during the loading process.
4884 result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
4885
4886 if (result == NULL)
4887 {
4888 LoaderAllocator *pLoaderAllocator = NULL;
4889
4890#ifndef CROSSGEN_COMPILE
4891 ICLRPrivBinder *pFileBinder = pFile->GetBindingContext();
4892 if (pFileBinder != NULL)
4893 {
4894 // Assemblies loaded with AssemblyLoadContext need to use a different LoaderAllocator if
4895 // marked as collectible
4896 pFileBinder->GetLoaderAllocator((LPVOID*)&pLoaderAllocator);
4897 }
4898#endif // !CROSSGEN_COMPILE
4899
4900 if (pLoaderAllocator == NULL)
4901 {
4902 pLoaderAllocator = this->GetLoaderAllocator();
4903 }
4904
4905 // Allocate the DomainAssembly a bit early to avoid GC mode problems. We could potentially avoid
4906 // a rare redundant allocation by moving this closer to FileLoadLock::Create, but it's not worth it.
4907 NewHolder<DomainAssembly> pDomainAssembly = new DomainAssembly(this, pFile, pLoaderAllocator);
4908
4909 LoadLockHolder lock(this);
4910
4911 // Find the list lock entry
4912 FileLoadLock * fileLock = (FileLoadLock *)lock->FindFileLock(pFile);
4913 if (fileLock == NULL)
4914 {
4915 // Check again in case we were racing
4916 result = FindAssembly(pFile, FindAssemblyOptions_IncludeFailedToLoad);
4917 if (result == NULL)
4918 {
4919 // We are the first one in - create the DomainAssembly
4920 fileLock = FileLoadLock::Create(lock, pFile, pDomainAssembly);
4921 pDomainAssembly.SuppressRelease();
4922#ifndef CROSSGEN_COMPILE
4923 if (pDomainAssembly->IsCollectible())
4924 {
4925 // We add the assembly to the LoaderAllocator only when we are sure that it can be added
4926 // and won't be deleted in case of a concurrent load from the same ALC
4927 ((AssemblyLoaderAllocator *)pLoaderAllocator)->AddDomainAssembly(pDomainAssembly);
4928 }
4929#endif // !CROSSGEN_COMPILE
4930 }
4931 }
4932 else
4933 {
4934 fileLock->AddRef();
4935 }
4936
4937 lock.Release();
4938
4939 if (result == NULL)
4940 {
4941 // We pass our ref on fileLock to LoadDomainFile to release.
4942
4943 // Note that if we throw here, we will poison fileLock with an error condition,
4944 // so it will not be removed until app domain unload. So there is no need
4945 // to release our ref count.
4946 result = (DomainAssembly *)LoadDomainFile(fileLock, targetLevel);
4947 }
4948 else
4949 {
4950 result->EnsureLoadLevel(targetLevel);
4951 }
4952 }
4953 else
4954 result->EnsureLoadLevel(targetLevel);
4955
4956 // Malformed metadata may contain a Module reference to what is actually
4957 // an Assembly. In this case we need to throw an exception, since returning
4958 // a DomainModule as a DomainAssembly is a type safety violation.
4959 if (!result->IsAssembly())
4960 {
4961 ThrowHR(COR_E_ASSEMBLYEXPECTED);
4962 }
4963
4964 // Cache result in all cases, since found pFile could be from a different AssemblyRef than pIdentity
4965 // Do not cache WindowsRuntime assemblies, they are cached in code:CLRPrivTypeCacheWinRT
4966 if ((pIdentity != NULL) && (pIdentity->CanUseWithBindingCache()) && (result->CanUseWithBindingCache()))
4967 GetAppDomain()->AddAssemblyToCache(pIdentity, result);
4968
4969 RETURN result;
4970} // AppDomain::LoadDomainAssembly
4971
4972
4973struct LoadFileArgs
4974{
4975 FileLoadLock *pLock;
4976 FileLoadLevel targetLevel;
4977 DomainFile *result;
4978};
4979
4980DomainFile *AppDomain::LoadDomainFile(FileLoadLock *pLock, FileLoadLevel targetLevel)
4981{
4982 CONTRACT(DomainFile *)
4983 {
4984 STANDARD_VM_CHECK;
4985 PRECONDITION(CheckPointer(pLock));
4986 PRECONDITION(pLock->GetDomainFile()->GetAppDomain() == this);
4987 POSTCONDITION(RETVAL->GetLoadLevel() >= GetThreadFileLoadLevel()
4988 || RETVAL->GetLoadLevel() >= targetLevel);
4989 POSTCONDITION(RETVAL->CheckNoError(targetLevel));
4990 }
4991 CONTRACT_END;
4992
4993 // Thread stress
4994 APIThreadStress::SyncThreadStress();
4995
4996 DomainFile *pFile = pLock->GetDomainFile();
4997
4998 // Make sure we release the lock on exit
4999 FileLoadLockRefHolder lockRef(pLock);
5000
5001 // We need to perform the early steps of loading mscorlib without a domain transition. This is
5002 // important for bootstrapping purposes - we need to get mscorlib at least partially loaded
5003 // into a domain before we can run serialization code to do the transition.
5004 //
5005 // Note that we cannot do this in general for all assemblies, because some of the security computations
5006 // require the managed exposed object, which must be created in the correct app domain.
5007
5008 if (this != GetAppDomain()
5009 && pFile->GetFile()->IsSystem()
5010 && targetLevel > FILE_LOAD_ALLOCATE)
5011 {
5012 // Re-call the routine with a limited load level. This will cause the first part of the load to
5013 // get performed in the current app domain.
5014
5015 pLock->AddRef();
5016 LoadDomainFile(pLock, targetLevel > FILE_LOAD_ALLOCATE ? FILE_LOAD_ALLOCATE : targetLevel);
5017
5018 // Now continue on to complete the rest of the load, if any.
5019 }
5020
5021 // Do a quick out check for the already loaded case.
5022 if (pLock->GetLoadLevel() >= targetLevel)
5023 {
5024 pFile->ThrowIfError(targetLevel);
5025
5026 RETURN pFile;
5027 }
5028
5029 // Initialize a loading queue. This will hold any loads which are triggered recursively but
5030 // which cannot be immediately satisfied due to anti-deadlock constraints.
5031
5032 // PendingLoadQueues are allocated on the stack during a load, and
5033 // shared with all nested loads on the same thread. (Note that we won't use
5034 // "candidate" if we are in a recursive load; that's OK since they are cheap to
5035 // construct.)
5036 FileLoadLevel immediateTargetLevel = targetLevel;
5037 {
5038 LoadLevelLimiter limit;
5039 limit.Activate();
5040
5041 // We cannot set a target level higher than that allowed by the limiter currently.
5042 // This is because of anti-deadlock constraints.
5043 if (immediateTargetLevel > limit.GetLoadLevel())
5044 immediateTargetLevel = limit.GetLoadLevel();
5045
5046 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t>>>Load initiated, %s/%s\n",
5047 pFile->GetAppDomain(), pFile->GetSimpleName(),
5048 fileLoadLevelName[immediateTargetLevel], fileLoadLevelName[targetLevel]));
5049
5050 // Now loop and do the load incrementally to the target level.
5051 if (pLock->GetLoadLevel() < immediateTargetLevel)
5052 {
5053 // Thread stress
5054 APIThreadStress::SyncThreadStress();
5055
5056 while (pLock->Acquire(immediateTargetLevel))
5057 {
5058 FileLoadLevel workLevel;
5059 {
5060 FileLoadLockHolder fileLock(pLock);
5061
5062 // Work level is next step to do
5063 workLevel = (FileLoadLevel)(fileLock->GetLoadLevel()+1);
5064
5065 // Set up the anti-deadlock constraint: we cannot safely recursively load any assemblies
5066 // on this thread to a higher level than this assembly is being loaded now.
5067 // Note that we do allow work at a parallel level; any deadlocks caused here will
5068 // be resolved by the deadlock detection in the FileLoadLocks.
5069 limit.SetLoadLevel(workLevel);
5070
5071 LOG((LF_LOADER,
5072 (workLevel == FILE_LOAD_BEGIN
5073 || workLevel == FILE_LOADED
5074 || workLevel == FILE_ACTIVE)
5075 ? LL_INFO10 : LL_INFO1000,
5076 "LOADER: %p:***%s*\t loading at level %s\n",
5077 this, pFile->GetSimpleName(), fileLoadLevelName[workLevel]));
5078
5079 TryIncrementalLoad(pFile, workLevel, fileLock);
5080 }
5081 TESTHOOKCALL(CompletedFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5082 }
5083
5084 if (pLock->GetLoadLevel() == immediateTargetLevel-1)
5085 {
5086 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load limited due to detected deadlock, %s\n",
5087 pFile->GetAppDomain(), pFile->GetSimpleName(),
5088 fileLoadLevelName[immediateTargetLevel-1]));
5089 }
5090 }
5091
5092 LOG((LF_LOADER, LL_INFO100, "LOADER: %x:***%s*\t<<<Load completed, %s\n",
5093 pFile->GetAppDomain(), pFile->GetSimpleName(),
5094 fileLoadLevelName[pLock->GetLoadLevel()]));
5095
5096 }
5097
5098 // There may have been an error stored on the domain file by another thread, or from a previous load
5099 pFile->ThrowIfError(targetLevel);
5100
5101 // There are two normal results from the above loop.
5102 //
5103 // 1. We succeeded in loading the file to the current thread's load level.
5104 // 2. We succeeded in loading the file to the current thread's load level - 1, due
5105 // to deadlock condition with another thread loading the same assembly.
5106 //
5107 // Either of these are considered satisfactory results, as code inside a load must expect
5108 // a parial load result.
5109 //
5110 // However, if load level elevation has occurred, then it is possible for a deadlock to
5111 // prevent us from loading an assembly which was loading before the elevation at a radically
5112 // lower level. In such a case, we throw an exception which transiently fails the current
5113 // load, since it is likely we have not satisfied the caller.
5114 // (An alternate, and possibly preferable, strategy here would be for all callers to explicitly
5115 // identify the minimum load level acceptable via CheckLoadDomainFile and throw from there.)
5116
5117 pFile->RequireLoadLevel((FileLoadLevel)(immediateTargetLevel-1));
5118
5119
5120 RETURN pFile;
5121}
5122
5123void AppDomain::TryIncrementalLoad(DomainFile *pFile, FileLoadLevel workLevel, FileLoadLockHolder &lockHolder)
5124{
5125 STANDARD_VM_CONTRACT;
5126
5127 // This is factored out so we don't call EX_TRY in a loop (EX_TRY can _alloca)
5128
5129 BOOL released = FALSE;
5130 FileLoadLock* pLoadLock = lockHolder.GetValue();
5131
5132 EX_TRY
5133 {
5134
5135 // Special case: for LoadLibrary, we cannot hold the lock during the
5136 // actual LoadLibrary call, because we might get a callback from _CorDllMain on any
5137 // other thread. (Note that this requires DomainFile's LoadLibrary to be independently threadsafe.)
5138
5139 if (workLevel == FILE_LOAD_LOADLIBRARY)
5140 {
5141 lockHolder.Release();
5142 released = TRUE;
5143 }
5144
5145 // Do the work
5146 TESTHOOKCALL(NextFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5147 BOOL success = pFile->DoIncrementalLoad(workLevel);
5148 TESTHOOKCALL(CompletingFileLoadLevel(GetId().m_dwId,pFile,workLevel));
5149 if (released)
5150 {
5151 // Reobtain lock to increment level. (Note that another thread may
5152 // have already done it which is OK.
5153 if (pLoadLock->Acquire(workLevel))
5154 {
5155 // note lockHolder.Acquire isn't wired up to actually take the lock
5156 lockHolder = pLoadLock;
5157 released = FALSE;
5158 }
5159 }
5160
5161 if (!released)
5162 {
5163 // Complete the level.
5164 if (pLoadLock->CompleteLoadLevel(workLevel, success) &&
5165 pLoadLock->GetLoadLevel()==FILE_LOAD_DELIVER_EVENTS)
5166 {
5167 lockHolder.Release();
5168 released = TRUE;
5169 pFile->DeliverAsyncEvents();
5170 };
5171 }
5172 }
5173 EX_HOOK
5174 {
5175 Exception *pEx = GET_EXCEPTION();
5176
5177
5178 //We will cache this error and wire this load to forever fail,
5179 // unless the exception is transient or the file is loaded OK but just cannot execute
5180 if (!pEx->IsTransient() && !pFile->IsLoaded())
5181 {
5182
5183 if (released)
5184 {
5185 // Reobtain lock to increment level. (Note that another thread may
5186 // have already done it which is OK.
5187 if (pLoadLock->Acquire(workLevel)) // note pLockHolder->Acquire isn't wired up to actually take the lock
5188 {
5189 // note lockHolder.Acquire isn't wired up to actually take the lock
5190 lockHolder = pLoadLock;
5191 released = FALSE;
5192 }
5193 }
5194
5195 if (!released)
5196 {
5197 // Report the error in the lock
5198 pLoadLock->SetError(pEx);
5199 }
5200
5201 if (!EEFileLoadException::CheckType(pEx))
5202 EEFileLoadException::Throw(pFile->GetFile(), pEx->GetHR(), pEx);
5203 }
5204
5205 // Otherwise, we simply abort this load, and can retry later on.
5206 // @todo cleanup: make sure that each level is restartable after an exception, and
5207 // leaves no bad side effects
5208 }
5209 EX_END_HOOK;
5210}
5211
5212// Checks whether the module is valid to be in the given app domain (need not be yet loaded)
5213CHECK AppDomain::CheckValidModule(Module * pModule)
5214{
5215 CONTRACTL
5216 {
5217 THROWS;
5218 GC_TRIGGERS;
5219 MODE_ANY;
5220 }
5221 CONTRACTL_END;
5222
5223 if (pModule->FindDomainFile(this) != NULL)
5224 CHECK_OK;
5225
5226 CHECK_OK;
5227}
5228
5229static void NormalizeAssemblySpecForNativeDependencies(AssemblySpec * pSpec)
5230{
5231 CONTRACTL
5232 {
5233 THROWS;
5234 GC_NOTRIGGER;
5235 MODE_ANY;
5236 }
5237 CONTRACTL_END;
5238
5239 if (pSpec->IsStrongNamed() && pSpec->HasPublicKey())
5240 {
5241 pSpec->ConvertPublicKeyToToken();
5242 }
5243
5244 //
5245 // CoreCLR binder unifies assembly versions. Ignore assembly version here to
5246 // detect more types of potential mismatches.
5247 //
5248 AssemblyMetaDataInternal * pContext = pSpec->GetContext();
5249 pContext->usMajorVersion = (USHORT)-1;
5250 pContext->usMinorVersion = (USHORT)-1;
5251 pContext->usBuildNumber = (USHORT)-1;
5252 pContext->usRevisionNumber = (USHORT)-1;
5253
5254 // Ignore the WinRT type while considering if two assemblies have the same identity.
5255 pSpec->SetWindowsRuntimeType(NULL, NULL);
5256}
5257
5258void AppDomain::CheckForMismatchedNativeImages(AssemblySpec * pSpec, const GUID * pGuid)
5259{
5260 STANDARD_VM_CONTRACT;
5261
5262 //
5263 // The native images are ever used only for trusted images in CoreCLR.
5264 // We don't wish to open the IL file at runtime so we just forgo any
5265 // eager consistency checking. But we still want to prevent mistmatched
5266 // NGen images from being used. We record all mappings between assembly
5267 // names and MVID, and fail once we detect mismatch.
5268 //
5269 NormalizeAssemblySpecForNativeDependencies(pSpec);
5270
5271 CrstHolder ch(&m_DomainCrst);
5272
5273 const NativeImageDependenciesEntry * pEntry = m_NativeImageDependencies.Lookup(pSpec);
5274
5275 if (pEntry != NULL)
5276 {
5277 if (*pGuid != pEntry->m_guidMVID)
5278 {
5279 SString msg;
5280 msg.Printf("ERROR: Native images generated against multiple versions of assembly %s. ", pSpec->GetName());
5281 WszOutputDebugString(msg.GetUnicode());
5282 COMPlusThrowNonLocalized(kFileLoadException, msg.GetUnicode());
5283 }
5284 }
5285 else
5286 {
5287 //
5288 // No entry yet - create one
5289 //
5290 NativeImageDependenciesEntry * pNewEntry = new NativeImageDependenciesEntry();
5291 pNewEntry->m_AssemblySpec.CopyFrom(pSpec);
5292 pNewEntry->m_AssemblySpec.CloneFields(AssemblySpec::ALL_OWNED);
5293 pNewEntry->m_guidMVID = *pGuid;
5294 m_NativeImageDependencies.Add(pNewEntry);
5295 }
5296}
5297
5298BOOL AppDomain::RemoveNativeImageDependency(AssemblySpec * pSpec)
5299{
5300 CONTRACTL
5301 {
5302 GC_NOTRIGGER;
5303 PRECONDITION(CheckPointer(pSpec));
5304 }
5305 CONTRACTL_END;
5306
5307 BOOL result = FALSE;
5308 NormalizeAssemblySpecForNativeDependencies(pSpec);
5309
5310 CrstHolder ch(&m_DomainCrst);
5311
5312 const NativeImageDependenciesEntry * pEntry = m_NativeImageDependencies.Lookup(pSpec);
5313
5314 if (pEntry != NULL)
5315 {
5316 m_NativeImageDependencies.Remove(pSpec);
5317 delete pEntry;
5318 result = TRUE;
5319 }
5320
5321 return result;
5322}
5323
5324void AppDomain::SetupSharedStatics()
5325{
5326 CONTRACTL
5327 {
5328 THROWS;
5329 GC_TRIGGERS;
5330 MODE_ANY;
5331 INJECT_FAULT(COMPlusThrowOM(););
5332 }
5333 CONTRACTL_END;
5334
5335#ifndef CROSSGEN_COMPILE
5336 if (NingenEnabled())
5337 return;
5338
5339 LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: SetupSharedStatics()"));
5340
5341 // don't do any work in init stage. If not init only do work in non-shared case if are default domain
5342 _ASSERTE(!g_fEEInit);
5343
5344 // Because we are allocating/referencing objects, need to be in cooperative mode
5345 GCX_COOP();
5346
5347 DomainLocalModule *pLocalModule = MscorlibBinder::GetModule()->GetDomainLocalModule();
5348
5349 // This is a convenient place to initialize String.Empty.
5350 // It is treated as intrinsic by the JIT as so the static constructor would never run.
5351 // Leaving it uninitialized would confuse debuggers.
5352
5353 // String should not have any static constructors.
5354 _ASSERTE(g_pStringClass->IsClassPreInited());
5355
5356 FieldDesc * pEmptyStringFD = MscorlibBinder::GetField(FIELD__STRING__EMPTY);
5357 OBJECTREF* pEmptyStringHandle = (OBJECTREF*)
5358 ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pEmptyStringFD->GetOffset());
5359 SetObjectReference( pEmptyStringHandle, StringObject::GetEmptyString(), this );
5360#endif // CROSSGEN_COMPILE
5361}
5362
5363DomainAssembly * AppDomain::FindAssembly(PEAssembly * pFile, FindAssemblyOptions options/* = FindAssemblyOptions_None*/)
5364{
5365 CONTRACTL
5366 {
5367 THROWS;
5368 GC_TRIGGERS;
5369 MODE_ANY;
5370 INJECT_FAULT(COMPlusThrowOM(););
5371 }
5372 CONTRACTL_END;
5373
5374 const bool includeFailedToLoad = (options & FindAssemblyOptions_IncludeFailedToLoad) != 0;
5375
5376 if (pFile->HasHostAssembly())
5377 {
5378 DomainAssembly * pDA = FindAssembly(pFile->GetHostAssembly());
5379 if (pDA != nullptr && (pDA->IsLoaded() || (includeFailedToLoad && pDA->IsError())))
5380 {
5381 return pDA;
5382 }
5383 return nullptr;
5384 }
5385
5386 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(
5387 kIncludeLoaded |
5388 (includeFailedToLoad ? kIncludeFailedToLoad : 0) |
5389 kIncludeExecution));
5390 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
5391
5392 while (i.Next(pDomainAssembly.This()))
5393 {
5394 PEFile * pManifestFile = pDomainAssembly->GetFile();
5395 if (pManifestFile &&
5396 !pManifestFile->IsResource() &&
5397 pManifestFile->Equals(pFile))
5398 {
5399 // Caller already has PEAssembly, so we can give DomainAssembly away freely without AddRef
5400 return pDomainAssembly.Extract();
5401 }
5402 }
5403 return NULL;
5404}
5405
5406static const AssemblyIterationFlags STANDARD_IJW_ITERATOR_FLAGS =
5407 (AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution | kExcludeCollectible);
5408
5409
5410void AppDomain::SetFriendlyName(LPCWSTR pwzFriendlyName, BOOL fDebuggerCares/*=TRUE*/)
5411{
5412 CONTRACTL
5413 {
5414 THROWS;
5415 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
5416 MODE_ANY;
5417 INJECT_FAULT(COMPlusThrowOM(););
5418 }
5419 CONTRACTL_END;
5420
5421 // Do all computations into a temporary until we're ensured of success
5422 SString tmpFriendlyName;
5423
5424
5425 if (pwzFriendlyName)
5426 tmpFriendlyName.Set(pwzFriendlyName);
5427 else
5428 {
5429 // If there is an assembly, try to get the name from it.
5430 // If no assembly, but if it's the DefaultDomain, then give it a name
5431
5432 if (m_pRootAssembly)
5433 {
5434 tmpFriendlyName.SetUTF8(m_pRootAssembly->GetSimpleName());
5435
5436 SString::Iterator i = tmpFriendlyName.End();
5437 if (tmpFriendlyName.FindBack(i, '.'))
5438 tmpFriendlyName.Truncate(i);
5439 }
5440 else
5441 {
5442 if (IsDefaultDomain())
5443 tmpFriendlyName.Set(DEFAULT_DOMAIN_FRIENDLY_NAME);
5444
5445 // This is for the profiler - if they call GetFriendlyName on an AppdomainCreateStarted
5446 // event, then we want to give them a temporary name they can use.
5447 else if (GetId().m_dwId != 0)
5448 {
5449 tmpFriendlyName.Clear();
5450 tmpFriendlyName.Printf(W("%s %d"), OTHER_DOMAIN_FRIENDLY_NAME_PREFIX, GetId().m_dwId);
5451 }
5452 }
5453
5454 }
5455
5456 tmpFriendlyName.Normalize();
5457
5458
5459 m_friendlyName = tmpFriendlyName;
5460 m_friendlyName.Normalize();
5461
5462 if(g_pDebugInterface)
5463 {
5464 // update the name in the IPC publishing block
5465 if (SUCCEEDED(g_pDebugInterface->UpdateAppDomainEntryInIPC(this)))
5466 {
5467 // inform the attached debugger that the name of this appdomain has changed.
5468 if (IsDebuggerAttached() && fDebuggerCares)
5469 g_pDebugInterface->NameChangeEvent(this, NULL);
5470 }
5471 }
5472}
5473
5474LPCWSTR AppDomain::GetFriendlyName(BOOL fDebuggerCares/*=TRUE*/)
5475{
5476 CONTRACT (LPCWSTR)
5477 {
5478 THROWS;
5479 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
5480 MODE_ANY;
5481 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
5482 INJECT_FAULT(COMPlusThrowOM(););
5483 }
5484 CONTRACT_END;
5485
5486#if _DEBUG
5487 // Handle NULL this pointer - this happens sometimes when printing log messages
5488 // but in general shouldn't occur in real code
5489 if (this == NULL)
5490 RETURN NULL;
5491#endif // _DEBUG
5492
5493 if (m_friendlyName.IsEmpty())
5494 SetFriendlyName(NULL, fDebuggerCares);
5495
5496 RETURN m_friendlyName;
5497}
5498
5499LPCWSTR AppDomain::GetFriendlyNameForLogging()
5500{
5501 CONTRACT(LPCWSTR)
5502 {
5503 NOTHROW;
5504 GC_NOTRIGGER;
5505 MODE_ANY;
5506 POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
5507 }
5508 CONTRACT_END;
5509#if _DEBUG
5510 // Handle NULL this pointer - this happens sometimes when printing log messages
5511 // but in general shouldn't occur in real code
5512 if (this == NULL)
5513 RETURN NULL;
5514#endif // _DEBUG
5515 RETURN (m_friendlyName.IsEmpty() ?W(""):(LPCWSTR)m_friendlyName);
5516}
5517
5518LPCWSTR AppDomain::GetFriendlyNameForDebugger()
5519{
5520 CONTRACT (LPCWSTR)
5521 {
5522 NOTHROW;
5523 if (GetThread()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
5524 MODE_ANY;
5525 POSTCONDITION(CheckPointer(RETVAL));
5526 }
5527 CONTRACT_END;
5528
5529
5530 if (m_friendlyName.IsEmpty())
5531 {
5532 BOOL fSuccess = FALSE;
5533
5534 EX_TRY
5535 {
5536 SetFriendlyName(NULL);
5537
5538 fSuccess = TRUE;
5539 }
5540 EX_CATCH
5541 {
5542 // Gobble all exceptions.
5543 }
5544 EX_END_CATCH(SwallowAllExceptions);
5545
5546 if (!fSuccess)
5547 {
5548 RETURN W("");
5549 }
5550 }
5551
5552 RETURN m_friendlyName;
5553}
5554
5555
5556#endif // !DACCESS_COMPILE
5557
5558#ifdef DACCESS_COMPILE
5559
5560PVOID AppDomain::GetFriendlyNameNoSet(bool* isUtf8)
5561{
5562 SUPPORTS_DAC;
5563
5564 if (!m_friendlyName.IsEmpty())
5565 {
5566 *isUtf8 = false;
5567 return m_friendlyName.DacGetRawContent();
5568 }
5569 else if (m_pRootAssembly)
5570 {
5571 *isUtf8 = true;
5572 return (PVOID)m_pRootAssembly->GetSimpleName();
5573 }
5574 else if (dac_cast<TADDR>(this) ==
5575 dac_cast<TADDR>(SystemDomain::System()->DefaultDomain()))
5576 {
5577 *isUtf8 = false;
5578 return (PVOID)DEFAULT_DOMAIN_FRIENDLY_NAME;
5579 }
5580 else
5581 {
5582 return NULL;
5583 }
5584}
5585
5586#endif // DACCESS_COMPILE
5587
5588#ifndef DACCESS_COMPILE
5589
5590BOOL AppDomain::AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAllowFailure)
5591{
5592 CONTRACTL
5593 {
5594 THROWS;
5595 GC_TRIGGERS;
5596 MODE_ANY;
5597 PRECONDITION(CheckPointer(pSpec));
5598 // Hosted fusion binder makes an exception here, so we cannot assert.
5599 //PRECONDITION(pSpec->CanUseWithBindingCache());
5600 //PRECONDITION(pFile->CanUseWithBindingCache());
5601 INJECT_FAULT(COMPlusThrowOM(););
5602 }
5603 CONTRACTL_END;
5604
5605 CrstHolder holder(&m_DomainCacheCrst);
5606 // !!! suppress exceptions
5607 if(!m_AssemblyCache.StoreFile(pSpec, pFile) && !fAllowFailure)
5608 {
5609 // TODO: Disabling the below assertion as currently we experience
5610 // inconsistency on resolving the Microsoft.Office.Interop.MSProject.dll
5611 // This causes below assertion to fire and crashes the VS. This issue
5612 // is being tracked with Dev10 Bug 658555. Brought back it when this bug
5613 // is fixed.
5614 // _ASSERTE(FALSE);
5615
5616 EEFileLoadException::Throw(pSpec, FUSION_E_CACHEFILE_FAILED, NULL);
5617 }
5618
5619 return TRUE;
5620}
5621
5622BOOL AppDomain::AddAssemblyToCache(AssemblySpec* pSpec, DomainAssembly *pAssembly)
5623{
5624 CONTRACTL
5625 {
5626 THROWS;
5627 GC_TRIGGERS;
5628 MODE_ANY;
5629 PRECONDITION(CheckPointer(pSpec));
5630 PRECONDITION(CheckPointer(pAssembly));
5631 PRECONDITION(pSpec->CanUseWithBindingCache());
5632 PRECONDITION(pAssembly->CanUseWithBindingCache());
5633 INJECT_FAULT(COMPlusThrowOM(););
5634 }
5635 CONTRACTL_END;
5636
5637 CrstHolder holder(&m_DomainCacheCrst);
5638 // !!! suppress exceptions
5639 BOOL bRetVal = m_AssemblyCache.StoreAssembly(pSpec, pAssembly);
5640 return bRetVal;
5641}
5642
5643BOOL AppDomain::AddExceptionToCache(AssemblySpec* pSpec, Exception *ex)
5644{
5645 CONTRACTL
5646 {
5647 THROWS;
5648 GC_TRIGGERS;
5649 MODE_ANY;
5650 PRECONDITION(CheckPointer(pSpec));
5651 PRECONDITION(pSpec->CanUseWithBindingCache());
5652 INJECT_FAULT(COMPlusThrowOM(););
5653 }
5654 CONTRACTL_END;
5655
5656 if (ex->IsTransient())
5657 return TRUE;
5658
5659 CrstHolder holder(&m_DomainCacheCrst);
5660 // !!! suppress exceptions
5661 return m_AssemblyCache.StoreException(pSpec, ex);
5662}
5663
5664void AppDomain::AddUnmanagedImageToCache(LPCWSTR libraryName, HMODULE hMod)
5665{
5666 CONTRACTL
5667 {
5668 THROWS;
5669 GC_TRIGGERS;
5670 MODE_ANY;
5671 PRECONDITION(CheckPointer(libraryName));
5672 INJECT_FAULT(COMPlusThrowOM(););
5673 }
5674 CONTRACTL_END;
5675 if (libraryName)
5676 {
5677 AssemblySpec spec;
5678 spec.SetCodeBase(libraryName);
5679 m_UnmanagedCache.InsertEntry(&spec, hMod);
5680 }
5681 return ;
5682}
5683
5684
5685HMODULE AppDomain::FindUnmanagedImageInCache(LPCWSTR libraryName)
5686{
5687 CONTRACT(HMODULE)
5688 {
5689 THROWS;
5690 GC_TRIGGERS;
5691 MODE_ANY;
5692 PRECONDITION(CheckPointer(libraryName,NULL_OK));
5693 POSTCONDITION(CheckPointer(RETVAL,NULL_OK));
5694 INJECT_FAULT(COMPlusThrowOM(););
5695 }
5696 CONTRACT_END;
5697 if(libraryName == NULL) RETURN NULL;
5698
5699 AssemblySpec spec;
5700 spec.SetCodeBase(libraryName);
5701 RETURN (HMODULE) m_UnmanagedCache.LookupEntry(&spec, 0);
5702}
5703
5704BOOL AppDomain::RemoveFileFromCache(PEAssembly *pFile)
5705{
5706 CONTRACTL
5707 {
5708 GC_TRIGGERS;
5709 PRECONDITION(CheckPointer(pFile));
5710 }
5711 CONTRACTL_END;
5712
5713 LoadLockHolder lock(this);
5714 FileLoadLock *fileLock = (FileLoadLock *)lock->FindFileLock(pFile);
5715
5716 if (fileLock == NULL)
5717 return FALSE;
5718
5719 VERIFY(lock->Unlink(fileLock));
5720
5721 fileLock->Release();
5722
5723 return TRUE;
5724}
5725
5726BOOL AppDomain::RemoveAssemblyFromCache(DomainAssembly* pAssembly)
5727{
5728 CONTRACTL
5729 {
5730 THROWS;
5731 GC_TRIGGERS;
5732 MODE_ANY;
5733 PRECONDITION(CheckPointer(pAssembly));
5734 INJECT_FAULT(COMPlusThrowOM(););
5735 }
5736 CONTRACTL_END;
5737
5738 CrstHolder holder(&m_DomainCacheCrst);
5739
5740 return m_AssemblyCache.RemoveAssembly(pAssembly);
5741}
5742
5743BOOL AppDomain::IsCached(AssemblySpec *pSpec)
5744{
5745 WRAPPER_NO_CONTRACT;
5746
5747 // Check to see if this fits our rather loose idea of a reference to mscorlib.
5748 // If so, don't use fusion to bind it - do it ourselves.
5749 if (pSpec->IsMscorlib())
5750 return TRUE;
5751
5752 return m_AssemblyCache.Contains(pSpec);
5753}
5754
5755void AppDomain::GetCacheAssemblyList(SetSHash<PTR_DomainAssembly>& assemblyList)
5756{
5757 CrstHolder holder(&m_DomainCacheCrst);
5758 m_AssemblyCache.GetAllAssemblies(assemblyList);
5759}
5760
5761PEAssembly* AppDomain::FindCachedFile(AssemblySpec* pSpec, BOOL fThrow /*=TRUE*/)
5762{
5763 CONTRACTL
5764 {
5765 if (fThrow) {
5766 GC_TRIGGERS;
5767 THROWS;
5768 }
5769 else {
5770 GC_NOTRIGGER;
5771 NOTHROW;
5772 }
5773 MODE_ANY;
5774 }
5775 CONTRACTL_END;
5776
5777 // Check to see if this fits our rather loose idea of a reference to mscorlib.
5778 // If so, don't use fusion to bind it - do it ourselves.
5779 if (fThrow && pSpec->IsMscorlib())
5780 {
5781 CONSISTENCY_CHECK(SystemDomain::System()->SystemAssembly() != NULL);
5782 PEAssembly *pFile = SystemDomain::System()->SystemFile();
5783 pFile->AddRef();
5784 return pFile;
5785 }
5786
5787 return m_AssemblyCache.LookupFile(pSpec, fThrow);
5788}
5789
5790
5791BOOL AppDomain::PostBindResolveAssembly(AssemblySpec *pPrePolicySpec,
5792 AssemblySpec *pPostPolicySpec,
5793 HRESULT hrBindResult,
5794 AssemblySpec **ppFailedSpec)
5795{
5796 STATIC_CONTRACT_THROWS;
5797 STATIC_CONTRACT_GC_TRIGGERS;
5798 PRECONDITION(CheckPointer(pPrePolicySpec));
5799 PRECONDITION(CheckPointer(pPostPolicySpec));
5800 PRECONDITION(CheckPointer(ppFailedSpec));
5801
5802 BOOL fFailure = TRUE;
5803 *ppFailedSpec = pPrePolicySpec;
5804
5805
5806 PEAssemblyHolder result;
5807
5808 if ((EEFileLoadException::GetFileLoadKind(hrBindResult) == kFileNotFoundException) ||
5809 (hrBindResult == FUSION_E_REF_DEF_MISMATCH) ||
5810 (hrBindResult == FUSION_E_INVALID_NAME))
5811 {
5812 result = TryResolveAssembly(*ppFailedSpec);
5813
5814 if (result != NULL && pPrePolicySpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
5815 {
5816 fFailure = FALSE;
5817
5818 // Given the post-policy resolve event construction of the CLR binder,
5819 // chained managed resolve events can race with each other, therefore we do allow
5820 // the adding of the result to fail. Checking for already chached specs
5821 // is not an option as it would introduce another race window.
5822 // The binder does a re-fetch of the
5823 // original binding spec and therefore will not cause inconsistency here.
5824 // For the purposes of the resolve event, failure to add to the cache still is a success.
5825 AddFileToCache(pPrePolicySpec, result, TRUE /* fAllowFailure */);
5826 if (*ppFailedSpec != pPrePolicySpec && pPostPolicySpec->CanUseWithBindingCache())
5827 {
5828 AddFileToCache(pPostPolicySpec, result, TRUE /* fAllowFailure */ );
5829 }
5830 }
5831 }
5832
5833 return fFailure;
5834}
5835
5836//----------------------------------------------------------------------------------------
5837// Helper class for hosted binder
5838
5839class PEAssemblyAsPrivAssemblyInfo : public IUnknownCommon<ICLRPrivAssemblyInfo>
5840{
5841public:
5842 //------------------------------------------------------------------------------------
5843 // Ctor
5844
5845 PEAssemblyAsPrivAssemblyInfo(PEAssembly *pPEAssembly)
5846 {
5847 LIMITED_METHOD_CONTRACT;
5848 STATIC_CONTRACT_THROWS;
5849
5850 if (pPEAssembly == nullptr)
5851 ThrowHR(E_UNEXPECTED);
5852
5853 pPEAssembly->AddRef();
5854 m_pPEAssembly = pPEAssembly;
5855 }
5856
5857 //------------------------------------------------------------------------------------
5858 // ICLRPrivAssemblyInfo methods
5859
5860 //------------------------------------------------------------------------------------
5861 STDMETHOD(GetAssemblyName)(
5862 __in DWORD cchBuffer,
5863 __out_opt LPDWORD pcchBuffer,
5864 __out_ecount_part_opt(cchBuffer, *pcchBuffer) LPWSTR wzBuffer)
5865 {
5866 CONTRACTL
5867 {
5868 NOTHROW;
5869 GC_TRIGGERS;
5870 MODE_ANY;
5871 }
5872 CONTRACTL_END;
5873
5874 HRESULT hr = S_OK;
5875
5876 if ((cchBuffer == 0) != (wzBuffer == nullptr))
5877 {
5878 return E_INVALIDARG;
5879 }
5880
5881 LPCUTF8 szName = m_pPEAssembly->GetSimpleName();
5882
5883 bool bIsAscii;
5884 DWORD cchName;
5885 IfFailRet(FString::Utf8_Unicode_Length(szName, &bIsAscii, &cchName));
5886
5887 if (cchBuffer < cchName + 1)
5888 {
5889 if (pcchBuffer != nullptr)
5890 {
5891 *pcchBuffer = cchName + 1;
5892 }
5893 return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
5894 }
5895 else
5896 {
5897 IfFailRet(FString::Utf8_Unicode(szName, bIsAscii, wzBuffer, cchName));
5898 if (pcchBuffer != nullptr)
5899 {
5900 *pcchBuffer = cchName;
5901 }
5902 return S_OK;
5903 }
5904 }
5905
5906 //------------------------------------------------------------------------------------
5907 STDMETHOD(GetAssemblyVersion)(
5908 USHORT *pMajor,
5909 USHORT *pMinor,
5910 USHORT *pBuild,
5911 USHORT *pRevision)
5912 {
5913 WRAPPER_NO_CONTRACT;
5914 return m_pPEAssembly->GetVersion(pMajor, pMinor, pBuild, pRevision);
5915 }
5916
5917 //------------------------------------------------------------------------------------
5918 STDMETHOD(GetAssemblyPublicKey)(
5919 DWORD cbBuffer,
5920 LPDWORD pcbBuffer,
5921 BYTE *pbBuffer)
5922 {
5923 STATIC_CONTRACT_LIMITED_METHOD;
5924 STATIC_CONTRACT_CAN_TAKE_LOCK;
5925
5926 VALIDATE_PTR_RET(pcbBuffer);
5927 VALIDATE_CONDITION((pbBuffer == nullptr) == (cbBuffer == 0), return E_INVALIDARG);
5928
5929 HRESULT hr = S_OK;
5930
5931 EX_TRY
5932 {
5933 // Note: PEAssembly::GetPublicKey will return bogus data pointer when *pcbBuffer == 0
5934 LPCVOID pbKey = m_pPEAssembly->GetPublicKey(pcbBuffer);
5935
5936 if (*pcbBuffer != 0)
5937 {
5938 if (pbBuffer != nullptr && cbBuffer >= *pcbBuffer)
5939 {
5940 memcpy(pbBuffer, pbKey, *pcbBuffer);
5941 hr = S_OK;
5942 }
5943 else
5944 {
5945 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
5946 }
5947 }
5948 else
5949 {
5950 hr = S_FALSE; // ==> No public key
5951 }
5952 }
5953 EX_CATCH_HRESULT(hr);
5954
5955 return hr;
5956 }
5957
5958private:
5959 ReleaseHolder<PEAssembly> m_pPEAssembly;
5960};
5961
5962//-----------------------------------------------------------------------------------------------------------------
5963HRESULT AppDomain::BindAssemblySpecForHostedBinder(
5964 AssemblySpec * pSpec,
5965 IAssemblyName * pAssemblyName,
5966 ICLRPrivBinder * pBinder,
5967 PEAssembly ** ppAssembly)
5968{
5969 STANDARD_VM_CONTRACT;
5970
5971 PRECONDITION(CheckPointer(pSpec));
5972 PRECONDITION(pSpec->GetAppDomain() == this);
5973 PRECONDITION(CheckPointer(ppAssembly));
5974 PRECONDITION(pSpec->GetCodeBase() == nullptr);
5975
5976 HRESULT hr = S_OK;
5977
5978
5979 // The Fusion binder can throw (to preserve compat, since it will actually perform an assembly
5980 // load as part of it's bind), so we need to be careful here to catch any FileNotFoundException
5981 // objects if fThrowIfNotFound is false.
5982 ReleaseHolder<ICLRPrivAssembly> pPrivAssembly;
5983
5984 // We return HRESULTs here on failure instead of throwing as failures here are not necessarily indicative
5985 // of an actual application problem. Returning an error code is substantially faster than throwing, and
5986 // should be used when possible.
5987 IfFailRet(pBinder->BindAssemblyByName(pAssemblyName, &pPrivAssembly));
5988
5989 IfFailRet(BindHostedPrivAssembly(nullptr, pPrivAssembly, pAssemblyName, ppAssembly));
5990
5991
5992 return S_OK;
5993}
5994
5995//-----------------------------------------------------------------------------------------------------------------
5996HRESULT
5997AppDomain::BindHostedPrivAssembly(
5998 PEAssembly * pParentAssembly,
5999 ICLRPrivAssembly * pPrivAssembly,
6000 IAssemblyName * pAssemblyName,
6001 PEAssembly ** ppAssembly)
6002{
6003 STANDARD_VM_CONTRACT;
6004
6005 PRECONDITION(CheckPointer(pPrivAssembly));
6006 PRECONDITION(CheckPointer(ppAssembly));
6007
6008 HRESULT hr = S_OK;
6009
6010 *ppAssembly = nullptr;
6011
6012 // See if result has been previously loaded.
6013 {
6014 DomainAssembly* pDomainAssembly = FindAssembly(pPrivAssembly);
6015 if (pDomainAssembly != nullptr)
6016 {
6017 *ppAssembly = clr::SafeAddRef(pDomainAssembly->GetFile());
6018 }
6019 }
6020
6021 if (*ppAssembly != nullptr)
6022 { // Already exists: return the assembly.
6023 return S_OK;
6024 }
6025
6026 // Get the IL PEFile.
6027 PEImageHolder pPEImageIL;
6028 {
6029 // Does not already exist, so get the resource for the assembly and load it.
6030 DWORD dwImageType;
6031 ReleaseHolder<ICLRPrivResource> pIResourceIL;
6032
6033 IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_IL, &dwImageType, &pIResourceIL));
6034 _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_IL);
6035
6036 pPEImageIL = PEImage::OpenImage(pIResourceIL, MDInternalImport_Default);
6037 }
6038
6039 // See if an NI is available.
6040 DWORD dwAvailableImages;
6041 IfFailRet(pPrivAssembly->GetAvailableImageTypes(&dwAvailableImages));
6042 _ASSERTE(dwAvailableImages & ASSEMBLY_IMAGE_TYPE_IL); // Just double checking that IL bit is always set.
6043
6044 // Get the NI PEFile if available.
6045 PEImageHolder pPEImageNI;
6046 if (dwAvailableImages & ASSEMBLY_IMAGE_TYPE_NATIVE)
6047 {
6048 DWORD dwImageType;
6049 ReleaseHolder<ICLRPrivResource> pIResourceNI;
6050
6051 IfFailRet(pPrivAssembly->GetImageResource(ASSEMBLY_IMAGE_TYPE_NATIVE, &dwImageType, &pIResourceNI));
6052 _ASSERTE(dwImageType == ASSEMBLY_IMAGE_TYPE_NATIVE || FAILED(hr));
6053
6054 pPEImageNI = PEImage::OpenImage(pIResourceNI, MDInternalImport_TrustedNativeImage);
6055 }
6056 _ASSERTE(pPEImageIL != nullptr);
6057
6058 // Create a PEAssembly using the IL and NI images.
6059 PEAssemblyHolder pPEAssembly = PEAssembly::Open(pParentAssembly, pPEImageIL, pPEImageNI, pPrivAssembly);
6060
6061 // The result.
6062 *ppAssembly = pPEAssembly.Extract();
6063
6064 return S_OK;
6065} // AppDomain::BindHostedPrivAssembly
6066
6067//---------------------------------------------------------------------------------------------------------------------
6068PEAssembly * AppDomain::BindAssemblySpec(
6069 AssemblySpec * pSpec,
6070 BOOL fThrowOnFileNotFound,
6071 BOOL fUseHostBinderIfAvailable)
6072{
6073 STATIC_CONTRACT_THROWS;
6074 STATIC_CONTRACT_GC_TRIGGERS;
6075 PRECONDITION(CheckPointer(pSpec));
6076 PRECONDITION(pSpec->GetAppDomain() == this);
6077 PRECONDITION(this==::GetAppDomain());
6078
6079 GCX_PREEMP();
6080
6081 BOOL fForceReThrow = FALSE;
6082
6083#if defined(FEATURE_COMINTEROP)
6084 // Handle WinRT assemblies in the classic/hybrid scenario. If this is an AppX process,
6085 // then this case will be handled by the previous block as part of the full set of
6086 // available binding hosts.
6087 if (pSpec->IsContentType_WindowsRuntime())
6088 {
6089 HRESULT hr = S_OK;
6090
6091 // Get the assembly display name.
6092 ReleaseHolder<IAssemblyName> pAssemblyName;
6093
6094 IfFailThrow(pSpec->CreateFusionName(&pAssemblyName, TRUE, TRUE));
6095
6096
6097 PEAssemblyHolder pAssembly;
6098
6099 EX_TRY
6100 {
6101 hr = BindAssemblySpecForHostedBinder(pSpec, pAssemblyName, m_pWinRtBinder, &pAssembly);
6102 if (FAILED(hr))
6103 goto EndTry2; // Goto end of try block.
6104EndTry2:;
6105 }
6106 // The combination of this conditional catch/ the following if statement which will throw reduces the count of exceptions
6107 // thrown in scenarios where the exception does not escape the method. We cannot get rid of the try/catch block, as
6108 // there are cases within some of the clrpriv binder's which throw.
6109 // Note: In theory, FileNotFound should always come here as HRESULT, never as exception.
6110 EX_CATCH_HRESULT_IF(hr,
6111 !fThrowOnFileNotFound && Assembly::FileNotFound(hr))
6112
6113 if (FAILED(hr) && (fThrowOnFileNotFound || !Assembly::FileNotFound(hr)))
6114 {
6115 if (Assembly::FileNotFound(hr))
6116 {
6117 _ASSERTE(fThrowOnFileNotFound);
6118 // Uses defaultScope
6119 EEFileLoadException::Throw(pSpec, hr);
6120 }
6121
6122 // WinRT type bind failures
6123 _ASSERTE(pSpec->IsContentType_WindowsRuntime());
6124 if (hr == HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE)) // Returned by RoResolveNamespace when using 3rd party WinRT types in classic process
6125 {
6126 if (fThrowOnFileNotFound)
6127 { // Throw NotSupportedException (with custom message) wrapped by TypeLoadException to give user type name for diagnostics
6128 // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6129 EEMessageException ex(kNotSupportedException, IDS_EE_WINRT_THIRDPARTY_NOTSUPPORTED);
6130 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
6131 }
6132 }
6133 else if ((hr == CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT) || // Returned e.g. for WinRT type name without namespace
6134 (hr == COR_E_PLATFORMNOTSUPPORTED)) // Using WinRT on pre-Win8 OS
6135 {
6136 if (fThrowOnFileNotFound)
6137 { // Throw ArgumentException/PlatformNotSupportedException wrapped by TypeLoadException to give user type name for diagnostics
6138 // Note: TypeLoadException is equivalent of FileNotFound in WinRT world
6139 EEMessageException ex(hr);
6140 EX_THROW_WITH_INNER(EETypeLoadException, (pSpec->GetWinRtTypeNamespace(), pSpec->GetWinRtTypeClassName(), nullptr, nullptr, IDS_EE_WINRT_LOADFAILURE), &ex);
6141 }
6142 }
6143 else
6144 {
6145 IfFailThrow(hr);
6146 }
6147 }
6148 _ASSERTE((FAILED(hr) && !fThrowOnFileNotFound) || pAssembly != nullptr);
6149
6150 return pAssembly.Extract();
6151 }
6152 else
6153#endif // FEATURE_COMINTEROP
6154 if (pSpec->HasUniqueIdentity())
6155 {
6156 HRESULT hrBindResult = S_OK;
6157 PEAssemblyHolder result;
6158
6159
6160 EX_TRY
6161 {
6162 if (!IsCached(pSpec))
6163 {
6164
6165 {
6166 bool fAddFileToCache = false;
6167
6168 // Use CoreClr's fusion alternative
6169 CoreBindResult bindResult;
6170
6171 pSpec->Bind(this, fThrowOnFileNotFound, &bindResult, FALSE /* fNgenExplicitBind */, FALSE /* fExplicitBindToNativeImage */);
6172 hrBindResult = bindResult.GetHRBindResult();
6173
6174 if (bindResult.Found())
6175 {
6176 if (SystemDomain::SystemFile() && bindResult.IsMscorlib())
6177 {
6178 // Avoid rebinding to another copy of mscorlib
6179 result = SystemDomain::SystemFile();
6180 result.SuppressRelease(); // Didn't get a refcount
6181 }
6182 else
6183 {
6184 // IsSystem on the PEFile should be false, even for mscorlib satellites
6185 result = PEAssembly::Open(&bindResult,
6186 FALSE);
6187 }
6188 fAddFileToCache = true;
6189
6190 // Setup the reference to the binder, which performed the bind, into the AssemblySpec
6191 ICLRPrivBinder* pBinder = result->GetBindingContext();
6192 _ASSERTE(pBinder != NULL);
6193 pSpec->SetBindingContext(pBinder);
6194 }
6195
6196
6197 if (fAddFileToCache)
6198 {
6199
6200
6201 if (pSpec->CanUseWithBindingCache() && result->CanUseWithBindingCache())
6202 {
6203 // Failure to add simply means someone else beat us to it. In that case
6204 // the FindCachedFile call below (after catch block) will update result
6205 // to the cached value.
6206 AddFileToCache(pSpec, result, TRUE /*fAllowFailure*/);
6207 }
6208 }
6209 else
6210 {
6211 _ASSERTE(fThrowOnFileNotFound == FALSE);
6212
6213 // Don't trigger the resolve event for the CoreLib satellite assembly. A misbehaving resolve event may
6214 // return an assembly that does not match, and this can cause recursive resource lookups during error
6215 // reporting. The CoreLib satellite assembly is loaded from relative locations based on the culture, see
6216 // AssemblySpec::Bind().
6217 if (!pSpec->IsMscorlibSatellite())
6218 {
6219 // Trigger the resolve event also for non-throw situation.
6220 // However, this code path will behave as if the resolve handler has thrown,
6221 // that is, not trigger an MDA.
6222
6223 AssemblySpec NewSpec(this);
6224 AssemblySpec *pFailedSpec = NULL;
6225
6226 fForceReThrow = TRUE; // Managed resolve event handler can throw
6227
6228 // Purposly ignore return value
6229 PostBindResolveAssembly(pSpec, &NewSpec, hrBindResult, &pFailedSpec);
6230 }
6231 }
6232 }
6233 }
6234 }
6235 EX_CATCH
6236 {
6237 Exception *ex = GET_EXCEPTION();
6238
6239 AssemblySpec NewSpec(this);
6240 AssemblySpec *pFailedSpec = NULL;
6241
6242 // Let transient exceptions or managed resolve event handler exceptions propagate
6243 if (ex->IsTransient() || fForceReThrow)
6244 {
6245 EX_RETHROW;
6246 }
6247
6248 {
6249 // This is not executed for SO exceptions so we need to disable the backout
6250 // stack validation to prevent false violations from being reported.
6251 DISABLE_BACKOUT_STACK_VALIDATION;
6252
6253 BOOL fFailure = PostBindResolveAssembly(pSpec, &NewSpec, ex->GetHR(), &pFailedSpec);
6254 if (fFailure)
6255 {
6256 BOOL bFileNotFoundException =
6257 (EEFileLoadException::GetFileLoadKind(ex->GetHR()) == kFileNotFoundException);
6258
6259 if (!bFileNotFoundException)
6260 {
6261 fFailure = AddExceptionToCache(pFailedSpec, ex);
6262 } // else, fFailure stays TRUE
6263 // Effectively, fFailure == bFileNotFoundException || AddExceptionToCache(pFailedSpec, ex)
6264
6265 // Only throw this exception if we are the first in the cache
6266 if (fFailure)
6267 {
6268 //
6269 // If the BindingFailure MDA is enabled, trigger one for this failure
6270 // Note: TryResolveAssembly() can also throw if an AssemblyResolve event subscriber throws
6271 // and the MDA isn't sent in this case (or for transient failure cases)
6272 //
6273#ifdef MDA_SUPPORTED
6274 MdaBindingFailure* pProbe = MDA_GET_ASSISTANT(BindingFailure);
6275 if (pProbe)
6276 {
6277 // Transition to cooperative GC mode before using any OBJECTREFs.
6278 GCX_COOP();
6279
6280 OBJECTREF exceptionObj = GET_THROWABLE();
6281 GCPROTECT_BEGIN(exceptionObj)
6282 {
6283 pProbe->BindFailed(pFailedSpec, &exceptionObj);
6284 }
6285 GCPROTECT_END();
6286 }
6287#endif
6288
6289 // In the same cases as for the MDA, store the failure information for DAC to read
6290 if (IsDebuggerAttached()) {
6291 FailedAssembly *pFailed = new FailedAssembly();
6292 pFailed->Initialize(pFailedSpec, ex);
6293 IfFailThrow(m_failedAssemblies.Append(pFailed));
6294 }
6295
6296 if (!bFileNotFoundException || fThrowOnFileNotFound)
6297 {
6298
6299 // V1.1 App-compatibility workaround. See VSW530166 if you want to whine about it.
6300 //
6301 // In Everett, if we failed to download an assembly because of a broken network cable,
6302 // we returned a FileNotFoundException with a COR_E_FILENOTFOUND hr embedded inside
6303 // (which would be exposed when marshaled to native.)
6304 //
6305 // In Whidbey, we now set the more appropriate INET_E_RESOURCE_NOT_FOUND hr. But
6306 // the online/offline switch code in VSTO for Everett hardcoded a check for
6307 // COR_E_FILENOTFOUND.
6308 //
6309 // So now, to keep that code from breaking, we have to remap INET_E_RESOURCE_NOT_FOUND
6310 // back to COR_E_FILENOTFOUND. We're doing it here rather down in Fusion so as to affect
6311 // the least number of callers.
6312
6313 if (ex->GetHR() == INET_E_RESOURCE_NOT_FOUND)
6314 {
6315 EEFileLoadException::Throw(pFailedSpec, COR_E_FILENOTFOUND, ex);
6316 }
6317
6318 if (EEFileLoadException::CheckType(ex))
6319 {
6320 if (pFailedSpec == pSpec)
6321 {
6322 EX_RETHROW; //preserve the information
6323 }
6324 else
6325 {
6326 StackSString exceptionDisplayName, failedSpecDisplayName;
6327
6328 ((EEFileLoadException*)ex)->GetName(exceptionDisplayName);
6329 pFailedSpec->GetFileOrDisplayName(0, failedSpecDisplayName);
6330
6331 if (exceptionDisplayName.CompareCaseInsensitive(failedSpecDisplayName) == 0)
6332 {
6333 EX_RETHROW; // Throw the original exception. Otherwise, we'd throw an exception that contains the same message twice.
6334 }
6335 }
6336 }
6337
6338 EEFileLoadException::Throw(pFailedSpec, ex->GetHR(), ex);
6339 }
6340
6341 }
6342 }
6343 }
6344 }
6345 EX_END_CATCH(RethrowTerminalExceptions);
6346
6347 // 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
6348 // thread to store our result. Note that we may throw from here, if there is a cached exception.
6349 // This will release the refcount of the current result holder (if any), and will replace
6350 // it with a non-addref'ed result
6351 if (pSpec->CanUseWithBindingCache() && (result== NULL || result->CanUseWithBindingCache()))
6352 {
6353 result = FindCachedFile(pSpec);
6354
6355 if (result != NULL)
6356 result->AddRef();
6357 }
6358
6359 return result.Extract();
6360 }
6361 else
6362 {
6363 // Unsupported content type
6364 if (fThrowOnFileNotFound)
6365 {
6366 ThrowHR(COR_E_BADIMAGEFORMAT);
6367 }
6368 return nullptr;
6369 }
6370} // AppDomain::BindAssemblySpec
6371
6372
6373
6374PEAssembly *AppDomain::TryResolveAssembly(AssemblySpec *pSpec)
6375{
6376 STATIC_CONTRACT_THROWS;
6377 STATIC_CONTRACT_GC_TRIGGERS;
6378 STATIC_CONTRACT_MODE_ANY;
6379
6380 PEAssembly *result = NULL;
6381
6382 EX_TRY
6383 {
6384 result = pSpec->ResolveAssemblyFile(this);
6385 }
6386 EX_HOOK
6387 {
6388 Exception *pEx = GET_EXCEPTION();
6389
6390 if (!pEx->IsTransient())
6391 {
6392 AddExceptionToCache(pSpec, pEx);
6393 if (!EEFileLoadException::CheckType(pEx))
6394 EEFileLoadException::Throw(pSpec, pEx->GetHR(), pEx);
6395 }
6396 }
6397 EX_END_HOOK;
6398
6399 return result;
6400}
6401
6402
6403ULONG AppDomain::AddRef()
6404{
6405 LIMITED_METHOD_CONTRACT;
6406 return InterlockedIncrement(&m_cRef);
6407}
6408
6409ULONG AppDomain::Release()
6410{
6411 CONTRACTL
6412 {
6413 NOTHROW;
6414 GC_TRIGGERS;
6415 MODE_ANY;
6416 PRECONDITION(m_cRef > 0);
6417 }
6418 CONTRACTL_END;
6419
6420 ULONG cRef = InterlockedDecrement(&m_cRef);
6421 if (!cRef)
6422 {
6423 _ASSERTE (m_Stage == STAGE_CREATING);
6424 ADID adid=GetId();
6425 delete this;
6426 TESTHOOKCALL(AppDomainDestroyed(adid.m_dwId));
6427 }
6428 return (cRef);
6429}
6430
6431
6432#ifndef CROSSGEN_COMPILE
6433
6434void AppDomain::RaiseLoadingAssemblyEvent(DomainAssembly *pAssembly)
6435{
6436 CONTRACTL
6437 {
6438 NOTHROW;
6439 GC_TRIGGERS;
6440 PRECONDITION(this == GetAppDomain());
6441 MODE_ANY;
6442 }
6443 CONTRACTL_END;
6444
6445 if (pAssembly->GetFile()->IsSystem())
6446 {
6447 return;
6448 }
6449
6450 GCX_COOP();
6451 FAULT_NOT_FATAL();
6452 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
6453
6454 EX_TRY
6455 {
6456 if (MscorlibBinder::GetField(FIELD__ASSEMBLYLOADCONTEXT__ASSEMBLY_LOAD)->GetStaticOBJECTREF() != NULL)
6457 {
6458 struct _gc {
6459 OBJECTREF orThis;
6460 } gc;
6461 ZeroMemory(&gc, sizeof(gc));
6462
6463 ARG_SLOT args[1];
6464 GCPROTECT_BEGIN(gc);
6465
6466 gc.orThis = pAssembly->GetExposedAssemblyObject();
6467
6468 MethodDescCallSite onAssemblyLoad(METHOD__ASSEMBLYLOADCONTEXT__ON_ASSEMBLY_LOAD);
6469
6470 // GetExposedAssemblyObject may cause a gc, so call this before filling args[0]
6471 args[0] = ObjToArgSlot(gc.orThis);
6472
6473 onAssemblyLoad.Call(args);
6474
6475 GCPROTECT_END();
6476 }
6477 }
6478 EX_CATCH
6479 {
6480 }
6481 EX_END_CATCH(SwallowAllExceptions);
6482}
6483
6484BOOL AppDomain::OnUnhandledException(OBJECTREF *pThrowable, BOOL isTerminating/*=TRUE*/)
6485{
6486 STATIC_CONTRACT_NOTHROW;
6487 STATIC_CONTRACT_GC_TRIGGERS;
6488 STATIC_CONTRACT_MODE_ANY;
6489
6490 BOOL retVal = FALSE;
6491
6492 GCX_COOP();
6493
6494 EX_TRY
6495 {
6496 retVal = GetAppDomain()->RaiseUnhandledExceptionEvent(pThrowable, isTerminating);
6497 }
6498 EX_CATCH
6499 {
6500 }
6501 EX_END_CATCH(SwallowAllExceptions) // Swallow any errors.
6502
6503 return retVal;
6504}
6505
6506static LONG s_ProcessedExitProcessEventCount = 0;
6507
6508LONG GetProcessedExitProcessEventCount()
6509{
6510 LIMITED_METHOD_CONTRACT;
6511 return s_ProcessedExitProcessEventCount;
6512}
6513
6514void AppDomain::RaiseExitProcessEvent()
6515{
6516 if (!g_fEEStarted)
6517 return;
6518
6519 STATIC_CONTRACT_MODE_COOPERATIVE;
6520 STATIC_CONTRACT_THROWS;
6521 STATIC_CONTRACT_GC_TRIGGERS;
6522
6523 // Only finalizer thread during shutdown can call this function.
6524 _ASSERTE ((g_fEEShutDown&ShutDown_Finalize1) && GetThread() == FinalizerThread::GetFinalizerThread());
6525
6526 _ASSERTE (GetThread()->PreemptiveGCDisabled());
6527
6528 MethodDescCallSite onProcessExit(METHOD__APPCONTEXT__ON_PROCESS_EXIT);
6529 onProcessExit.Call(NULL);
6530}
6531
6532BOOL
6533AppDomain::RaiseUnhandledExceptionEvent(OBJECTREF *pThrowable, BOOL isTerminating)
6534{
6535 CONTRACTL
6536 {
6537 THROWS;
6538 GC_TRIGGERS;
6539 MODE_COOPERATIVE;
6540 INJECT_FAULT(COMPlusThrowOM(););
6541 }
6542 CONTRACTL_END;
6543
6544 _ASSERTE(pThrowable != NULL && IsProtectedByGCFrame(pThrowable));
6545
6546 _ASSERTE(this == GetThread()->GetDomain());
6547
6548 OBJECTREF orDelegate = MscorlibBinder::GetField(FIELD__APPCONTEXT__UNHANDLED_EXCEPTION)->GetStaticOBJECTREF();
6549 if (orDelegate == NULL)
6550 return FALSE;
6551
6552 struct _gc {
6553 OBJECTREF Delegate;
6554 OBJECTREF Sender;
6555 } gc;
6556 ZeroMemory(&gc, sizeof(gc));
6557
6558 GCPROTECT_BEGIN(gc);
6559 gc.Delegate = orDelegate;
6560 if (orDelegate != NULL)
6561 {
6562 DistributeUnhandledExceptionReliably(&gc.Delegate, &gc.Sender, pThrowable, isTerminating);
6563 }
6564 GCPROTECT_END();
6565 return TRUE;
6566}
6567
6568#endif // CROSSGEN_COMPILE
6569
6570IUnknown *AppDomain::CreateFusionContext()
6571{
6572 CONTRACT(IUnknown *)
6573 {
6574 GC_TRIGGERS;
6575 THROWS;
6576 MODE_ANY;
6577 POSTCONDITION(CheckPointer(RETVAL));
6578 INJECT_FAULT(COMPlusThrowOM(););
6579 }
6580 CONTRACT_END;
6581
6582 if (!m_pFusionContext)
6583 {
6584 ETWOnStartup (FusionAppCtx_V1, FusionAppCtxEnd_V1);
6585 CLRPrivBinderCoreCLR *pTPABinder = NULL;
6586
6587 GCX_PREEMP();
6588
6589 // Initialize the assembly binder for the default context loads for CoreCLR.
6590 IfFailThrow(CCoreCLRBinderHelper::DefaultBinderSetupContext(GetId().m_dwId, &pTPABinder));
6591 m_pFusionContext = reinterpret_cast<IUnknown *>(pTPABinder);
6592
6593 // By default, initial binding context setup for CoreCLR is also the TPABinding context
6594 (m_pTPABinderContext = pTPABinder)->AddRef();
6595
6596 }
6597
6598 RETURN m_pFusionContext;
6599}
6600
6601
6602
6603//---------------------------------------------------------------------------------------
6604//
6605// AppDomain::IsDebuggerAttached - is a debugger attached to this process
6606//
6607// Arguments:
6608// None
6609//
6610// Return Value:
6611// TRUE if a debugger is attached to this process, FALSE otherwise.
6612//
6613// Notes:
6614// This is identical to CORDebuggerAttached. This exists idependantly for legacy reasons - we used to
6615// support attaching to individual AppDomains. This should probably go away eventually.
6616//
6617
6618BOOL AppDomain::IsDebuggerAttached()
6619{
6620 LIMITED_METHOD_CONTRACT;
6621
6622 if (CORDebuggerAttached())
6623 {
6624 return TRUE;
6625 }
6626 else
6627 {
6628 return FALSE;
6629 }
6630}
6631
6632#ifdef DEBUGGING_SUPPORTED
6633
6634// This is called from the debugger to request notification events from
6635// Assemblies, Modules, Types in this appdomain.
6636BOOL AppDomain::NotifyDebuggerLoad(int flags, BOOL attaching)
6637{
6638 WRAPPER_NO_CONTRACT;
6639 BOOL result = FALSE;
6640
6641 if (!attaching && !IsDebuggerAttached())
6642 return FALSE;
6643
6644 AssemblyIterator i;
6645
6646 // Attach to our assemblies
6647 LOG((LF_CORDB, LL_INFO100, "AD::NDA: Iterating assemblies\n"));
6648 i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution));
6649 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
6650 while (i.Next(pDomainAssembly.This()))
6651 {
6652 result = (pDomainAssembly->NotifyDebuggerLoad(flags, attaching) ||
6653 result);
6654 }
6655
6656 return result;
6657}
6658
6659void AppDomain::NotifyDebuggerUnload()
6660{
6661 WRAPPER_NO_CONTRACT;
6662 if (!IsDebuggerAttached())
6663 return;
6664
6665 LOG((LF_CORDB, LL_INFO10, "AD::NDD domain [%d] %#08x %ls\n",
6666 GetId().m_dwId, this, GetFriendlyNameForLogging()));
6667
6668 LOG((LF_CORDB, LL_INFO100, "AD::NDD: Interating domain bound assemblies\n"));
6669 AssemblyIterator i = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeLoading | kIncludeExecution));
6670 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
6671
6672 // Detach from our assemblies
6673 while (i.Next(pDomainAssembly.This()))
6674 {
6675 LOG((LF_CORDB, LL_INFO100, "AD::NDD: Iterating assemblies\n"));
6676 pDomainAssembly->NotifyDebuggerUnload();
6677 }
6678}
6679#endif // DEBUGGING_SUPPORTED
6680
6681void AppDomain::SetSystemAssemblyLoadEventSent(BOOL fFlag)
6682{
6683 LIMITED_METHOD_CONTRACT;
6684 if (fFlag == TRUE)
6685 m_dwFlags |= LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
6686 else
6687 m_dwFlags &= ~LOAD_SYSTEM_ASSEMBLY_EVENT_SENT;
6688}
6689
6690BOOL AppDomain::WasSystemAssemblyLoadEventSent(void)
6691{
6692 LIMITED_METHOD_CONTRACT;
6693 return ((m_dwFlags & LOAD_SYSTEM_ASSEMBLY_EVENT_SENT) == 0) ? FALSE : TRUE;
6694}
6695
6696#ifndef CROSSGEN_COMPILE
6697
6698#ifdef FEATURE_COMINTEROP
6699
6700RCWRefCache *AppDomain::GetRCWRefCache()
6701{
6702 CONTRACT(RCWRefCache*)
6703 {
6704 THROWS;
6705 GC_NOTRIGGER;
6706 MODE_ANY;
6707 POSTCONDITION(CheckPointer(RETVAL));
6708 }
6709 CONTRACT_END;
6710
6711 if (!m_pRCWRefCache) {
6712 NewHolder<RCWRefCache> pRCWRefCache = new RCWRefCache(this);
6713 if (FastInterlockCompareExchangePointer(&m_pRCWRefCache, (RCWRefCache *)pRCWRefCache, NULL) == NULL)
6714 {
6715 pRCWRefCache.SuppressRelease();
6716 }
6717 }
6718 RETURN m_pRCWRefCache;
6719}
6720
6721RCWCache *AppDomain::CreateRCWCache()
6722{
6723 CONTRACT(RCWCache*)
6724 {
6725 THROWS;
6726 GC_TRIGGERS;
6727 MODE_ANY;
6728 INJECT_FAULT(COMPlusThrowOM(););
6729 POSTCONDITION(CheckPointer(RETVAL));
6730 }
6731 CONTRACT_END;
6732
6733 // Initialize the global RCW cleanup list here as well. This is so that it
6734 // it guaranteed to exist if any RCW's are created, but it is not created
6735 // unconditionally.
6736 if (!g_pRCWCleanupList)
6737 {
6738 SystemDomain::LockHolder lh;
6739
6740 if (!g_pRCWCleanupList)
6741 g_pRCWCleanupList = new RCWCleanupList();
6742 }
6743 _ASSERTE(g_pRCWCleanupList);
6744
6745 {
6746 BaseDomain::LockHolder lh(this);
6747
6748 if (!m_pRCWCache)
6749 m_pRCWCache = new RCWCache(this);
6750 }
6751
6752 RETURN m_pRCWCache;
6753}
6754
6755void AppDomain::ReleaseRCWs(LPVOID pCtxCookie)
6756{
6757 WRAPPER_NO_CONTRACT;
6758 if (m_pRCWCache)
6759 m_pRCWCache->ReleaseWrappersWorker(pCtxCookie);
6760
6761 RemoveWinRTFactoryObjects(pCtxCookie);
6762}
6763
6764void AppDomain::DetachRCWs()
6765{
6766 WRAPPER_NO_CONTRACT;
6767 if (m_pRCWCache)
6768 m_pRCWCache->DetachWrappersWorker();
6769}
6770
6771#endif // FEATURE_COMINTEROP
6772
6773void AppDomain::ExceptionUnwind(Frame *pFrame)
6774{
6775 CONTRACTL
6776 {
6777 DISABLED(GC_TRIGGERS); // EEResourceException
6778 DISABLED(THROWS); // EEResourceException
6779 MODE_ANY;
6780 }
6781 CONTRACTL_END;
6782
6783 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind for %8.8x\n", pFrame));
6784#if _DEBUG_ADUNLOAD
6785 printf("%x AppDomain::ExceptionUnwind for %8.8p\n", GetThread()->GetThreadId(), pFrame);
6786#endif
6787 Thread *pThread = GetThread();
6788 _ASSERTE(pThread);
6789
6790 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::ExceptionUnwind: not first transition or abort\n"));
6791}
6792
6793BOOL AppDomain::StopEEAndUnwindThreads(unsigned int retryCount, BOOL *pFMarkUnloadRequestThread)
6794{
6795 CONTRACTL
6796 {
6797 THROWS;
6798 GC_TRIGGERS;
6799 MODE_ANY;
6800 SO_INTOLERANT;
6801 }
6802 CONTRACTL_END;
6803
6804 Thread *pThread = NULL;
6805 DWORD nThreadsNeedMoreWork=0;
6806 if (retryCount != (unsigned int)-1 && retryCount < g_pConfig->AppDomainUnloadRetryCount())
6807 {
6808 Thread *pCurThread = GetThread();
6809 if (pCurThread->CatchAtSafePoint())
6810 pCurThread->PulseGCMode();
6811
6812 m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
6813 return !nThreadsNeedMoreWork;
6814 }
6815
6816 // For now piggyback on the GC's suspend EE mechanism
6817 ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
6818#ifdef _DEBUG
6819 // <TODO>@todo: what to do with any threads that didn't stop?</TODO>
6820 _ASSERTE(ThreadStore::s_pThreadStore->DbgBackgroundThreadCount() > 0);
6821#endif // _DEBUG
6822
6823 int totalADCount = 0;
6824 int finalizerADCount = 0;
6825 pThread = NULL;
6826
6827 RuntimeExceptionKind reKind = kLastException;
6828 UINT resId = 0;
6829 SmallStackSString ssThreadId;
6830
6831 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
6832 {
6833 // we already checked that we're not running in the unload domain
6834 if (pThread == GetThread())
6835 {
6836 continue;
6837 }
6838
6839#ifdef _DEBUG
6840 void PrintStackTraceWithADToLog(Thread *pThread);
6841 if (LoggingOn(LF_APPDOMAIN, LL_INFO100)) {
6842 LOG((LF_APPDOMAIN, LL_INFO100, "\nStackTrace for %x\n", pThread->GetThreadId()));
6843 PrintStackTraceWithADToLog(pThread);
6844 }
6845#endif // _DEBUG
6846 int count = 0;
6847 Frame *pFrame = pThread->GetFirstTransitionInto(this, &count);
6848 if (! pFrame) {
6849 _ASSERTE(count == 0);
6850 continue;
6851 }
6852
6853 if (pThread != FinalizerThread::GetFinalizerThread())
6854 {
6855 totalADCount += count;
6856 nThreadsNeedMoreWork++;
6857 }
6858 else
6859 {
6860 finalizerADCount = count;
6861 }
6862
6863 // don't setup the exception info for the unloading thread unless it's the last one in
6864 if (retryCount != ((unsigned int) -1) && retryCount > g_pConfig->AppDomainUnloadRetryCount() && reKind == kLastException)
6865 {
6866#ifdef AD_BREAK_ON_CANNOT_UNLOAD
6867 static int breakOnCannotUnload = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ADBreakOnCannotUnload);
6868 if (breakOnCannotUnload)
6869 _ASSERTE(!"Cannot unload AD");
6870#endif // AD_BREAK_ON_CANNOT_UNLOAD
6871 reKind = kCannotUnloadAppDomainException;
6872 resId = IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD;
6873 ssThreadId.Printf(W("%x"), pThread->GetThreadId());
6874 STRESS_LOG2(LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads cannot stop thread %x with %d transitions\n", pThread->GetThreadId(), count);
6875 // don't break out of this early or the assert totalADCount == (int)m_dwThreadEnterCount below will fire
6876 // it's better to chew a little extra time here and make sure our counts are consistent
6877 }
6878 // only abort the thread requesting the unload if it's the last one in, that way it will get
6879 // notification that the unload failed for some other thread not being aborted. And don't abort
6880 // the finalizer thread - let it finish it's work as it's allowed to be in there. If it won't finish,
6881 // then we will eventually get a CannotUnloadException on it.
6882
6883 if (pThread != FinalizerThread::GetFinalizerThread())
6884 {
6885
6886 STRESS_LOG2(LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count);
6887 LOG((LF_APPDOMAIN, LL_INFO100, "AppDomain::UnwindThreads stopping %x with %d transitions\n", pThread->GetThreadId(), count));
6888#if _DEBUG_ADUNLOAD
6889 printf("AppDomain::UnwindThreads %x stopping %x with first frame %8.8p\n", GetThread()->GetThreadId(), pThread->GetThreadId(), pFrame);
6890#endif
6891 pThread->SetAbortRequest(EEPolicy::TA_V1Compatible);
6892 }
6893 TESTHOOKCALL(UnwindingThreads(GetId().m_dwId)) ;
6894 }
6895 _ASSERTE(totalADCount + finalizerADCount == (int)m_dwThreadEnterCount);
6896
6897 //@TODO: This is intended to catch a stress bug. Remove when no longer needed.
6898 if (totalADCount + finalizerADCount != (int)m_dwThreadEnterCount)
6899 FreeBuildDebugBreak();
6900
6901 // if our count did get messed up, set it to whatever count we actually found in the domain to avoid looping
6902 // or other problems related to incorrect count. This is very much a bug if this happens - a thread should always
6903 // exit the domain gracefully.
6904 // m_dwThreadEnterCount = totalADCount;
6905
6906 // CommonTripThread will handle the abort for any threads that we've marked
6907 ThreadSuspend::RestartEE(FALSE, TRUE);
6908 if (reKind != kLastException)
6909 COMPlusThrow(reKind, resId, ssThreadId.GetUnicode());
6910
6911 _ASSERTE((totalADCount==0 && nThreadsNeedMoreWork==0) ||(totalADCount!=0 && nThreadsNeedMoreWork!=0));
6912
6913 m_dwThreadsStillInAppDomain=nThreadsNeedMoreWork;
6914 return (totalADCount == 0);
6915}
6916
6917void AppDomain::UnwindThreads()
6918{
6919 // This function should guarantee appdomain
6920 // consistency even if it fails. Everything that is going
6921 // to make the appdomain impossible to reenter
6922 // should be factored out
6923
6924 // <TODO>@todo: need real synchronization here!!!</TODO>
6925 CONTRACTL
6926 {
6927 MODE_COOPERATIVE;
6928 THROWS;
6929 GC_TRIGGERS;
6930 }
6931 CONTRACTL_END;
6932
6933 int retryCount = -1;
6934 m_dwThreadsStillInAppDomain=(ULONG)-1;
6935 ULONGLONG startTime = CLRGetTickCount64();
6936
6937 // Force threads to go through slow path during AD unload.
6938 TSSuspendHolder shTrap;
6939
6940 BOOL fMarkUnloadRequestThread = TRUE;
6941
6942 // now wait for all the threads running in our AD to get out
6943 do
6944 {
6945 DWORD timeout = GetEEPolicy()->GetTimeout(OPR_AppDomainUnload);
6946 EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(OPR_AppDomainUnload, NULL);
6947 if (timeout != INFINITE && action >= eExitProcess) {
6948 // Escalation policy specified.
6949 ULONGLONG curTime = CLRGetTickCount64();
6950 ULONGLONG elapseTime = curTime - startTime;
6951 if (elapseTime > timeout)
6952 {
6953 // Escalate
6954 switch (action)
6955 {
6956 case eExitProcess:
6957 case eFastExitProcess:
6958 case eRudeExitProcess:
6959 case eDisableRuntime:
6960 GetEEPolicy()->NotifyHostOnTimeout(OPR_AppDomainUnload, action);
6961 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
6962 _ASSERTE (!"Should not reach here");
6963 break;
6964 default:
6965 break;
6966 }
6967 }
6968 }
6969#ifdef _DEBUG
6970 if (LoggingOn(LF_APPDOMAIN, LL_INFO100))
6971 DumpADThreadTrack();
6972#endif // _DEBUG
6973 if (StopEEAndUnwindThreads(retryCount, &fMarkUnloadRequestThread))
6974 break;
6975 if (timeout != INFINITE)
6976 {
6977 // Turn off the timeout used by AD.
6978 retryCount = 1;
6979 }
6980 else
6981 {
6982 // GCStress takes a long time to unwind, due to expensive creation of
6983 // a threadabort exception.
6984 if (!GCStress<cfg_any>::IsEnabled())
6985 ++retryCount;
6986 LOG((LF_APPDOMAIN, LL_INFO10, "AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount));
6987#if _DEBUG_ADUNLOAD
6988 printf("AppDomain::UnwindThreads iteration %d waiting on thread count %d\n", retryCount, m_dwThreadEnterCount);
6989#endif
6990 }
6991
6992 if (m_dwThreadEnterCount != 0)
6993 {
6994#ifdef _DEBUG
6995 GetThread()->UserSleep(20);
6996#else // !_DEBUG
6997 GetThread()->UserSleep(10);
6998#endif // !_DEBUG
6999 }
7000 }
7001 while (TRUE) ;
7002}
7003
7004#ifdef _DEBUG
7005
7006void AppDomain::TrackADThreadEnter(Thread *pThread, Frame *pFrame)
7007{
7008 CONTRACTL
7009 {
7010 NOTHROW;
7011 GC_NOTRIGGER;
7012 // REENTRANT
7013 PRECONDITION(CheckPointer(pThread));
7014 PRECONDITION(pFrame != (Frame*)(size_t) INVALID_POINTER_CD);
7015 }
7016 CONTRACTL_END;
7017
7018 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
7019 ;
7020 if (m_pThreadTrackInfoList == NULL)
7021 m_pThreadTrackInfoList = new (nothrow) ThreadTrackInfoList;
7022 // If we don't assert here, we will AV in the for loop below
7023 _ASSERTE(m_pThreadTrackInfoList);
7024
7025 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
7026
7027 ThreadTrackInfo *pTrack = NULL;
7028 int i;
7029 for (i=0; i < pTrackList->Count(); i++) {
7030 if ((*(pTrackList->Get(i)))->pThread == pThread) {
7031 pTrack = *(pTrackList->Get(i));
7032 break;
7033 }
7034 }
7035 if (! pTrack) {
7036 pTrack = new (nothrow) ThreadTrackInfo;
7037 // If we don't assert here, we will AV in the for loop below.
7038 _ASSERTE(pTrack);
7039 pTrack->pThread = pThread;
7040 ThreadTrackInfo **pSlot = pTrackList->Append();
7041 *pSlot = pTrack;
7042 }
7043
7044 InterlockedIncrement((LONG*)&m_dwThreadEnterCount);
7045 Frame **pSlot;
7046 if (pTrack)
7047 {
7048 pSlot = pTrack->frameStack.Insert(0);
7049 *pSlot = pFrame;
7050 }
7051 int totThreads = 0;
7052 for (i=0; i < pTrackList->Count(); i++)
7053 totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
7054 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
7055
7056 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
7057}
7058
7059
7060void AppDomain::TrackADThreadExit(Thread *pThread, Frame *pFrame)
7061{
7062 CONTRACTL
7063 {
7064 if (GetThread()) {MODE_COOPERATIVE;}
7065 NOTHROW;
7066 GC_NOTRIGGER;
7067 }
7068 CONTRACTL_END;
7069
7070 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
7071 ;
7072 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
7073 _ASSERTE(pTrackList);
7074 ThreadTrackInfo *pTrack = NULL;
7075 int i;
7076 for (i=0; i < pTrackList->Count(); i++)
7077 {
7078 if ((*(pTrackList->Get(i)))->pThread == pThread)
7079 {
7080 pTrack = *(pTrackList->Get(i));
7081 break;
7082 }
7083 }
7084 _ASSERTE(pTrack);
7085 _ASSERTE(*(pTrack->frameStack.Get(0)) == pFrame);
7086 pTrack->frameStack.Delete(0);
7087 InterlockedDecrement((LONG*)&m_dwThreadEnterCount);
7088
7089 int totThreads = 0;
7090 for (i=0; i < pTrackList->Count(); i++)
7091 totThreads += (*(pTrackList->Get(i)))->frameStack.Count();
7092 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
7093
7094 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
7095}
7096
7097void AppDomain::DumpADThreadTrack()
7098{
7099 CONTRACTL
7100 {
7101 NOTHROW;
7102 GC_NOTRIGGER;
7103 MODE_COOPERATIVE;
7104 }
7105 CONTRACTL_END;
7106
7107 while (FastInterlockCompareExchange((LONG*)&m_TrackSpinLock, 1, 0) != 0)
7108 ;
7109 ThreadTrackInfoList *pTrackList= m_pThreadTrackInfoList;
7110 if (!pTrackList)
7111 goto end;
7112
7113 {
7114 LOG((LF_APPDOMAIN, LL_INFO10000, "\nThread dump of %d threads for [%d] %#08x %S\n",
7115 m_dwThreadEnterCount, GetId().m_dwId, this, GetFriendlyNameForLogging()));
7116 int totThreads = 0;
7117 for (int i=0; i < pTrackList->Count(); i++)
7118 {
7119 ThreadTrackInfo *pTrack = *(pTrackList->Get(i));
7120 if (pTrack->frameStack.Count()==0)
7121 continue;
7122 LOG((LF_APPDOMAIN, LL_INFO100, " ADEnterCount for %x is %d\n", pTrack->pThread->GetThreadId(), pTrack->frameStack.Count()));
7123 totThreads += pTrack->frameStack.Count();
7124 for (int j=0; j < pTrack->frameStack.Count(); j++)
7125 LOG((LF_APPDOMAIN, LL_INFO100, " frame %8.8x\n", *(pTrack->frameStack.Get(j))));
7126 }
7127 _ASSERTE(totThreads == (int)m_dwThreadEnterCount);
7128 }
7129end:
7130 InterlockedExchange((LONG*)&m_TrackSpinLock, 0);
7131}
7132#endif // _DEBUG
7133
7134#endif // CROSSGEN_COMPILE
7135
7136#endif // !DACCESS_COMPILE
7137
7138DWORD DomainLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex /*=(DWORD)-1*/)
7139{
7140 CONTRACTL {
7141 NOTHROW;
7142 GC_NOTRIGGER;
7143 SO_TOLERANT;
7144 } CONTRACTL_END;
7145
7146 { // SO tolerance exception for debug-only assertion.
7147 CONTRACT_VIOLATION(SOToleranceViolation);
7148 CONSISTENCY_CHECK(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
7149 }
7150
7151 if (pMT->IsDynamicStatics())
7152 {
7153 _ASSERTE(!pMT->ContainsGenericVariables());
7154 DWORD dynamicClassID = pMT->GetModuleDynamicEntryID();
7155 if(m_aDynamicEntries <= dynamicClassID)
7156 return FALSE;
7157 return (m_pDynamicClassTable[dynamicClassID].m_dwFlags);
7158 }
7159 else
7160 {
7161 if (iClassIndex == (DWORD)-1)
7162 iClassIndex = pMT->GetClassIndex();
7163 return GetPrecomputedStaticsClassData()[iClassIndex];
7164 }
7165}
7166
7167#ifndef DACCESS_COMPILE
7168
7169void DomainLocalModule::SetClassInitialized(MethodTable* pMT)
7170{
7171 CONTRACTL
7172 {
7173 THROWS;
7174 GC_TRIGGERS;
7175 MODE_ANY;
7176 }
7177 CONTRACTL_END;
7178
7179 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
7180
7181 _ASSERTE(!IsClassInitialized(pMT));
7182 _ASSERTE(!IsClassInitError(pMT));
7183
7184 SetClassFlags(pMT, ClassInitFlags::INITIALIZED_FLAG);
7185}
7186
7187void DomainLocalModule::SetClassInitError(MethodTable* pMT)
7188{
7189 WRAPPER_NO_CONTRACT;
7190
7191 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
7192
7193 SetClassFlags(pMT, ClassInitFlags::ERROR_FLAG);
7194}
7195
7196void DomainLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags)
7197{
7198 CONTRACTL {
7199 THROWS;
7200 GC_TRIGGERS;
7201 PRECONDITION(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
7202 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
7203 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
7204 } CONTRACTL_END;
7205
7206 if (pMT->IsDynamicStatics())
7207 {
7208 _ASSERTE(!pMT->ContainsGenericVariables());
7209 DWORD dwID = pMT->GetModuleDynamicEntryID();
7210 EnsureDynamicClassIndex(dwID);
7211 m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags;
7212 }
7213 else
7214 {
7215 GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags;
7216 }
7217}
7218
7219void DomainLocalModule::EnsureDynamicClassIndex(DWORD dwID)
7220{
7221 CONTRACTL
7222 {
7223 THROWS;
7224 GC_TRIGGERS;
7225 MODE_ANY;
7226 INJECT_FAULT(COMPlusThrowOM(););
7227 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
7228 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
7229 }
7230 CONTRACTL_END;
7231
7232 if (dwID < m_aDynamicEntries)
7233 {
7234 _ASSERTE(m_pDynamicClassTable.Load() != NULL);
7235 return;
7236 }
7237
7238 SIZE_T aDynamicEntries = max(16, m_aDynamicEntries.Load());
7239 while (aDynamicEntries <= dwID)
7240 {
7241 aDynamicEntries *= 2;
7242 }
7243
7244 DynamicClassInfo* pNewDynamicClassTable;
7245 pNewDynamicClassTable = (DynamicClassInfo*)
7246 (void*)GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(
7247 S_SIZE_T(sizeof(DynamicClassInfo)) * S_SIZE_T(aDynamicEntries));
7248
7249 memcpy(pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * m_aDynamicEntries);
7250
7251 // Note: Memory allocated on loader heap is zero filled
7252 // memset(pNewDynamicClassTable + m_aDynamicEntries, 0, (aDynamicEntries - m_aDynamicEntries) * sizeof(DynamicClassInfo));
7253
7254 _ASSERTE(m_aDynamicEntries%2 == 0);
7255
7256 // Commit new dynamic table. The lock-free helpers depend on the order.
7257 MemoryBarrier();
7258 m_pDynamicClassTable = pNewDynamicClassTable;
7259 MemoryBarrier();
7260 m_aDynamicEntries = aDynamicEntries;
7261}
7262
7263#ifndef CROSSGEN_COMPILE
7264void DomainLocalModule::AllocateDynamicClass(MethodTable *pMT)
7265{
7266 CONTRACTL
7267 {
7268 THROWS;
7269 GC_TRIGGERS;
7270 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
7271 PRECONDITION(GetDomainFile()->GetAppDomain()->OwnDomainLocalBlockLock());
7272 }
7273 CONTRACTL_END;
7274
7275 _ASSERTE(!pMT->ContainsGenericVariables());
7276 _ASSERTE(!pMT->IsSharedByGenericInstantiations());
7277 _ASSERTE(GetDomainFile()->GetModule() == pMT->GetModuleForStatics());
7278 _ASSERTE(pMT->IsDynamicStatics());
7279
7280 DWORD dynamicEntryIDIndex = pMT->GetModuleDynamicEntryID();
7281
7282 EnsureDynamicClassIndex(dynamicEntryIDIndex);
7283
7284 _ASSERTE(m_aDynamicEntries > dynamicEntryIDIndex);
7285
7286 EEClass *pClass = pMT->GetClass();
7287
7288 DWORD dwStaticBytes = pClass->GetNonGCRegularStaticFieldBytes();
7289 DWORD dwNumHandleStatics = pClass->GetNumHandleRegularStatics();
7290
7291 _ASSERTE(!IsClassAllocated(pMT));
7292 _ASSERTE(!IsClassInitialized(pMT));
7293 _ASSERTE(!IsClassInitError(pMT));
7294
7295 DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry;
7296
7297 // We need this check because maybe a class had a cctor but no statics
7298 if (dwStaticBytes > 0 || dwNumHandleStatics > 0)
7299 {
7300 if (pDynamicStatics == NULL)
7301 {
7302 LoaderHeap * pLoaderAllocator = GetDomainFile()->GetLoaderAllocator()->GetHighFrequencyHeap();
7303
7304 if (pMT->Collectible())
7305 {
7306 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(sizeof(CollectibleDynamicEntry)));
7307 }
7308 else
7309 {
7310 SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes;
7311
7312#ifdef FEATURE_64BIT_ALIGNMENT
7313 // Allocate memory with extra alignment only if it is really necessary
7314 if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
7315 {
7316 static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0);
7317 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE);
7318 }
7319 else
7320#endif
7321 pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(dynamicEntrySize));
7322 }
7323
7324 // Note: Memory allocated on loader heap is zero filled
7325
7326 m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry = pDynamicStatics;
7327 }
7328
7329 if (pMT->Collectible() && (dwStaticBytes != 0))
7330 {
7331 GCX_COOP();
7332 OBJECTREF nongcStaticsArray = NULL;
7333 GCPROTECT_BEGIN(nongcStaticsArray);
7334#ifdef FEATURE_64BIT_ALIGNMENT
7335 // Allocate memory with extra alignment only if it is really necessary
7336 if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE)
7337 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8)-1)) / (sizeof(CLR_I8)));
7338 else
7339#endif
7340 nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes);
7341 ((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray);
7342 GCPROTECT_END();
7343 }
7344 if (dwNumHandleStatics > 0)
7345 {
7346 if (!pMT->Collectible())
7347 {
7348 GetAppDomain()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
7349 &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics);
7350 }
7351 else
7352 {
7353 GCX_COOP();
7354 OBJECTREF gcStaticsArray = NULL;
7355 GCPROTECT_BEGIN(gcStaticsArray);
7356 gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass);
7357 ((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = GetDomainFile()->GetModule()->GetLoaderAllocator()->AllocateHandle(gcStaticsArray);
7358 GCPROTECT_END();
7359 }
7360 }
7361 }
7362}
7363
7364
7365void DomainLocalModule::PopulateClass(MethodTable *pMT)
7366{
7367 CONTRACTL
7368 {
7369 THROWS;
7370 GC_TRIGGERS;
7371 }
7372 CONTRACTL_END;
7373
7374 _ASSERTE(!pMT->ContainsGenericVariables());
7375
7376 // <todo> the only work actually done here for non-dynamics is the freezing related work.
7377 // See if we can eliminate this and make this a dynamic-only path </todo>
7378 DWORD iClassIndex = pMT->GetClassIndex();
7379
7380 if (!IsClassAllocated(pMT, iClassIndex))
7381 {
7382 BaseDomain::DomainLocalBlockLockHolder lh(GetDomainFile()->GetAppDomain());
7383
7384 if (!IsClassAllocated(pMT, iClassIndex))
7385 {
7386 // Allocate dynamic space if necessary
7387 if (pMT->IsDynamicStatics())
7388 AllocateDynamicClass(pMT);
7389
7390 // determine flags to set on the statics block
7391 DWORD dwFlags = ClassInitFlags::ALLOCATECLASS_FLAG;
7392
7393 if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics())
7394 {
7395 _ASSERTE(!IsClassInitialized(pMT));
7396 _ASSERTE(!IsClassInitError(pMT));
7397 dwFlags |= ClassInitFlags::INITIALIZED_FLAG;
7398 }
7399
7400 if (pMT->Collectible())
7401 {
7402 dwFlags |= ClassInitFlags::COLLECTIBLE_FLAG;
7403 }
7404
7405 // Set all flags at the same time to avoid races
7406 SetClassFlags(pMT, dwFlags);
7407 }
7408 }
7409
7410 return;
7411}
7412#endif // CROSSGEN_COMPILE
7413
7414void DomainLocalBlock::EnsureModuleIndex(ModuleIndex index)
7415{
7416 CONTRACTL
7417 {
7418 THROWS;
7419 GC_TRIGGERS;
7420 MODE_ANY;
7421 INJECT_FAULT(COMPlusThrowOM(););
7422 // Assumes BaseDomain::DomainLocalBlockLockHolder is taken
7423 PRECONDITION(m_pDomain->OwnDomainLocalBlockLock());
7424 }
7425 CONTRACTL_END;
7426
7427 if (m_aModuleIndices > index.m_dwIndex)
7428 {
7429 _ASSERTE(m_pModuleSlots != NULL);
7430 return;
7431 }
7432
7433 SIZE_T aModuleIndices = max(16, m_aModuleIndices);
7434 while (aModuleIndices <= index.m_dwIndex)
7435 {
7436 aModuleIndices *= 2;
7437 }
7438
7439 PTR_DomainLocalModule* pNewModuleSlots = (PTR_DomainLocalModule*) (void*)m_pDomain->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(PTR_DomainLocalModule)) * S_SIZE_T(aModuleIndices));
7440
7441 memcpy(pNewModuleSlots, m_pModuleSlots, sizeof(SIZE_T)*m_aModuleIndices);
7442
7443 // Note: Memory allocated on loader heap is zero filled
7444 // memset(pNewModuleSlots + m_aModuleIndices, 0 , (aModuleIndices - m_aModuleIndices)*sizeof(PTR_DomainLocalModule) );
7445
7446 // Commit new table. The lock-free helpers depend on the order.
7447 MemoryBarrier();
7448 m_pModuleSlots = pNewModuleSlots;
7449 MemoryBarrier();
7450 m_aModuleIndices = aModuleIndices;
7451
7452}
7453
7454void DomainLocalBlock::SetModuleSlot(ModuleIndex index, PTR_DomainLocalModule pLocalModule)
7455{
7456 // Need to synchronize with table growth in this domain
7457 BaseDomain::DomainLocalBlockLockHolder lh(m_pDomain);
7458
7459 EnsureModuleIndex(index);
7460
7461 _ASSERTE(index.m_dwIndex < m_aModuleIndices);
7462
7463 // We would like this assert here, unfortunately, loading a module in this appdomain can fail
7464 // after here and we will keep the module around and reuse the slot when we retry (if
7465 // the failure happened due to a transient error, such as OOM). In that case the slot wont
7466 // be null.
7467 //_ASSERTE(m_pModuleSlots[index.m_dwIndex] == 0);
7468
7469 m_pModuleSlots[index.m_dwIndex] = pLocalModule;
7470}
7471
7472#ifndef CROSSGEN_COMPILE
7473
7474DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef)
7475{
7476 CONTRACTL
7477 {
7478 MODE_ANY;
7479 GC_TRIGGERS;
7480 THROWS;
7481 INJECT_FAULT(COMPlusThrowOM(););
7482 }
7483 CONTRACTL_END;
7484
7485 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
7486
7487 DomainAssembly* pResolvedAssembly = NULL;
7488 _ASSERTE(strcmp(szName, g_AppDomainClassName));
7489
7490 GCX_COOP();
7491
7492 struct _gc {
7493 OBJECTREF AssemblyRef;
7494 STRINGREF str;
7495 } gc;
7496 ZeroMemory(&gc, sizeof(gc));
7497
7498 GCPROTECT_BEGIN(gc);
7499
7500 if (pAssembly != NULL)
7501 gc.AssemblyRef = pAssembly->GetExposedAssemblyObject();
7502
7503 MethodDescCallSite onTypeResolve(METHOD__ASSEMBLYLOADCONTEXT__ON_TYPE_RESOLVE);
7504
7505 gc.str = StringObject::NewString(szName);
7506 ARG_SLOT args[2] =
7507 {
7508 ObjToArgSlot(gc.AssemblyRef),
7509 ObjToArgSlot(gc.str)
7510 };
7511 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onTypeResolve.Call_RetOBJECTREF(args);
7512
7513 if (ResultingAssemblyRef != NULL)
7514 {
7515 pResolvedAssembly = ResultingAssemblyRef->GetDomainAssembly();
7516
7517 if (pResultingAssemblyRef)
7518 *pResultingAssemblyRef = ResultingAssemblyRef;
7519 else
7520 {
7521 if (pResolvedAssembly->IsCollectible())
7522 {
7523 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
7524 }
7525 }
7526 }
7527 GCPROTECT_END();
7528
7529 return pResolvedAssembly;
7530}
7531
7532
7533Assembly* AppDomain::RaiseResourceResolveEvent(DomainAssembly* pAssembly, LPCSTR szName)
7534{
7535 CONTRACT(Assembly*)
7536 {
7537 THROWS;
7538 GC_TRIGGERS;
7539 MODE_ANY;
7540 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
7541 INJECT_FAULT(COMPlusThrowOM(););
7542 }
7543 CONTRACT_END;
7544
7545 Assembly* pResolvedAssembly = NULL;
7546
7547 GCX_COOP();
7548
7549 struct _gc {
7550 OBJECTREF AssemblyRef;
7551 STRINGREF str;
7552 } gc;
7553 ZeroMemory(&gc, sizeof(gc));
7554
7555 GCPROTECT_BEGIN(gc);
7556
7557 if (pAssembly != NULL)
7558 gc.AssemblyRef=pAssembly->GetExposedAssemblyObject();
7559
7560 MethodDescCallSite onResourceResolve(METHOD__ASSEMBLYLOADCONTEXT__ON_RESOURCE_RESOLVE);
7561 gc.str = StringObject::NewString(szName);
7562 ARG_SLOT args[2] =
7563 {
7564 ObjToArgSlot(gc.AssemblyRef),
7565 ObjToArgSlot(gc.str)
7566 };
7567 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onResourceResolve.Call_RetOBJECTREF(args);
7568 if (ResultingAssemblyRef != NULL)
7569 {
7570 pResolvedAssembly = ResultingAssemblyRef->GetAssembly();
7571 if (pResolvedAssembly->IsCollectible())
7572 {
7573 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
7574 }
7575 }
7576 GCPROTECT_END();
7577
7578 RETURN pResolvedAssembly;
7579}
7580
7581
7582Assembly *
7583AppDomain::RaiseAssemblyResolveEvent(
7584 AssemblySpec * pSpec)
7585{
7586 CONTRACT(Assembly*)
7587 {
7588 THROWS;
7589 GC_TRIGGERS;
7590 MODE_ANY;
7591 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
7592 INJECT_FAULT(COMPlusThrowOM(););
7593 }
7594 CONTRACT_END;
7595
7596 StackSString ssName;
7597 pSpec->GetFileOrDisplayName(0, ssName);
7598
7599 // Elevate threads allowed loading level. This allows the host to load an assembly even in a restricted
7600 // condition. Note, however, that this exposes us to possible recursion failures, if the host tries to
7601 // load the assemblies currently being loaded. (Such cases would then throw an exception.)
7602
7603 OVERRIDE_LOAD_LEVEL_LIMIT(FILE_ACTIVE);
7604 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);
7605
7606 GCX_COOP();
7607
7608 Assembly* pAssembly = NULL;
7609
7610 struct _gc {
7611 OBJECTREF AssemblyRef;
7612 STRINGREF str;
7613 } gc;
7614 ZeroMemory(&gc, sizeof(gc));
7615
7616 GCPROTECT_BEGIN(gc);
7617 {
7618 if (pSpec->GetParentAssembly() != NULL)
7619 {
7620 gc.AssemblyRef=pSpec->GetParentAssembly()->GetExposedAssemblyObject();
7621 }
7622
7623 MethodDescCallSite onAssemblyResolve(METHOD__ASSEMBLYLOADCONTEXT__ON_ASSEMBLY_RESOLVE);
7624
7625 gc.str = StringObject::NewString(ssName);
7626 ARG_SLOT args[2] = {
7627 ObjToArgSlot(gc.AssemblyRef),
7628 ObjToArgSlot(gc.str)
7629 };
7630
7631 ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) onAssemblyResolve.Call_RetOBJECTREF(args);
7632
7633 if (ResultingAssemblyRef != NULL)
7634 {
7635 pAssembly = ResultingAssemblyRef->GetAssembly();
7636 if (pAssembly->IsCollectible())
7637 {
7638 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
7639 }
7640 }
7641 }
7642 GCPROTECT_END();
7643
7644 if (pAssembly != NULL)
7645 {
7646 // Check that the public key token matches the one specified in the spec
7647 // MatchPublicKeys throws as appropriate
7648 pSpec->MatchPublicKeys(pAssembly);
7649 }
7650
7651 RETURN pAssembly;
7652} // AppDomain::RaiseAssemblyResolveEvent
7653
7654
7655ULONGLONG g_ObjFinalizeStartTime = 0;
7656Volatile<BOOL> g_FinalizerIsRunning = FALSE;
7657Volatile<ULONG> g_FinalizerLoopCount = 0;
7658
7659ULONGLONG GetObjFinalizeStartTime()
7660{
7661 LIMITED_METHOD_CONTRACT;
7662 return g_ObjFinalizeStartTime;
7663}
7664
7665void FinalizerThreadAbortOnTimeout()
7666{
7667 STATIC_CONTRACT_NOTHROW;
7668 STATIC_CONTRACT_MODE_COOPERATIVE;
7669 STATIC_CONTRACT_GC_TRIGGERS;
7670
7671 {
7672 // If finalizer thread is blocked because scheduler is running another task,
7673 // or it is waiting for another thread, we first see if we get finalizer thread
7674 // running again.
7675 Thread::ThreadAbortWatchDog();
7676 }
7677
7678 EX_TRY
7679 {
7680 Thread *pFinalizerThread = FinalizerThread::GetFinalizerThread();
7681 EPolicyAction action = GetEEPolicy()->GetActionOnTimeout(OPR_FinalizerRun, pFinalizerThread);
7682 switch (action)
7683 {
7684 case eAbortThread:
7685 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
7686 pFinalizerThread->UserAbort(Thread::TAR_Thread,
7687 EEPolicy::TA_Safe,
7688 INFINITE,
7689 Thread::UAC_FinalizerTimeout);
7690 break;
7691 case eRudeAbortThread:
7692 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
7693 pFinalizerThread->UserAbort(Thread::TAR_Thread,
7694 EEPolicy::TA_Rude,
7695 INFINITE,
7696 Thread::UAC_FinalizerTimeout);
7697 break;
7698 case eUnloadAppDomain:
7699 {
7700 AppDomain *pDomain = pFinalizerThread->GetDomain();
7701 pFinalizerThread->UserAbort(Thread::TAR_Thread,
7702 EEPolicy::TA_Safe,
7703 INFINITE,
7704 Thread::UAC_FinalizerTimeout);
7705 }
7706 break;
7707 case eRudeUnloadAppDomain:
7708 {
7709 AppDomain *pDomain = pFinalizerThread->GetDomain();
7710 pFinalizerThread->UserAbort(Thread::TAR_Thread,
7711 EEPolicy::TA_Rude,
7712 INFINITE,
7713 Thread::UAC_FinalizerTimeout);
7714 }
7715 break;
7716 case eExitProcess:
7717 case eFastExitProcess:
7718 case eRudeExitProcess:
7719 case eDisableRuntime:
7720 GetEEPolicy()->NotifyHostOnTimeout(OPR_FinalizerRun, action);
7721 EEPolicy::HandleExitProcessFromEscalation(action, HOST_E_EXITPROCESS_TIMEOUT);
7722 _ASSERTE (!"Should not get here");
7723 break;
7724 default:
7725 break;
7726 }
7727 }
7728 EX_CATCH
7729 {
7730 }
7731 EX_END_CATCH(SwallowAllExceptions);
7732}
7733
7734enum WorkType
7735{
7736 WT_UnloadDomain = 0x1,
7737 WT_ThreadAbort = 0x2,
7738 WT_FinalizerThread = 0x4
7739};
7740
7741static Volatile<DWORD> s_WorkType = 0;
7742
7743void SystemDomain::ProcessDelayedUnloadLoaderAllocators()
7744{
7745 CONTRACTL
7746 {
7747 NOTHROW;
7748 GC_TRIGGERS;
7749 MODE_COOPERATIVE;
7750 }
7751 CONTRACTL_END;
7752
7753 int iGCRefPoint=GCHeapUtilities::GetGCHeap()->CollectionCount(GCHeapUtilities::GetGCHeap()->GetMaxGeneration());
7754 if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCInProgress())
7755 iGCRefPoint--;
7756
7757 LoaderAllocator * pAllocatorsToDelete = NULL;
7758
7759 {
7760 CrstHolder lh(&m_DelayedUnloadCrst);
7761
7762 LoaderAllocator ** ppAllocator=&m_pDelayedUnloadListOfLoaderAllocators;
7763 while (*ppAllocator!= NULL)
7764 {
7765 LoaderAllocator * pAllocator = *ppAllocator;
7766 if (0 < iGCRefPoint - pAllocator->GetGCRefPoint())
7767 {
7768 *ppAllocator = pAllocator->m_pLoaderAllocatorDestroyNext;
7769
7770 pAllocator->m_pLoaderAllocatorDestroyNext = pAllocatorsToDelete;
7771 pAllocatorsToDelete = pAllocator;
7772 }
7773 else
7774 {
7775 ppAllocator = &pAllocator->m_pLoaderAllocatorDestroyNext;
7776 }
7777 }
7778 }
7779
7780 // Delete collected loader allocators on the finalizer thread. We cannot offload it to appdomain unload thread because of
7781 // there is not guaranteed to be one, and it is not that expensive operation anyway.
7782 while (pAllocatorsToDelete != NULL)
7783 {
7784 LoaderAllocator * pAllocator = pAllocatorsToDelete;
7785 pAllocatorsToDelete = pAllocator->m_pLoaderAllocatorDestroyNext;
7786 delete pAllocator;
7787 }
7788}
7789
7790#endif // CROSSGEN_COMPILE
7791
7792void AppDomain::EnumStaticGCRefs(promote_func* fn, ScanContext* sc)
7793{
7794 CONTRACT_VOID
7795 {
7796 NOTHROW;
7797 GC_NOTRIGGER;
7798 }
7799 CONTRACT_END;
7800
7801 _ASSERTE(GCHeapUtilities::IsGCInProgress() &&
7802 GCHeapUtilities::IsServerHeap() &&
7803 IsGCSpecialThread());
7804
7805 AppDomain::AssemblyIterator asmIterator = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution));
7806 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
7807 while (asmIterator.Next(pDomainAssembly.This()))
7808 {
7809 // @TODO: Review when DomainAssemblies get added.
7810 _ASSERTE(pDomainAssembly != NULL);
7811 pDomainAssembly->EnumStaticGCRefs(fn, sc);
7812 }
7813
7814 RETURN;
7815}
7816
7817#endif // !DACCESS_COMPILE
7818
7819//------------------------------------------------------------------------
7820PTR_LoaderAllocator BaseDomain::GetLoaderAllocator()
7821{
7822 WRAPPER_NO_CONTRACT;
7823 return SystemDomain::GetGlobalLoaderAllocator(); // The one and only domain is not unloadable
7824}
7825
7826//------------------------------------------------------------------------
7827UINT32 BaseDomain::GetTypeID(PTR_MethodTable pMT) {
7828 CONTRACTL {
7829 THROWS;
7830 GC_TRIGGERS;
7831 PRECONDITION(pMT->GetDomain() == this);
7832 } CONTRACTL_END;
7833
7834 return m_typeIDMap.GetTypeID(pMT);
7835}
7836
7837//------------------------------------------------------------------------
7838// Returns the ID of the type if found. If not found, returns INVALID_TYPE_ID
7839UINT32 BaseDomain::LookupTypeID(PTR_MethodTable pMT)
7840{
7841 CONTRACTL {
7842 NOTHROW;
7843 SO_TOLERANT;
7844 WRAPPER(GC_TRIGGERS);
7845 PRECONDITION(pMT->GetDomain() == this);
7846 } CONTRACTL_END;
7847
7848 return m_typeIDMap.LookupTypeID(pMT);
7849}
7850
7851//------------------------------------------------------------------------
7852PTR_MethodTable BaseDomain::LookupType(UINT32 id) {
7853 CONTRACTL {
7854 NOTHROW;
7855 SO_TOLERANT;
7856 WRAPPER(GC_TRIGGERS);
7857 CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS);
7858 } CONTRACTL_END;
7859
7860 PTR_MethodTable pMT = m_typeIDMap.LookupType(id);
7861
7862 CONSISTENCY_CHECK(CheckPointer(pMT));
7863 CONSISTENCY_CHECK(pMT->IsInterface());
7864 return pMT;
7865}
7866
7867//---------------------------------------------------------------------------------------
7868//
7869BOOL
7870AppDomain::AssemblyIterator::Next(
7871 CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
7872{
7873 CONTRACTL {
7874 NOTHROW;
7875 WRAPPER(GC_TRIGGERS); // Triggers only in MODE_COOPERATIVE (by taking the lock)
7876 MODE_ANY;
7877 } CONTRACTL_END;
7878
7879 CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
7880 return Next_Unlocked(pDomainAssemblyHolder);
7881}
7882
7883//---------------------------------------------------------------------------------------
7884//
7885// Note: Does not lock the assembly list, but locks collectible assemblies for adding references.
7886//
7887BOOL
7888AppDomain::AssemblyIterator::Next_Unlocked(
7889 CollectibleAssemblyHolder<DomainAssembly *> * pDomainAssemblyHolder)
7890{
7891 CONTRACTL {
7892 NOTHROW;
7893 GC_NOTRIGGER;
7894 MODE_ANY;
7895 } CONTRACTL_END;
7896
7897#ifndef DACCESS_COMPILE
7898 _ASSERTE(m_pAppDomain->GetAssemblyListLock()->OwnedByCurrentThread());
7899#endif
7900
7901 while (m_Iterator.Next())
7902 {
7903 // Get element from the list/iterator (without adding reference to the assembly)
7904 DomainAssembly * pDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
7905 if (pDomainAssembly == NULL)
7906 {
7907 continue;
7908 }
7909
7910 if (pDomainAssembly->IsError())
7911 {
7912 if (m_assemblyIterationFlags & kIncludeFailedToLoad)
7913 {
7914 *pDomainAssemblyHolder = pDomainAssembly;
7915 return TRUE;
7916 }
7917 continue; // reject
7918 }
7919
7920 // First, reject DomainAssemblies whose load status is not to be included in
7921 // the enumeration
7922
7923 if (pDomainAssembly->IsAvailableToProfilers() &&
7924 (m_assemblyIterationFlags & kIncludeAvailableToProfilers))
7925 {
7926 // The assembly has reached the state at which we would notify profilers,
7927 // and we're supposed to include such assemblies in the enumeration. So
7928 // don't reject it (i.e., noop here, and don't bother with the rest of
7929 // the load status checks). Check for this first, since
7930 // kIncludeAvailableToProfilers contains some loaded AND loading
7931 // assemblies.
7932 }
7933 else if (pDomainAssembly->IsLoaded())
7934 {
7935 // A loaded assembly
7936 if (!(m_assemblyIterationFlags & kIncludeLoaded))
7937 {
7938 continue; // reject
7939 }
7940 }
7941 else
7942 {
7943 // A loading assembly
7944 if (!(m_assemblyIterationFlags & kIncludeLoading))
7945 {
7946 continue; // reject
7947 }
7948 }
7949
7950 // Next, reject DomainAssemblies whose execution status is
7951 // not to be included in the enumeration
7952
7953 // execution assembly
7954 if (!(m_assemblyIterationFlags & kIncludeExecution))
7955 {
7956 continue; // reject
7957 }
7958
7959 // Next, reject collectible assemblies
7960 if (pDomainAssembly->IsCollectible())
7961 {
7962 if (m_assemblyIterationFlags & kExcludeCollectible)
7963 {
7964 _ASSERTE(!(m_assemblyIterationFlags & kIncludeCollected));
7965 continue; // reject
7966 }
7967
7968 // Un-tenured collectible assemblies should not be returned. (This can only happen in a brief
7969 // window during collectible assembly creation. No thread should need to have a pointer
7970 // to the just allocated DomainAssembly at this stage.)
7971 if (!pDomainAssembly->GetAssembly()->GetManifestModule()->IsTenured())
7972 {
7973 continue; // reject
7974 }
7975
7976 if (pDomainAssembly->GetLoaderAllocator()->AddReferenceIfAlive())
7977 { // The assembly is alive
7978
7979 // Set the holder value (incl. increasing ref-count)
7980 *pDomainAssemblyHolder = pDomainAssembly;
7981
7982 // Now release the reference we took in the if-condition
7983 pDomainAssembly->GetLoaderAllocator()->Release();
7984 return TRUE;
7985 }
7986 // The assembly is not alive anymore (and we didn't increase its ref-count in the
7987 // if-condition)
7988
7989 if (!(m_assemblyIterationFlags & kIncludeCollected))
7990 {
7991 continue; // reject
7992 }
7993 // Set the holder value to assembly with 0 ref-count without increasing the ref-count (won't
7994 // call Release either)
7995 pDomainAssemblyHolder->Assign(pDomainAssembly, FALSE);
7996 return TRUE;
7997 }
7998
7999 *pDomainAssemblyHolder = pDomainAssembly;
8000 return TRUE;
8001 }
8002
8003 *pDomainAssemblyHolder = NULL;
8004 return FALSE;
8005} // AppDomain::AssemblyIterator::Next_Unlocked
8006
8007#ifndef DACCESS_COMPILE
8008
8009//---------------------------------------------------------------------------------------
8010//
8011// Can be called only from AppDomain shutdown code:AppDomain::ShutdownAssemblies.
8012// Does not add-ref collectible assemblies (as the LoaderAllocator might not be reachable from the
8013// DomainAssembly anymore).
8014//
8015BOOL
8016AppDomain::AssemblyIterator::Next_UnsafeNoAddRef(
8017 DomainAssembly ** ppDomainAssembly)
8018{
8019 CONTRACTL {
8020 NOTHROW;
8021 GC_TRIGGERS;
8022 MODE_ANY;
8023 } CONTRACTL_END;
8024
8025 // Make sure we are iterating all assemblies (see the only caller code:AppDomain::ShutdownAssemblies)
8026 _ASSERTE(m_assemblyIterationFlags ==
8027 (kIncludeLoaded | kIncludeLoading | kIncludeExecution | kIncludeFailedToLoad | kIncludeCollected));
8028 // It also means that we do not exclude anything
8029 _ASSERTE((m_assemblyIterationFlags & kExcludeCollectible) == 0);
8030
8031 // We are on shutdown path, so lock shouldn't be neccessary, but all _Unlocked methods on AssemblyList
8032 // have asserts that the lock is held, so why not to take it ...
8033 CrstHolder ch(m_pAppDomain->GetAssemblyListLock());
8034
8035 while (m_Iterator.Next())
8036 {
8037 // Get element from the list/iterator (without adding reference to the assembly)
8038 *ppDomainAssembly = dac_cast<PTR_DomainAssembly>(m_Iterator.GetElement());
8039 if (*ppDomainAssembly == NULL)
8040 {
8041 continue;
8042 }
8043
8044 return TRUE;
8045 }
8046
8047 *ppDomainAssembly = NULL;
8048 return FALSE;
8049} // AppDomain::AssemblyIterator::Next_UnsafeNoAddRef
8050
8051
8052#endif //!DACCESS_COMPILE
8053
8054#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
8055
8056// Returns S_OK if the assembly was successfully loaded
8057HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, IAssemblyName *pIAssemblyName, CLRPrivBinderCoreCLR *pTPABinder, BINDER_SPACE::AssemblyName *pAssemblyName, ICLRPrivAssembly **ppLoadedAssembly)
8058{
8059 CONTRACTL
8060 {
8061 THROWS;
8062 GC_TRIGGERS;
8063 MODE_ANY;
8064 PRECONDITION(ppLoadedAssembly != NULL);
8065 }
8066 CONTRACTL_END;
8067
8068 HRESULT hr = E_FAIL;
8069
8070 // DevDiv #933506: Exceptions thrown during AssemblyLoadContext.Load should propagate
8071 // EX_TRY
8072 {
8073 // Switch to COOP mode since we are going to work with managed references
8074 GCX_COOP();
8075
8076 struct
8077 {
8078 ASSEMBLYNAMEREF oRefAssemblyName;
8079 ASSEMBLYREF oRefLoadedAssembly;
8080 } _gcRefs;
8081
8082 ZeroMemory(&_gcRefs, sizeof(_gcRefs));
8083
8084 GCPROTECT_BEGIN(_gcRefs);
8085
8086 ICLRPrivAssembly *pAssemblyBindingContext = NULL;
8087
8088 bool fInvokedForTPABinder = (pTPABinder == NULL)?true:false;
8089
8090 // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.Resolve method.
8091 //
8092 // First, initialize an assembly spec for the requested assembly
8093 //
8094 AssemblySpec spec;
8095 hr = spec.Init(pIAssemblyName);
8096 if (SUCCEEDED(hr))
8097 {
8098 bool fResolvedAssembly = false;
8099 bool fResolvedAssemblyViaTPALoadContext = false;
8100
8101 // Allocate an AssemblyName managed object
8102 _gcRefs.oRefAssemblyName = (ASSEMBLYNAMEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME));
8103
8104 // Initialize the AssemblyName object from the AssemblySpec
8105 spec.AssemblyNameInit(&_gcRefs.oRefAssemblyName, NULL);
8106
8107 if (!fInvokedForTPABinder)
8108 {
8109 // Step 2 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName) - Invoke Load method
8110 // This is not invoked for TPA Binder since it always returns NULL.
8111
8112 // Finally, setup arguments for invocation
8113 BinderMethodID idHAR_Resolve = METHOD__ASSEMBLYLOADCONTEXT__RESOLVE;
8114 MethodDescCallSite methLoadAssembly(idHAR_Resolve);
8115
8116 // Setup the arguments for the call
8117 ARG_SLOT args[2] =
8118 {
8119 PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
8120 ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
8121 };
8122
8123 // Make the call
8124 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
8125 if (_gcRefs.oRefLoadedAssembly != NULL)
8126 {
8127 fResolvedAssembly = true;
8128 }
8129
8130 // Step 3 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
8131 if (!fResolvedAssembly)
8132 {
8133 // If we could not resolve the assembly using Load method, then attempt fallback with TPA Binder.
8134 // Since TPA binder cannot fallback to itself, this fallback does not happen for binds within TPA binder.
8135 //
8136 // Switch to pre-emp mode before calling into the binder
8137 GCX_PREEMP();
8138 ICLRPrivAssembly *pCoreCLRFoundAssembly = NULL;
8139 hr = pTPABinder->BindAssemblyByName(pIAssemblyName, &pCoreCLRFoundAssembly);
8140 if (SUCCEEDED(hr))
8141 {
8142 pAssemblyBindingContext = pCoreCLRFoundAssembly;
8143 fResolvedAssembly = true;
8144 fResolvedAssemblyViaTPALoadContext = true;
8145 }
8146 }
8147 }
8148
8149 if (!fResolvedAssembly)
8150 {
8151 // Step 4 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName)
8152 //
8153 // If we couldnt resolve the assembly using TPA LoadContext as well, then
8154 // attempt to resolve it using the Resolving event.
8155 // Finally, setup arguments for invocation
8156 BinderMethodID idHAR_ResolveUsingEvent = METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUSINGEVENT;
8157 MethodDescCallSite methLoadAssembly(idHAR_ResolveUsingEvent);
8158
8159 // Setup the arguments for the call
8160 ARG_SLOT args[2] =
8161 {
8162 PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
8163 ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
8164 };
8165
8166 // Make the call
8167 _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args);
8168 if (_gcRefs.oRefLoadedAssembly != NULL)
8169 {
8170 // Set the flag indicating we found the assembly
8171 fResolvedAssembly = true;
8172 }
8173 }
8174
8175 if (fResolvedAssembly && !fResolvedAssemblyViaTPALoadContext)
8176 {
8177 // If we are here, assembly was successfully resolved via Load or Resolving events.
8178 _ASSERTE(_gcRefs.oRefLoadedAssembly != NULL);
8179
8180 // We were able to get the assembly loaded. Now, get its name since the host could have
8181 // performed the resolution using an assembly with different name.
8182 DomainAssembly *pDomainAssembly = _gcRefs.oRefLoadedAssembly->GetDomainAssembly();
8183 PEAssembly *pLoadedPEAssembly = NULL;
8184 bool fFailLoad = false;
8185 if (!pDomainAssembly)
8186 {
8187 // Reflection emitted assemblies will not have a domain assembly.
8188 fFailLoad = true;
8189 }
8190 else
8191 {
8192 pLoadedPEAssembly = pDomainAssembly->GetFile();
8193 if (pLoadedPEAssembly->HasHostAssembly() != true)
8194 {
8195 // Reflection emitted assemblies will not have a domain assembly.
8196 fFailLoad = true;
8197 }
8198 }
8199
8200 // The loaded assembly's ICLRPrivAssembly* is saved as HostAssembly in PEAssembly
8201 if (fFailLoad)
8202 {
8203 SString name;
8204 spec.GetFileOrDisplayName(0, name);
8205 COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_DYNAMICALLY_EMITTED_ASSEMBLIES_UNSUPPORTED, name);
8206 }
8207
8208 // Is the assembly already bound using a binding context that will be incompatible?
8209 // An example is attempting to consume an assembly bound to WinRT binder.
8210 pAssemblyBindingContext = pLoadedPEAssembly->GetHostAssembly();
8211 }
8212
8213#ifdef FEATURE_COMINTEROP
8214 if (AreSameBinderInstance(pAssemblyBindingContext, GetAppDomain()->GetWinRtBinder()))
8215 {
8216 // It is invalid to return an assembly bound to an incompatible binder
8217 *ppLoadedAssembly = NULL;
8218 SString name;
8219 spec.GetFileOrDisplayName(0, name);
8220 COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_BINDING_CONTEXT, name);
8221 }
8222#endif // FEATURE_COMINTEROP
8223
8224 // Get the ICLRPrivAssembly reference to return back to.
8225 *ppLoadedAssembly = clr::SafeAddRef(pAssemblyBindingContext);
8226 hr = S_OK;
8227 }
8228
8229 GCPROTECT_END();
8230 }
8231 // EX_CATCH_HRESULT(hr);
8232
8233 return hr;
8234
8235}
8236#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
8237
8238//approximate size of loader data
8239//maintained for each assembly
8240#define APPROX_LOADER_DATA_PER_ASSEMBLY 8196
8241
8242size_t AppDomain::EstimateSize()
8243{
8244 CONTRACTL
8245 {
8246 NOTHROW;
8247 GC_TRIGGERS;
8248 MODE_ANY;
8249 }
8250 CONTRACTL_END;
8251
8252 size_t retval = sizeof(AppDomain);
8253 retval += GetLoaderAllocator()->EstimateSize();
8254 //very rough estimate
8255 retval += GetAssemblyCount() * APPROX_LOADER_DATA_PER_ASSEMBLY;
8256 return retval;
8257}
8258
8259#ifdef DACCESS_COMPILE
8260
8261void
8262DomainLocalModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
8263{
8264 SUPPORTS_DAC;
8265
8266 // Enumerate the DomainLocalModule itself. DLMs are allocated to be larger than
8267 // sizeof(DomainLocalModule) to make room for ClassInit flags and non-GC statics.
8268 // "DAC_ENUM_DTHIS()" probably does not account for this, so we might not enumerate
8269 // all of the ClassInit flags and non-GC statics.
8270 // sizeof(DomainLocalModule) == 0x28
8271 DAC_ENUM_DTHIS();
8272
8273 if (m_pDomainFile.IsValid())
8274 {
8275 m_pDomainFile->EnumMemoryRegions(flags);
8276 }
8277
8278 if (m_pDynamicClassTable.Load().IsValid())
8279 {
8280 DacEnumMemoryRegion(dac_cast<TADDR>(m_pDynamicClassTable.Load()),
8281 m_aDynamicEntries * sizeof(DynamicClassInfo));
8282
8283 for (SIZE_T i = 0; i < m_aDynamicEntries; i++)
8284 {
8285 PTR_DynamicEntry entry = dac_cast<PTR_DynamicEntry>(m_pDynamicClassTable[i].m_pDynamicEntry.Load());
8286 if (entry.IsValid())
8287 {
8288 // sizeof(DomainLocalModule::DynamicEntry) == 8
8289 entry.EnumMem();
8290 }
8291 }
8292 }
8293}
8294
8295void
8296DomainLocalBlock::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
8297{
8298 SUPPORTS_DAC;
8299 // Block is contained in AppDomain, don't enum this.
8300
8301 if (m_pModuleSlots.IsValid())
8302 {
8303 DacEnumMemoryRegion(dac_cast<TADDR>(m_pModuleSlots),
8304 m_aModuleIndices * sizeof(TADDR));
8305
8306 for (SIZE_T i = 0; i < m_aModuleIndices; i++)
8307 {
8308 PTR_DomainLocalModule domMod = m_pModuleSlots[i];
8309 if (domMod.IsValid())
8310 {
8311 domMod->EnumMemoryRegions(flags);
8312 }
8313 }
8314 }
8315}
8316
8317void
8318BaseDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
8319 bool enumThis)
8320{
8321 SUPPORTS_DAC;
8322 if (enumThis)
8323 {
8324 // This is wrong. Don't do it.
8325 // BaseDomain cannot be instantiated.
8326 // The only thing this code can hope to accomplish is to potentially break
8327 // memory enumeration walking through the derived class if we
8328 // explicitly call the base class enum first.
8329// DAC_ENUM_VTHIS();
8330 }
8331
8332 EMEM_OUT(("MEM: %p BaseDomain\n", dac_cast<TADDR>(this)));
8333}
8334
8335void
8336AppDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
8337 bool enumThis)
8338{
8339 SUPPORTS_DAC;
8340
8341 if (enumThis)
8342 {
8343 //sizeof(AppDomain) == 0xeb0
8344 DAC_ENUM_VTHIS();
8345 }
8346 BaseDomain::EnumMemoryRegions(flags, false);
8347
8348 // We don't need AppDomain name in triage dumps.
8349 if (flags != CLRDATA_ENUM_MEM_TRIAGE)
8350 {
8351 m_friendlyName.EnumMemoryRegions(flags);
8352 }
8353
8354 m_Assemblies.EnumMemoryRegions(flags);
8355 AssemblyIterator assem = IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded | kIncludeExecution));
8356 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
8357
8358 while (assem.Next(pDomainAssembly.This()))
8359 {
8360 pDomainAssembly->EnumMemoryRegions(flags);
8361 }
8362
8363 m_sDomainLocalBlock.EnumMemoryRegions(flags);
8364}
8365
8366void
8367SystemDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags,
8368 bool enumThis)
8369{
8370 SUPPORTS_DAC;
8371 if (enumThis)
8372 {
8373 DAC_ENUM_VTHIS();
8374 }
8375 BaseDomain::EnumMemoryRegions(flags, false);
8376
8377 if (m_pSystemFile.IsValid())
8378 {
8379 m_pSystemFile->EnumMemoryRegions(flags);
8380 }
8381 if (m_pSystemAssembly.IsValid())
8382 {
8383 m_pSystemAssembly->EnumMemoryRegions(flags);
8384 }
8385 if (AppDomain::GetCurrentDomain())
8386 {
8387 AppDomain::GetCurrentDomain()->EnumMemoryRegions(flags, true);
8388 }
8389
8390 m_appDomainIndexList.EnumMem();
8391 (&m_appDomainIndexList)->EnumMemoryRegions(flags);
8392}
8393
8394#endif //DACCESS_COMPILE
8395
8396
8397PTR_LoaderAllocator SystemDomain::GetGlobalLoaderAllocator()
8398{
8399 return PTR_LoaderAllocator(PTR_HOST_MEMBER_TADDR(SystemDomain,System(),m_GlobalAllocator));
8400}
8401
8402#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
8403
8404#ifndef CROSSGEN_COMPILE
8405// Return the total processor time (user and kernel) used by threads executing in this AppDomain so far. The
8406// result is in 100ns units.
8407ULONGLONG AppDomain::QueryProcessorUsage()
8408{
8409 CONTRACTL
8410 {
8411 NOTHROW;
8412 GC_TRIGGERS;
8413 MODE_ANY;
8414 }
8415 CONTRACTL_END;
8416
8417#ifndef DACCESS_COMPILE
8418 Thread *pThread = NULL;
8419
8420 // Need to update our accumulated processor time count with current values from each thread that is
8421 // currently executing in this domain.
8422
8423 // Take the thread store lock while we enumerate threads.
8424 ThreadStoreLockHolder tsl;
8425 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
8426 {
8427 // Skip unstarted and dead threads and those that are currently executing in a different AppDomain.
8428 if (pThread->IsUnstarted() || pThread->IsDead() || pThread->GetDomain(INDEBUG(TRUE)) != this)
8429 continue;
8430
8431 // Add the amount of time spent by the thread in the AppDomain since the last time we asked (calling
8432 // Thread::QueryThreadProcessorUsage() will reset the thread's counter).
8433 UpdateProcessorUsage(pThread->QueryThreadProcessorUsage());
8434 }
8435#endif // !DACCESS_COMPILE
8436
8437 // Return the updated total.
8438 return m_ullTotalProcessorUsage;
8439}
8440
8441// Add to the current count of processor time used by threads within this AppDomain. This API is called by
8442// threads transitioning between AppDomains.
8443void AppDomain::UpdateProcessorUsage(ULONGLONG ullAdditionalUsage)
8444{
8445 LIMITED_METHOD_CONTRACT;
8446
8447 // Need to be careful to synchronize here, multiple threads could be racing to update this count.
8448 ULONGLONG ullOldValue;
8449 ULONGLONG ullNewValue;
8450 do
8451 {
8452 ullOldValue = m_ullTotalProcessorUsage;
8453 ullNewValue = ullOldValue + ullAdditionalUsage;
8454 } while (InterlockedCompareExchange64((LONGLONG*)&m_ullTotalProcessorUsage,
8455 (LONGLONG)ullNewValue,
8456 (LONGLONG)ullOldValue) != (LONGLONG)ullOldValue);
8457}
8458#endif // CROSSGEN_COMPILE
8459
8460#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
8461
8462#if defined(FEATURE_TYPEEQUIVALENCE)
8463
8464#ifndef DACCESS_COMPILE
8465TypeEquivalenceHashTable * AppDomain::GetTypeEquivalenceCache()
8466{
8467 CONTRACTL
8468 {
8469 THROWS;
8470 GC_TRIGGERS;
8471 INJECT_FAULT(COMPlusThrowOM());
8472 MODE_ANY;
8473 }
8474 CONTRACTL_END;
8475
8476 // Take the critical section all of the time in debug builds to ensure that it is safe to take
8477 // the critical section in the unusual times when it may actually be needed in retail builds
8478#ifdef _DEBUG
8479 CrstHolder ch(&m_TypeEquivalenceCrst);
8480#endif
8481
8482 if (m_pTypeEquivalenceTable.Load() == NULL)
8483 {
8484#ifndef _DEBUG
8485 CrstHolder ch(&m_TypeEquivalenceCrst);
8486#endif
8487 if (m_pTypeEquivalenceTable.Load() == NULL)
8488 {
8489 m_pTypeEquivalenceTable = TypeEquivalenceHashTable::Create(this, /* bucket count */ 12, &m_TypeEquivalenceCrst);
8490 }
8491 }
8492 return m_pTypeEquivalenceTable;
8493}
8494#endif //!DACCESS_COMPILE
8495
8496#endif //FEATURE_TYPEEQUIVALENCE
8497
8498#if !defined(DACCESS_COMPILE)
8499
8500//---------------------------------------------------------------------------------------------------------------------
8501void AppDomain::PublishHostedAssembly(
8502 DomainAssembly * pDomainAssembly)
8503{
8504 CONTRACTL
8505 {
8506 THROWS;
8507 GC_NOTRIGGER;
8508 MODE_ANY;
8509 }
8510 CONTRACTL_END
8511
8512 if (pDomainAssembly->GetFile()->HasHostAssembly())
8513 {
8514 // We have to serialize all Add operations
8515 CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
8516 _ASSERTE(m_hostAssemblyMap.Lookup(pDomainAssembly->GetFile()->GetHostAssembly()) == nullptr);
8517
8518 // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
8519 HostAssemblyMap::AddPhases addCall;
8520
8521 // 1. Preallocate one element
8522 addCall.PreallocateForAdd(&m_hostAssemblyMap);
8523 {
8524 // 2. Take the reader lock which can be taken during stack walking
8525 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
8526 ForbidSuspendThreadHolder suspend;
8527 {
8528 CrstHolder lock(&m_crstHostAssemblyMap);
8529 // 3. Add the element to the hash table (no call out into host)
8530 addCall.Add(pDomainAssembly);
8531 }
8532 }
8533 // 4. Cleanup the old memory (if any)
8534 addCall.DeleteOldTable();
8535 }
8536 else
8537 {
8538 }
8539}
8540
8541//---------------------------------------------------------------------------------------------------------------------
8542void AppDomain::UpdatePublishHostedAssembly(
8543 DomainAssembly * pAssembly,
8544 PTR_PEFile pFile)
8545{
8546 CONTRACTL
8547 {
8548 THROWS;
8549 GC_NOTRIGGER;
8550 MODE_ANY;
8551 CAN_TAKE_LOCK;
8552 }
8553 CONTRACTL_END
8554
8555 if (pAssembly->GetFile()->HasHostAssembly())
8556 {
8557 // We have to serialize all Add operations
8558 CrstHolder lockAdd(&m_crstHostAssemblyMapAdd);
8559 {
8560 // Wrapper for m_hostAssemblyMap.Add that avoids call out into host
8561 OriginalFileHostAssemblyMap::AddPhases addCall;
8562 bool fAddOrigFile = false;
8563
8564 // For cases where the pefile is being updated
8565 // 1. Preallocate one element
8566 if (pFile != pAssembly->GetFile())
8567 {
8568 addCall.PreallocateForAdd(&m_hostAssemblyMapForOrigFile);
8569 fAddOrigFile = true;
8570 }
8571
8572 {
8573 // We cannot call out into host from ForbidSuspend region (i.e. no allocations/deallocations)
8574 ForbidSuspendThreadHolder suspend;
8575 {
8576 CrstHolder lock(&m_crstHostAssemblyMap);
8577
8578 // Remove from hash table.
8579 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
8580 m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
8581
8582 // Update PEFile on DomainAssembly. (This may cause the key for the hash to change, which is why we need this function)
8583 pAssembly->UpdatePEFileWorker(pFile);
8584
8585 _ASSERTE(fAddOrigFile == (pAssembly->GetOriginalFile() != pAssembly->GetFile()));
8586 if (fAddOrigFile)
8587 {
8588 // 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)
8589 addCall.Add(pAssembly);
8590 }
8591
8592 // Add back to the hashtable (the call to Remove above guarantees that we will not call into host for table reallocation)
8593 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) == nullptr);
8594 m_hostAssemblyMap.Add(pAssembly);
8595 }
8596 }
8597
8598 // 4. Cleanup the old memory (if any)
8599 if (fAddOrigFile)
8600 addCall.DeleteOldTable();
8601 }
8602 }
8603 else
8604 {
8605
8606 pAssembly->UpdatePEFileWorker(pFile);
8607 }
8608}
8609
8610//---------------------------------------------------------------------------------------------------------------------
8611void AppDomain::UnPublishHostedAssembly(
8612 DomainAssembly * pAssembly)
8613{
8614 CONTRACTL
8615 {
8616 NOTHROW;
8617 GC_NOTRIGGER;
8618 MODE_ANY;
8619 CAN_TAKE_LOCK;
8620 }
8621 CONTRACTL_END
8622
8623 if (pAssembly->GetFile()->HasHostAssembly())
8624 {
8625 ForbidSuspendThreadHolder suspend;
8626 {
8627 CrstHolder lock(&m_crstHostAssemblyMap);
8628 _ASSERTE(m_hostAssemblyMap.Lookup(pAssembly->GetFile()->GetHostAssembly()) != nullptr);
8629 m_hostAssemblyMap.Remove(pAssembly->GetFile()->GetHostAssembly());
8630
8631 // We also have an entry in m_hostAssemblyMapForOrigFile. Handle that case.
8632 if (pAssembly->GetOriginalFile() != pAssembly->GetFile())
8633 {
8634 m_hostAssemblyMapForOrigFile.Remove(pAssembly->GetOriginalFile()->GetHostAssembly());
8635 }
8636 }
8637 }
8638 else
8639 {
8640 // In AppX processes, all PEAssemblies that are reach this stage should have host binders.
8641 _ASSERTE(!AppX::IsAppXProcess());
8642 }
8643}
8644
8645#if defined(FEATURE_COMINTEROP)
8646HRESULT AppDomain::SetWinrtApplicationContext(LPCWSTR pwzAppLocalWinMD)
8647{
8648 STANDARD_VM_CONTRACT;
8649
8650 _ASSERTE(WinRTSupported());
8651 _ASSERTE(m_pWinRtBinder != nullptr);
8652
8653 _ASSERTE(GetTPABinderContext() != NULL);
8654 BINDER_SPACE::ApplicationContext *pApplicationContext = GetTPABinderContext()->GetAppContext();
8655 _ASSERTE(pApplicationContext != NULL);
8656
8657 return m_pWinRtBinder->SetApplicationContext(pApplicationContext, pwzAppLocalWinMD);
8658}
8659
8660#endif // FEATURE_COMINTEROP
8661
8662#endif //!DACCESS_COMPILE
8663
8664//---------------------------------------------------------------------------------------------------------------------
8665PTR_DomainAssembly AppDomain::FindAssembly(PTR_ICLRPrivAssembly pHostAssembly)
8666{
8667 CONTRACTL
8668 {
8669 NOTHROW;
8670 GC_NOTRIGGER;
8671 MODE_ANY;
8672 SUPPORTS_DAC;
8673 }
8674 CONTRACTL_END
8675
8676 if (pHostAssembly == nullptr)
8677 return NULL;
8678
8679 {
8680 ForbidSuspendThreadHolder suspend;
8681 {
8682 CrstHolder lock(&m_crstHostAssemblyMap);
8683 PTR_DomainAssembly returnValue = m_hostAssemblyMap.Lookup(pHostAssembly);
8684 if (returnValue == NULL)
8685 {
8686 // If not found in the m_hostAssemblyMap, look in the m_hostAssemblyMapForOrigFile
8687 // This is necessary as it may happen during in a second AppDomain that the PEFile
8688 // first discovered in the AppDomain may not be used by the DomainFile, but the CLRPrivBinderFusion
8689 // will in some cases find the pHostAssembly associated with this no longer used PEFile
8690 // instead of the PEFile that was finally decided upon.
8691 returnValue = m_hostAssemblyMapForOrigFile.Lookup(pHostAssembly);
8692 }
8693
8694 return returnValue;
8695 }
8696 }
8697}
8698
8699#if !defined(DACCESS_COMPILE) && defined(FEATURE_NATIVE_IMAGE_GENERATION)
8700
8701void ZapperSetBindingPaths(ICorCompilationDomain *pDomain, SString &trustedPlatformAssemblies, SString &platformResourceRoots, SString &appPaths, SString &appNiPaths)
8702{
8703 CLRPrivBinderCoreCLR *pBinder = static_cast<CLRPrivBinderCoreCLR*>(((CompilationDomain *)pDomain)->GetFusionContext());
8704 _ASSERTE(pBinder != NULL);
8705 pBinder->SetupBindingPaths(trustedPlatformAssemblies, platformResourceRoots, appPaths, appNiPaths);
8706#ifdef FEATURE_COMINTEROP
8707 ((CompilationDomain*)pDomain)->SetWinrtApplicationContext(NULL);
8708#endif
8709}
8710
8711#endif
8712