Merge pull request #9796 from pgavlin/FixOurGetThreadCycles
[platform/upstream/coreclr.git] / src / vm / virtualcallstub.h
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 // File: VirtualCallStub.h
6 //
7
8
9
10 //
11 // See code:VirtualCallStubManager for details
12 //
13 // ============================================================================
14
15 #ifndef _VIRTUAL_CALL_STUB_H 
16 #define _VIRTUAL_CALL_STUB_H
17
18 #ifndef CROSSGEN_COMPILE
19
20 #define CHAIN_LOOKUP
21
22 #if defined(_TARGET_X86_)
23 // If this is uncommented, leaves a file "StubLog_<pid>.log" with statistics on the behavior
24 // of stub-based interface dispatch.
25 //#define STUB_LOGGING
26 #endif
27
28 #include "stubmgr.h"
29
30 /////////////////////////////////////////////////////////////////////////////////////
31 // Forward class declarations
32 class FastTable;
33 class BucketTable;
34 class Entry;
35 class Prober;
36 class VirtualCallStubManager;
37 class VirtualCallStubManagerManager;
38 struct LookupHolder;
39 struct DispatchHolder;
40 struct ResolveHolder;
41
42 /////////////////////////////////////////////////////////////////////////////////////
43 // Forward function declarations
44 extern "C" void InContextTPQuickDispatchAsmStub();
45
46 extern "C" PCODE STDCALL StubDispatchFixupWorker(TransitionBlock * pTransitionBlock, 
47                                                  TADDR siteAddrForRegisterIndirect,
48                                                  DWORD sectionIndex, 
49                                                  Module * pModule);
50
51 extern "C" PCODE STDCALL VSD_ResolveWorker(TransitionBlock * pTransitionBlock,
52                                            TADDR siteAddrForRegisterIndirect,
53                                            size_t token
54 #ifndef _TARGET_X86_
55                                            , UINT_PTR flags
56 #endif                               
57                                            );
58
59
60 /////////////////////////////////////////////////////////////////////////////////////
61 #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
62 typedef INT32 DISPL;
63 #endif
64
65 /////////////////////////////////////////////////////////////////////////////////////
66 // Represents the struct that is added to the resolve cache
67 // NOTE: If you change the layout of this struct, you'll need to update various
68 //       ASM helpers in VirtualCallStubCpu that rely on offsets of members.
69 //
70 struct ResolveCacheElem
71 {
72     void *pMT;
73     size_t token;   // DispatchToken
74     void *target;
75
76     // These are used for chaining
77     ResolveCacheElem *pNext;
78     ResolveCacheElem *Next()
79     { LIMITED_METHOD_CONTRACT; return VolatileLoad(&pNext); }
80
81 #ifdef _DEBUG 
82     UINT16 debug_hash;
83     UINT16 debug_index;
84 #endif // _DEBUG
85
86     BOOL Equals(size_t token, void *pMT)
87     { LIMITED_METHOD_CONTRACT; return (this->pMT == pMT && this->token == token); }
88
89     BOOL Equals(ResolveCacheElem *pElem)
90     { WRAPPER_NO_CONTRACT; return Equals(pElem->token, pElem->pMT); }
91
92 };
93
94 enum
95 {
96     e_resolveCacheElem_sizeof_mt                 = sizeof(void *),
97     e_resolveCacheElem_sizeof_token              = sizeof(size_t),
98     e_resolveCacheElem_sizeof_target             = sizeof(void *),
99     e_resolveCacheElem_sizeof_next               = sizeof(ResolveCacheElem *),
100
101     e_resolveCacheElem_offset_mt                 = 0,
102     e_resolveCacheElem_offset_token              = e_resolveCacheElem_offset_mt + e_resolveCacheElem_sizeof_mt,
103     e_resolveCacheElem_offset_target             = e_resolveCacheElem_offset_token + e_resolveCacheElem_sizeof_token,
104     e_resolveCacheElem_offset_next               = e_resolveCacheElem_offset_target + e_resolveCacheElem_sizeof_target,
105 };
106
107 /////////////////////////////////////////////////////////////////////////////////////
108 // A utility class to help manipulate a call site
109 struct StubCallSite
110 {
111     friend class VirtualCallStubManager;
112
113 private:
114
115     // On x86 are four possible kinds of callsites when you take into account all features
116     //  Relative:                  direct call, e.g. "call addr". Not used currently.
117     //  RelativeIndirect (JmpRel): indirect call through a relative address, e.g. "call [addr]"
118     //  RegisterIndirect:          indirect call through a register, e.g. "call [eax]"
119     //  DelegateCallSite:          anything else, tail called through a register by shuffle thunk, e.g. "jmp [eax]"
120     //
121     // On all other platforms we always use an indirect call through an indirection cell
122     // In these cases all calls are made by the platform equivalent of "call [addr]".
123     //
124     // DelegateCallSite are particular in that they can come in a variety of forms:
125     // a direct delegate call has a sequence defined by the jit but a multicast or secure delegate
126     // are defined in a stub and have a different shape
127     //
128     PTR_PCODE       m_siteAddr;     // Stores the address of an indirection cell
129     PCODE           m_returnAddr;
130
131 public:
132
133 #if defined(_TARGET_X86_) 
134     StubCallSite(TADDR siteAddrForRegisterIndirect, PCODE returnAddr);
135
136     PCODE           GetCallerAddress();
137 #else // !defined(_TARGET_X86_)
138     // On platforms where we always use an indirection cell things
139     // are much simpler - the siteAddr always stores a pointer to a
140     // value that in turn points to the indirection cell.
141
142     StubCallSite(TADDR siteAddr, PCODE returnAddr)
143        { LIMITED_METHOD_CONTRACT; m_siteAddr = dac_cast<PTR_PCODE>(siteAddr); m_returnAddr = returnAddr; }
144
145     PCODE           GetCallerAddress()     { LIMITED_METHOD_CONTRACT; return m_returnAddr; }
146 #endif // !defined(_TARGET_X86_)
147
148     PCODE           GetSiteTarget()        { WRAPPER_NO_CONTRACT; return *(GetIndirectCell()); }
149     void            SetSiteTarget(PCODE newTarget);
150     PTR_PCODE       GetIndirectCell()      { LIMITED_METHOD_CONTRACT; return dac_cast<PTR_PCODE>(m_siteAddr); }
151     PTR_PCODE *     GetIndirectCellAddress() { LIMITED_METHOD_CONTRACT; return &m_siteAddr; }
152
153     PCODE           GetReturnAddress() { LIMITED_METHOD_CONTRACT; return m_returnAddr; }
154 };
155
156 #ifdef FEATURE_PREJIT
157 extern "C" void StubDispatchFixupStub();              // for lazy fixup of ngen call sites
158 #endif
159
160 // These are the assembly language entry points that the stubs use when they want to go into the EE
161
162 extern "C" void ResolveWorkerAsmStub();               // resolve a token and transfer control to that method
163 extern "C" void ResolveWorkerChainLookupAsmStub();    // for chaining of entries in the cache
164
165 #ifdef _TARGET_X86_ 
166 extern "C" void BackPatchWorkerAsmStub();             // backpatch a call site to point to a different stub
167 #ifdef FEATURE_PAL
168 extern "C" void BackPatchWorkerStaticStub(PCODE returnAddr, TADDR siteAddrForRegisterIndirect);
169 #endif // FEATURE_PAL
170 #endif // _TARGET_X86_
171
172
173 typedef VPTR(class VirtualCallStubManager) PTR_VirtualCallStubManager;
174
175 // VirtualCallStubManager is the heart of the stub dispatch logic. See the book of the runtime entry
176 // 
177 // file:../../doc/BookOfTheRuntime/ClassLoader/VirtualStubDispatchDesign.doc
178 // 
179 // The basic idea is that a call to an interface (it could also be used for virtual calls in general, but we
180 // do not do this), is simply the code
181 // 
182 //     call [DispatchCell]
183 // 
184 // Where we make sure 'DispatchCell' points at stubs that will do the right thing. DispatchCell is writable
185 // so we can udpate the code over time. There are three basic types of stubs that the dispatch cell can point
186 // to.
187 //     * Lookup: The intial stub that has no 'fast path' and simply pushes a ID for interface being called
188 //         and calls into the runtime at code:VirtualCallStubManager.ResolveWorkerStatic.
189 //     * Dispatch: Lookup stubs are patched to this stub which has a fast path that checks for a particular
190 //         Method Table and if that fails jumps to code that
191 //         * Decrements a 'missCount' (starts out as code:STUB_MISS_COUNT_VALUE). If this count goes to zero
192 //             code:VirtualCallStubManager.BackPatchWorkerStatic is called, morphs it into a resolve stub
193 //             (however since this decrementing logic is SHARED among all dispatch stubs, it may take
194 //             multiples of code:STUB_MISS_COUNT_VALUE if mulitple call sites are actively polymorphic (this
195 //             seems unlikley).
196 //         * Calls a resolve stub (Whenever a dispatch stub is created, it always has a cooresponding resolve
197 //             stub (but the resolve stubs are shared among many dispatch stubs).
198 //     * Resolve: see code:ResolveStub. This looks up the Method table in a process wide cache (see
199 //         code:ResolveCacheElem, and if found, jumps to it. This code path is about 17 instructions long (so
200 //         pretty fast, but certainly much slower than a normal call). If the method table is not found in
201 //         the cache, it calls into the runtime code:VirtualCallStubManager.ResolveWorkerStatic, which
202 //         populates it.
203 // So the general progression is call site's cells
204 //     * start out life pointing to a lookup stub
205 //     * On first call they get updated into a dispatch stub. When this misses, it calls a resolve stub,
206 //         which populates a resovle stub's cache, but does not update the call site' cell (thus it is still
207 //         pointing at the dispatch cell.
208 //     * After code:STUB_MISS_COUNT_VALUE misses, we update the call site's cell to point directly at the
209 //         resolve stub (thus avoiding the overhead of the quick check that always seems to be failing and
210 //         the miss count update).
211 //         
212 // QUESTION: What is the lifetimes of the various stubs and hash table entries?
213 // 
214 // QUESTION: There does not seem to be any logic that will change a call site's cell once it becomes a
215 // Resolve stub. Thus once a particular call site becomes a Resolve stub we live with the Resolve stub's
216 // (in)efficiency forever.
217 // 
218 // see code:#StubDispatchNotes for more
219 class VirtualCallStubManager : public StubManager
220 {
221     friend class ClrDataAccess;
222     friend class VirtualCallStubManagerManager;
223     friend class VirtualCallStubManagerIterator;
224
225     VPTR_VTABLE_CLASS(VirtualCallStubManager, StubManager)
226
227 public:
228 #ifdef _DEBUG
229     virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "VirtualCallStubManager"; }
230 #endif    
231
232     // The reason for our existence, return a callstub for type id and slot number
233     // where type id = 0 for the class contract (i.e. a virtual call), and type id > 0 for an
234     // interface invoke where the id indicates which interface it is.
235     //
236     // The function is idempotent, i.e.
237     // you'll get the same callstub twice if you call it with identical inputs.
238     PCODE GetCallStub(TypeHandle ownerType, MethodDesc *pMD);
239     PCODE GetCallStub(TypeHandle ownerType, DWORD slot);
240
241     // Generate an fresh indirection cell.
242     BYTE* GenerateStubIndirection(PCODE stub, BOOL fUseRecycledCell = FALSE);
243
244     // Set up static data structures - called during EEStartup
245     static void InitStatic();
246     static void UninitStatic();
247
248     // Per instance initialization - called during AppDomain::Init and ::Uninit and for collectible loader allocators
249     void Init(BaseDomain* pDomain, LoaderAllocator *pLoaderAllocator);
250     void Uninit();
251
252     //@TODO: the logging should be tied into the VMs normal loggin mechanisms,
253     //@TODO: for now we just always write a short log file called "StubLog_<pid>.log"
254     static void StartupLogging();
255     static void LoggingDump();
256     static void FinishLogging();
257
258     static void ResetCache();
259
260     // Reclaim/rearrange any structures that can only be done during a gc sync point.
261     // This is the mechanism we are using to avoid synchronization of alot of our
262     // cache and hash table accesses.  We are requiring that during a gc sync point we are not
263     // executing any stub code at all, hence at this time we are serialized on a single thread (gc)
264     // and no other thread is accessing the data structures.
265     static void ReclaimAll();
266     void Reclaim();
267
268 #ifndef DACCESS_COMPILE 
269     VirtualCallStubManager()
270         : StubManager(),
271           lookup_rangeList(),
272           resolve_rangeList(),
273           dispatch_rangeList(),
274           cache_entry_rangeList(),
275           parentDomain(NULL),
276           isCollectible(false),
277           m_initialReservedMemForHeaps(NULL),
278           m_FreeIndCellList(NULL),
279           m_RecycledIndCellList(NULL),
280           indcell_heap(NULL),
281           cache_entry_heap(NULL),
282           lookup_heap(NULL),
283           dispatch_heap(NULL),
284           resolve_heap(NULL),
285 #ifdef _TARGET_AMD64_
286           m_fShouldAllocateLongJumpDispatchStubs(FALSE),
287 #endif
288           lookups(NULL),
289           cache_entries(NULL),
290           dispatchers(NULL),
291           resolvers(NULL),
292           m_counters(NULL),
293           m_cur_counter_block(NULL),
294           m_cur_counter_block_for_reclaim(NULL),
295           m_cur_counter_block_for_reclaim_index(NULL),
296           m_pNext(NULL)
297     {
298         LIMITED_METHOD_CONTRACT;
299         ZeroMemory(&stats, sizeof(stats));
300     }
301
302     ~VirtualCallStubManager();
303 #endif // !DACCESS_COMPILE
304
305
306     enum StubKind { 
307         SK_UNKNOWN, 
308         SK_LOOKUP,      // Lookup Stubs are SLOW stubs that simply call into the runtime to do all work.
309         SK_DISPATCH,    // Dispatch Stubs have a fast check for one type otherwise jumps to runtime.  Works for monomorphic sites
310         SK_RESOLVE,     // Resolve Stubs do a hash lookup before fallling back to the runtime.  Works for polymorphic sites.
311         SK_BREAKPOINT 
312     };
313
314     // peek at the assembly code and predict which kind of a stub we have
315     StubKind predictStubKind(PCODE stubStartAddress);
316
317     /* know thine own stubs.  It is possible that when multiple
318     virtualcallstub managers are built that these may need to become
319     non-static, and the callers modified accordingly */
320     StubKind getStubKind(PCODE stubStartAddress)
321     {
322         WRAPPER_NO_CONTRACT;
323         SUPPORTS_DAC;
324
325         // This method can called with stubStartAddress==NULL, e.g. when handling null reference exceptions
326         // caused by IP=0. Early out for this case to avoid confusing handled access violations inside predictStubKind.
327         if (PCODEToPINSTR(stubStartAddress) == NULL)
328             return SK_UNKNOWN;
329
330         // Rather than calling IsInRange(stubStartAddress) for each possible stub kind
331         // we can peek at the assembly code and predict which kind of a stub we have
332         StubKind predictedKind = predictStubKind(stubStartAddress);
333
334         if (predictedKind == SK_DISPATCH)
335         {
336             if (isDispatchingStub(stubStartAddress))
337                 return SK_DISPATCH;
338         }
339         else if (predictedKind == SK_LOOKUP)
340         {
341             if (isLookupStub(stubStartAddress))
342                 return SK_LOOKUP;
343         }
344         else if (predictedKind == SK_RESOLVE)
345         {
346             if (isResolvingStub(stubStartAddress))
347                 return SK_RESOLVE;
348         }
349
350         // This is the slow case. If the predict returned SK_UNKNOWN, SK_BREAKPOINT,
351         // or the predict was found to be incorrect when checked against the RangeLists
352         // (isXXXStub), then we'll check each stub heap in sequence.
353         if (isDispatchingStub(stubStartAddress))
354             return SK_DISPATCH;
355         else if (isLookupStub(stubStartAddress))
356             return SK_LOOKUP;
357         else if (isResolvingStub(stubStartAddress))
358             return SK_RESOLVE;
359
360         return SK_UNKNOWN;
361     }
362
363     inline BOOL isStub(PCODE stubStartAddress)
364     {
365         WRAPPER_NO_CONTRACT;
366         SUPPORTS_DAC;
367
368         return (getStubKind(stubStartAddress) != SK_UNKNOWN);
369     }
370
371     BOOL isDispatchingStub(PCODE stubStartAddress)
372     {
373         WRAPPER_NO_CONTRACT;
374         SUPPORTS_DAC;
375
376         return GetDispatchRangeList()->IsInRange(stubStartAddress);
377     }
378
379     BOOL isResolvingStub(PCODE stubStartAddress)
380     {
381         WRAPPER_NO_CONTRACT;
382         SUPPORTS_DAC;
383
384         return GetResolveRangeList()->IsInRange(stubStartAddress);
385     }
386
387     BOOL isLookupStub(PCODE stubStartAddress)
388     {
389         WRAPPER_NO_CONTRACT;
390         SUPPORTS_DAC;
391
392         return GetLookupRangeList()->IsInRange(stubStartAddress);
393     }
394
395     static BOOL isDispatchingStubStatic(PCODE addr)
396     {
397         WRAPPER_NO_CONTRACT;
398         StubKind stubKind;
399         FindStubManager(addr, &stubKind);
400         return stubKind == SK_DISPATCH;
401     }
402
403     static BOOL isResolvingStubStatic(PCODE addr)
404     {
405         WRAPPER_NO_CONTRACT;
406         StubKind stubKind;
407         FindStubManager(addr, &stubKind);
408         return stubKind == SK_RESOLVE;
409     }
410
411     static BOOL isLookupStubStatic(PCODE addr)
412     {
413         WRAPPER_NO_CONTRACT;
414         StubKind stubKind;
415         FindStubManager(addr, &stubKind);
416         return stubKind == SK_LOOKUP;
417     }
418
419     //use range lists to track the chunks of memory that are part of each heap
420     LockedRangeList lookup_rangeList;
421     LockedRangeList resolve_rangeList;
422     LockedRangeList dispatch_rangeList;
423     LockedRangeList cache_entry_rangeList;
424
425     // Get dac-ized pointers to rangelist.
426     RangeList* GetLookupRangeList() 
427     {
428         SUPPORTS_DAC;
429
430         TADDR addr = PTR_HOST_MEMBER_TADDR(VirtualCallStubManager, this, lookup_rangeList);
431         return PTR_RangeList(addr);
432     }
433     RangeList* GetResolveRangeList() 
434     {
435         SUPPORTS_DAC;
436
437         TADDR addr = PTR_HOST_MEMBER_TADDR(VirtualCallStubManager, this, resolve_rangeList);
438         return PTR_RangeList(addr);
439     }
440     RangeList* GetDispatchRangeList() 
441     {
442         SUPPORTS_DAC;
443
444         TADDR addr = PTR_HOST_MEMBER_TADDR(VirtualCallStubManager, this, dispatch_rangeList);
445         return PTR_RangeList(addr);
446     }
447     RangeList* GetCacheEntryRangeList() 
448     {
449         SUPPORTS_DAC;
450         TADDR addr = PTR_HOST_MEMBER_TADDR(VirtualCallStubManager, this, cache_entry_rangeList);
451         return PTR_RangeList(addr);
452     }
453
454 private:
455
456     //allocate and initialize a stub of the desired kind
457     DispatchHolder *GenerateDispatchStub(PCODE addrOfCode,
458                                          PCODE addrOfFail,
459                                          void *pMTExpected,
460                                          size_t dispatchToken);
461
462 #ifdef _TARGET_AMD64_
463     // Used to allocate a long jump dispatch stub. See comment around
464     // m_fShouldAllocateLongJumpDispatchStubs for explaination.
465     DispatchHolder *GenerateDispatchStubLong(PCODE addrOfCode,
466                                              PCODE addrOfFail,
467                                              void *pMTExpected,
468                                              size_t dispatchToken);
469 #endif
470
471     ResolveHolder *GenerateResolveStub(PCODE addrOfResolver,
472                                        PCODE addrOfPatcher,
473                                        size_t dispatchToken);
474
475     LookupHolder *GenerateLookupStub(PCODE addrOfResolver,
476                                      size_t dispatchToken);
477
478     template <typename STUB_HOLDER>
479     void AddToCollectibleVSDRangeList(STUB_HOLDER *holder)
480     {
481         if (isCollectible)
482         {
483             parentDomain->GetCollectibleVSDRanges()->AddRange(reinterpret_cast<BYTE *>(holder->stub()),
484                 reinterpret_cast<BYTE *>(holder->stub()) + holder->stub()->size(),
485                 this);
486         }
487     }
488
489     // The resolve cache is static across all AppDomains
490     ResolveCacheElem *GenerateResolveCacheElem(void *addrOfCode,
491                                                void *pMTExpected,
492                                                size_t token);
493
494     ResolveCacheElem *GetResolveCacheElem(void *pMT,
495                                           size_t token,
496                                           void *target);
497
498     //Given a dispatch token, an object and a method table, determine the
499     //target address to go to.  The return value (BOOL) states whether this address
500     //is cacheable or not.
501     static BOOL Resolver(MethodTable   * pMT,
502                          DispatchToken   token,
503                          OBJECTREF     * protectedObj,
504                          PCODE         * ppTarget);
505
506     // This can be used to find a target without needing the ability to throw
507     static BOOL TraceResolver(Object *pObj, DispatchToken token, TraceDestination *trace);
508
509 public:
510     // Return the MethodDesc corresponding to this token.
511     static MethodDesc *GetRepresentativeMethodDescFromToken(DispatchToken token, MethodTable *pMT);
512     static MethodDesc *GetInterfaceMethodDescFromToken(DispatchToken token);
513     static MethodTable *GetTypeFromToken(DispatchToken token);
514
515     //This is used to get the token out of a stub
516     static size_t GetTokenFromStub(PCODE stub);
517
518     //This is used to get the token out of a stub and we know the stub manager and stub kind
519     static size_t GetTokenFromStubQuick(VirtualCallStubManager * pMgr, PCODE stub, StubKind kind);
520
521     // General utility functions
522     // Quick lookup in the cache. NOTHROW, GC_NOTRIGGER
523     static PCODE CacheLookup(size_t token, UINT16 tokenHash, MethodTable *pMT);
524
525     // Full exhaustive lookup. THROWS, GC_TRIGGERS
526     static PCODE GetTarget(DispatchToken token, MethodTable *pMT);
527
528 private:
529     // Given a dispatch token, return true if the token represents an interface, false if just a slot.
530     static BOOL IsInterfaceToken(DispatchToken token);
531
532     // Given a dispatch token, return true if the token represents a slot on the target.
533     static BOOL IsClassToken(DispatchToken token);
534
535 #ifdef CHAIN_LOOKUP 
536     static ResolveCacheElem* __fastcall PromoteChainEntry(ResolveCacheElem *pElem);
537 #endif
538
539     // Flags used by the non-x86 versions of VSD_ResolveWorker
540
541 #define SDF_ResolveBackPatch        (0x01)
542 #define SDF_ResolvePromoteChain     (0x02)
543 #define SDF_ResolveFlags            (0x03)
544
545     // These method needs to call the instance methods.
546     friend PCODE VSD_ResolveWorker(TransitionBlock * pTransitionBlock,
547                                    TADDR siteAddrForRegisterIndirect,
548                                    size_t token
549 #ifndef _TARGET_X86_
550                                    , UINT_PTR flags
551 #endif                            
552                                    );
553
554 #if defined(_TARGET_X86_) && defined(FEATURE_PAL)
555     friend void BackPatchWorkerStaticStub(PCODE returnAddr, TADDR siteAddrForRegisterIndirect);
556 #endif
557
558     //These are the entrypoints that the stubs actually end up calling via the
559     // xxxAsmStub methods above
560     static void STDCALL BackPatchWorkerStatic(PCODE returnAddr, TADDR siteAddrForRegisterIndirect);
561
562 public:
563     PCODE ResolveWorker(StubCallSite* pCallSite, OBJECTREF *protectedObj, DispatchToken token, StubKind stubKind);
564     void BackPatchWorker(StubCallSite* pCallSite);
565
566     //Change the callsite to point to stub
567     void BackPatchSite(StubCallSite* pCallSite, PCODE stub);
568
569 public:
570     /* the following two public functions are to support tracing or stepping thru
571     stubs via the debugger. */
572     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
573     virtual BOOL TraceManager(Thread *thread,
574                               TraceDestination *trace,
575                               T_CONTEXT *pContext,
576                               BYTE **pRetAddr);
577     size_t GetSize()
578     {
579         LIMITED_METHOD_CONTRACT;
580         size_t retval=0;
581         if(indcell_heap)
582             retval+=indcell_heap->GetSize();
583         if(cache_entry_heap)
584             retval+=cache_entry_heap->GetSize();
585         if(lookup_heap)
586             retval+=lookup_heap->GetSize();
587          if(dispatch_heap)
588             retval+=dispatch_heap->GetSize();
589          if(resolve_heap)
590             retval+=resolve_heap->GetSize();
591          return retval;
592     };
593
594 private:
595     /* the following two private functions are to support tracing or stepping thru
596     stubs via the debugger. */
597     virtual BOOL DoTraceStub(PCODE stubStartAddress,
598                              TraceDestination *trace);
599
600 private:
601     // The parent domain of this manager
602     PTR_BaseDomain  parentDomain;
603     bool            isCollectible;
604
605     BYTE *          m_initialReservedMemForHeaps;
606
607     static const UINT32 INDCELLS_PER_BLOCK = 32;    // 32 indirection cells per block.
608
609     CrstExplicitInit m_indCellLock;
610
611     // List of free indirection cells. The cells were directly allocated from the loader heap
612     // (code:VirtualCallStubManager::GenerateStubIndirection) 
613     BYTE * m_FreeIndCellList;
614
615     // List of recycled indirection cells. The cells were recycled from finalized dynamic methods
616     // (code:LCGMethodResolver::RecycleIndCells).
617     BYTE * m_RecycledIndCellList;
618
619 #ifndef DACCESS_COMPILE 
620     // This methods returns the a free cell from m_FreeIndCellList. It returns NULL if the list is empty.
621     BYTE * GetOneFreeIndCell()
622     {
623         WRAPPER_NO_CONTRACT;
624
625         return GetOneIndCell(&m_FreeIndCellList);
626     }
627
628     // This methods returns the a recycled cell from m_RecycledIndCellList. It returns NULL if the list is empty.
629     BYTE * GetOneRecycledIndCell()
630     {
631         WRAPPER_NO_CONTRACT;
632
633         return GetOneIndCell(&m_RecycledIndCellList);
634     }
635
636     // This methods returns the a cell from ppList. It returns NULL if the list is empty.
637     BYTE * GetOneIndCell(BYTE ** ppList)
638     {
639         CONTRACT (BYTE*) {
640             NOTHROW;
641             GC_NOTRIGGER;
642             MODE_ANY;
643             PRECONDITION(CheckPointer(ppList));
644             PRECONDITION(m_indCellLock.OwnedByCurrentThread());        
645         } CONTRACT_END;
646
647         BYTE * temp = *ppList;
648
649         if (temp)
650         {
651             BYTE * pNext = *((BYTE **)temp);
652             *ppList = pNext;
653             RETURN temp;
654         }
655
656         RETURN NULL;
657     }
658
659     // insert a linked list of indirection cells at the beginning of m_FreeIndCellList
660     void InsertIntoFreeIndCellList(BYTE * head, BYTE * tail)
661     {
662         WRAPPER_NO_CONTRACT;
663
664         InsertIntoIndCellList(&m_FreeIndCellList, head, tail);
665     }
666
667     // insert a linked list of indirection cells at the beginning of ppList
668     void InsertIntoIndCellList(BYTE ** ppList, BYTE * head, BYTE * tail)
669     {
670         CONTRACTL {
671             NOTHROW;
672             GC_NOTRIGGER;
673             PRECONDITION(CheckPointer(ppList));
674             PRECONDITION(CheckPointer(head));
675             PRECONDITION(CheckPointer(tail));
676             PRECONDITION(m_indCellLock.OwnedByCurrentThread());        
677         } CONTRACTL_END;
678
679         BYTE * temphead = *ppList;
680         *((BYTE**)tail) = temphead;
681         *ppList = head;
682     }
683 #endif // !DACCESS_COMPILE
684
685     PTR_LoaderHeap  indcell_heap;       // indirection cells go here
686     PTR_LoaderHeap  cache_entry_heap;   // resolve cache elem entries go here
687     PTR_LoaderHeap  lookup_heap;        // lookup stubs go here
688     PTR_LoaderHeap  dispatch_heap;      // dispatch stubs go here
689     PTR_LoaderHeap  resolve_heap;       // resolve stubs go here
690
691 #ifdef _TARGET_AMD64_
692     // When we layout the stub heaps, we put them close together in a sequential order
693     // so that we maximize performance with respect to branch predictions. On AMD64,
694     // dispatch stubs use a rel32 jump on failure to the resolve stub. This works for
695     // a while because of the ordering, but as soon as we have to start allocating more
696     // memory for either the dispatch or resolve heaps we have a chance that we'll be
697     // further away than a rel32 jump can reach, because we're in a 64-bit address
698     // space. As such, this flag will indicate when we allocate the first dispatch stub
699     // that cannot reach a resolve stub, and when this happens we'll switch over to
700     // allocating the larger version of the dispatch stub which contains an abs64 jump.
701     //@TODO: This is a bit of a workaround, but the limitations of LoaderHeap require that we
702     //@TODO: take this approach. Hopefully in Orcas we'll have a chance to rewrite LoaderHeap.
703     BOOL            m_fShouldAllocateLongJumpDispatchStubs; // Defaults to FALSE.
704 #endif
705
706     BucketTable *   lookups;            // hash table of lookups keyed by tokens
707     BucketTable *   cache_entries;      // hash table of dispatch token/target structs for dispatch cache
708     BucketTable *   dispatchers;        // hash table of dispatching stubs keyed by tokens/actualtype
709     BucketTable *   resolvers;          // hash table of resolvers keyed by tokens/resolverstub
710
711     // This structure is used to keep track of the fail counters.
712     // We only need one fail counter per ResolveStub,
713     //  and most programs use less than 250 ResolveStubs
714     // We allocate these on the main heap using "new counter block"
715     struct counter_block
716     {
717         static const UINT32 MAX_COUNTER_ENTRIES = 256-2;  // 254 counters should be enough for most cases.
718
719         counter_block *  next;                            // the next block
720         UINT32           used;                            // the index of the next free entry
721         INT32            block[MAX_COUNTER_ENTRIES];      // the counters
722     };
723
724     counter_block *m_counters;                            // linked list of counter blocks of failure counters
725     counter_block *m_cur_counter_block;                   // current block for updating counts
726     counter_block *m_cur_counter_block_for_reclaim;       // current block for updating
727     UINT32         m_cur_counter_block_for_reclaim_index; // index into the current block for updating
728
729     // Used to keep track of all the VCSManager objects in the system.
730     PTR_VirtualCallStubManager m_pNext;            // Linked list pointer
731
732 public:
733     // Given a stub address, find the VCSManager that owns it.
734     static VirtualCallStubManager *FindStubManager(PCODE addr,
735                                                    StubKind* wbStubKind = NULL);
736
737 #ifndef DACCESS_COMPILE
738     // insert a linked list of indirection cells at the beginning of m_RecycledIndCellList
739     void InsertIntoRecycledIndCellList_Locked(BYTE * head, BYTE * tail)
740     {
741         CONTRACTL {
742             NOTHROW;
743             GC_TRIGGERS;
744             MODE_ANY;
745         } CONTRACTL_END;
746
747         CrstHolder lh(&m_indCellLock);
748
749         InsertIntoIndCellList(&m_RecycledIndCellList, head, tail);
750     }
751 #endif // !DACCESS_COMPILE
752
753     // These are the counters for keeping statistics
754     struct
755     {
756         UINT32 site_counter;            //# of call sites
757         UINT32 stub_lookup_counter;     //# of lookup stubs
758         UINT32 stub_poly_counter;       //# of resolve stubs
759         UINT32 stub_mono_counter;       //# of dispatch stubs
760         UINT32 site_write;              //# of call site backpatch writes
761         UINT32 site_write_poly;         //# of call site backpatch writes to point to resolve stubs
762         UINT32 site_write_mono;         //# of call site backpatch writes to point to dispatch stubs
763         UINT32 worker_call;             //# of calls into ResolveWorker
764         UINT32 worker_call_no_patch;    //# of times call_worker resulted in no patch
765         UINT32 worker_collide_to_mono;  //# of times we converted a poly stub to a mono stub instead of writing the cache entry
766         UINT32 stub_space;              //# of bytes of stubs
767         UINT32 cache_entry_counter;     //# of cache structs
768         UINT32 cache_entry_space;       //# of bytes used by cache lookup structs
769     } stats;
770
771     void LogStats();
772
773 #ifdef DACCESS_COMPILE 
774 protected:
775     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
776     virtual LPCWSTR GetStubManagerName(PCODE addr)
777     {
778         WRAPPER_NO_CONTRACT;
779         CONSISTENCY_CHECK(isStub(addr));
780
781         if (isLookupStub(addr))
782         {
783             return W("VSD_LookupStub");
784         }
785         else if (isDispatchingStub(addr))
786         {
787             return W("VSD_DispatchStub");
788         }
789         else
790         {
791             CONSISTENCY_CHECK(isResolvingStub(addr));
792             return W("VSD_ResolveStub");
793         }
794     }
795 #endif
796 };
797
798 /********************************************************************************************************
799 ********************************************************************************************************/
800 typedef VPTR(class VirtualCallStubManagerManager) PTR_VirtualCallStubManagerManager;
801
802 class VirtualCallStubManagerIterator;
803 class VirtualCallStubManagerManager : public StubManager
804 {
805     VPTR_VTABLE_CLASS(VirtualCallStubManagerManager, StubManager)
806
807     friend class StubManager;
808     friend class VirtualCallStubManager;
809     friend class VirtualCallStubManagerIterator;
810     friend class StubManagerIterator;
811
812   public:
813     virtual BOOL TraceManager(Thread *thread, TraceDestination *trace,
814                               T_CONTEXT *pContext, BYTE **pRetAddr);
815
816     virtual BOOL CheckIsStub_Internal(PCODE stubStartAddress);
817
818     virtual BOOL DoTraceStub(PCODE stubStartAddress, TraceDestination *trace);
819
820     static MethodDesc *Entry2MethodDesc(PCODE stubStartAddress, MethodTable *pMT);
821
822 #ifdef DACCESS_COMPILE
823     virtual void DoEnumMemoryRegions(CLRDataEnumMemoryFlags flags);
824     virtual LPCWSTR GetStubManagerName(PCODE addr)
825         { WRAPPER_NO_CONTRACT; return FindVirtualCallStubManager(addr)->GetStubManagerName(addr); }
826 #endif
827
828   private:
829     // Used to keep track of all the VCSManager objects in the system.
830     PTR_VirtualCallStubManager m_pManagers;  // Head of the linked list
831
832 #ifndef DACCESS_COMPILE
833     // Ctor. This is only used by StaticInit.
834     VirtualCallStubManagerManager();
835 #endif
836     
837     // A cache element to quickly check the last matched manager.
838     Volatile<VirtualCallStubManager*> m_pCacheElem;
839
840     // RW lock for reading entries and removing them.
841     SimpleRWLock m_RWLock;
842
843     // This will look through all the managers in an intelligent fashion to
844     // find the manager that owns the address.
845     VirtualCallStubManager *FindVirtualCallStubManager(PCODE stubAddress);
846
847   protected:
848     // Add a VCSManager to the linked list.
849     void AddStubManager(VirtualCallStubManager *pMgr);
850
851     // Remove a VCSManager from the linked list.
852     void RemoveStubManager(VirtualCallStubManager *pMgr);
853
854     VirtualCallStubManager *FirstManager()
855         { WRAPPER_NO_CONTRACT; return m_pManagers; }
856
857 #ifndef DACCESS_COMPILE
858     static void InitStatic();
859 #endif
860
861   public:
862     SPTR_DECL(VirtualCallStubManagerManager, g_pManager);
863
864     static VirtualCallStubManagerManager *GlobalManager()
865         { LIMITED_METHOD_DAC_CONTRACT; CONSISTENCY_CHECK(CheckPointer(g_pManager)); return g_pManager; }
866
867     VirtualCallStubManagerIterator IterateVirtualCallStubManagers();
868
869 #ifdef _DEBUG
870     // Debug helper to help identify stub-managers.
871     virtual const char * DbgGetName() { LIMITED_METHOD_CONTRACT; return "VirtualCallStubManagerManager"; }
872 #endif
873 };
874
875 /********************************************************************************************************
876 ********************************************************************************************************/
877 class VirtualCallStubManagerIterator
878 {
879     friend class VirtualCallStubManagerManager;
880
881   public:
882     BOOL Next();
883     VirtualCallStubManager *Current();
884
885     // Copy ctor
886     inline VirtualCallStubManagerIterator(const VirtualCallStubManagerIterator &it);
887
888   protected:
889     inline VirtualCallStubManagerIterator(VirtualCallStubManagerManager *pMgr);
890
891     BOOL                    m_fIsStart;
892     VirtualCallStubManager *m_pCurMgr;
893 };
894
895 /////////////////////////////////////////////////////////////////////////////////////////////
896 // Ctor
897 inline VirtualCallStubManagerIterator::VirtualCallStubManagerIterator(VirtualCallStubManagerManager *pMgr)
898     : m_fIsStart(TRUE), m_pCurMgr(pMgr->m_pManagers)
899 {
900     LIMITED_METHOD_DAC_CONTRACT;
901     CONSISTENCY_CHECK(CheckPointer(pMgr));
902 }
903
904 /////////////////////////////////////////////////////////////////////////////////////////////
905 // Copy ctor
906 inline VirtualCallStubManagerIterator::VirtualCallStubManagerIterator(const VirtualCallStubManagerIterator &it)
907     : m_fIsStart(it.m_fIsStart), m_pCurMgr(it.m_pCurMgr)
908 {
909     LIMITED_METHOD_DAC_CONTRACT;
910 }
911
912 /********************************************************************************************************
913 #StubDispatchNotes
914
915 A note on approach.  The cache and hash tables used by the stub and lookup mechanism
916 are designed with an eye to minimizing interlocking and/or syncing and/or locking operations.
917 They are intended to run in a highly concurrent environment.  Since there is no magic,
918 some tradeoffs and and some implementation constraints are required.  The basic notion
919 is that if all reads and writes are atomic and if all functions and operations operate
920 correctly in the face of commutative reorderings of the visibility of all reads and writes
921 across threads, then we don't have to interlock, sync, or serialize.  Our approximation of
922 this is:
923
924 1. All reads and all writes to tables must be atomic.  This effectively limits the actual entry
925 size in a table to be a pointer or a pointer sized thing.
926
927 2. All functions, like comparisons for equality or computation of hash values must function
928 correctly in the face of concurrent updating of the underlying table.  This is accomplished
929 by making the underlying structures/entries effectively immutable, if concurrency is in anyway possible.
930 By effectively immutatable, we mean that the stub or token structure is either immutable or that
931 if it is ever written, all possibley concurrent writes are attempting to write the same value (atomically)
932 or that the competing (atomic) values do not affect correctness, and that the function operates correctly whether
933 or not any of the writes have taken place (is visible yet).  The constraint we maintain is that all competeing
934 updates (and their visibility or lack thereof) do not alter the correctness of the program.
935
936 3. All tables are inexact.  The counts they hold (e.g. number of contained entries) may be inaccurrate,
937 but that inaccurracy cannot affect their correctness.  Table modifications, such as insertion of
938 an new entry may not succeed, but such failures cannot affect correctness.  This implies that just
939 because a stub/entry is not present in a table, e.g. has been removed, that does not mean that
940 it is not in use.  It also implies that internal table structures, such as discarded hash table buckets,
941 cannot be freely recycled since another concurrent thread may still be walking thru it.
942
943 4. Occassionaly it is necessary to pick up the pieces that have been dropped on the floor
944 so to speak, e.g. actually recycle hash buckets that aren't in use.  Since we have a natural
945 sync point already in the GC, we use that to provide cleanup points.  We need to make sure that code that
946 is walking our structures is not a GC safe point.  Hence if the GC calls back into us inside the GC
947 sync point, we know that nobody is inside our stuctures and we can safely rearrange and recycle things.
948 ********************************************************************************************************/
949
950 //initial and increment value for fail stub counters
951 #ifdef STUB_LOGGING 
952 extern UINT32 STUB_MISS_COUNT_VALUE;
953 extern UINT32 STUB_COLLIDE_WRITE_PCT;
954 extern UINT32 STUB_COLLIDE_MONO_PCT;
955 #else // !STUB_LOGGING
956 #define STUB_MISS_COUNT_VALUE   100
957 #define STUB_COLLIDE_WRITE_PCT  100
958 #define STUB_COLLIDE_MONO_PCT     0
959 #endif // !STUB_LOGGING
960
961 //size and mask of the cache used by resolve stubs
962 // CALL_STUB_CACHE_SIZE must be equal to 2^CALL_STUB_CACHE_NUM_BITS
963 #define CALL_STUB_CACHE_NUM_BITS 12 //10
964 #define CALL_STUB_CACHE_SIZE 4096 //1024
965 #define CALL_STUB_CACHE_MASK (CALL_STUB_CACHE_SIZE-1)
966 #define CALL_STUB_CACHE_PROBES 5
967 //min sizes for BucketTable and buckets and the growth and hashing constants
968 #define CALL_STUB_MIN_BUCKETS 32
969 #define CALL_STUB_MIN_ENTRIES 4
970 //this is so that the very first growth will jump from 4 to 32 entries, then double from there.
971 #define CALL_STUB_SECONDARY_ENTRIES 8
972 #define CALL_STUB_GROWTH_FACTOR 2
973 #define CALL_STUB_LOAD_FACTOR 90
974 #define CALL_STUB_HASH_CONST1 1327
975 #define CALL_STUB_HASH_CONST2 43627
976 #define LARGE_PRIME 7199369
977 //internal layout of buckets=size-1,count,entries....
978 #define CALL_STUB_MASK_INDEX 0
979 #define CALL_STUB_COUNT_INDEX 1
980 #define CALL_STUB_DEAD_LINK 2
981 #define CALL_STUB_FIRST_INDEX 3
982 //marker entries in cache and hash tables
983 #define CALL_STUB_EMPTY_ENTRY   0
984 // number of successes for a chained element before it gets moved to the front
985 #define CALL_STUB_CACHE_INITIAL_SUCCESS_COUNT (0x100)
986
987 /*******************************************************************************************************
988 Entry is an abstract class.  We will make specific subclasses for each kind of
989 entry.  Entries hold references to stubs or tokens.  The principle thing they provide
990 is a virtual Equals function that is used by the caching and hashing tables within which
991 the stubs and tokens are stored.  Entries are typically stack allocated by the routines
992 that call into the hash and caching functions, and the functions stuff stubs into the entry
993 to do the comparisons.  Essentially specific entry subclasses supply a vtable to a stub
994 as and when needed.  This means we don't have to have vtables attached to stubs.
995
996 Summarizing so far, there is a struct for each kind of stub or token of the form XXXXStub.
997 They provide that actual storage layouts.
998 There is a stuct in which each stub which has code is containted of the form XXXXHolder.
999 They provide alignment and anciliary storage for the stub code.
1000 There is a subclass of Entry for each kind of stub or token, of the form XXXXEntry.
1001 They provide the specific implementations of the virtual functions declared in Entry. */
1002 class Entry
1003 {
1004 public:
1005     //access and compare the keys of the entry
1006     virtual BOOL Equals(size_t keyA, size_t keyB)=0;
1007     virtual size_t KeyA()=0;
1008     virtual size_t KeyB()=0;
1009
1010     //contents is the struct or token that the entry exposes
1011     virtual void SetContents(size_t contents)=0;
1012 };
1013
1014 /* define the platform specific Stubs and stub holders */
1015
1016 #include <virtualcallstubcpu.hpp>
1017
1018 #if USES_LOOKUP_STUBS 
1019 /**********************************************************************************************
1020 LookupEntry wraps LookupStubs and provide the concrete implementation of the abstract class Entry.
1021 Virtual and interface call sites when they are first jitted point to LookupStubs.  The hash table
1022 that contains look up stubs is keyed by token, hence the Equals function uses the embedded token in
1023 the stub for comparison purposes.  Since we are willing to allow duplicates in the hash table (as
1024 long as they are relatively rare) we do use direct comparison of the tokens rather than extracting
1025 the fields from within the tokens, for perf reasons. */
1026 class LookupEntry : public Entry
1027 {
1028 public:
1029     //Creates an entry that wraps lookup stub s
1030     LookupEntry(size_t s)
1031     {
1032         LIMITED_METHOD_CONTRACT;
1033         _ASSERTE(VirtualCallStubManager::isLookupStubStatic((PCODE)s));
1034         stub = (LookupStub*) s;
1035     }
1036
1037     //default contructor to allow stack and inline allocation of lookup entries
1038     LookupEntry() {LIMITED_METHOD_CONTRACT; stub = NULL;}
1039
1040     //implementations of abstract class Entry
1041     BOOL Equals(size_t keyA, size_t keyB)
1042          { WRAPPER_NO_CONTRACT; return stub && (keyA == KeyA()) && (keyB == KeyB()); }
1043
1044     size_t KeyA() { WRAPPER_NO_CONTRACT; return Token(); }
1045     size_t KeyB() { WRAPPER_NO_CONTRACT; return (size_t)0; }
1046
1047     void SetContents(size_t contents)
1048     {
1049         LIMITED_METHOD_CONTRACT;
1050         _ASSERTE(VirtualCallStubManager::isLookupStubStatic((PCODE)contents));
1051         stub = LookupHolder::FromLookupEntry((PCODE)contents)->stub();
1052     }
1053
1054     //extract the token of the underlying lookup stub
1055
1056     inline size_t Token()                 { LIMITED_METHOD_CONTRACT; return stub ? stub->token() : 0; }
1057
1058 private:
1059     LookupStub* stub;   //the stub the entry wrapping
1060 };
1061 #endif // USES_LOOKUP_STUBS
1062
1063 /**********************************************************************************************
1064 ResolveCacheEntry wraps a ResolveCacheElem and provides lookup functionality for entries that
1065 were created that may be added to the ResolveCache
1066 */
1067 class ResolveCacheEntry : public Entry
1068 {
1069 public:
1070     ResolveCacheEntry(size_t elem)
1071     {
1072         LIMITED_METHOD_CONTRACT;
1073         _ASSERTE(elem != 0);
1074         pElem = (ResolveCacheElem*) elem;
1075     }
1076
1077     //default contructor to allow stack and inline allocation of lookup entries
1078     ResolveCacheEntry() { LIMITED_METHOD_CONTRACT; pElem = NULL; }
1079
1080     //access and compare the keys of the entry
1081     virtual BOOL Equals(size_t keyA, size_t keyB)
1082         { WRAPPER_NO_CONTRACT; return pElem && (keyA == KeyA()) && (keyB == KeyB()); }
1083     virtual size_t KeyA()
1084         { LIMITED_METHOD_CONTRACT; return pElem != NULL ? pElem->token : 0; }
1085     virtual size_t KeyB()
1086         { LIMITED_METHOD_CONTRACT; return pElem != NULL ? (size_t) pElem->pMT : 0; }
1087
1088     //contents is the struct or token that the entry exposes
1089     virtual void SetContents(size_t contents)
1090     {
1091         LIMITED_METHOD_CONTRACT;
1092         pElem = (ResolveCacheElem*) contents;
1093     }
1094
1095     inline const BYTE *Target()
1096     {
1097         LIMITED_METHOD_CONTRACT;
1098         return pElem != NULL ? (const BYTE *)pElem->target : NULL;
1099     }
1100
1101 private:
1102     ResolveCacheElem *pElem;
1103 };
1104
1105 /**********************************************************************************************
1106 ResolveEntry wraps ResolveStubs and provide the concrete implementation of the abstract class Entry.
1107 Polymorphic call sites and monomorphic calls that fail end up in a ResolveStub.  Resolve stubs
1108 are stored in hash tables keyed by token, hence the Equals function uses the embedded token in
1109 the stub for comparison purposes.  Since we are willing to allow duplicates in the hash table (as
1110 long as they are relatively rare) we do use direct comparison of the tokens rather than extracting
1111 the fields from within the tokens, for perf reasons. */
1112 class ResolveEntry : public Entry
1113 {
1114 public:
1115     //Creates an entry that wraps resolve stub s
1116     ResolveEntry (size_t s)
1117     {
1118         LIMITED_METHOD_CONTRACT;
1119         _ASSERTE(VirtualCallStubManager::isResolvingStubStatic((PCODE)s));
1120         stub = (ResolveStub*) s;
1121     }
1122     //default contructor to allow stack and inline allocation of resovler entries
1123     ResolveEntry()  { LIMITED_METHOD_CONTRACT;    stub = CALL_STUB_EMPTY_ENTRY; }
1124
1125     //implementations of abstract class Entry
1126     inline BOOL Equals(size_t keyA, size_t keyB)
1127          { WRAPPER_NO_CONTRACT; return stub && (keyA == KeyA()) && (keyB == KeyB()); }
1128     inline size_t KeyA() { WRAPPER_NO_CONTRACT; return Token(); }
1129     inline size_t KeyB() { WRAPPER_NO_CONTRACT; return (size_t)0; }
1130
1131     void SetContents(size_t contents)
1132     {
1133         LIMITED_METHOD_CONTRACT;
1134         _ASSERTE(VirtualCallStubManager::isResolvingStubStatic((PCODE)contents));
1135         stub = ResolveHolder::FromResolveEntry((PCODE)contents)->stub();
1136     }
1137     //extract the token of the underlying resolve stub
1138     inline size_t Token()  { WRAPPER_NO_CONTRACT; return stub ? (size_t)(stub->token()) : 0; }
1139 private:
1140     ResolveStub* stub;          //the stub the entry is wrapping
1141 };
1142
1143 /**********************************************************************************************
1144 DispatchEntry wraps DispatchStubs and provide the concrete implementation of the abstract class Entry.
1145 Monomorphic and mostly monomorphic call sites eventually point to DispatchStubs.  Dispatch stubs
1146 are placed in hash and cache tables keyed by the expected Method Table and token they are built for.
1147 Since we are willing to allow duplicates in the hash table (as long as they are relatively rare)
1148 we do use direct comparison of the tokens rather than extracting the fields from within the tokens,
1149 for perf reasons.*/
1150 class DispatchEntry : public Entry
1151 {
1152 public:
1153     //Creates an entry that wraps dispatch stub s
1154     DispatchEntry (size_t s)
1155     {
1156         LIMITED_METHOD_CONTRACT;
1157         _ASSERTE(VirtualCallStubManager::isDispatchingStubStatic((PCODE)s));
1158         stub = (DispatchStub*) s;
1159     }
1160     //default contructor to allow stack and inline allocation of resovler entries
1161     DispatchEntry()                       { LIMITED_METHOD_CONTRACT;    stub = CALL_STUB_EMPTY_ENTRY; }
1162
1163     //implementations of abstract class Entry
1164     inline BOOL Equals(size_t keyA, size_t keyB)
1165          { WRAPPER_NO_CONTRACT; return stub && (keyA == KeyA()) && (keyB == KeyB()); }
1166     inline size_t KeyA() { WRAPPER_NO_CONTRACT; return Token(); }
1167     inline size_t KeyB() { WRAPPER_NO_CONTRACT; return ExpectedMT();}
1168
1169     void SetContents(size_t contents)
1170     {
1171         LIMITED_METHOD_CONTRACT;
1172         _ASSERTE(VirtualCallStubManager::isDispatchingStubStatic((PCODE)contents));
1173         stub = DispatchHolder::FromDispatchEntry((PCODE)contents)->stub();
1174     }
1175
1176     //extract the fields of the underlying dispatch stub
1177     inline size_t ExpectedMT()
1178           { WRAPPER_NO_CONTRACT; return stub ? (size_t)(stub->expectedMT()) : 0; }
1179
1180     size_t Token()
1181     {
1182         WRAPPER_NO_CONTRACT;
1183         if (stub)
1184         {
1185             ResolveHolder * resolveHolder = ResolveHolder::FromFailEntry(stub->failTarget());
1186             size_t token = resolveHolder->stub()->token();
1187             _ASSERTE(token == VirtualCallStubManager::GetTokenFromStub((PCODE)stub));
1188             return token;
1189         }
1190         else
1191         {
1192             return 0;
1193         }
1194     }
1195
1196     inline PCODE Target()
1197           { WRAPPER_NO_CONTRACT; return stub ? stub->implTarget()  : 0; }
1198
1199 private:
1200     DispatchStub* stub;
1201 };
1202
1203 /*************************************************************************************************
1204 DispatchCache is the cache table that the resolve stubs use for inline polymorphic resolution
1205 of a call.  The cache entry is logically a triplet of (method table, token, impl address) where method table
1206 is the type of the calling frame's <this>, token identifies the method being invoked,
1207 i.e. is a (type id,slot #) pair, and impl address is the address of the method implementation.
1208 */
1209 class DispatchCache
1210 {
1211 public:
1212     static const UINT16 INVALID_HASH = (UINT16)(-1);
1213
1214     DispatchCache();
1215
1216     //read and write the cache keyed by (method table,token) pair.
1217     inline ResolveCacheElem* Lookup(size_t token, void* mt)
1218         { WRAPPER_NO_CONTRACT; return Lookup(token, INVALID_HASH, mt);}
1219
1220     ResolveCacheElem* Lookup(size_t token, UINT16 tokenHash, void* mt);
1221
1222     enum InsertKind {IK_NONE, IK_DISPATCH, IK_RESOLVE, IK_SHARED, IK_EXTERNAL};
1223
1224     BOOL Insert(ResolveCacheElem* elem, InsertKind insertKind);
1225 #ifdef CHAIN_LOOKUP 
1226     void PromoteChainEntry(ResolveCacheElem* elem);
1227 #endif
1228
1229     // This is the heavyweight hashing algorithm. Use sparingly.
1230     static UINT16 HashToken(size_t token);
1231
1232     inline void GetLoadFactor(size_t *total, size_t *used)
1233     {
1234         LIMITED_METHOD_CONTRACT;
1235
1236         *total = CALL_STUB_CACHE_SIZE;
1237         size_t count = 0;
1238         for (size_t i = 0; i < CALL_STUB_CACHE_SIZE; i++)
1239             if (cache[i] != empty)
1240                 count++;
1241         *used = count;
1242     }
1243
1244     inline void *GetCacheBaseAddr()
1245         { LIMITED_METHOD_CONTRACT; return &cache[0]; }
1246     inline size_t GetCacheCount()
1247         { LIMITED_METHOD_CONTRACT; return CALL_STUB_CACHE_SIZE; }
1248     inline ResolveCacheElem *GetCacheEntry(size_t idx)
1249         { LIMITED_METHOD_CONTRACT; return VolatileLoad(&cache[idx]); }
1250     inline BOOL IsCacheEntryEmpty(size_t idx)
1251         { LIMITED_METHOD_CONTRACT; return cache[idx] == empty; }
1252
1253     inline void SetCacheEntry(size_t idx, ResolveCacheElem *elem)
1254     {
1255         LIMITED_METHOD_CONTRACT;
1256 #ifdef STUB_LOGGING 
1257           cacheData[idx].numWrites++;
1258 #endif
1259 #ifdef CHAIN_LOOKUP 
1260         CONSISTENCY_CHECK(m_writeLock.OwnedByCurrentThread());
1261 #endif
1262           cache[idx] = elem;
1263         }
1264
1265     inline void ClearCacheEntry(size_t idx)
1266     {
1267         LIMITED_METHOD_CONTRACT;
1268 #ifdef STUB_LOGGING 
1269           cacheData[idx].numClears++;
1270 #endif
1271           cache[idx] = empty;
1272         }
1273
1274     struct
1275     {
1276         UINT32 insert_cache_external;     //# of times Insert was called for IK_EXTERNAL
1277         UINT32 insert_cache_shared;       //# of times Insert was called for IK_SHARED
1278         UINT32 insert_cache_dispatch;     //# of times Insert was called for IK_DISPATCH
1279         UINT32 insert_cache_resolve;      //# of times Insert was called for IK_RESOLVE
1280         UINT32 insert_cache_hit;          //# of times Insert found an empty cache entry
1281         UINT32 insert_cache_miss;         //# of times Insert already had a matching cache entry
1282         UINT32 insert_cache_collide;      //# of times Insert found a used cache entry
1283         UINT32 insert_cache_write;        //# of times Insert wrote a cache entry
1284     } stats;
1285
1286     void LogStats();
1287
1288     // Unlocked iterator of entries. Use only when read/write access to the cache
1289     // is safe. This would typically be at GC sync points, currently needed during
1290     // appdomain unloading.
1291     class Iterator
1292     {
1293       public:
1294         Iterator(DispatchCache *pCache);
1295         inline BOOL IsValid()
1296         { WRAPPER_NO_CONTRACT; return (m_curBucket < (INT32)m_pCache->GetCacheCount()); }
1297         void Next();
1298         // Unlink the current entry.
1299         // **NOTE** Using this method implicitly performs a call to Next to move
1300         //          past the unlinked entry. Thus, one could accidentally skip
1301         //          entries unless you take this into consideration.
1302         ResolveCacheElem *UnlinkEntry();
1303         inline ResolveCacheElem *Entry()
1304         { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsValid()); return *m_ppCurElem; }
1305
1306       private:
1307         void NextValidBucket();
1308         inline void NextBucket()
1309         { LIMITED_METHOD_CONTRACT; m_curBucket++; m_ppCurElem = &m_pCache->cache[m_curBucket]; }
1310
1311         DispatchCache     *m_pCache;
1312         INT32              m_curBucket;
1313         ResolveCacheElem **m_ppCurElem;
1314     };
1315
1316 private:
1317 #ifdef CHAIN_LOOKUP 
1318     Crst m_writeLock;
1319 #endif
1320
1321     //the following hash computation is also inlined in the resolve stub in asm (SO NO TOUCHIE)
1322     inline static UINT16 HashMT(UINT16 tokenHash, void* mt)
1323     {
1324         LIMITED_METHOD_CONTRACT;
1325
1326         UINT16 hash;
1327
1328         size_t mtHash = (size_t) mt;
1329         mtHash = (((mtHash >> CALL_STUB_CACHE_NUM_BITS) + mtHash) >> LOG2_PTRSIZE) & CALL_STUB_CACHE_MASK;
1330         hash  = (UINT16) mtHash;
1331
1332         hash ^= (tokenHash & CALL_STUB_CACHE_MASK);
1333
1334         return hash;
1335     }
1336
1337     ResolveCacheElem* cache[CALL_STUB_CACHE_SIZE]; //must be first
1338     ResolveCacheElem* empty;                    //empty entry, initialized to fail all comparisons
1339 #ifdef STUB_LOGGING 
1340 public:
1341     struct CacheEntryData {
1342         UINT32 numWrites;
1343         UINT16 numClears;
1344     };
1345     CacheEntryData cacheData[CALL_STUB_CACHE_SIZE];
1346 #endif // STUB_LOGGING
1347 };
1348
1349 /**************************************************************************************************
1350 The hash tables are accessed via instances of the Prober.  Prober is a probe into a bucket
1351 of the hash table, and therefore has an index which is the current probe position.
1352 It includes a count of the number of probes done in that bucket so far and a stride
1353 to step thru the bucket with.  To do comparisons, it has a reference to an entry with which
1354 it can do comparisons (Equals(...)) of the entries (stubs) inside the hash table.  It also has
1355 the key pair (keyA, keyB) that it is looking for.
1356
1357 Typically, an entry of the appropriate type is created on the stack and then the prober is created passing
1358 in a reference to the entry.  The prober is used for a  complete operation, such as look for and find an
1359 entry (stub), creating and inserting it as necessary.
1360
1361 The initial index and the stride are orthogonal hashes of the key pair, i.e. we are doing a varient of
1362 double hashing.  When we initialize the prober (see FormHash below) we set the initial probe based on
1363 one hash.  The stride (used as a modulo addition of the probe position) is based on a different hash and
1364 is such that it will vist every location in the bucket before repeating.  Hence it is imperative that
1365 the bucket size and the stride be relative prime wrt each other.  We have chosen to make bucket sizes
1366 a power of 2, so we force stride to be odd.
1367
1368 Note -- it must be assumed that multiple probers are walking the same tables and buckets at the same time.
1369 Additionally, the counts may not be accurate, and there may be duplicates in the tables.  Since the tables
1370 do not allow concurrrent deletion, some of the concurrency issues are ameliorated.
1371 */
1372 class Prober
1373 {
1374     friend class FastTable;
1375     friend class BucketTable;
1376 public:
1377     Prober(Entry* e) {LIMITED_METHOD_CONTRACT; comparer = e;}
1378     //find the requested entry, if not there return CALL_STUB_EMPTY_ENTRY
1379     size_t Find();
1380     //add the entry into the bucket, if it is not already in the bucket.
1381     //return the entry actually in the bucket (existing or added)
1382     size_t Add(size_t entry);
1383 private:
1384     //return the bucket (FastTable*) that the prober is currently walking
1385     inline size_t* items() {LIMITED_METHOD_CONTRACT; return &base[-CALL_STUB_FIRST_INDEX];}
1386     //are there more probes possible, or have we probed everything in the bucket
1387     inline BOOL NoMore() {LIMITED_METHOD_CONTRACT; return probes>mask;} //both probes and mask are (-1)
1388     //advance the probe to a new place in the bucket
1389     inline BOOL Next()
1390     {
1391         WRAPPER_NO_CONTRACT;
1392         index = (index + stride) & mask;
1393         probes++;
1394         return !NoMore();
1395     }
1396     inline size_t Read()
1397     {
1398         LIMITED_METHOD_CONTRACT;
1399         _ASSERTE(base);
1400         return VolatileLoad(&base[index]);
1401     }
1402     //initialize a prober across a bucket (table) for the specified keys.
1403     void InitProber(size_t key1, size_t key2, size_t* table);
1404     //set up the initial index and stride and probe count
1405     inline void FormHash()
1406     {
1407         LIMITED_METHOD_CONTRACT;
1408
1409         probes = 0;
1410         //these two hash functions have not been formally measured for effectiveness
1411         //but they are at least orthogonal
1412
1413         size_t a = ((keyA>>16) + keyA);
1414         size_t b = ((keyB>>16) ^ keyB);
1415         index    = (((a*CALL_STUB_HASH_CONST1)>>4)+((b*CALL_STUB_HASH_CONST2)>>4)+CALL_STUB_HASH_CONST1) & mask;
1416         stride   = ((a+(b*CALL_STUB_HASH_CONST1)+CALL_STUB_HASH_CONST2) | 1) & mask;
1417     }
1418     //atomically grab an empty slot so we can insert a new entry into the bucket
1419     BOOL GrabEntry(size_t entryValue);
1420     size_t keyA;        //key pair we are looking for
1421     size_t keyB;
1422     size_t* base;       //we have our own pointer to the bucket, so races don't matter.
1423                         //  We won't care if we do the lookup in an
1424                         //  outdated bucket (has grown out from under us).
1425                         //  All that will happen is possibly dropping an entry
1426                         //  on the floor or adding a duplicate.
1427     size_t index;       //current probe point in the bucket
1428     size_t stride;      //amount to step on each successive probe, must be relatively prime wrt the bucket size
1429     size_t mask;        //size of bucket - 1
1430     size_t probes;      //number probes - 1
1431     Entry* comparer;//used to compare an entry against the sought after key pair
1432 };
1433
1434 /********************************************************************************************************
1435 FastTable is used to implement the buckets of a BucketTable, a bucketized hash table.  A FastTable is
1436 an array of entries (contents).  The first two slots of contents store the size-1 and count of entries
1437 actually in the FastTable.  Note that the count may be inaccurate and there may be duplicates.  Careful
1438 attention must be paid to eliminate the need for interlocked or serialized or locked operations in face
1439 of concurrency.
1440 */
1441 #ifdef _MSC_VER 
1442 #pragma warning(push)
1443 #pragma warning(disable : 4200)     // disable zero-sized array warning
1444 #endif // _MSC_VER
1445 class FastTable
1446 {
1447     friend class BucketTable;
1448 public:
1449 private:
1450     FastTable() { LIMITED_METHOD_CONTRACT; }
1451     ~FastTable() { LIMITED_METHOD_CONTRACT; }
1452
1453     //initialize a prober for the specified keys.
1454     inline BOOL SetUpProber(size_t keyA, size_t keyB, Prober* probe)
1455     {
1456         CONTRACTL {
1457             NOTHROW;
1458             GC_NOTRIGGER;
1459             FORBID_FAULT;
1460         } CONTRACTL_END;
1461
1462         _ASSERTE(probe);
1463         _ASSERTE(contents);
1464         probe->InitProber(keyA, keyB, &contents[0]);
1465         return TRUE;
1466     }
1467     //find the requested entry (keys of prober), if not there return CALL_STUB_EMPTY_ENTRY
1468     size_t Find(Prober* probe);
1469     //add the entry, if it is not already there.  Probe is used to search.
1470     //Return the entry actually containted (existing or added)
1471     size_t Add(size_t entry, Prober* probe);
1472     void IncrementCount();
1473
1474     // Create a FastTable with space for numberOfEntries. Please note that this method
1475     // does not throw on OOM. **YOU MUST CHECK FOR NULL RETURN**
1476     static FastTable* MakeTable(size_t numberOfEntries)
1477     {
1478         CONTRACTL {
1479             THROWS;
1480             GC_TRIGGERS;
1481             INJECT_FAULT(COMPlusThrowOM(););
1482         } CONTRACTL_END;
1483
1484         size_t size = CALL_STUB_MIN_ENTRIES;
1485         while (size < numberOfEntries) {size = size<<1;}
1486 //        if (size == CALL_STUB_MIN_ENTRIES)
1487 //            size += 3;
1488         size_t* bucket = new size_t[(sizeof(FastTable)/sizeof(size_t))+size+CALL_STUB_FIRST_INDEX];
1489         FastTable* table = new (bucket) FastTable();
1490         table->InitializeContents(size);
1491         return table;
1492     }
1493     //Initialize as empty
1494     void InitializeContents(size_t size)
1495     {
1496         LIMITED_METHOD_CONTRACT;
1497         memset(&contents[0], CALL_STUB_EMPTY_ENTRY, (size+CALL_STUB_FIRST_INDEX)*sizeof(BYTE*));
1498         contents[CALL_STUB_MASK_INDEX] = size-1;
1499     }
1500     inline size_t tableMask() {LIMITED_METHOD_CONTRACT; return (size_t) (contents[CALL_STUB_MASK_INDEX]);}
1501     inline size_t tableSize() {LIMITED_METHOD_CONTRACT; return tableMask()+1;}
1502     inline size_t tableCount() {LIMITED_METHOD_CONTRACT; return (size_t) (contents[CALL_STUB_COUNT_INDEX]);}
1503     inline BOOL isFull()
1504     {
1505         LIMITED_METHOD_CONTRACT;
1506         return (tableCount()+1) * 100 / CALL_STUB_LOAD_FACTOR >= tableSize();
1507     }
1508     //we store (size-1) in bucket[CALL_STUB_MASK_INDEX==0],
1509     //we store the used count in bucket[CALL_STUB_COUNT_INDEX==1],
1510     //we have an unused cell to use as a temp at bucket[CALL_STUB_DEAD_LINK==2],
1511     //and the table starts at bucket[CALL_STUB_FIRST_INDEX==3],
1512     size_t contents[];
1513 };
1514 #ifdef _MSC_VER 
1515 #pragma warning(pop)
1516 #endif
1517
1518 /******************************************************************************************************
1519 BucketTable is a bucketized hash table.  It uses FastTables for its buckets.  The hash tables
1520 used by the VirtualCallStubManager are BucketTables.  The number of buckets is fixed at the time
1521 the table is created.  The actual buckets are allocated as needed, and grow as necessary.  The reason
1522 for using buckets is primarily to reduce the cost of growing, since only a single bucket is actually
1523 grown at any given time.  Since the hash tables are accessed infrequently, the load factor that
1524 controls growth is quite high (90%).  Since we use hashing to pick the bucket, and we use hashing to
1525 lookup inside the bucket, it is important that the hashing function used here is orthogonal to the ones
1526 used in the buckets themselves (see FastTable::FormHash).
1527 */
1528 class BucketTable
1529 {
1530 public:
1531     BucketTable(size_t numberOfBuckets)
1532     {
1533         WRAPPER_NO_CONTRACT;
1534         size_t size = CALL_STUB_MIN_BUCKETS;
1535         while (size < numberOfBuckets) {size = size<<1;}
1536         buckets = AllocateBuckets(size);
1537         // Initialize statistics counters
1538         memset(&stats, 0, sizeof(stats));
1539     }
1540
1541     ~BucketTable()
1542     {
1543         LIMITED_METHOD_CONTRACT;
1544         if(buckets != NULL)
1545         {
1546             size_t size = bucketCount()+CALL_STUB_FIRST_INDEX;
1547             for(size_t ix = CALL_STUB_FIRST_INDEX; ix < size; ix++) delete (FastTable*)(buckets[ix]);
1548             delete buckets;
1549         }
1550     }
1551
1552     //initialize a prober for the specified keys.
1553     BOOL SetUpProber(size_t keyA, size_t keyB, Prober *prober);
1554     //find the requested entry (keys of prober), if not there return CALL_STUB_EMPTY_ENTRY
1555     inline size_t Find(Prober* probe) {WRAPPER_NO_CONTRACT; return probe->Find();}
1556     //add the entry, if it is not already there.  Probe is used to search.
1557     size_t Add(size_t entry, Prober* probe);
1558     //reclaim abandoned buckets.  Buckets are abaondoned when they need to grow.
1559     //needs to be called inside a gc sync point.
1560     static void Reclaim();
1561
1562     struct
1563     {
1564         UINT32 bucket_space;                    //# of bytes in caches and tables, not including the stubs themselves
1565         UINT32 bucket_space_dead;               //# of bytes of abandoned buckets not yet recycled.
1566     } stats;
1567
1568     void LogStats();
1569
1570 private:
1571     inline size_t bucketMask() {LIMITED_METHOD_CONTRACT; return (size_t) (buckets[CALL_STUB_MASK_INDEX]);}
1572     inline size_t bucketCount() {LIMITED_METHOD_CONTRACT; return bucketMask()+1;}
1573     inline size_t ComputeBucketIndex(size_t keyA, size_t keyB)
1574     {
1575         LIMITED_METHOD_CONTRACT;
1576         size_t a = ((keyA>>16) + keyA);
1577         size_t b = ((keyB>>16) ^ keyB);
1578         return CALL_STUB_FIRST_INDEX+(((((a*CALL_STUB_HASH_CONST2)>>5)^((b*CALL_STUB_HASH_CONST1)>>5))+CALL_STUB_HASH_CONST2) & bucketMask());
1579     }
1580     //grows the bucket referenced by probe.
1581     BOOL GetMoreSpace(const Prober* probe);
1582     //creates storage in which to store references to the buckets
1583     static size_t* AllocateBuckets(size_t size)
1584     {
1585         LIMITED_METHOD_CONTRACT;
1586         size_t* buckets = new size_t[size+CALL_STUB_FIRST_INDEX];
1587         if (buckets != NULL)
1588         {
1589             memset(&buckets[0], CALL_STUB_EMPTY_ENTRY, (size+CALL_STUB_FIRST_INDEX)*sizeof(void*));
1590             buckets[CALL_STUB_MASK_INDEX] =  size-1;
1591         }
1592         return buckets;
1593     }
1594     inline size_t Read(size_t index)
1595     {
1596         LIMITED_METHOD_CONTRACT;
1597         CONSISTENCY_CHECK(index <= bucketMask()+CALL_STUB_FIRST_INDEX);
1598         return VolatileLoad(&buckets[index]);
1599     }
1600
1601 #ifdef _MSC_VER
1602 #pragma warning(disable: 4267) //work-around for the compiler
1603 #endif
1604     inline void Write(size_t index, size_t value)
1605     {
1606         LIMITED_METHOD_CONTRACT;
1607         CONSISTENCY_CHECK(index <= bucketMask()+CALL_STUB_FIRST_INDEX);
1608         VolatileStore(&buckets[index], value);
1609     }
1610 #ifdef _MSC_VER
1611 #pragma warning(default: 4267)
1612 #endif
1613
1614     // We store (#buckets-1) in    bucket[CALL_STUB_MASK_INDEX  ==0]
1615     // We have two unused cells at bucket[CALL_STUB_COUNT_INDEX ==1]
1616     //                         and bucket[CALL_STUB_DEAD_LINK   ==2]
1617     // and the table starts at     bucket[CALL_STUB_FIRST_INDEX ==3]
1618     // the number of elements is   bucket[CALL_STUB_MASK_INDEX]+CALL_STUB_FIRST_INDEX
1619     size_t* buckets;
1620     static FastTable* dead;             //linked list head of to be deleted (abandoned) buckets
1621 };
1622
1623 #endif // !CROSSGEN_COMPILE
1624
1625 #endif // !_VIRTUAL_CALL_STUB_H