[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / loaderallocator.hpp
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:  LoaderAllocator.hpp
8 ** 
9
10 **
11 ** Purpose: Implements collection of loader heaps
12 **
13 **
14 ===========================================================*/
15
16 #ifndef __LoaderAllocator_h__
17 #define __LoaderAllocator_h__
18
19 class FuncPtrStubs;
20 #include "qcall.h"
21 #include "ilstubcache.h"
22
23 #include "callcounter.h"
24 #include "methoddescbackpatchinfo.h"
25 #include "crossloaderallocatorhash.h"
26
27 #define VPTRU_LoaderAllocator 0x3200
28
29 enum LoaderAllocatorType
30 {
31     LAT_Invalid,
32     LAT_Global,
33     LAT_Assembly
34 };
35
36 typedef SHash<PtrSetSHashTraits<LoaderAllocator *>> LoaderAllocatorSet;
37
38 class CLRPrivBinderAssemblyLoadContext;
39
40 // Iterator over a DomainAssembly in the same ALC
41 class DomainAssemblyIterator
42 {
43     DomainAssembly* pCurrentAssembly;
44     DomainAssembly* pNextAssembly;
45
46 public:
47     DomainAssemblyIterator(DomainAssembly* pFirstAssembly);
48
49     bool end() const
50     {
51         return pCurrentAssembly == NULL;
52     }
53
54     operator DomainAssembly*() const
55     {
56         return pCurrentAssembly;
57     }
58
59     DomainAssembly* operator ->() const
60     {
61         return pCurrentAssembly;
62     }
63
64     void operator++();
65
66     void operator++(int dummy)
67     {
68         this->operator++();
69     }
70 };
71
72 class LoaderAllocatorID
73 {
74
75 protected:
76     LoaderAllocatorType m_type;
77     union
78     {
79         DomainAssembly* m_pDomainAssembly;
80         void* m_pValue;
81     };
82
83     VOID * GetValue();
84
85 public:
86     LoaderAllocatorID(LoaderAllocatorType laType=LAT_Invalid, VOID* value = 0)
87     {
88         m_type = laType;
89         m_pValue = value;
90     };
91     VOID Init();
92     LoaderAllocatorType GetType();
93     VOID AddDomainAssembly(DomainAssembly* pDomainAssembly);
94     DomainAssemblyIterator GetDomainAssemblyIterator();
95     BOOL Equals(LoaderAllocatorID* pId);
96     COUNT_T Hash();
97 };
98
99 // Segmented stack to store freed handle indices
100 class SegmentedHandleIndexStack
101 {
102     // Segment of the stack
103     struct Segment
104     {
105         static const int Size = 64;
106
107         Segment* m_prev;
108         DWORD    m_data[Size];
109     };
110
111     // Segment containing the TOS
112     Segment * m_TOSSegment = NULL;
113     // One free segment to prevent rapid delete / new if pop / push happens rapidly
114     // at the boundary of two segments.
115     Segment * m_freeSegment = NULL;
116     // Index of the top of stack in the TOS segment
117     int       m_TOSIndex = Segment::Size;
118
119 public:
120
121     // Push the value to the stack. If the push cannot be done due to OOM, return false;
122     inline bool Push(DWORD value);
123
124     // Pop the value from the stack
125     inline DWORD Pop();
126
127     // Check if the stack is empty.
128     inline bool IsEmpty();
129 };
130
131 class StringLiteralMap;
132 class VirtualCallStubManager;
133 template <typename ELEMENT>
134 class ListLockEntryBase;
135 typedef ListLockEntryBase<void*> ListLockEntry;
136 class UMEntryThunkCache;
137
138 #ifdef FEATURE_COMINTEROP
139 class ComCallWrapperCache;
140 #endif // FEATURE_COMINTEROP
141 class EEMarshalingData;
142
143 class LoaderAllocator
144 {
145     VPTR_BASE_VTABLE_CLASS(LoaderAllocator)
146     VPTR_UNIQUE(VPTRU_LoaderAllocator)
147 protected:    
148    
149     //****************************************************************************************
150     // #LoaderAllocator Heaps
151     // Heaps for allocating data that persists for the life of the AppDomain
152     // Objects that are allocated frequently should be allocated into the HighFreq heap for
153     // better page management
154     BYTE *              m_InitialReservedMemForLoaderHeaps;
155     BYTE                m_LowFreqHeapInstance[sizeof(LoaderHeap)];
156     BYTE                m_HighFreqHeapInstance[sizeof(LoaderHeap)];
157     BYTE                m_StubHeapInstance[sizeof(LoaderHeap)];
158     BYTE                m_PrecodeHeapInstance[sizeof(CodeFragmentHeap)];
159     PTR_LoaderHeap      m_pLowFrequencyHeap;
160     PTR_LoaderHeap      m_pHighFrequencyHeap;
161     PTR_LoaderHeap      m_pStubHeap; // stubs for PInvoke, remoting, etc
162     PTR_CodeFragmentHeap m_pPrecodeHeap;
163     PTR_LoaderHeap      m_pExecutableHeap;
164 #ifdef FEATURE_READYTORUN
165     PTR_CodeFragmentHeap m_pDynamicHelpersHeap;
166 #endif
167     //****************************************************************************************
168     OBJECTHANDLE        m_hLoaderAllocatorObjectHandle;
169     FuncPtrStubs *      m_pFuncPtrStubs; // for GetMultiCallableAddrOfCode()
170     // The LoaderAllocator specific string literal map.
171     StringLiteralMap   *m_pStringLiteralMap;
172     CrstExplicitInit    m_crstLoaderAllocator;
173     bool                m_fGCPressure;
174     bool                m_fUnloaded;
175     bool                m_fTerminated;
176     bool                m_fMarked;
177     int                 m_nGCCount;
178     bool                m_IsCollectible;
179
180     // Pre-allocated blocks of heap for collectible assemblies. Will be set to NULL as soon as it is 
181     // used. See code in GetVSDHeapInitialBlock and GetCodeHeapInitialBlock
182     BYTE *              m_pVSDHeapInitialAlloc;
183     BYTE *              m_pCodeHeapInitialAlloc;
184
185     // U->M thunks that are not associated with a delegate.
186     // The cache is keyed by MethodDesc pointers.
187     UMEntryThunkCache * m_pUMEntryThunkCache;
188
189     // IL stub cache with fabricated MethodTable parented by a random module in this LoaderAllocator.
190     ILStubCache         m_ILStubCache;
191
192 public:
193     BYTE *GetVSDHeapInitialBlock(DWORD *pSize);
194     BYTE *GetCodeHeapInitialBlock(const BYTE * loAddr, const BYTE * hiAddr, DWORD minimumSize, DWORD *pSize);
195
196     BaseDomain *m_pDomain;
197
198     // ExecutionManager caches
199     void * m_pLastUsedCodeHeap;
200     void * m_pLastUsedDynamicCodeHeap;
201     void * m_pJumpStubCache;
202
203     // LoaderAllocator GC Structures
204     PTR_LoaderAllocator m_pLoaderAllocatorDestroyNext; // Used in LoaderAllocator GC process (during sweeping)
205 protected:
206     void ClearMark();
207     void Mark();
208     bool Marked();
209
210 #ifdef FAT_DISPATCH_TOKENS
211     struct DispatchTokenFatSHashTraits : public DefaultSHashTraits<DispatchTokenFat*>
212     {
213         typedef DispatchTokenFat* key_t;
214
215         static key_t GetKey(element_t e)
216             { return e; }
217
218         static BOOL Equals(key_t k1, key_t k2)
219             { return *k1 == *k2; }
220
221         static count_t Hash(key_t k)
222             { return (count_t)(size_t)*k; }
223     };
224
225     typedef SHash<DispatchTokenFatSHashTraits> FatTokenSet;
226     SimpleRWLock *m_pFatTokenSetLock;
227     FatTokenSet *m_pFatTokenSet;
228 #endif
229
230 #ifndef CROSSGEN_COMPILE
231     VirtualCallStubManager *m_pVirtualCallStubManager;
232 #endif
233
234 private:
235     LoaderAllocatorSet m_LoaderAllocatorReferences;
236     Volatile<UINT32>   m_cReferences;
237     // This will be set by code:LoaderAllocator::Destroy (from managed scout finalizer) and signalizes that 
238     // the assembly was collected
239     DomainAssembly * m_pFirstDomainAssemblyFromSameALCToDelete;
240     
241     BOOL CheckAddReference_Unlocked(LoaderAllocator *pOtherLA);
242     
243     static UINT64 cLoaderAllocatorsCreated;
244     UINT64 m_nLoaderAllocator;
245     
246     struct FailedTypeInitCleanupListItem
247     {
248         SLink m_Link;
249         ListLockEntry *m_pListLockEntry;
250         explicit FailedTypeInitCleanupListItem(ListLockEntry *pListLockEntry)
251                 :
252             m_pListLockEntry(pListLockEntry)
253         {
254         }
255     };
256
257     SList<FailedTypeInitCleanupListItem> m_failedTypeInitCleanupList;
258
259     SegmentedHandleIndexStack m_freeHandleIndexesStack;
260 #ifdef FEATURE_COMINTEROP
261     // The wrapper cache for this loader allocator - it has its own CCacheLineAllocator on a per loader allocator basis
262     // to allow the loader allocator to go away and eventually kill the memory when all refs are gone
263     
264     VolatilePtr<ComCallWrapperCache> m_pComCallWrapperCache;
265     // Used for synchronizing creation of the m_pComCallWrapperCache
266     CrstExplicitInit m_ComCallWrapperCrst;
267     // Hash table that maps a MethodTable to COM Interop compatibility data.
268     PtrHashMap m_interopDataHash;
269
270 #endif
271
272     // Used for synchronizing access to the m_interopDataHash and m_pMarshalingData
273     CrstExplicitInit m_InteropDataCrst;
274     EEMarshalingData* m_pMarshalingData;
275
276 #ifdef FEATURE_TIERED_COMPILATION
277     CallCounter m_callCounter;
278 #endif
279
280 #ifndef CROSSGEN_COMPILE
281     MethodDescBackpatchInfoTracker m_methodDescBackpatchInfoTracker;
282 #endif
283
284 #ifndef DACCESS_COMPILE
285
286 public:
287     // CleanupFailedTypeInit is called from AppDomain
288     // This method accesses loader allocator state in a thread unsafe manner.
289     // It expects to be called only from Terminate.
290     void CleanupFailedTypeInit();
291 #endif //!DACCESS_COMPILE
292     
293     // Collect unreferenced assemblies, remove them from the assembly list and return their loader allocator 
294     // list.
295     static LoaderAllocator * GCLoaderAllocators_RemoveAssemblies(AppDomain * pAppDomain);
296     
297 public:
298
299     // 
300     // The scheme for ensuring that LoaderAllocators are destructed correctly is substantially
301     // complicated by the requirement that LoaderAllocators that are eligible for destruction
302     // must be destroyed as a group due to issues where there may be ordering issues in destruction
303     // of LoaderAllocators.
304     // Thus, while there must be a complete web of references keeping the LoaderAllocator alive in
305     // managed memory, we must also have an analogous web in native memory to manage the specific
306     // ordering requirements.
307     //
308     // Thus we have an extra garbage collector here to manage the native web of LoaderAllocator references
309     // Also, we have a reference count scheme so that LCG methods keep their associated LoaderAllocator
310     // alive. LCG methods cannot be referenced by LoaderAllocators, so they do not need to participate
311     // in the garbage collection scheme except by using AddRef/Release to adjust the root set of this
312     // garbage collector.
313     // 
314     
315     //#AssemblyPhases
316     // The phases of unloadable assembly are:
317     // 
318     // 1. Managed LoaderAllocator is alive.
319     //    - Assembly is visible to managed world, the managed scout is alive and was not finalized yet.
320     //      Note that the fact that the managed scout is in the finalizer queue is not important as it can 
321     //      (and in certain cases has to) ressurect itself.
322     //    Detection:
323     //        code:IsAlive ... TRUE
324     //        code:IsManagedScoutAlive ... TRUE
325     //        code:DomainAssembly::GetExposedAssemblyObject ... non-NULL (may need to allocate GC object)
326     //        
327     //        code:AddReferenceIfAlive ... TRUE (+ adds reference)
328     // 
329     // 2. Managed scout is alive, managed LoaderAllocator is collected.
330     //    - All managed object related to this assembly (types, their instances, Assembly/AssemblyBuilder) 
331     //      are dead and/or about to disappear and cannot be recreated anymore. We are just waiting for the 
332     //      managed scout to run its finalizer.
333     //    Detection:
334     //        code:IsAlive ... TRUE
335     //        code:IsManagedScoutAlive ... TRUE
336     //        code:DomainAssembly::GetExposedAssemblyObject ... NULL (change from phase #1)
337     //        
338     //        code:AddReferenceIfAlive ... TRUE (+ adds reference)
339     // 
340     // 3. Native LoaderAllocator is alive, managed scout is collected.
341     //    - The native LoaderAllocator can be kept alive via native reference with code:AddRef call, e.g.:
342     //        * Reference from LCG method, 
343     //        * Reference recieved from assembly iterator code:AppDomain::AssemblyIterator::Next and/or 
344     //          held by code:CollectibleAssemblyHolder.
345     //    - Other LoaderAllocator can have this LoaderAllocator in its reference list 
346     //      (code:m_LoaderAllocatorReferences), but without call to code:AddRef.
347     //    - LoaderAllocator cannot ever go back to phase #1 or #2, but it can skip this phase if there are 
348     //      not any LCG method references keeping it alive at the time of manged scout finalization.
349     //    Detection:
350     //        code:IsAlive ... TRUE
351     //        code:IsManagedScoutAlive ... FALSE (change from phase #2)
352     //        code:DomainAssembly::GetExposedAssemblyObject ... NULL
353     //        
354     //        code:AddReferenceIfAlive ... TRUE (+ adds reference)
355     // 
356     // 4. LoaderAllocator is dead.
357     //    - The managed scout was collected. No one holds a native reference with code:AddRef to this 
358     //      LoaderAllocator.
359     //    - Other LoaderAllocator can have this LoaderAllocator in its reference list 
360     //      (code:m_LoaderAllocatorReferences), but without call to code:AddRef.
361     //    - LoaderAllocator cannot ever become alive again (i.e. go back to phase #3, #2 or #1).
362     //    Detection:
363     //        code:IsAlive ... FALSE (change from phase #3, #2 and #1)
364     //        
365     //        code:AddReferenceIfAlive ... FALSE (change from phase #3, #2 and #1)
366     // 
367     
368     void AddReference();
369     // Adds reference if the native object is alive  - code:#AssemblyPhases.
370     // Returns TRUE if the reference was added.
371     BOOL AddReferenceIfAlive();
372     BOOL Release();
373     // Checks if the native object is alive - see code:#AssemblyPhases.
374     BOOL IsAlive() { LIMITED_METHOD_DAC_CONTRACT; return (m_cReferences != (UINT32)0); }
375     // Checks if managed scout is alive - see code:#AssemblyPhases.
376     BOOL IsManagedScoutAlive()
377     {
378         return (m_pFirstDomainAssemblyFromSameALCToDelete == NULL);
379     }
380     
381     // Collect unreferenced assemblies, delete all their remaining resources.
382     static void GCLoaderAllocators(LoaderAllocator* firstLoaderAllocator);
383     
384     UINT64 GetCreationNumber() { LIMITED_METHOD_DAC_CONTRACT; return m_nLoaderAllocator; }
385
386     // Ensure this LoaderAllocator has a reference to another LoaderAllocator
387     BOOL EnsureReference(LoaderAllocator *pOtherLA);
388
389     // Ensure this LoaderAllocator has a reference to every LoaderAllocator of the types
390     // in an instantiation
391     BOOL EnsureInstantiation(Module *pDefiningModule, Instantiation inst);
392
393     // Given typeId and slotNumber, GetDispatchToken will return a DispatchToken
394     // representing <typeId, slotNumber>. If the typeId is big enough, this
395     // method will automatically allocate a DispatchTokenFat and encapsulate it
396     // in the return value.
397     DispatchToken GetDispatchToken(UINT32 typeId, UINT32 slotNumber);
398
399     // Same as GetDispatchToken, but returns invalid DispatchToken  when the
400     // value doesn't exist or a transient exception (OOM, stack overflow) is
401     // encountered. To check if the token is valid, use DispatchToken::IsValid
402     DispatchToken TryLookupDispatchToken(UINT32 typeId, UINT32 slotNumber);
403
404     virtual LoaderAllocatorID* Id() =0;
405     BOOL IsCollectible() { WRAPPER_NO_CONTRACT; return m_IsCollectible; }
406
407 #ifdef DACCESS_COMPILE
408     void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
409 #endif
410
411     PTR_LoaderHeap GetLowFrequencyHeap()
412     {
413         LIMITED_METHOD_CONTRACT;
414         return m_pLowFrequencyHeap;
415     }
416
417     PTR_LoaderHeap GetHighFrequencyHeap()
418     {
419         LIMITED_METHOD_CONTRACT;
420         return m_pHighFrequencyHeap;
421     }
422
423     PTR_LoaderHeap GetStubHeap()
424     {
425         LIMITED_METHOD_CONTRACT;
426         return m_pStubHeap;
427     }
428
429     PTR_CodeFragmentHeap GetPrecodeHeap()
430     {
431         LIMITED_METHOD_CONTRACT;
432         return m_pPrecodeHeap;
433     }
434
435     // The executable heap is intended to only be used by the global loader allocator.
436     // It refers to executable memory that is not associated with a rangelist.
437     PTR_LoaderHeap GetExecutableHeap()
438     {
439         LIMITED_METHOD_CONTRACT;
440         return m_pExecutableHeap;
441     }
442
443     PTR_CodeFragmentHeap GetDynamicHelpersHeap();
444
445     FuncPtrStubs * GetFuncPtrStubs();
446
447     FuncPtrStubs * GetFuncPtrStubsNoCreate()
448     {
449         LIMITED_METHOD_CONTRACT;
450         return m_pFuncPtrStubs;
451     }
452
453     OBJECTHANDLE GetLoaderAllocatorObjectHandle()
454     {
455         LIMITED_METHOD_CONTRACT;
456         return m_hLoaderAllocatorObjectHandle;
457     }
458
459     LOADERALLOCATORREF GetExposedObject();
460
461 #ifndef DACCESS_COMPILE
462     LOADERHANDLE AllocateHandle(OBJECTREF value);
463
464     void SetHandleValue(LOADERHANDLE handle, OBJECTREF value);
465     OBJECTREF CompareExchangeValueInHandle(LOADERHANDLE handle, OBJECTREF value, OBJECTREF compare);
466     void FreeHandle(LOADERHANDLE handle);
467
468     // The default implementation is a no-op. Only collectible loader allocators implement this method.
469     virtual void RegisterHandleForCleanup(OBJECTHANDLE /* objHandle */) { }
470     virtual void CleanupHandles() { }
471
472     void RegisterFailedTypeInitForCleanup(ListLockEntry *pListLockEntry);
473 #endif // !defined(DACCESS_COMPILE)
474
475
476     // This function is only safe to call if the handle is known to be a handle in a collectible
477     // LoaderAllocator, and the handle is allocated, and the LoaderAllocator is also not collected.
478     FORCEINLINE OBJECTREF GetHandleValueFastCannotFailType2(LOADERHANDLE handle);
479
480     // These functions are designed to be used for maximum performance to access handle values
481     // The GetHandleValueFast will handle the scenario where a loader allocator pointer does not
482     // need to be acquired to do the handle lookup, and the GetHandleValueFastPhase2 handles
483     // the scenario where the LoaderAllocator pointer is required.
484     // Do not use these functions directly - use GET_LOADERHANDLE_VALUE_FAST macro instead.
485     FORCEINLINE static BOOL GetHandleValueFast(LOADERHANDLE handle, OBJECTREF *pValue);
486     FORCEINLINE BOOL GetHandleValueFastPhase2(LOADERHANDLE handle, OBJECTREF *pValue);
487
488 #define GET_LOADERHANDLE_VALUE_FAST(pLoaderAllocator, handle, pRetVal)              \
489     do {                                                                            \
490         LOADERHANDLE __handle__ = handle;                                           \
491         if (!LoaderAllocator::GetHandleValueFast(__handle__, pRetVal) &&            \
492             !pLoaderAllocator->GetHandleValueFastPhase2(__handle__, pRetVal))       \
493         {                                                                           \
494             *(pRetVal) = NULL;                                                      \
495         }                                                                           \
496     } while (0)
497
498     OBJECTREF GetHandleValue(LOADERHANDLE handle);
499
500     LoaderAllocator();
501     virtual ~LoaderAllocator();
502     BaseDomain *GetDomain() { LIMITED_METHOD_CONTRACT; return m_pDomain; }
503     virtual BOOL CanUnload() = 0;
504     void Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory = NULL);
505     void Terminate();
506     virtual void ReleaseManagedAssemblyLoadContext() {}
507
508     SIZE_T EstimateSize();
509
510     void SetupManagedTracking(LOADERALLOCATORREF *pLoaderAllocatorKeepAlive);
511     void ActivateManagedTracking();
512
513     // Unloaded in this context means that there is no managed code running against this loader allocator.
514     // This flag is used by debugger to filter out methods in modules that are being destructed.
515     bool IsUnloaded() { LIMITED_METHOD_CONTRACT; return m_fUnloaded; }
516     void SetIsUnloaded() { LIMITED_METHOD_CONTRACT; m_fUnloaded = true; }
517
518     void SetGCRefPoint(int gccounter)
519     {
520         LIMITED_METHOD_CONTRACT;
521         m_nGCCount=gccounter;
522     }
523     int GetGCRefPoint()
524     {
525         LIMITED_METHOD_CONTRACT;
526         return m_nGCCount;
527     }
528
529     static BOOL QCALLTYPE Destroy(QCall::LoaderAllocatorHandle pLoaderAllocator);
530
531     //****************************************************************************************
532     // Methods to retrieve a pointer to the COM+ string STRINGREF for a string constant.
533     // If the string is not currently in the hash table it will be added and if the
534     // copy string flag is set then the string will be copied before it is inserted.
535     STRINGREF *GetStringObjRefPtrFromUnicodeString(EEStringData *pStringData);
536     void LazyInitStringLiteralMap();
537     STRINGREF *IsStringInterned(STRINGREF *pString);
538     STRINGREF *GetOrInternString(STRINGREF *pString);
539     void CleanupStringLiteralMap();
540
541     void InitVirtualCallStubManager(BaseDomain *pDomain);
542     void UninitVirtualCallStubManager();
543
544 #ifndef CROSSGEN_COMPILE
545     inline VirtualCallStubManager *GetVirtualCallStubManager()
546     {
547         LIMITED_METHOD_CONTRACT;
548         return m_pVirtualCallStubManager;
549     }
550
551     UMEntryThunkCache *GetUMEntryThunkCache();
552
553 #endif
554
555     static LoaderAllocator* GetLoaderAllocator(ILStubCache* pILStubCache)
556     {
557          return CONTAINING_RECORD(pILStubCache, LoaderAllocator, m_ILStubCache);
558     }
559
560     ILStubCache* GetILStubCache()
561     {
562         LIMITED_METHOD_CONTRACT;
563         return &m_ILStubCache;
564     }
565
566     //****************************************************************************************
567     // This method returns marshaling data that the EE uses that is stored on a per LoaderAllocator
568     // basis.
569     EEMarshalingData *GetMarshalingData();
570
571 private:
572     // Deletes marshaling data at shutdown (which contains cached factories that needs to be released)
573     void DeleteMarshalingData();
574
575 public:
576
577 #ifdef FEATURE_COMINTEROP
578
579     ComCallWrapperCache * GetComCallWrapperCache();
580
581     void ResetComCallWrapperCache()
582     {
583         LIMITED_METHOD_CONTRACT;
584         m_pComCallWrapperCache = NULL;
585     }
586
587 #ifndef DACCESS_COMPILE
588
589     // Look up interop data for a method table
590     // Returns the data pointer if present, NULL otherwise
591     InteropMethodTableData *LookupComInteropData(MethodTable *pMT);
592
593     // Returns TRUE if successfully inserted, FALSE if this would be a duplicate entry
594     BOOL InsertComInteropData(MethodTable* pMT, InteropMethodTableData *pData);
595
596 #endif // DACCESS_COMPILE
597
598 #endif // FEATURE_COMINTEROP
599
600 #ifdef FEATURE_TIERED_COMPILATION
601 public:
602     CallCounter* GetCallCounter()
603     {
604         LIMITED_METHOD_CONTRACT;
605         return &m_callCounter;
606     }
607 #endif // FEATURE_TIERED_COMPILATION
608
609 #ifndef CROSSGEN_COMPILE
610     MethodDescBackpatchInfoTracker *GetMethodDescBackpatchInfoTracker()
611     {
612         LIMITED_METHOD_CONTRACT;
613         return &m_methodDescBackpatchInfoTracker;
614     }
615 #endif
616 };  // class LoaderAllocator
617
618 typedef VPTR(LoaderAllocator) PTR_LoaderAllocator;
619
620 class GlobalLoaderAllocator : public LoaderAllocator
621 {
622     VPTR_VTABLE_CLASS(GlobalLoaderAllocator, LoaderAllocator)
623     VPTR_UNIQUE(VPTRU_LoaderAllocator+1)
624
625     BYTE                m_ExecutableHeapInstance[sizeof(LoaderHeap)];
626
627 protected:
628     LoaderAllocatorID m_Id;
629     
630 public:
631     void Init(BaseDomain *pDomain);
632     GlobalLoaderAllocator() : m_Id(LAT_Global, (void*)1) { LIMITED_METHOD_CONTRACT;};
633     virtual LoaderAllocatorID* Id();
634     virtual BOOL CanUnload();
635 };
636
637 typedef VPTR(GlobalLoaderAllocator) PTR_GlobalLoaderAllocator;
638
639 class ShuffleThunkCache;
640
641 class AssemblyLoaderAllocator : public LoaderAllocator
642 {
643     VPTR_VTABLE_CLASS(AssemblyLoaderAllocator, LoaderAllocator)
644     VPTR_UNIQUE(VPTRU_LoaderAllocator+3)
645
646 protected:
647     LoaderAllocatorID  m_Id;
648     ShuffleThunkCache* m_pShuffleThunkCache;
649 public:    
650     virtual LoaderAllocatorID* Id();
651     AssemblyLoaderAllocator() : m_Id(LAT_Assembly), m_pShuffleThunkCache(NULL)
652 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
653         , m_binderToRelease(NULL)
654 #endif
655     { LIMITED_METHOD_CONTRACT; }
656     void Init(AppDomain *pAppDomain);
657     virtual BOOL CanUnload();
658
659     void SetCollectible();
660
661     void AddDomainAssembly(DomainAssembly *pDomainAssembly)
662     {
663         WRAPPER_NO_CONTRACT; 
664         m_Id.AddDomainAssembly(pDomainAssembly); 
665     }
666
667     ShuffleThunkCache* GetShuffleThunkCache()
668     {
669         return m_pShuffleThunkCache;
670     }
671
672 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
673     virtual void RegisterHandleForCleanup(OBJECTHANDLE objHandle);
674     virtual void CleanupHandles();
675     CLRPrivBinderAssemblyLoadContext* GetBinder()
676     {
677         return m_binderToRelease;
678     }
679     virtual ~AssemblyLoaderAllocator();
680     void RegisterBinder(CLRPrivBinderAssemblyLoadContext* binderToRelease);
681     virtual void ReleaseManagedAssemblyLoadContext();
682 #endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
683
684 private:
685     struct HandleCleanupListItem
686     {    
687         SLink m_Link;
688         OBJECTHANDLE m_handle;
689         explicit HandleCleanupListItem(OBJECTHANDLE handle)
690                 :
691             m_handle(handle)
692         {
693         }
694     };
695     
696     SList<HandleCleanupListItem> m_handleCleanupList;
697 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
698     CLRPrivBinderAssemblyLoadContext* m_binderToRelease;
699 #endif
700 };
701
702 typedef VPTR(AssemblyLoaderAllocator) PTR_AssemblyLoaderAllocator;
703
704
705 #include "loaderallocator.inl"
706
707 #endif //  __LoaderAllocator_h__
708