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: CLASS.H |
6 | |
7 | #ifndef CLASSCOMPAT_H |
8 | #define CLASSCOMPAT_H |
9 | |
10 | #ifdef FEATURE_COMINTEROP |
11 | |
12 | /* |
13 | * Include Files |
14 | */ |
15 | #include "eecontract.h" |
16 | #include "argslot.h" |
17 | #include "vars.hpp" |
18 | #include "cor.h" |
19 | #include "clrex.h" |
20 | #include "hash.h" |
21 | #include "crst.h" |
22 | #include "cgensys.h" |
23 | #include "declsec.h" |
24 | #include "stdinterfaces.h" |
25 | #include "slist.h" |
26 | #include "spinlock.h" |
27 | #include "typehandle.h" |
28 | #include "perfcounters.h" |
29 | #include "methodtable.h" |
30 | #include "eeconfig.h" |
31 | #include "typectxt.h" |
32 | #include "stackingallocator.h" |
33 | #include "class.h" |
34 | |
35 | /* |
36 | * Forward declarations |
37 | */ |
38 | class AppDomain; |
39 | class ArrayClass; |
40 | class ArrayMethodDesc; |
41 | class Assembly; |
42 | class ClassLoader; |
43 | class DomainLocalBlock; |
44 | class FCallMethodDesc; |
45 | class EEClass; |
46 | class LayoutEEClass; |
47 | class EnCFieldDesc; |
48 | class FieldDesc; |
49 | class FieldMarshaler; |
50 | struct LayoutRawFieldInfo; |
51 | class MetaSig; |
52 | class MethodDesc; |
53 | class MethodDescChunk; |
54 | class MethodNameHash; |
55 | class MethodTable; |
56 | class Module; |
57 | struct ModuleCtorInfo; |
58 | class Object; |
59 | class Stub; |
60 | class Substitution; |
61 | class SystemDomain; |
62 | class TypeHandle; |
63 | class AllocMemTracker; |
64 | class ZapCodeMap; |
65 | class InteropMethodTableSlotDataMap; |
66 | class LoadingEntry_LockHolder; |
67 | class DispatchMapBuilder; |
68 | |
69 | namespace ClassCompat |
70 | { |
71 | |
72 | //******************************************************************************* |
73 | // workaround: These classification bits need cleanup bad: for now, this gets around |
74 | // IJW setting both mdUnmanagedExport & mdPinvokeImpl on expored methods. |
75 | #define IsReallyMdPinvokeImpl(x) ( ((x) & mdPinvokeImpl) && !((x) & mdUnmanagedExport) ) |
76 | |
77 | //******************************************************************************* |
78 | // |
79 | // The MethodNameHash is a temporary loader structure which may be allocated if there are a large number of |
80 | // methods in a class, to quickly get from a method name to a MethodDesc (potentially a chain of MethodDescs). |
81 | // |
82 | |
83 | //******************************************************************************* |
84 | // Entry in the method hash table |
85 | class MethodHashEntry |
86 | { |
87 | public: |
88 | MethodHashEntry * m_pNext; // Next item with same hash value |
89 | DWORD m_dwHashValue; // Hash value |
90 | MethodDesc * m_pDesc; |
91 | LPCUTF8 m_pKey; // Method name |
92 | }; |
93 | |
94 | //******************************************************************************* |
95 | class MethodNameHash |
96 | { |
97 | public: |
98 | |
99 | MethodHashEntry **m_pBuckets; // Pointer to first entry for each bucket |
100 | DWORD m_dwNumBuckets; |
101 | BYTE * m_pMemory; // Current pointer into preallocated memory for entries |
102 | BYTE * m_pMemoryStart; // Start pointer of pre-allocated memory fo entries |
103 | MethodNameHash *m_pNext; // Chain them for stub dispatch lookup |
104 | INDEBUG( BYTE * m_pDebugEndMemory; ) |
105 | |
106 | MethodNameHash() |
107 | { |
108 | LIMITED_METHOD_CONTRACT; |
109 | m_pMemoryStart = NULL; |
110 | m_pNext = NULL; |
111 | } |
112 | |
113 | ~MethodNameHash() |
114 | { |
115 | LIMITED_METHOD_CONTRACT; |
116 | if (m_pMemoryStart != NULL) |
117 | delete(m_pMemoryStart); |
118 | } |
119 | |
120 | // Throws on error |
121 | void Init(DWORD dwMaxEntries, StackingAllocator *pAllocator = NULL); |
122 | |
123 | // Insert new entry at head of list |
124 | void Insert( |
125 | LPCUTF8 pszName, |
126 | MethodDesc *pDesc); |
127 | |
128 | // Return the first MethodHashEntry with this name, or NULL if there is no such entry |
129 | MethodHashEntry *Lookup( |
130 | LPCUTF8 pszName, |
131 | DWORD dwHash); |
132 | |
133 | void SetNext(MethodNameHash *pNext) { m_pNext = pNext; } |
134 | MethodNameHash *GetNext() { return m_pNext; } |
135 | }; |
136 | |
137 | |
138 | //******************************************************************************* |
139 | // |
140 | // This structure is used only when the classloader is building the interface map. Before the class |
141 | // is resolved, the EEClass contains an array of these, which are all interfaces *directly* declared |
142 | // for this class/interface by the metadata - inherited interfaces will not be present if they are |
143 | // not specifically declared. |
144 | // |
145 | // This structure is destroyed after resolving has completed. |
146 | // |
147 | typedef struct |
148 | { |
149 | // The interface method table; for instantiated interfaces, this is the generic interface |
150 | MethodTable *m_pMethodTable; |
151 | } BuildingInterfaceInfo_t; |
152 | |
153 | //******************************************************************************* |
154 | struct InterfaceInfo_t |
155 | { |
156 | #ifdef DACCESS_COMPILE |
157 | friend class NativeImageDumper; |
158 | #endif |
159 | enum { |
160 | interface_declared_on_class = 0x1, |
161 | interface_implemented_on_parent = 0x2, |
162 | }; |
163 | |
164 | MethodTable* m_pMethodTable; // Method table of the interface |
165 | WORD m_wFlags; |
166 | |
167 | private: |
168 | WORD m_wStartSlot; // starting slot of interface in vtable |
169 | |
170 | public: |
171 | WORD GetInteropStartSlot() |
172 | { |
173 | return m_wStartSlot; |
174 | } |
175 | void SetInteropStartSlot(WORD wStartSlot) |
176 | { |
177 | m_wStartSlot = wStartSlot; |
178 | } |
179 | |
180 | BOOL IsDeclaredOnClass() |
181 | { |
182 | LIMITED_METHOD_CONTRACT; |
183 | return (m_wFlags & interface_declared_on_class); |
184 | } |
185 | |
186 | BOOL IsImplementedByParent() |
187 | { |
188 | LIMITED_METHOD_CONTRACT; |
189 | return (m_wFlags & interface_implemented_on_parent); |
190 | } |
191 | }; |
192 | |
193 | //******************************************************************************* |
194 | // MethodTableBuilder simply acts as a holder for the |
195 | // large algorithm that "compiles" a type into |
196 | // a MethodTable/EEClass/DispatchMap/VTable etc. etc. |
197 | // |
198 | // The user of this class (the ClassLoader) currently builds the EEClass |
199 | // first, and does a couple of other things too, though all |
200 | // that work should probably be folded into BuildMethodTableThrowing. |
201 | // |
202 | class MethodTableBuilder |
203 | { |
204 | public: |
205 | MethodTableBuilder(MethodTable * pMT) |
206 | { |
207 | LIMITED_METHOD_CONTRACT; |
208 | m_pHalfBakedMT = pMT; |
209 | m_pHalfBakedClass = pMT->GetClass(); |
210 | NullBMTData(); |
211 | } |
212 | public: |
213 | |
214 | // This method is purely for backward compatibility of COM Interop, and its |
215 | // implementation can be found in ClassCompat.cpp |
216 | InteropMethodTableData *BuildInteropVTable(AllocMemTracker *pamTracker); |
217 | InteropMethodTableData *BuildInteropVTableForArray(AllocMemTracker *pamTracker); |
218 | |
219 | LPCWSTR GetPathForErrorMessages(); |
220 | |
221 | private: |
222 | enum e_METHOD_IMPL |
223 | { |
224 | METHOD_IMPL_NOT, |
225 | #ifndef STUB_DISPATCH_ALL |
226 | METHOD_IMPL, |
227 | #endif |
228 | METHOD_IMPL_COUNT |
229 | }; |
230 | |
231 | enum e_METHOD_TYPE |
232 | { |
233 | METHOD_TYPE_NORMAL, |
234 | METHOD_TYPE_FCALL, |
235 | METHOD_TYPE_EEIMPL, |
236 | METHOD_TYPE_NDIRECT, |
237 | METHOD_TYPE_INTEROP, |
238 | METHOD_TYPE_INSTANTIATED, |
239 | METHOD_TYPE_COUNT |
240 | }; |
241 | |
242 | private: |
243 | // <NICE> Get rid of this.</NICE> |
244 | EEClass *m_pHalfBakedClass; |
245 | MethodTable * m_pHalfBakedMT; |
246 | |
247 | // GetHalfBakedClass: The EEClass you get back from this function may not have all its fields filled in yet. |
248 | // Thus you have to make sure that the relevant item which you are accessing has |
249 | // been correctly initialized in the EEClass/MethodTable construction sequence |
250 | // at the point at which you access it. |
251 | // |
252 | // Gradually we will move the code to a model where the process of constructing an EEClass/MethodTable |
253 | // is more obviously correct, e.g. by relying much less on reading information using GetHalfBakedClass |
254 | // and GetHalfBakedMethodTable. |
255 | // |
256 | // <NICE> Get rid of this.</NICE> |
257 | EEClass *GetHalfBakedClass() { LIMITED_METHOD_CONTRACT; return m_pHalfBakedClass; } |
258 | MethodTable *GetHalfBakedMethodTable() { WRAPPER_NO_CONTRACT; return m_pHalfBakedMT; } |
259 | |
260 | mdTypeDef GetCl() { LIMITED_METHOD_CONTRACT; return bmtType->cl; } |
261 | BOOL IsGlobalClass() { WRAPPER_NO_CONTRACT; return GetCl() == COR_GLOBAL_PARENT_TOKEN; } |
262 | BOOL IsEnum() { LIMITED_METHOD_CONTRACT; return bmtProp->fIsEnum; } |
263 | DWORD GetAttrClass() { LIMITED_METHOD_CONTRACT; return bmtType->dwAttr; } |
264 | BOOL IsInterface() { WRAPPER_NO_CONTRACT; return IsTdInterface(GetAttrClass()); } |
265 | BOOL IsValueClass() { LIMITED_METHOD_CONTRACT; return bmtProp->fIsValueClass; } |
266 | BOOL IsAbstract() { LIMITED_METHOD_CONTRACT; return IsTdAbstract(bmtType->dwAttr); } |
267 | BOOL HasLayout() { LIMITED_METHOD_CONTRACT; return bmtProp->fHasLayout; } |
268 | BOOL IsDelegate() { LIMITED_METHOD_CONTRACT; return bmtProp->fIsDelegate; } |
269 | Module *GetModule() { LIMITED_METHOD_CONTRACT; return bmtType->pModule; } |
270 | Assembly *GetAssembly() { WRAPPER_NO_CONTRACT; return GetModule()->GetAssembly(); } |
271 | ClassLoader *GetClassLoader() { WRAPPER_NO_CONTRACT; return GetModule()->GetClassLoader(); } |
272 | IMDInternalImport* GetMDImport() { WRAPPER_NO_CONTRACT; return GetModule()->GetMDImport(); } |
273 | #ifdef _DEBUG |
274 | LPCUTF8 GetDebugClassName() { LIMITED_METHOD_CONTRACT; return bmtProp->szDebugClassName; } |
275 | #endif // _DEBUG |
276 | BOOL IsComImport() { WRAPPER_NO_CONTRACT; return IsTdImport(GetAttrClass()); } |
277 | BOOL IsComClassInterface() { LIMITED_METHOD_CONTRACT; return bmtProp->fIsComClassInterface; } |
278 | |
279 | // <NOTE> The following functions are used during MethodTable construction to setup information |
280 | // about the type being constructedm in particular information stored in the EEClass. |
281 | // USE WITH CAUTION!! TRY NOT TO ADD MORE OF THESE!! </NOTE> |
282 | // |
283 | // <NICE> Get rid of all of these - we should be able to evaluate these conditions BEFORE |
284 | // we create the EEClass object, and thus set the flags immediately at the point |
285 | // we create that object.</NICE> |
286 | void SetIsValueClass() { LIMITED_METHOD_CONTRACT; bmtProp->fIsValueClass = TRUE; } |
287 | void SetEnum() { LIMITED_METHOD_CONTRACT; bmtProp->fIsEnum = TRUE; } |
288 | void SetHasLayout() { LIMITED_METHOD_CONTRACT; bmtProp->fHasLayout = TRUE; } |
289 | void SetIsDelegate() { LIMITED_METHOD_CONTRACT; bmtProp->fIsDelegate = TRUE; } |
290 | #ifdef _DEBUG |
291 | void SetDebugClassName(LPUTF8 x) { LIMITED_METHOD_CONTRACT; bmtProp->szDebugClassName = x; } |
292 | #endif |
293 | void SetIsComClassInterface() { LIMITED_METHOD_CONTRACT; bmtProp->fIsComClassInterface = TRUE; } |
294 | |
295 | /************************************ |
296 | * PRIVATE INTERNAL STRUCTS |
297 | ************************************/ |
298 | private: |
299 | struct bmtErrorInfo |
300 | { |
301 | UINT resIDWhy; |
302 | LPCUTF8 szMethodNameForError; |
303 | mdToken dMethodDefInError; |
304 | Module* pModule; |
305 | mdTypeDef cl; |
306 | OBJECTREF *pThrowable; |
307 | |
308 | // Set the reason and the offending method def. If the method information |
309 | // is not from this class set the method name and it will override the method def. |
310 | inline bmtErrorInfo() : resIDWhy(0), szMethodNameForError(NULL), dMethodDefInError(mdMethodDefNil), pThrowable(NULL) {LIMITED_METHOD_CONTRACT; } |
311 | }; |
312 | |
313 | struct bmtProperties |
314 | { |
315 | BOOL fSparse; // Set to true if a sparse interface is being used. |
316 | |
317 | // Com Interop, ComWrapper classes extend from ComObject |
318 | BOOL fIsComObjectType; // whether this class is an instance of ComObject class |
319 | |
320 | BOOL fIsMngStandardItf; // Set to true if the interface is a manages standard interface. |
321 | BOOL fComEventItfType; // Set to true if the class is a special COM event interface. |
322 | |
323 | BOOL fIsValueClass; |
324 | BOOL fIsEnum; |
325 | BOOL fIsComClassInterface; |
326 | BOOL fHasLayout; |
327 | BOOL fIsDelegate; |
328 | |
329 | LPUTF8 szDebugClassName; |
330 | |
331 | inline bmtProperties() |
332 | { |
333 | LIMITED_METHOD_CONTRACT; |
334 | memset((void *)this, NULL, sizeof(*this)); |
335 | } |
336 | }; |
337 | |
338 | struct bmtVtable |
339 | { |
340 | WORD wCurrentVtableSlot; |
341 | WORD wCurrentNonVtableSlot; |
342 | |
343 | // Temporary vtable - use GetMethodDescForSlot/SetMethodDescForSlot for access. |
344 | // pVtableMD is initialized lazily from pVtable |
345 | // pVtable is invalidated if the slot is overwritten. |
346 | PCODE* pVtable; |
347 | MethodDesc** pVtableMD; |
348 | MethodTable *pParentMethodTable; |
349 | |
350 | MethodDesc** pNonVtableMD; |
351 | InteropMethodTableSlotData **ppSDVtable; |
352 | InteropMethodTableSlotData **ppSDNonVtable; |
353 | DWORD dwMaxVtableSize; // Upper bound on size of vtable |
354 | InteropMethodTableSlotDataMap *pInteropData; |
355 | |
356 | DispatchMapBuilder *pDispatchMapBuilder; |
357 | |
358 | MethodDesc* GetMethodDescForSlot(WORD slot) |
359 | { |
360 | CONTRACTL |
361 | { |
362 | NOTHROW; |
363 | GC_NOTRIGGER; |
364 | SO_TOLERANT; |
365 | MODE_ANY; |
366 | } |
367 | CONTRACTL_END; |
368 | if (pVtable[slot] != NULL && pVtableMD[slot] == NULL) |
369 | pVtableMD[slot] = pParentMethodTable->GetMethodDescForSlot(slot); |
370 | _ASSERTE((pVtable[slot] == NULL) || |
371 | (MethodTable::GetMethodDescForSlotAddress(pVtable[slot]) == pVtableMD[slot])); |
372 | return pVtableMD[slot]; |
373 | } |
374 | |
375 | void SetMethodDescForSlot(WORD slot, MethodDesc* pMD) |
376 | { |
377 | WRAPPER_NO_CONTRACT; |
378 | pVtable[slot] = NULL; |
379 | pVtableMD[slot] = pMD; |
380 | } |
381 | |
382 | inline bmtVtable() { LIMITED_METHOD_CONTRACT; memset((void *)this, NULL, sizeof(*this)); } |
383 | }; |
384 | |
385 | struct bmtParentInfo |
386 | { |
387 | WORD wNumParentInterfaces; |
388 | MethodDesc **ppParentMethodDescBuf; // Cache for declared methods |
389 | MethodDesc **ppParentMethodDescBufPtr; // Pointer for iterating over the cache |
390 | |
391 | MethodNameHash *pParentMethodHash; |
392 | Substitution parentSubst; |
393 | MethodTable *pParentMethodTable; |
394 | mdToken token; |
395 | |
396 | inline bmtParentInfo() { LIMITED_METHOD_CONTRACT; memset((void *)this, NULL, sizeof(*this)); } |
397 | }; |
398 | |
399 | struct bmtInterfaceInfo |
400 | { |
401 | DWORD dwTotalNewInterfaceMethods; |
402 | InterfaceInfo_t *pInterfaceMap; // Temporary interface map |
403 | |
404 | // ppInterfaceSubstitutionChains[i][0] holds the primary substitution for each interface |
405 | // ppInterfaceSubstitutionChains[i][0..depth[i] ] is the chain of substitutions for each interface |
406 | Substitution **ppInterfaceSubstitutionChains; |
407 | |
408 | DWORD *pdwOriginalStart; // If an interface is moved this is the original starting location. |
409 | WORD wInterfaceMapSize; // # members in interface map |
410 | DWORD dwLargestInterfaceSize; // # members in largest interface we implement |
411 | DWORD dwMaxExpandedInterfaces; // Upper bound on size of interface map |
412 | MethodDesc **ppInterfaceMethodDescList; // List of MethodDescs for current interface |
413 | MethodDesc **ppInterfaceDeclMethodDescList; // List of MethodDescs for the interface itself |
414 | |
415 | MethodDesc ***pppInterfaceImplementingMD; // List of MethodDescs that implement interface methods |
416 | MethodDesc ***pppInterfaceDeclaringMD; // List of MethodDescs from the interface itself |
417 | |
418 | inline bmtInterfaceInfo() { LIMITED_METHOD_CONTRACT; memset((void *)this, NULL, sizeof(*this)); } |
419 | }; |
420 | |
421 | struct bmtMethodInfo |
422 | { |
423 | DWORD cMethAndGaps; // # meta-data methods of this class ( including the gaps ) |
424 | |
425 | WORD cMethods; // # meta-data methods of this class |
426 | mdToken * rgMethodTokens; // Enumeration of metadata methods |
427 | DWORD * rgMethodAttrs; // Enumeration of the attributes of the methods |
428 | DWORD * rgMethodImplFlags; // Enumeration of the method implementation flags |
429 | ULONG * rgMethodRVA; // Enumeration of the method RVA's |
430 | DWORD * rgMethodClassifications; // Enumeration of the method classifications |
431 | LPCSTR * rgszMethodName; // Enumeration of the method names |
432 | BYTE * rgMethodImpl; // Enumeration of impl value |
433 | BYTE * rgMethodType; // Enumeration of type value |
434 | |
435 | HENUMInternalHolder hEnumMethod; |
436 | |
437 | MethodDesc ** ppUnboxMethodDescList; // Keep track unboxed entry points (for value classes) |
438 | MethodDesc ** ppMethodDescList; // MethodDesc pointer for each member |
439 | |
440 | inline bmtMethodInfo(IMDInternalImport *pMDImport) |
441 | : cMethAndGaps(0), |
442 | cMethods(0), |
443 | rgMethodTokens(NULL), |
444 | rgMethodAttrs(NULL), |
445 | rgMethodImplFlags(NULL), |
446 | rgMethodRVA(NULL), |
447 | rgMethodClassifications(NULL), |
448 | rgszMethodName(NULL), |
449 | rgMethodImpl(NULL), |
450 | hEnumMethod(pMDImport), |
451 | ppUnboxMethodDescList(NULL), |
452 | ppMethodDescList(NULL) |
453 | { |
454 | WRAPPER_NO_CONTRACT; |
455 | } |
456 | |
457 | inline void SetMethodData(int idx, |
458 | mdToken tok, |
459 | DWORD dwAttrs, |
460 | DWORD dwRVA, |
461 | DWORD dwImplFlags, |
462 | DWORD classification, |
463 | LPCSTR szMethodName, |
464 | BYTE impl, |
465 | BYTE type) |
466 | { |
467 | LIMITED_METHOD_CONTRACT; |
468 | rgMethodTokens[idx] = tok; |
469 | rgMethodAttrs[idx] = dwAttrs; |
470 | rgMethodRVA[idx] = dwRVA; |
471 | rgMethodImplFlags[idx] = dwImplFlags; |
472 | rgMethodClassifications[idx] = classification; |
473 | rgszMethodName[idx] = szMethodName; |
474 | rgMethodImpl[idx] = impl; |
475 | rgMethodType[idx] = type; |
476 | } |
477 | }; |
478 | |
479 | struct bmtTypeInfo |
480 | { |
481 | IMDInternalImport * pMDImport; |
482 | Module * pModule; |
483 | mdToken cl; |
484 | DWORD dwAttr; |
485 | |
486 | inline bmtTypeInfo() { LIMITED_METHOD_CONTRACT; memset((void *)this, NULL, sizeof(*this)); } |
487 | }; |
488 | |
489 | struct bmtMethodImplInfo |
490 | { |
491 | DWORD dwNumberMethodImpls; // Number of method impls defined for this type |
492 | HENUMInternalMethodImplHolder hEnumMethodImpl; |
493 | |
494 | struct MethodImplTokenPair |
495 | { |
496 | mdToken methodBody; // MethodDef's for the bodies of MethodImpls. Must be defined in this type. |
497 | mdToken methodDecl; // Method token that body implements. Is a MethodDef or MemberRef |
498 | static int __cdecl Compare(const void *elem1, const void *elem2); |
499 | static BOOL Equal(const MethodImplTokenPair *elem1, const MethodImplTokenPair *elem2); |
500 | }; |
501 | |
502 | MethodImplTokenPair * rgMethodImplTokens; |
503 | Substitution * pMethodDeclSubsts; // Used to interpret generic variables in the interface of the declaring type |
504 | |
505 | DWORD pIndex; // Next open spot in array, we load the BodyDesc's up in order of appearance in the |
506 | // type's list of methods (a body can appear more then once in the list of MethodImpls) |
507 | struct Entry |
508 | { |
509 | mdToken declToken; // Either the token or the method desc is set for the declaration |
510 | Substitution declSubst; // Signature instantiations of parent types for Declaration (NULL if not instantiated) |
511 | MethodDesc* pDeclDesc; // Method descs for Declaration. If null then Declaration is in this type and use the token |
512 | MethodDesc* pBodyDesc; // Method descs created for Method impl bodies |
513 | DWORD dwFlags; |
514 | }; |
515 | |
516 | Entry *rgEntries; |
517 | |
518 | void AddMethod(MethodDesc* pImplDesc, MethodDesc* pDeclDesc, mdToken mdDecl, Substitution *pDeclSubst); |
519 | |
520 | MethodDesc* GetDeclarationMethodDesc(DWORD i) |
521 | { |
522 | LIMITED_METHOD_CONTRACT; |
523 | _ASSERTE(i < pIndex); |
524 | return rgEntries[i].pDeclDesc; |
525 | } |
526 | |
527 | mdToken GetDeclarationToken(DWORD i) |
528 | { |
529 | LIMITED_METHOD_CONTRACT; |
530 | _ASSERTE(i < pIndex); |
531 | return rgEntries[i].declToken; |
532 | } |
533 | |
534 | const Substitution *GetDeclarationSubst(DWORD i) |
535 | { |
536 | LIMITED_METHOD_CONTRACT; |
537 | |
538 | _ASSERTE(i < pIndex); |
539 | return &rgEntries[i].declSubst; |
540 | } |
541 | |
542 | MethodDesc* GetBodyMethodDesc(DWORD i) |
543 | { |
544 | LIMITED_METHOD_CONTRACT; |
545 | _ASSERTE(i < pIndex); |
546 | return rgEntries[i].pBodyDesc; |
547 | } |
548 | |
549 | // Returns TRUE if tok acts as a body for any methodImpl entry. FALSE, otherwise. |
550 | BOOL IsBody(mdToken tok); |
551 | |
552 | inline bmtMethodImplInfo(IMDInternalImport * pMDImport) |
553 | : dwNumberMethodImpls(0), |
554 | hEnumMethodImpl(pMDImport), |
555 | pIndex(0), |
556 | rgEntries(NULL) |
557 | { |
558 | LIMITED_METHOD_CONTRACT; |
559 | } |
560 | }; |
561 | |
562 | // The following structs, defined as private members of MethodTableBuilder, contain the necessary local |
563 | // parameters needed for BuildMethodTable |
564 | |
565 | // Look at the struct definitions for a detailed list of all parameters available |
566 | // to BuildMethodTable. |
567 | |
568 | bmtErrorInfo *bmtError; |
569 | bmtProperties *bmtProp; |
570 | bmtVtable *bmtVT; |
571 | bmtParentInfo *bmtParent; |
572 | bmtInterfaceInfo *bmtInterface; |
573 | bmtMethodInfo *bmtMethod; |
574 | bmtTypeInfo *bmtType; |
575 | bmtMethodImplInfo *bmtMethodImpl; |
576 | |
577 | void SetBMTData( |
578 | bmtErrorInfo *bmtError, |
579 | bmtProperties *bmtProp, |
580 | bmtVtable *bmtVT, |
581 | bmtParentInfo *bmtParent, |
582 | bmtInterfaceInfo *bmtInterface, |
583 | bmtMethodInfo *bmtMethod, |
584 | bmtTypeInfo *bmtType, |
585 | bmtMethodImplInfo *bmtMethodImpl); |
586 | |
587 | void NullBMTData(); |
588 | |
589 | class DeclaredMethodIterator |
590 | { |
591 | private: |
592 | MethodTableBuilder &m_mtb; |
593 | int m_idx; |
594 | |
595 | public: |
596 | inline DeclaredMethodIterator(MethodTableBuilder &mtb); |
597 | inline int CurrentIndex(); |
598 | inline BOOL Next(); |
599 | inline mdToken Token(); |
600 | inline DWORD Attrs(); |
601 | inline DWORD RVA(); |
602 | inline DWORD ImplFlags(); |
603 | inline DWORD Classification(); |
604 | inline LPCSTR Name(); |
605 | inline PCCOR_SIGNATURE GetSig(DWORD *pcbSig); |
606 | inline BYTE MethodImpl(); |
607 | inline BOOL IsMethodImpl(); |
608 | inline BYTE MethodType(); |
609 | inline MethodDesc *GetMethodDesc(); |
610 | inline void SetMethodDesc(MethodDesc *pMD); |
611 | inline MethodDesc *GetParentMethodDesc(); |
612 | inline void SetParentMethodDesc(MethodDesc *pMD); |
613 | inline MethodDesc *GetUnboxedMethodDesc(); |
614 | }; |
615 | friend class DeclaredMethodIterator; |
616 | |
617 | inline WORD NumDeclaredMethods() { LIMITED_METHOD_CONTRACT; return bmtMethod->cMethods; } |
618 | inline void IncNumDeclaredMethods() { LIMITED_METHOD_CONTRACT; bmtMethod->cMethods++; } |
619 | |
620 | private: |
621 | static VOID DECLSPEC_NORETURN BuildMethodTableThrowException(HRESULT hr, |
622 | const bmtErrorInfo & bmtError); |
623 | |
624 | |
625 | inline VOID DECLSPEC_NORETURN BuildMethodTableThrowException( |
626 | HRESULT hr, |
627 | UINT idResWhy, |
628 | mdMethodDef tokMethodDef) |
629 | { |
630 | STANDARD_VM_CONTRACT; |
631 | bmtError->resIDWhy = idResWhy; |
632 | bmtError->dMethodDefInError = tokMethodDef; |
633 | bmtError->szMethodNameForError = NULL; |
634 | bmtError->cl = GetCl(); |
635 | BuildMethodTableThrowException(hr, *bmtError); |
636 | } |
637 | |
638 | inline VOID DECLSPEC_NORETURN BuildMethodTableThrowException( |
639 | HRESULT hr, |
640 | UINT idResWhy, |
641 | LPCUTF8 szMethodName) |
642 | { |
643 | STANDARD_VM_CONTRACT; |
644 | bmtError->resIDWhy = idResWhy; |
645 | bmtError->dMethodDefInError = mdMethodDefNil; |
646 | bmtError->szMethodNameForError = szMethodName; |
647 | bmtError->cl = GetCl(); |
648 | BuildMethodTableThrowException(hr, *bmtError); |
649 | } |
650 | |
651 | inline VOID DECLSPEC_NORETURN BuildMethodTableThrowException( |
652 | UINT idResWhy, |
653 | mdMethodDef tokMethodDef = mdMethodDefNil) |
654 | { |
655 | STANDARD_VM_CONTRACT; |
656 | BuildMethodTableThrowException(COR_E_TYPELOAD, idResWhy, tokMethodDef); |
657 | } |
658 | |
659 | inline VOID DECLSPEC_NORETURN BuildMethodTableThrowException( |
660 | UINT idResWhy, |
661 | LPCUTF8 szMethodName) |
662 | { |
663 | STANDARD_VM_CONTRACT; |
664 | BuildMethodTableThrowException(COR_E_TYPELOAD, idResWhy, szMethodName); |
665 | } |
666 | |
667 | private: |
668 | MethodNameHash *CreateMethodChainHash( |
669 | MethodTable *pMT); |
670 | |
671 | HRESULT LoaderFindMethodInClass( |
672 | LPCUTF8 pszMemberName, |
673 | Module* pModule, |
674 | mdMethodDef mdToken, |
675 | MethodDesc ** ppMethodDesc, |
676 | PCCOR_SIGNATURE * ppMemberSignature, |
677 | DWORD * pcMemberSignature, |
678 | DWORD dwHashName, |
679 | BOOL * pMethodConstraintsMatch); |
680 | |
681 | // Finds a method declaration from a MemberRef or Def. It handles the case where |
682 | // the Ref or Def point back to this class even though it has not been fully |
683 | // laid out. |
684 | HRESULT FindMethodDeclarationForMethodImpl( |
685 | IMDInternalImport *pMDInternalImport, // Scope in which tkClass and tkMethod are defined. |
686 | mdTypeDef tkClass, // Type that the method def resides in |
687 | mdToken tkMethod, // Token that is being located (MemberRef or MethodDef) |
688 | mdToken* ptkMethodDef); // Method definition for Member |
689 | |
690 | // Enumerates the method impl token pairs and resolves the impl tokens to mdtMethodDef |
691 | // tokens, since we currently have the limitation that all impls are in the current class. |
692 | VOID EnumerateMethodImpls(); |
693 | |
694 | VOID EnumerateClassMethods(); |
695 | |
696 | // Allocate temporary memory for tracking all information used in building the MethodTable |
697 | VOID AllocateMethodWorkingMemory(); |
698 | |
699 | VOID BuildInteropVTable_InterfaceList( |
700 | BuildingInterfaceInfo_t **ppBuildingInterfaceList, |
701 | WORD *pcBuildingInterfaceList); |
702 | |
703 | VOID BuildInteropVTable_PlaceMembers( |
704 | bmtTypeInfo* bmtType, |
705 | DWORD numDeclaredInterfaces, |
706 | BuildingInterfaceInfo_t *pBuildingInterfaceList, |
707 | bmtMethodInfo* bmtMethod, |
708 | bmtErrorInfo* bmtError, |
709 | bmtProperties* bmtProp, |
710 | bmtParentInfo* bmtParent, |
711 | bmtInterfaceInfo* bmtInterface, |
712 | bmtMethodImplInfo* bmtMethodImpl, |
713 | bmtVtable* bmtVT); |
714 | |
715 | VOID BuildInteropVTable_ResolveInterfaces( |
716 | BuildingInterfaceInfo_t *pBuildingInterfaceList, |
717 | bmtTypeInfo* bmtType, |
718 | bmtInterfaceInfo* bmtInterface, |
719 | bmtVtable* bmtVT, |
720 | bmtParentInfo* bmtParent, |
721 | const bmtErrorInfo & bmtError); |
722 | |
723 | VOID BuildInteropVTable_CreateInterfaceMap( |
724 | BuildingInterfaceInfo_t *pBuildingInterfaceList, |
725 | bmtInterfaceInfo* bmtInterface, |
726 | WORD *pwInterfaceListSize, |
727 | DWORD *pdwMaxInterfaceMethods, |
728 | MethodTable *pParentMethodTable); |
729 | |
730 | VOID BuildInteropVTable_ExpandInterface( |
731 | InterfaceInfo_t *pInterfaceMap, |
732 | MethodTable *pNewInterface, |
733 | WORD *pwInterfaceListSize, |
734 | DWORD *pdwMaxInterfaceMethods, |
735 | BOOL fDirect); |
736 | |
737 | VOID BuildInteropVTable_PlaceVtableMethods( |
738 | bmtInterfaceInfo* bmtInterface, |
739 | DWORD numDeclaredInterfaces, |
740 | BuildingInterfaceInfo_t *pBuildingInterfaceList, |
741 | bmtVtable* bmtVT, |
742 | bmtMethodInfo* bmtMethod, |
743 | bmtTypeInfo* bmtType, |
744 | bmtErrorInfo* bmtError, |
745 | bmtProperties* bmtProp, |
746 | bmtParentInfo* bmtParent); |
747 | |
748 | VOID BuildInteropVTable_PlaceMethodImpls( |
749 | bmtTypeInfo* bmtType, |
750 | bmtMethodImplInfo* bmtMethodImpl, |
751 | bmtErrorInfo* bmtError, |
752 | bmtInterfaceInfo* bmtInterface, |
753 | bmtVtable* bmtVT, |
754 | bmtParentInfo* bmtParent); |
755 | |
756 | VOID BuildInteropVTable_PlaceLocalDeclaration( |
757 | mdMethodDef mdef, |
758 | MethodDesc* body, |
759 | bmtTypeInfo* bmtType, |
760 | bmtErrorInfo* bmtError, |
761 | bmtVtable* bmtVT, |
762 | DWORD* slots, |
763 | MethodDesc** replaced, |
764 | DWORD* pSlotIndex, |
765 | PCCOR_SIGNATURE* ppBodySignature, |
766 | DWORD* pcBodySignature); |
767 | |
768 | VOID BuildInteropVTable_PlaceInterfaceDeclaration( |
769 | MethodDesc* pDecl, |
770 | MethodDesc* pImplBody, |
771 | const Substitution *pDeclSubst, |
772 | bmtTypeInfo* bmtType, |
773 | bmtInterfaceInfo* bmtInterface, |
774 | bmtErrorInfo* bmtError, |
775 | bmtVtable* bmtVT, |
776 | DWORD* slots, |
777 | MethodDesc** replaced, |
778 | DWORD* pSlotIndex, |
779 | PCCOR_SIGNATURE* ppBodySignature, |
780 | DWORD* pcBodySignature); |
781 | |
782 | VOID BuildInteropVTable_PlaceParentDeclaration( |
783 | MethodDesc* pDecl, |
784 | MethodDesc* pImplBody, |
785 | const Substitution *pDeclSubst, |
786 | bmtTypeInfo* bmtType, |
787 | bmtErrorInfo* bmtError, |
788 | bmtVtable* bmtVT, |
789 | bmtParentInfo* bmtParent, |
790 | DWORD* slots, |
791 | MethodDesc** replaced, |
792 | DWORD* pSlotIndex, |
793 | PCCOR_SIGNATURE* ppBodySignature, |
794 | DWORD* pcBodySignature); |
795 | |
796 | VOID BuildInteropVTable_PropagateInheritance( |
797 | bmtVtable *bmtVT); |
798 | |
799 | VOID FinalizeInteropVTable( |
800 | AllocMemTracker *pamTracker, |
801 | LoaderAllocator*, |
802 | bmtVtable*, |
803 | bmtInterfaceInfo*, |
804 | bmtTypeInfo*, |
805 | bmtProperties*, |
806 | bmtMethodInfo*, |
807 | bmtErrorInfo*, |
808 | bmtParentInfo*, |
809 | InteropMethodTableData**); |
810 | }; // MethodTableBuilder |
811 | |
812 | }; // Namespace ClassCompat |
813 | |
814 | #endif // FEATURE_COMINTEROP |
815 | |
816 | #endif // !CLASSCOMPAT_H |
817 | |