summaryrefslogtreecommitdiff
path: root/src/vm/classcompat.h
blob: e1de0b169d09777673044bc50fc44ef92f2739bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
// ===========================================================================
// File: CLASS.H

#ifndef CLASSCOMPAT_H
#define CLASSCOMPAT_H

#ifdef FEATURE_COMINTEROP

/*
 *  Include Files
 */
#include "eecontract.h"
#include "argslot.h"
#include "vars.hpp"
#include "cor.h"
#include "clrex.h"
#include "hash.h"
#include "crst.h"
#include "objecthandle.h"
#include "cgensys.h"
#include "declsec.h"
#include "stdinterfaces.h"
#include "slist.h"
#include "spinlock.h"
#include "typehandle.h"
#include "perfcounters.h"
#include "methodtable.h"
#include "eeconfig.h"
#include "typectxt.h"
#include "stackingallocator.h"
#include "class.h"

/*
 *  Forward declarations
 */
class   AppDomain;
class   ArrayClass;
class   ArrayMethodDesc;
class   Assembly;
class   ClassLoader;
class   DomainLocalBlock;
class   FCallMethodDesc;
class   EEClass;
class   LayoutEEClass;
class   EnCFieldDesc;
class   FieldDesc;
class   FieldMarshaler;
struct  LayoutRawFieldInfo;
class   MetaSig;
class   MethodDesc;
class   MethodDescChunk;
class   MethodNameHash;
class   MethodTable;
class   Module;
struct  ModuleCtorInfo;
class   Object;
class   Stub;
class   Substitution;
class   SystemDomain;
class   TypeHandle;
class   AllocMemTracker;
class   ZapCodeMap;
class   InteropMethodTableSlotDataMap;
class   LoadingEntry_LockHolder;
class   DispatchMapBuilder;

namespace ClassCompat
{

//*******************************************************************************
// workaround: These classification bits need cleanup bad: for now, this gets around
// IJW setting both mdUnmanagedExport & mdPinvokeImpl on expored methods.
#define IsReallyMdPinvokeImpl(x) ( ((x) & mdPinvokeImpl) && !((x) & mdUnmanagedExport) )

//*******************************************************************************
//
// The MethodNameHash is a temporary loader structure which may be allocated if there are a large number of
// methods in a class, to quickly get from a method name to a MethodDesc (potentially a chain of MethodDescs).
//

//*******************************************************************************
// Entry in the method hash table
class MethodHashEntry
{
public:
    MethodHashEntry *   m_pNext;        // Next item with same hash value
    DWORD               m_dwHashValue;  // Hash value
    MethodDesc *        m_pDesc;
    LPCUTF8             m_pKey;         // Method name
};

//*******************************************************************************
class MethodNameHash
{
public:

    MethodHashEntry **m_pBuckets;       // Pointer to first entry for each bucket
    DWORD             m_dwNumBuckets;
    BYTE *            m_pMemory;        // Current pointer into preallocated memory for entries
    BYTE *            m_pMemoryStart;   // Start pointer of pre-allocated memory fo entries
    MethodNameHash   *m_pNext;          // Chain them for stub dispatch lookup
    INDEBUG( BYTE *            m_pDebugEndMemory; )

    MethodNameHash()
    {
        LIMITED_METHOD_CONTRACT;
        m_pMemoryStart = NULL;
        m_pNext = NULL;
    }

    ~MethodNameHash()
    {
        LIMITED_METHOD_CONTRACT;
        if (m_pMemoryStart != NULL)
            delete(m_pMemoryStart);
    }

    // Throws on error
    void Init(DWORD dwMaxEntries, StackingAllocator *pAllocator = NULL);

    // Insert new entry at head of list
    void Insert(
        LPCUTF8 pszName,
        MethodDesc *pDesc);

    // Return the first MethodHashEntry with this name, or NULL if there is no such entry
    MethodHashEntry *Lookup(
        LPCUTF8 pszName,
        DWORD dwHash);

    void SetNext(MethodNameHash *pNext) { m_pNext = pNext; }
    MethodNameHash *GetNext() { return m_pNext; }
};


//*******************************************************************************
//
// This structure is used only when the classloader is building the interface map.  Before the class
// is resolved, the EEClass contains an array of these, which are all interfaces *directly* declared
// for this class/interface by the metadata - inherited interfaces will not be present if they are
// not specifically declared.
//
// This structure is destroyed after resolving has completed.
//
typedef struct
{
    // The interface method table; for instantiated interfaces, this is the generic interface
    MethodTable     *m_pMethodTable;
} BuildingInterfaceInfo_t;

//*******************************************************************************
struct InterfaceInfo_t
{
#ifdef DACCESS_COMPILE
    friend class NativeImageDumper;
#endif
    enum {
        interface_declared_on_class = 0x1,
        interface_implemented_on_parent = 0x2,
    };

    MethodTable* m_pMethodTable;        // Method table of the interface
    WORD         m_wFlags;
    
private:
    WORD         m_wStartSlot;          // starting slot of interface in vtable
    
public:
    WORD         GetInteropStartSlot()
    {
        return m_wStartSlot;
    }
    void         SetInteropStartSlot(WORD wStartSlot)
    {
        m_wStartSlot = wStartSlot;
    }

    BOOL         IsDeclaredOnClass()
    {
        LIMITED_METHOD_CONTRACT;
        return (m_wFlags & interface_declared_on_class);
    }

    BOOL         IsImplementedByParent()
    {
        LIMITED_METHOD_CONTRACT;
        return (m_wFlags & interface_implemented_on_parent);
    }
};

//*******************************************************************************
// MethodTableBuilder simply acts as a holder for the 
// large algorithm that "compiles" a type into
// a MethodTable/EEClass/DispatchMap/VTable etc. etc. 
// 
// The user of this class (the ClassLoader) currently builds the EEClass 
// first, and does a couple of other things too, though all
// that work should probably be folded into BuildMethodTableThrowing.
//
class MethodTableBuilder
{
public:
    MethodTableBuilder(MethodTable * pMT) 
    {
        LIMITED_METHOD_CONTRACT;
        m_pHalfBakedMT = pMT;
        m_pHalfBakedClass = pMT->GetClass();
        NullBMTData();
    }
public:

    // This method is purely for backward compatibility of COM Interop, and its
    // implementation can be found in ClassCompat.cpp
    InteropMethodTableData *BuildInteropVTable(AllocMemTracker *pamTracker);
    InteropMethodTableData *BuildInteropVTableForArray(AllocMemTracker *pamTracker);

    LPCWSTR GetPathForErrorMessages();

private:
    enum e_METHOD_IMPL
    {
        METHOD_IMPL_NOT,
#ifndef STUB_DISPATCH_ALL 
        METHOD_IMPL,
#endif
        METHOD_IMPL_COUNT
    };

    enum e_METHOD_TYPE
    {
        METHOD_TYPE_NORMAL,
        METHOD_TYPE_FCALL,
        METHOD_TYPE_EEIMPL,
        METHOD_TYPE_NDIRECT,
        METHOD_TYPE_INTEROP,
        METHOD_TYPE_INSTANTIATED,
        METHOD_TYPE_COUNT
    };

private:
    // <NICE> Get rid of this.</NICE>
    EEClass *m_pHalfBakedClass;
    MethodTable * m_pHalfBakedMT;

    // GetHalfBakedClass: The EEClass you get back from this function may not have all its fields filled in yet.
    // Thus you have to make sure that the relevant item which you are accessing has
    // been correctly initialized in the EEClass/MethodTable construction sequence
    // at the point at which you access it.  
    //
    // Gradually we will move the code to a model where the process of constructing an EEClass/MethodTable
    // is more obviously correct, e.g. by relying much less on reading information using GetHalfBakedClass
    // and GetHalfBakedMethodTable.
    //
    // <NICE> Get rid of this.</NICE>
    EEClass *GetHalfBakedClass() { LIMITED_METHOD_CONTRACT; return m_pHalfBakedClass; }
    MethodTable *GetHalfBakedMethodTable() { WRAPPER_NO_CONTRACT; return m_pHalfBakedMT; } 

    mdTypeDef GetCl()    { LIMITED_METHOD_CONTRACT; return bmtType->cl; }
    BOOL IsGlobalClass() { WRAPPER_NO_CONTRACT; return GetCl() == COR_GLOBAL_PARENT_TOKEN; }
    BOOL IsEnum() { LIMITED_METHOD_CONTRACT; return bmtProp->fIsEnum; } 
    DWORD GetAttrClass() { LIMITED_METHOD_CONTRACT; return bmtType->dwAttr; }
    BOOL IsInterface() { WRAPPER_NO_CONTRACT; return IsTdInterface(GetAttrClass()); } 
    BOOL IsValueClass() { LIMITED_METHOD_CONTRACT; return bmtProp->fIsValueClass; } 
    BOOL IsAbstract() { LIMITED_METHOD_CONTRACT; return IsTdAbstract(bmtType->dwAttr); } 
    BOOL HasLayout() { LIMITED_METHOD_CONTRACT; return bmtProp->fHasLayout; } 
    BOOL IsDelegate() { LIMITED_METHOD_CONTRACT; return bmtProp->fIsDelegate; } 
    BOOL IsContextful() { LIMITED_METHOD_CONTRACT; return bmtProp->fIsContextful; } 
    Module *GetModule() { LIMITED_METHOD_CONTRACT; return bmtType->pModule; } 
    Assembly *GetAssembly() { WRAPPER_NO_CONTRACT; return GetModule()->GetAssembly(); } 
    BaseDomain *GetDomain() { LIMITED_METHOD_CONTRACT; return bmtDomain; } 
    ClassLoader *GetClassLoader() { WRAPPER_NO_CONTRACT; return GetModule()->GetClassLoader(); } 
    IMDInternalImport* GetMDImport()  { WRAPPER_NO_CONTRACT; return GetModule()->GetMDImport(); } 
#ifdef _DEBUG
    LPCUTF8 GetDebugClassName() { LIMITED_METHOD_CONTRACT; return bmtProp->szDebugClassName; } 
#endif // _DEBUG
     BOOL IsComImport() { WRAPPER_NO_CONTRACT; return IsTdImport(GetAttrClass()); } 
    BOOL IsComClassInterface() { LIMITED_METHOD_CONTRACT; return bmtProp->fIsComClassInterface; } 

    // <NOTE> The following functions are used during MethodTable construction to setup information 
    // about the type being constructedm in particular information stored in the EEClass.
    // USE WITH CAUTION!!  TRY NOT TO ADD MORE OF THESE!! </NOTE>
    //
    // <NICE> Get rid of all of these - we should be able to evaluate these conditions BEFORE
    // we create the EEClass object, and thus set the flags immediately at the point
    // we create that object.</NICE>
    void SetIsValueClass() { LIMITED_METHOD_CONTRACT; bmtProp->fIsValueClass = TRUE; }
    void SetEnum() { LIMITED_METHOD_CONTRACT; bmtProp->fIsEnum = TRUE; }
    void SetHasLayout() { LIMITED_METHOD_CONTRACT; bmtProp->fHasLayout = TRUE; }
    void SetIsDelegate() { LIMITED_METHOD_CONTRACT; bmtProp->fIsDelegate = TRUE; }
    void SetContextful() { LIMITED_METHOD_CONTRACT; bmtProp->fIsContextful = TRUE; }
#ifdef _DEBUG
    void SetDebugClassName(LPUTF8 x) { LIMITED_METHOD_CONTRACT; bmtProp->szDebugClassName = x; }
#endif
     void SetIsComClassInterface() { LIMITED_METHOD_CONTRACT; bmtProp->fIsComClassInterface = TRUE; }

    /************************************
     *  PRIVATE INTERNAL STRUCTS
     ************************************/
private:
    struct bmtErrorInfo
    {
        UINT resIDWhy;
        LPCUTF8 szMethodNameForError;
        mdToken dMethodDefInError;
        Module* pModule;
        mdTypeDef cl;
        OBJECTREF *pThrowable;

        // Set the reason and the offending method def. If the method information
        // is not from this class set the method name and it will override the method def.
        inline bmtErrorInfo() : resIDWhy(0), szMethodNameForError(NULL), dMethodDefInError(mdMethodDefNil), pThrowable(NULL) {LIMITED_METHOD_CONTRACT; }
    };

    struct bmtProperties
    {
        BOOL fSparse;                           // Set to true if a sparse interface is being used.

         // Com Interop, ComWrapper classes extend from ComObject
        BOOL fIsComObjectType;                  // whether this class is an instance of ComObject class

        BOOL fIsMngStandardItf;                 // Set to true if the interface is a manages standard interface.
        BOOL fComEventItfType;                  // Set to true if the class is a special COM event interface.
 
        BOOL fIsValueClass;
        BOOL fIsEnum;
        BOOL fIsContextful;
        BOOL fIsComClassInterface;
        BOOL fHasLayout;
        BOOL fIsDelegate;

        LPUTF8 szDebugClassName;

        inline bmtProperties()
        {
            LIMITED_METHOD_CONTRACT;
            memset((void *)this, NULL, sizeof(*this));
        }
    };

    struct bmtVtable
    {
        WORD wCurrentVtableSlot;
        WORD wCurrentNonVtableSlot;

        // Temporary vtable - use GetMethodDescForSlot/SetMethodDescForSlot for access.
        // pVtableMD is initialized lazily from pVtable
        // pVtable is invalidated if the slot is overwritten.
        PCODE* pVtable;
        MethodDesc** pVtableMD;
        MethodTable *pParentMethodTable;

        MethodDesc** pNonVtableMD;
        InteropMethodTableSlotData **ppSDVtable;
        InteropMethodTableSlotData **ppSDNonVtable;
        DWORD dwMaxVtableSize;                  // Upper bound on size of vtable
        InteropMethodTableSlotDataMap *pInteropData;

        DispatchMapBuilder *pDispatchMapBuilder;

        MethodDesc* GetMethodDescForSlot(WORD slot)
        {
            CONTRACTL
            {
                NOTHROW;
                GC_NOTRIGGER;
                SO_TOLERANT;
                MODE_ANY;
            }
            CONTRACTL_END;
            if (pVtable[slot] != NULL && pVtableMD[slot] == NULL)
                pVtableMD[slot] = pParentMethodTable->GetMethodDescForSlot(slot);
            _ASSERTE((pVtable[slot] == NULL) ||
                (MethodTable::GetMethodDescForSlotAddress(pVtable[slot]) == pVtableMD[slot]));
            return pVtableMD[slot];
        }

        void SetMethodDescForSlot(WORD slot, MethodDesc* pMD)
        {
            WRAPPER_NO_CONTRACT;
            pVtable[slot] = NULL;
            pVtableMD[slot] = pMD;
        }

        inline bmtVtable() { LIMITED_METHOD_CONTRACT; memset((void *)this, NULL, sizeof(*this)); }
    };

    struct bmtParentInfo
    {
        WORD wNumParentInterfaces;
        MethodDesc **ppParentMethodDescBuf;     // Cache for declared methods
        MethodDesc **ppParentMethodDescBufPtr;  // Pointer for iterating over the cache

        MethodNameHash *pParentMethodHash;
        Substitution parentSubst;
        MethodTable *pParentMethodTable;
        mdToken token;

        inline bmtParentInfo() { LIMITED_METHOD_CONTRACT; memset((void *)this, NULL, sizeof(*this)); }
    };

    struct bmtInterfaceInfo
    {
        DWORD dwTotalNewInterfaceMethods;
        InterfaceInfo_t *pInterfaceMap;         // Temporary interface map

        // ppInterfaceSubstitutionChains[i][0] holds the primary substitution for each interface
        // ppInterfaceSubstitutionChains[i][0..depth[i] ] is the chain of substitutions for each interface
        Substitution **ppInterfaceSubstitutionChains;        
           
        DWORD *pdwOriginalStart;                // If an interface is moved this is the original starting location.
        WORD  wInterfaceMapSize;                // # members in interface map
        DWORD dwLargestInterfaceSize;           // # members in largest interface we implement
        DWORD dwMaxExpandedInterfaces;          // Upper bound on size of interface map
        MethodDesc **ppInterfaceMethodDescList; // List of MethodDescs for current interface
        MethodDesc **ppInterfaceDeclMethodDescList; // List of MethodDescs for the interface itself

        MethodDesc ***pppInterfaceImplementingMD; // List of MethodDescs that implement interface methods
        MethodDesc ***pppInterfaceDeclaringMD;    // List of MethodDescs from the interface itself

        inline bmtInterfaceInfo() { LIMITED_METHOD_CONTRACT; memset((void *)this, NULL, sizeof(*this)); }
    };

    struct bmtMethodInfo
    {
        DWORD                           cMethAndGaps;                       // # meta-data methods of this class ( including the gaps )

        WORD                            cMethods;                           // # meta-data methods of this class
        mdToken *                       rgMethodTokens;                     // Enumeration of metadata methods
        DWORD   *                       rgMethodAttrs;                      // Enumeration of the attributes of the methods
        DWORD   *                       rgMethodImplFlags;                  // Enumeration of the method implementation flags
        ULONG   *                       rgMethodRVA;                        // Enumeration of the method RVA's
        DWORD   *                       rgMethodClassifications;            // Enumeration of the method classifications
        LPCSTR  *                       rgszMethodName;                     // Enumeration of the method names
        BYTE    *                       rgMethodImpl;                       // Enumeration of impl value
        BYTE    *                       rgMethodType;                       // Enumeration of type value

        HENUMInternalHolder             hEnumMethod;

        MethodDesc **                   ppUnboxMethodDescList;              // Keep track unboxed entry points (for value classes)
        MethodDesc **                   ppMethodDescList;                   // MethodDesc pointer for each member

        inline bmtMethodInfo(IMDInternalImport *pMDImport)
            : cMethAndGaps(0),
              cMethods(0),
              rgMethodTokens(NULL),
              rgMethodAttrs(NULL),
              rgMethodImplFlags(NULL),
              rgMethodRVA(NULL),
              rgMethodClassifications(NULL),
              rgszMethodName(NULL),
              rgMethodImpl(NULL),
              hEnumMethod(pMDImport),
              ppUnboxMethodDescList(NULL),
              ppMethodDescList(NULL)
        {
            WRAPPER_NO_CONTRACT;
        }

        inline void SetMethodData(int idx,
            mdToken tok,
            DWORD dwAttrs,
            DWORD dwRVA,
            DWORD dwImplFlags,
            DWORD classification,
            LPCSTR szMethodName,
            BYTE  impl,
            BYTE  type)
        {
            LIMITED_METHOD_CONTRACT;
            rgMethodTokens[idx] = tok;
            rgMethodAttrs[idx] = dwAttrs;
            rgMethodRVA[idx] = dwRVA;
            rgMethodImplFlags[idx] = dwImplFlags;
            rgMethodClassifications[idx] = classification;
            rgszMethodName[idx] = szMethodName;
            rgMethodImpl[idx] = impl;
            rgMethodType[idx] = type;
        }
    };

    struct bmtTypeInfo
    {
        IMDInternalImport * pMDImport;
        Module *            pModule;
        mdToken             cl;
        DWORD               dwAttr;

        inline bmtTypeInfo() { LIMITED_METHOD_CONTRACT; memset((void *)this, NULL, sizeof(*this)); }
    };

    struct bmtMethodImplInfo
    {
        DWORD                           dwNumberMethodImpls;  // Number of method impls defined for this type
        HENUMInternalMethodImplHolder   hEnumMethodImpl;

        struct MethodImplTokenPair
        {
            mdToken methodBody;             // MethodDef's for the bodies of MethodImpls. Must be defined in this type.
            mdToken methodDecl;             // Method token that body implements. Is a MethodDef or MemberRef
            static int __cdecl Compare(const void *elem1, const void *elem2);
            static BOOL Equal(const MethodImplTokenPair *elem1, const MethodImplTokenPair *elem2);
        };

        MethodImplTokenPair *           rgMethodImplTokens;
        Substitution *                  pMethodDeclSubsts;    // Used to interpret generic variables in the interface of the declaring type

        DWORD            pIndex;     // Next open spot in array, we load the BodyDesc's up in order of appearance in the
                                     // type's list of methods (a body can appear more then once in the list of MethodImpls)
        struct Entry
        {
            mdToken      declToken;  // Either the token or the method desc is set for the declaration
            Substitution declSubst;  // Signature instantiations of parent types for Declaration (NULL if not instantiated)
            MethodDesc*  pDeclDesc;  // Method descs for Declaration. If null then Declaration is in this type and use the token
            MethodDesc*  pBodyDesc;  // Method descs created for Method impl bodies
            DWORD        dwFlags;
        };

        Entry *rgEntries;

        void AddMethod(MethodDesc* pImplDesc, MethodDesc* pDeclDesc, mdToken mdDecl, Substitution *pDeclSubst);

        MethodDesc* GetDeclarationMethodDesc(DWORD i)
        {
            LIMITED_METHOD_CONTRACT;
            _ASSERTE(i < pIndex);
            return rgEntries[i].pDeclDesc;
        }

        mdToken GetDeclarationToken(DWORD i)
        {
            LIMITED_METHOD_CONTRACT;
            _ASSERTE(i < pIndex);
            return rgEntries[i].declToken;
        }

        const Substitution *GetDeclarationSubst(DWORD i)
        {
            LIMITED_METHOD_CONTRACT;

            _ASSERTE(i < pIndex);
            return &rgEntries[i].declSubst;
        }

        MethodDesc* GetBodyMethodDesc(DWORD i)
        {
            LIMITED_METHOD_CONTRACT;
            _ASSERTE(i < pIndex);
            return rgEntries[i].pBodyDesc;
        }

        // Returns TRUE if tok acts as a body for any methodImpl entry. FALSE, otherwise.
        BOOL IsBody(mdToken tok);

        inline bmtMethodImplInfo(IMDInternalImport * pMDImport)
            : dwNumberMethodImpls(0),
              hEnumMethodImpl(pMDImport),
              pIndex(0),
              rgEntries(NULL)
        {
            LIMITED_METHOD_CONTRACT;
        }
    };

    // The following structs, defined as private members of MethodTableBuilder, contain the necessary local
    // parameters needed for BuildMethodTable

    // Look at the struct definitions for a detailed list of all parameters available
    // to BuildMethodTable.

    BaseDomain *bmtDomain;
    bmtErrorInfo *bmtError;
    bmtProperties *bmtProp;
    bmtVtable *bmtVT;
    bmtParentInfo *bmtParent;
    bmtInterfaceInfo *bmtInterface;
    bmtMethodInfo *bmtMethod;
    bmtTypeInfo *bmtType;
    bmtMethodImplInfo *bmtMethodImpl;

    void SetBMTData(
        BaseDomain *bmtDomain,
        bmtErrorInfo *bmtError,
        bmtProperties *bmtProp,
        bmtVtable *bmtVT,
        bmtParentInfo *bmtParent,
        bmtInterfaceInfo *bmtInterface,
        bmtMethodInfo *bmtMethod,
        bmtTypeInfo *bmtType,
        bmtMethodImplInfo *bmtMethodImpl);

    void NullBMTData();

    class DeclaredMethodIterator
    {
      private:
        MethodTableBuilder &m_mtb;
        int                 m_idx;

      public:
        inline                  DeclaredMethodIterator(MethodTableBuilder &mtb);
        inline int              CurrentIndex();
        inline BOOL             Next();
        inline mdToken          Token();
        inline DWORD            Attrs();
        inline DWORD            RVA();
        inline DWORD            ImplFlags();
        inline DWORD            Classification();
        inline LPCSTR           Name();
        inline PCCOR_SIGNATURE  GetSig(DWORD *pcbSig);
        inline BYTE             MethodImpl();
        inline BOOL             IsMethodImpl();
        inline BYTE             MethodType();
        inline MethodDesc      *GetMethodDesc();
        inline void             SetMethodDesc(MethodDesc *pMD);
        inline MethodDesc      *GetParentMethodDesc();
        inline void             SetParentMethodDesc(MethodDesc *pMD);
        inline MethodDesc      *GetUnboxedMethodDesc();
    };
    friend class DeclaredMethodIterator;

    inline WORD NumDeclaredMethods() { LIMITED_METHOD_CONTRACT; return bmtMethod->cMethods; }
    inline void  IncNumDeclaredMethods() { LIMITED_METHOD_CONTRACT; bmtMethod->cMethods++; }

private:
    static VOID DECLSPEC_NORETURN BuildMethodTableThrowException(HRESULT hr,
                                              const bmtErrorInfo & bmtError);


    inline VOID DECLSPEC_NORETURN BuildMethodTableThrowException(
                                              HRESULT hr,
                                              UINT idResWhy,
                                              mdMethodDef tokMethodDef)
    {
        WRAPPER_NO_CONTRACT;
        bmtError->resIDWhy = idResWhy;
        bmtError->dMethodDefInError = tokMethodDef;
        bmtError->szMethodNameForError = NULL;
        bmtError->cl = GetCl();
        BuildMethodTableThrowException(hr, *bmtError);
    }

    inline VOID DECLSPEC_NORETURN BuildMethodTableThrowException(
        HRESULT hr,
        UINT idResWhy,
        LPCUTF8 szMethodName)
    {
        WRAPPER_NO_CONTRACT;
        bmtError->resIDWhy = idResWhy;
        bmtError->dMethodDefInError = mdMethodDefNil;
        bmtError->szMethodNameForError = szMethodName;
        bmtError->cl = GetCl();
        BuildMethodTableThrowException(hr, *bmtError);
    }

    inline VOID DECLSPEC_NORETURN BuildMethodTableThrowException(
                                              UINT idResWhy,
                                              mdMethodDef tokMethodDef = mdMethodDefNil)
    {
        WRAPPER_NO_CONTRACT;
        BuildMethodTableThrowException(COR_E_TYPELOAD, idResWhy, tokMethodDef);
    }

    inline VOID DECLSPEC_NORETURN BuildMethodTableThrowException(
        UINT idResWhy,
        LPCUTF8 szMethodName)
    {
        WRAPPER_NO_CONTRACT;
        BuildMethodTableThrowException(COR_E_TYPELOAD, idResWhy, szMethodName);
    }

private:
    MethodNameHash *CreateMethodChainHash(
        MethodTable *pMT);

    HRESULT LoaderFindMethodInClass(
        LPCUTF8             pszMemberName,
        Module*             pModule,
        mdMethodDef         mdToken,
        MethodDesc **       ppMethodDesc,
        PCCOR_SIGNATURE *   ppMemberSignature,
        DWORD *             pcMemberSignature,
        DWORD               dwHashName,
        BOOL *              pMethodConstraintsMatch);

    // Finds a method declaration from a MemberRef or Def. It handles the case where
    // the Ref or Def point back to this class even though it has not been fully
    // laid out.
    HRESULT FindMethodDeclarationForMethodImpl(
        IMDInternalImport *pMDInternalImport, // Scope in which tkClass and tkMethod are defined.
        mdTypeDef          tkClass,           // Type that the method def resides in
        mdToken            tkMethod,          // Token that is being located (MemberRef or MethodDef)
        mdToken*           ptkMethodDef);     // Method definition for Member

    // Enumerates the method impl token pairs and resolves the impl tokens to mdtMethodDef
    // tokens, since we currently have the limitation that all impls are in the current class.
    VOID EnumerateMethodImpls();

    VOID EnumerateClassMethods();

    // Allocate temporary memory for tracking all information used in building the MethodTable
    VOID AllocateMethodWorkingMemory();

    VOID BuildInteropVTable_InterfaceList(
        BuildingInterfaceInfo_t **ppBuildingInterfaceList,
        WORD *pcBuildingInterfaceList);

    VOID BuildInteropVTable_PlaceMembers(
        BaseDomain *bmtDomain,
        bmtTypeInfo* bmtType,
        DWORD numDeclaredInterfaces,
        BuildingInterfaceInfo_t *pBuildingInterfaceList,
        bmtMethodInfo* bmtMethod,
        bmtErrorInfo* bmtError,
        bmtProperties* bmtProp,
        bmtParentInfo* bmtParent,
        bmtInterfaceInfo* bmtInterface,
        bmtMethodImplInfo* bmtMethodImpl,
        bmtVtable* bmtVT);

    VOID BuildInteropVTable_ResolveInterfaces(
        BaseDomain *bmtDomain,
        BuildingInterfaceInfo_t *pBuildingInterfaceList,
        bmtTypeInfo* bmtType,
        bmtInterfaceInfo* bmtInterface,
        bmtVtable* bmtVT,
        bmtParentInfo* bmtParent,
        const bmtErrorInfo & bmtError);

    VOID BuildInteropVTable_CreateInterfaceMap(
        BuildingInterfaceInfo_t *pBuildingInterfaceList,
        bmtInterfaceInfo* bmtInterface,
        WORD *pwInterfaceListSize,
        DWORD *pdwMaxInterfaceMethods,
        MethodTable *pParentMethodTable);

    VOID BuildInteropVTable_ExpandInterface(
        InterfaceInfo_t *pInterfaceMap,
        MethodTable *pNewInterface,
        WORD *pwInterfaceListSize,
        DWORD *pdwMaxInterfaceMethods,
        BOOL fDirect);

    VOID BuildInteropVTable_PlaceVtableMethods(
        bmtInterfaceInfo* bmtInterface,
        DWORD numDeclaredInterfaces,
        BuildingInterfaceInfo_t *pBuildingInterfaceList,
        bmtVtable* bmtVT,
        bmtMethodInfo* bmtMethod,
        bmtTypeInfo* bmtType,
        bmtErrorInfo* bmtError,
        bmtProperties* bmtProp,
        bmtParentInfo* bmtParent);

    VOID BuildInteropVTable_PlaceMethodImpls(
        BaseDomain *bmtDomain,
        bmtTypeInfo* bmtType,
        bmtMethodImplInfo* bmtMethodImpl,
        bmtErrorInfo* bmtError,
        bmtInterfaceInfo* bmtInterface,
        bmtVtable* bmtVT,
        bmtParentInfo* bmtParent);

    VOID BuildInteropVTable_PlaceLocalDeclaration(
        mdMethodDef      mdef,
        MethodDesc*      body,
        bmtTypeInfo* bmtType,
        bmtErrorInfo*    bmtError,
        bmtVtable*       bmtVT,
        DWORD*           slots,
        MethodDesc**     replaced,
        DWORD*           pSlotIndex,
        PCCOR_SIGNATURE* ppBodySignature,
        DWORD*           pcBodySignature);

    VOID BuildInteropVTable_PlaceInterfaceDeclaration(
        MethodDesc*       pDecl,
        MethodDesc*       pImplBody,
        const Substitution *pDeclSubst,
        bmtTypeInfo*  bmtType,
        bmtInterfaceInfo* bmtInterface,
        bmtErrorInfo*     bmtError,
        bmtVtable*        bmtVT,
        DWORD*            slots,
        MethodDesc**      replaced,
        DWORD*            pSlotIndex,
        PCCOR_SIGNATURE*  ppBodySignature,
        DWORD*            pcBodySignature);

    VOID BuildInteropVTable_PlaceParentDeclaration(
        MethodDesc*       pDecl,
        MethodDesc*       pImplBody,
        const Substitution *pDeclSubst,
        bmtTypeInfo*  bmtType,
        bmtErrorInfo*     bmtError,
        bmtVtable*        bmtVT,
        bmtParentInfo*    bmtParent,
        DWORD*            slots,
        MethodDesc**      replaced,
        DWORD*            pSlotIndex,
        PCCOR_SIGNATURE*  ppBodySignature,
        DWORD*            pcBodySignature);

    VOID   BuildInteropVTable_PropagateInheritance(
        bmtVtable *bmtVT);

    VOID FinalizeInteropVTable(
        AllocMemTracker *pamTracker,
        LoaderAllocator*,
        bmtVtable*,
        bmtInterfaceInfo*,
        bmtTypeInfo*,
        bmtProperties*,
        bmtMethodInfo*,
        bmtErrorInfo*,
        bmtParentInfo*,
        InteropMethodTableData**);
}; // MethodTableBuilder
 
}; // Namespace ClassCompat

#endif // FEATURE_COMINTEROP

#endif // !CLASSCOMPAT_H