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