diff options
Diffstat (limited to 'src/vm/classcompat.h')
-rw-r--r-- | src/vm/classcompat.h | 826 |
1 files changed, 826 insertions, 0 deletions
diff --git a/src/vm/classcompat.h b/src/vm/classcompat.h new file mode 100644 index 0000000000..678cb799c3 --- /dev/null +++ b/src/vm/classcompat.h @@ -0,0 +1,826 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more 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) + { + STANDARD_VM_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) + { + STANDARD_VM_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) + { + STANDARD_VM_CONTRACT; + BuildMethodTableThrowException(COR_E_TYPELOAD, idResWhy, tokMethodDef); + } + + inline VOID DECLSPEC_NORETURN BuildMethodTableThrowException( + UINT idResWhy, + LPCUTF8 szMethodName) + { + STANDARD_VM_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 |