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: memberload.cpp
6//
7
8
9//
10
11//
12// ============================================================================
13
14#include "common.h"
15#include "clsload.hpp"
16#include "method.hpp"
17#include "class.h"
18#include "object.h"
19#include "field.h"
20#include "util.hpp"
21#include "excep.h"
22#include "siginfo.hpp"
23#include "threads.h"
24#include "stublink.h"
25#include "ecall.h"
26#include "dllimport.h"
27#include "jitinterface.h"
28#include "eeconfig.h"
29#include "log.h"
30#include "fieldmarshaler.h"
31#include "cgensys.h"
32#include "gcheaputilities.h"
33#include "dbginterface.h"
34#include "comdelegate.h"
35#include "sigformat.h"
36#include "eeprofinterfaces.h"
37#include "dllimportcallback.h"
38#include "listlock.h"
39#include "methodimpl.h"
40#include "stackprobe.h"
41#include "encee.h"
42#include "comsynchronizable.h"
43#include "customattribute.h"
44#include "virtualcallstub.h"
45#include "eeconfig.h"
46#include "contractimpl.h"
47#include "generics.h"
48#include "instmethhash.h"
49#include "typestring.h"
50
51#ifndef DACCESS_COMPILE
52
53void DECLSPEC_NORETURN MemberLoader::ThrowMissingFieldException(MethodTable* pMT, LPCSTR szMember)
54{
55 CONTRACTL
56 {
57 THROWS;
58 GC_TRIGGERS;
59 MODE_ANY;
60 PRECONDITION(CheckPointer(pMT, NULL_OK));
61 PRECONDITION(CheckPointer(szMember,NULL_OK));
62 }
63 CONTRACTL_END;
64
65 LPCUTF8 szClassName;
66
67 DefineFullyQualifiedNameForClass();
68 if (pMT)
69 {
70 szClassName = GetFullyQualifiedNameForClass(pMT);
71 }
72 else
73 {
74 szClassName = "?";
75 };
76
77
78 LPUTF8 szFullName;
79 MAKE_FULLY_QUALIFIED_MEMBER_NAME(szFullName, NULL, szClassName, (szMember?szMember:"?"), "");
80 PREFIX_ASSUME(szFullName!=NULL);
81 MAKE_WIDEPTR_FROMUTF8(szwFullName, szFullName);
82 EX_THROW(EEMessageException, (kMissingFieldException, IDS_EE_MISSING_FIELD, szwFullName));
83}
84
85void DECLSPEC_NORETURN MemberLoader::ThrowMissingMethodException(MethodTable* pMT, LPCSTR szMember, Module *pModule, PCCOR_SIGNATURE pSig,DWORD cSig,const SigTypeContext *pTypeContext)
86{
87 CONTRACTL
88 {
89 THROWS;
90 GC_TRIGGERS;
91 MODE_ANY;
92 PRECONDITION(CheckPointer(pMT,NULL_OK));
93 PRECONDITION(CheckPointer(szMember,NULL_OK));
94 PRECONDITION(CheckPointer(pSig,NULL_OK));
95 PRECONDITION(CheckPointer(pModule,NULL_OK));
96 PRECONDITION(CheckPointer(pTypeContext,NULL_OK));
97 }
98 CONTRACTL_END;
99 LPCUTF8 szClassName;
100
101 DefineFullyQualifiedNameForClass();
102 if (pMT)
103 {
104 szClassName = GetFullyQualifiedNameForClass(pMT);
105 }
106 else
107 {
108 szClassName = "?";
109 };
110
111 if (pSig && cSig && pModule)
112 {
113 MetaSig tmp(pSig, cSig, pModule, pTypeContext);
114 SigFormat sf(tmp, szMember ? szMember : "?", szClassName, NULL);
115 MAKE_WIDEPTR_FROMUTF8(szwFullName, sf.GetCString());
116 EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, szwFullName));
117 }
118 else
119 {
120 EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?")));
121 }
122}
123
124//---------------------------------------------------------------------------------------
125//
126void MemberLoader::GetDescFromMemberRef(Module * pModule,
127 mdToken MemberRef,
128 MethodDesc ** ppMD,
129 FieldDesc ** ppFD,
130 const SigTypeContext *pTypeContext,
131 BOOL strictMetadataChecks,
132 TypeHandle *ppTH,
133 BOOL actualTypeRequired,
134 PCCOR_SIGNATURE * ppTypeSig,
135 ULONG * pcbTypeSig)
136{
137 CONTRACTL
138 {
139 THROWS;
140 GC_TRIGGERS;
141 PRECONDITION(TypeFromToken(MemberRef) == mdtMemberRef);
142 PRECONDITION(ppMD != NULL && *ppMD == NULL);
143 PRECONDITION(ppFD != NULL && *ppFD == NULL);
144 PRECONDITION(ppTH != NULL && ppTH->IsNull());
145 PRECONDITION(!((ppTypeSig == NULL) ^ (pcbTypeSig == NULL)));
146 }
147 CONTRACTL_END;
148
149 // In lookup table?
150 BOOL fIsMethod;
151 TADDR pDatum = pModule->LookupMemberRef(MemberRef, &fIsMethod);
152
153 if (pDatum != NULL)
154 {
155 if (!fIsMethod)
156 {
157 FieldDesc * pFD = dac_cast<PTR_FieldDesc>(pDatum);
158 *ppFD = pFD;
159
160 // Fields are not inherited so we can always return the exact type right away.
161 *ppTH = pFD->GetEnclosingMethodTable();
162 return;
163 }
164 else
165 {
166 MethodDesc * pMD = dac_cast<PTR_MethodDesc>(pDatum);
167 pMD->CheckRestore();
168 *ppMD = pMD;
169
170 // We are done if the caller is not interested in actual type.
171 if (!actualTypeRequired)
172 {
173 *ppTH = pMD->GetMethodTable();
174 return;
175 }
176 }
177 }
178
179 // No, so do it the long way
180 IMDInternalImport * pInternalImport = pModule->GetMDImport();
181
182 mdTypeRef parent;
183 IfFailThrow(pInternalImport->GetParentOfMemberRef(MemberRef, &parent));
184
185 // If parent is a method def, then this is a varargs method and the
186 // desc lives in the same module.
187 if (TypeFromToken(parent) == mdtMethodDef)
188 {
189 // Return now if actualTypeRequired was set and the desc was cached
190 if (pDatum != NULL)
191 {
192 *ppTH = dac_cast<PTR_MethodDesc>(pDatum)->GetMethodTable();
193 return;
194 }
195
196 MethodDesc *pMethodDef = pModule->LookupMethodDef(parent);
197 if (!pMethodDef)
198 {
199 // There is no value for this def so we haven't yet loaded the class.
200 mdTypeDef typeDef;
201 IfFailThrow(pInternalImport->GetParentToken(parent, &typeDef));
202
203 // Make sure it is a typedef
204 if (TypeFromToken(typeDef) != mdtTypeDef)
205 {
206 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_WO_TYPEDEF_PARENT);
207 }
208
209 // load the class
210
211 TypeHandle th = ClassLoader::LoadTypeDefThrowing(
212 pModule,
213 typeDef,
214 ClassLoader::ThrowIfNotFound,
215 strictMetadataChecks ?
216 ClassLoader::FailIfUninstDefOrRef : ClassLoader::PermitUninstDefOrRef);
217
218 // the class has been loaded and the method should be in the rid map!
219 pMethodDef = pModule->LookupMethodDef(parent);
220 }
221
222 LPCUTF8 szMember;
223 PCCOR_SIGNATURE pSig;
224 DWORD cSig;
225
226 IfFailThrow(pInternalImport->GetNameAndSigOfMemberRef(MemberRef, &pSig, &cSig, &szMember));
227
228 BOOL fMissingMethod = FALSE;
229 if (!pMethodDef)
230 {
231 fMissingMethod = TRUE;
232 }
233 else
234 if (pMethodDef->HasClassOrMethodInstantiation())
235 {
236 // A memberref to a varargs method must not find a MethodDesc that is generic (as varargs methods may not be implemented on generics)
237 fMissingMethod = TRUE;
238 }
239 else
240 {
241 // Ensure the found method matches up correctly
242 PCCOR_SIGNATURE pMethodSig;
243 DWORD cMethodSig;
244
245 pMethodDef->GetSig(&pMethodSig, &cMethodSig);
246 if (!MetaSig::CompareMethodSigs(pSig, cSig, pModule, NULL, pMethodSig,
247 cMethodSig, pModule, NULL))
248 {
249 // If the signatures do not match, then the correct MethodDesc has not been found.
250 fMissingMethod = TRUE;
251 }
252 }
253
254 if (fMissingMethod)
255 {
256 ThrowMissingMethodException(
257 (pMethodDef != NULL) ? pMethodDef->GetMethodTable() : NULL,
258 szMember,
259 pModule,
260 pSig,
261 cSig,
262 pTypeContext);
263 }
264
265 pMethodDef->CheckRestore();
266
267 *ppMD = pMethodDef;
268 *ppTH = pMethodDef->GetMethodTable();
269
270 pModule->StoreMemberRef(MemberRef, pMethodDef);
271 return;
272 }
273
274 TypeHandle typeHnd;
275 PCCOR_SIGNATURE pTypeSig = NULL;
276 ULONG cTypeSig = 0;
277
278 switch (TypeFromToken(parent))
279 {
280 case mdtModuleRef:
281 {
282 DomainFile *pTargetModule = pModule->LoadModule(GetAppDomain(), parent, FALSE /* loadResources */);
283 if (pTargetModule == NULL)
284 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
285 typeHnd = TypeHandle(pTargetModule->GetModule()->GetGlobalMethodTable());
286 if (typeHnd.IsNull())
287 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
288 }
289 break;
290
291 case mdtTypeDef:
292 case mdtTypeRef:
293 typeHnd = ClassLoader::LoadTypeDefOrRefThrowing(pModule, parent,
294 ClassLoader::ThrowIfNotFound,
295 strictMetadataChecks ?
296 ClassLoader::FailIfUninstDefOrRef : ClassLoader::PermitUninstDefOrRef);
297 break;
298
299 case mdtTypeSpec:
300 {
301 IfFailThrow(pInternalImport->GetTypeSpecFromToken(parent, &pTypeSig, &cTypeSig));
302
303 if (ppTypeSig != NULL)
304 {
305 *ppTypeSig = pTypeSig;
306 *pcbTypeSig = cTypeSig;
307 }
308
309 SigPointer sigptr(pTypeSig, cTypeSig);
310 typeHnd = sigptr.GetTypeHandleThrowing(pModule, pTypeContext);
311 }
312 break;
313
314 default:
315 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
316 }
317
318 // Return now if actualTypeRequired was set and the desc was cached
319 if (pDatum != NULL)
320 {
321 *ppTH = typeHnd;
322 return;
323 }
324
325 // Now load the parent of the method ref
326 MethodTable * pMT = typeHnd.GetMethodTable();
327
328 // pMT will be null if typeHnd is a variable type
329 if (pMT == NULL)
330 {
331 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_METHODDEF_PARENT_NO_MEMBERS);
332 }
333
334 PREFIX_ASSUME(pMT != NULL);
335
336 LPCUTF8 szMember;
337 PCCOR_SIGNATURE pSig;
338 DWORD cSig;
339
340 IfFailThrow(pInternalImport->GetNameAndSigOfMemberRef(MemberRef, &pSig, &cSig, &szMember));
341
342 BOOL fIsField = isCallConv(
343 MetaSig::GetCallingConvention(pModule, Signature(pSig, cSig)),
344 IMAGE_CEE_CS_CALLCONV_FIELD);
345
346 if (fIsField)
347 {
348 FieldDesc * pFD = MemberLoader::FindField(pMT, szMember, pSig, cSig, pModule);
349
350 if (pFD == NULL)
351 ThrowMissingFieldException(pMT, szMember);
352
353 if (pFD->IsStatic() && pMT->HasGenericsStaticsInfo())
354 {
355 //
356 // <NICE> this is duplicated logic GetFieldDescByIndex </NICE>
357 //
358 INDEBUG(mdFieldDef token = pFD->GetMemberDef();)
359
360 DWORD pos = static_cast<DWORD>(pFD - (pMT->GetApproxFieldDescListRaw() + pMT->GetNumIntroducedInstanceFields()));
361 _ASSERTE(pos >= 0 && pos < pMT->GetNumStaticFields());
362
363 pFD = pMT->GetGenericsStaticFieldDescs() + pos;
364 _ASSERTE(pFD->GetMemberDef() == token);
365 _ASSERTE(!pFD->IsSharedByGenericInstantiations());
366 _ASSERTE(pFD->GetEnclosingMethodTable() == pMT);
367 }
368
369 *ppFD = pFD;
370 *ppTH = typeHnd;
371
372 //@GENERICS: don't store FieldDescs for instantiated types
373 //or we'll get the wrong one for another instantiation!
374 if (!pMT->HasInstantiation())
375 {
376 pModule->StoreMemberRef(MemberRef, pFD);
377
378 // Verify that the exact type returned here is same as exact type returned by the cached path
379 _ASSERTE(TypeHandle(pFD->GetEnclosingMethodTable()) == *ppTH);
380 }
381 }
382 else
383 {
384 // For array method signatures, the caller's signature contains "actual" types whereas the callee's signature has
385 // formals (ELEMENT_TYPE_VAR 0 wherever the element type of the array occurs). So we need to pass in a substitution
386 // built from the signature of the element type.
387 Substitution sigSubst(pModule, SigPointer(), NULL);
388
389 if (typeHnd.IsArray())
390 {
391 _ASSERTE(pTypeSig != NULL && cTypeSig != 0);
392
393 SigPointer sigptr = SigPointer(pTypeSig, cTypeSig);
394 CorElementType type;
395 IfFailThrow(sigptr.GetElemType(&type));
396
397 THROW_BAD_FORMAT_MAYBE(
398 ((type == ELEMENT_TYPE_SZARRAY) || (type == ELEMENT_TYPE_ARRAY)),
399 BFA_NOT_AN_ARRAY,
400 pModule);
401 sigSubst = Substitution(pModule, sigptr, NULL);
402 }
403
404 // Lookup the method in the class.
405 MethodDesc * pMD = MemberLoader::FindMethod(pMT,
406 szMember,
407 pSig,
408 cSig,
409 pModule,
410 MemberLoader::FM_Default,
411 &sigSubst);
412 if (pMD == NULL)
413 {
414 ThrowMissingMethodException(pMT, szMember, pModule, pSig, cSig, pTypeContext);
415 }
416
417 pMD->CheckRestore();
418
419 *ppMD = pMD;
420 *ppTH = typeHnd;
421
422 // Don't store MethodDescs for instantiated types or we'll get
423 // the wrong one for another instantiation!
424 // The same thing happens for arrays as the same MemberRef can be used for multiple array types
425 // e.g. the member ref in
426 // call void MyList<!0>[,]::Set(int32,int32,MyList<!0>)
427 // could be used for the Set method in MyList<string>[,] and MyList<int32>[,], etc.
428 // <NICE>use cache when memberref is closed (contains no free type parameters) as then it does identify</NICE>
429 // a method-desc uniquely
430 if (!pMD->HasClassOrMethodInstantiation() && !typeHnd.IsArray())
431 {
432 pModule->StoreMemberRef(MemberRef, pMD);
433
434 // Return actual type only if caller asked for it
435 if (!actualTypeRequired)
436 *ppTH = pMD->GetMethodTable();
437 }
438 }
439}
440
441//---------------------------------------------------------------------------------------
442//
443MethodDesc * MemberLoader::GetMethodDescFromMemberRefAndType(Module * pModule,
444 mdToken MemberRef,
445 MethodTable * pMT)
446{
447 CONTRACTL
448 {
449 THROWS;
450 GC_TRIGGERS;
451 PRECONDITION(TypeFromToken(MemberRef) == mdtMemberRef);
452 }
453 CONTRACTL_END;
454
455 //
456 // Fraction of MemberLoader::GetDescFromMemberRef that we actually need here
457 //
458
459 IMDInternalImport * pInternalImport = pModule->GetMDImport();
460
461 LPCUTF8 szMember;
462 PCCOR_SIGNATURE pSig;
463 DWORD cSig;
464
465 IfFailThrow(pInternalImport->GetNameAndSigOfMemberRef(MemberRef, &pSig, &cSig, &szMember));
466
467 _ASSERTE(!isCallConv(MetaSig::GetCallingConvention(pModule, Signature(pSig, cSig)), IMAGE_CEE_CS_CALLCONV_FIELD));
468
469 // For array method signatures, the caller's signature contains "actual" types whereas the callee's signature has
470 // formals (ELEMENT_TYPE_VAR 0 wherever the element type of the array occurs). So we need to pass in a substitution
471 // built from the signature of the element type.
472 Substitution sigSubst(pModule, SigPointer(), NULL);
473
474 if (pMT->IsArray())
475 {
476 mdTypeRef parent;
477 IfFailThrow(pInternalImport->GetParentOfMemberRef(MemberRef, &parent));
478
479 PCCOR_SIGNATURE pTypeSig = NULL;
480 ULONG cTypeSig = 0;
481 IfFailThrow(pInternalImport->GetTypeSpecFromToken(parent, &pTypeSig, &cTypeSig));
482 _ASSERTE(pTypeSig != NULL && cTypeSig != 0);
483
484 SigPointer sigptr = SigPointer(pTypeSig, cTypeSig);
485 CorElementType type;
486 IfFailThrow(sigptr.GetElemType(&type));
487
488 _ASSERTE((type == ELEMENT_TYPE_SZARRAY) || (type == ELEMENT_TYPE_ARRAY));
489
490 sigSubst = Substitution(pModule, sigptr, NULL);
491 }
492
493 // Lookup the method in the class.
494 MethodDesc * pMD = MemberLoader::FindMethod(pMT,
495 szMember,
496 pSig,
497 cSig,
498 pModule,
499 MemberLoader::FM_Default,
500 &sigSubst);
501 if (pMD == NULL)
502 {
503 ThrowMissingMethodException(pMT, szMember, pModule, pSig, cSig, NULL);
504 }
505
506 pMD->CheckRestore();
507
508 return pMD;
509}
510
511//---------------------------------------------------------------------------------------
512//
513FieldDesc * MemberLoader::GetFieldDescFromMemberRefAndType(Module * pModule,
514 mdToken MemberRef,
515 MethodTable * pMT)
516{
517 CONTRACTL
518 {
519 THROWS;
520 GC_TRIGGERS;
521 PRECONDITION(TypeFromToken(MemberRef) == mdtMemberRef);
522 }
523 CONTRACTL_END;
524
525 //
526 // Fraction of MemberLoader::GetDescFromMemberRef that we actually need here
527 //
528
529 IMDInternalImport * pInternalImport = pModule->GetMDImport();
530
531 LPCUTF8 szMember;
532 PCCOR_SIGNATURE pSig;
533 DWORD cSig;
534
535 IfFailThrow(pInternalImport->GetNameAndSigOfMemberRef(MemberRef, &pSig, &cSig, &szMember));
536
537 _ASSERTE(isCallConv(MetaSig::GetCallingConvention(pModule, Signature(pSig, cSig)), IMAGE_CEE_CS_CALLCONV_FIELD));
538
539 FieldDesc * pFD = MemberLoader::FindField(pMT, szMember, pSig, cSig, pModule);
540
541 if (pFD == NULL)
542 ThrowMissingFieldException(pMT, szMember);
543
544 if (pFD->IsStatic() && pMT->HasGenericsStaticsInfo())
545 {
546 //
547 // <NICE> this is duplicated logic GetFieldDescByIndex </NICE>
548 //
549 INDEBUG(mdFieldDef token = pFD->GetMemberDef();)
550
551 DWORD pos = static_cast<DWORD>(pFD - (pMT->GetApproxFieldDescListRaw() + pMT->GetNumIntroducedInstanceFields()));
552 _ASSERTE(pos >= 0 && pos < pMT->GetNumStaticFields());
553
554 pFD = pMT->GetGenericsStaticFieldDescs() + pos;
555 _ASSERTE(pFD->GetMemberDef() == token);
556 _ASSERTE(!pFD->IsSharedByGenericInstantiations());
557 _ASSERTE(pFD->GetEnclosingMethodTable() == pMT);
558 }
559
560 return pFD;
561}
562
563//---------------------------------------------------------------------------------------
564//
565MethodDesc* MemberLoader::GetMethodDescFromMethodDef(Module *pModule,
566 mdToken MethodDef,
567 BOOL strictMetadataChecks)
568{
569 CONTRACTL
570 {
571 THROWS;
572 GC_TRIGGERS;
573 PRECONDITION(TypeFromToken(MethodDef) == mdtMethodDef);
574 }
575 CONTRACTL_END;
576
577 // In lookup table?
578 MethodDesc * pMD = pModule->LookupMethodDef(MethodDef);
579 if (!pMD)
580 {
581 // No, so do it the long way
582 //
583 // Notes on methodDefs to generic things
584 //
585 // For internal purposes we wish to resolve MethodDef from generic classes or for generic methods to
586 // the corresponding fully uninstantiated descriptor. For example, for
587 // class C<T> { void m(); }
588 // then then MethodDef for m resolves to a method descriptor for C<T>.m(). This is the
589 // descriptor that gets stored in the RID map.
590 //
591 // Normal IL code that uses generic code cannot use MethodDefs in this way: all calls
592 // to generic code must be emitted as MethodRefs and MethodSpecs. However, at other
593 // points in tthe codebase we need to resolve MethodDefs to generic uninstantiated
594 // method descriptors, and this is the best place to implement that.
595 //
596 mdTypeDef typeDef;
597 IfFailThrow(pModule->GetMDImport()->GetParentToken(MethodDef, &typeDef));
598
599 TypeHandle th = ClassLoader::LoadTypeDefThrowing(
600 pModule,
601 typeDef,
602 ClassLoader::ThrowIfNotFound,
603 strictMetadataChecks ?
604 ClassLoader::FailIfUninstDefOrRef : ClassLoader::PermitUninstDefOrRef);
605
606 // The RID map should have been filled out if we fully loaded the class
607 pMD = pModule->LookupMethodDef(MethodDef);
608
609 if (pMD == NULL)
610 {
611 LPCUTF8 szMember;
612 PCCOR_SIGNATURE pSig;
613 DWORD cSig;
614
615 IfFailThrow(pModule->GetMDImport()->GetSigOfMethodDef(MethodDef, &cSig, &pSig));
616 IfFailThrow(pModule->GetMDImport()->GetNameOfMethodDef(MethodDef, &szMember));
617
618 ThrowMissingMethodException(
619 th.GetMethodTable(),
620 szMember,
621 pModule,
622 pSig,
623 cSig,
624 NULL);
625 }
626 }
627
628 pMD->CheckRestore();
629
630#if 0
631 // <TODO> Generics: enable this check after the findMethod call in the Zapper which passes
632 // naked generic MethodDefs across the JIT interface is moved over into the EE</TODO>
633 if (strictMetadataChecks && pDatum->GetNumGenericClassArgs() != 0)
634 {
635 THROW_BAD_FORMAT_MAYBE(!"Methods inside generic classes must be referenced using MemberRefs or MethodSpecs, even in the same module as the class", 0, pModule);
636 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
637 }
638#endif
639
640 return pMD;
641}
642
643//---------------------------------------------------------------------------------------
644//
645FieldDesc* MemberLoader::GetFieldDescFromFieldDef(Module *pModule,
646 mdToken FieldDef,
647 BOOL strictMetadataChecks)
648{
649 CONTRACTL
650 {
651 THROWS;
652 GC_TRIGGERS;
653 PRECONDITION(TypeFromToken(FieldDef) == mdtFieldDef);
654 }
655 CONTRACTL_END;
656
657 // In lookup table?
658 FieldDesc * pFD = pModule->LookupFieldDef(FieldDef);
659 if (!pFD)
660 {
661 // No, so do it the long way
662 mdTypeDef typeDef;
663 IfFailThrow(pModule->GetMDImport()->GetParentToken(FieldDef, &typeDef));
664
665 // Load the class - that should set the desc in the rid map
666 // Field defs to generic things resolve to the formal instantiation
667 // without taking the type context into account. They are only valid internally.
668 // <TODO> check that we rule out field defs to generic things in IL streams elsewhere</TODO>
669
670 TypeHandle th = ClassLoader::LoadTypeDefThrowing(
671 pModule,
672 typeDef,
673 ClassLoader::ThrowIfNotFound,
674 strictMetadataChecks ?
675 ClassLoader::FailIfUninstDefOrRef : ClassLoader::PermitUninstDefOrRef);
676
677 pFD = pModule->LookupFieldDef(FieldDef);
678 if (pFD == NULL)
679 {
680 LPCUTF8 szMember;
681 if (FAILED(pModule->GetMDImport()->GetNameOfFieldDef(FieldDef, &szMember)))
682 {
683 szMember = "Invalid FieldDef record";
684 }
685 ThrowMissingFieldException(th.GetMethodTable(), szMember);
686 }
687 }
688
689 pFD->GetApproxEnclosingMethodTable()->CheckRestore();
690
691#ifdef EnC_SUPPORTED
692 if (pModule->IsEditAndContinueEnabled() && pFD->IsEnCNew())
693 {
694 EnCFieldDesc *pEnCFD = (EnCFieldDesc*)pFD;
695 // we may not have the full FieldDesc info at applyEnC time becuase we don't
696 // have a thread so can't do things like load classes (due to possible exceptions)
697 if (pEnCFD->NeedsFixup())
698 {
699 GCX_COOP();
700 pEnCFD->Fixup(FieldDef);
701 }
702 }
703#endif // EnC_SUPPORTED
704
705 return pFD;
706}
707
708//---------------------------------------------------------------------------------------
709//
710MethodDesc *
711MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(
712 Module * pModule,
713 mdMemberRef MemberRef,
714 const SigTypeContext * pTypeContext,
715 BOOL strictMetadataChecks,
716 // Normally true - the zapper is one exception. Throw an exception if no generic method args
717 // given for a generic method, otherwise return the 'generic' instantiation
718 BOOL allowInstParam)
719{
720 CONTRACTL
721 {
722 THROWS;
723 GC_TRIGGERS;
724 INJECT_FAULT(COMPlusThrowOM(););
725 PRECONDITION(CheckPointer(pModule));
726 }
727 CONTRACTL_END;
728
729 IMDInternalImport *pInternalImport = pModule->GetMDImport();
730 if(!pInternalImport->IsValidToken(MemberRef))
731 {
732 // The exception type and message preserved for compatibility
733 THROW_BAD_FORMAT(BFA_INVALID_METHOD_TOKEN, pModule);
734 }
735
736 MethodDesc * pMD = NULL;
737 FieldDesc * pFD = NULL;
738 TypeHandle th;
739
740 switch (TypeFromToken(MemberRef))
741 {
742 case mdtMethodDef:
743 pMD = GetMethodDescFromMethodDef(pModule, MemberRef, strictMetadataChecks);
744 th = pMD->GetMethodTable();
745 break;
746
747 case mdtMemberRef:
748 GetDescFromMemberRef(pModule, MemberRef, &pMD, &pFD, pTypeContext, strictMetadataChecks, &th);
749
750 if (pMD == NULL)
751 {
752 // The exception type and message preserved for compatibility
753 EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?")));
754 }
755 break;
756
757 case mdtMethodSpec:
758 return GetMethodDescFromMethodSpec(pModule, MemberRef, pTypeContext, strictMetadataChecks, allowInstParam, &th);
759
760 default:
761 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
762 }
763
764 // Apply the method instantiation if any. If not applying strictMetadataChecks we
765 // generate the "generic" instantiation - this is used by FuncEval.
766 //
767 // For generic code this call will return an instantiating stub where needed. If the method
768 // is a generic method then instantiate it with the given parameters.
769 // For non-generic code this will just return pDatum
770 return MethodDesc::FindOrCreateAssociatedMethodDesc(
771 pMD,
772 th.GetMethodTable(),
773 FALSE /* don't get unboxing entry point */,
774 strictMetadataChecks ? Instantiation() : pMD->LoadMethodInstantiation(),
775 allowInstParam);
776} // MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec
777
778//---------------------------------------------------------------------------------------
779//
780MethodDesc * MemberLoader::GetMethodDescFromMethodSpec(Module * pModule,
781 mdToken MethodSpec,
782 const SigTypeContext *pTypeContext,
783 BOOL strictMetadataChecks,
784 BOOL allowInstParam,
785 TypeHandle *ppTH,
786 BOOL actualTypeRequired,
787 PCCOR_SIGNATURE * ppTypeSig,
788 ULONG * pcbTypeSig,
789 PCCOR_SIGNATURE * ppMethodSig,
790 ULONG * pcbMethodSig)
791
792{
793 CONTRACTL
794 {
795 THROWS;
796 GC_TRIGGERS;
797 PRECONDITION(TypeFromToken(MethodSpec) == mdtMethodSpec);
798 PRECONDITION(ppTH != NULL && ppTH->IsNull());
799 PRECONDITION(!((ppTypeSig == NULL) ^ (pcbTypeSig == NULL)));
800 PRECONDITION(!((ppMethodSig == NULL) ^ (pcbMethodSig == NULL)));
801 }
802 CONTRACTL_END;
803
804 CQuickBytes qbGenericMethodArgs;
805
806 mdMemberRef GenericMemberRef;
807 PCCOR_SIGNATURE pSig;
808 ULONG cSig;
809
810 IMDInternalImport * pInternalImport = pModule->GetMDImport();
811
812 // Get the member def/ref and instantiation signature
813 IfFailThrow(pInternalImport->GetMethodSpecProps(MethodSpec, &GenericMemberRef, &pSig, &cSig));
814
815 if (ppMethodSig != NULL)
816 {
817 *ppMethodSig = pSig;
818 *pcbMethodSig = cSig;
819 }
820
821 SigPointer sp(pSig, cSig);
822
823 BYTE etype;
824 IfFailThrow(sp.GetByte(&etype));
825
826 // Load the generic method instantiation
827 THROW_BAD_FORMAT_MAYBE(etype == (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST, 0, pModule);
828
829 DWORD nGenericMethodArgs = 0;
830 IfFailThrow(sp.GetData(&nGenericMethodArgs));
831
832 DWORD cbAllocSize = 0;
833 if (!ClrSafeInt<DWORD>::multiply(nGenericMethodArgs, sizeof(TypeHandle), cbAllocSize))
834 {
835 COMPlusThrowHR(COR_E_OVERFLOW);
836 }
837
838 TypeHandle *genericMethodArgs = reinterpret_cast<TypeHandle *>(qbGenericMethodArgs.AllocThrows(cbAllocSize));
839
840 for (DWORD i = 0; i < nGenericMethodArgs; i++)
841 {
842 genericMethodArgs[i] = sp.GetTypeHandleThrowing(pModule, pTypeContext);
843 _ASSERTE (!genericMethodArgs[i].IsNull());
844 IfFailThrow(sp.SkipExactlyOne());
845 }
846
847 MethodDesc * pMD = NULL;
848 FieldDesc * pFD = NULL;
849
850 switch (TypeFromToken(GenericMemberRef))
851 {
852 case mdtMethodDef:
853 pMD = GetMethodDescFromMethodDef(pModule, GenericMemberRef, strictMetadataChecks);
854 *ppTH = pMD->GetMethodTable();
855 break;
856
857 case mdtMemberRef:
858 GetDescFromMemberRef(pModule, GenericMemberRef, &pMD, &pFD, pTypeContext, strictMetadataChecks, ppTH,
859 actualTypeRequired, ppTypeSig, pcbTypeSig);
860
861 if (pMD == NULL)
862 {
863 // The exception type and message preserved for compatibility
864 EX_THROW(EEMessageException, (kMissingMethodException, IDS_EE_MISSING_METHOD, W("?")));
865 }
866 break;
867
868 default:
869 // The exception type and message preserved for compatibility
870 THROW_BAD_FORMAT(
871 BFA_EXPECTED_METHODDEF_OR_MEMBERREF,
872 pModule);
873 }
874
875 return MethodDesc::FindOrCreateAssociatedMethodDesc(
876 pMD,
877 ppTH->GetMethodTable(),
878 FALSE /* don't get unboxing entry point */,
879 Instantiation(genericMethodArgs, nGenericMethodArgs),
880 allowInstParam);
881}
882
883//---------------------------------------------------------------------------------------
884//
885MethodDesc *
886MemberLoader::GetMethodDescFromMethodDef(
887 Module * pModule,
888 mdMethodDef MethodDef, // MethodDef token
889 Instantiation classInst, // Generic arguments for declaring class
890 Instantiation methodInst, // Generic arguments for declaring method
891 BOOL forceRemotable /* = FALSE */)
892{
893 CONTRACTL
894 {
895 THROWS;
896 GC_TRIGGERS;
897 INJECT_FAULT(COMPlusThrowOM(););
898 PRECONDITION(CheckPointer(pModule));
899 PRECONDITION(TypeFromToken(MethodDef) == mdtMethodDef);
900 }
901 CONTRACTL_END;
902
903 // Get the generic method definition. The functions above are guaranteed to
904 // return the generic definition when given a MethodDef.
905 MethodDesc* pDefMD = GetMethodDescFromMethodDef(pModule, MethodDef, FALSE);
906 if (pDefMD->GetNumGenericMethodArgs() != methodInst.GetNumArgs())
907 {
908 COMPlusThrowHR(COR_E_TARGETPARAMCOUNT);
909 }
910
911 // If the class isn't generic then LoadGenericInstantiation just checks that
912 // we're not supplying type parameters and then returns us the class as a type handle
913 MethodTable *pMT = ClassLoader::LoadGenericInstantiationThrowing(
914 pModule, pDefMD->GetMethodTable()->GetCl(), classInst).AsMethodTable();
915
916 // Apply the instantiations (if any).
917 MethodDesc *pMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pDefMD, pMT,
918 FALSE, /* don't get unboxing entry point */
919 methodInst,
920 FALSE /* no allowInstParam */,
921 forceRemotable);
922
923 return pMD;
924}
925
926FieldDesc* MemberLoader::GetFieldDescFromMemberDefOrRef(
927 Module *pModule,
928 mdMemberRef MemberDefOrRef,
929 const SigTypeContext *pTypeContext,
930 BOOL strictMetadataChecks // Normally true - reflection is the one exception. Throw an exception if no generic method args given for a generic field, otherwise return the 'generic' instantiation
931 )
932{
933 CONTRACTL
934 {
935 THROWS;
936 GC_TRIGGERS;
937 INJECT_FAULT(COMPlusThrowOM(););
938 }
939 CONTRACTL_END;
940
941 FieldDesc * pFD = NULL;
942 MethodDesc * pMD = NULL;
943 TypeHandle th;
944
945 switch (TypeFromToken(MemberDefOrRef))
946 {
947 case mdtFieldDef:
948 pFD = GetFieldDescFromFieldDef(pModule, MemberDefOrRef, strictMetadataChecks);
949 break;
950
951 case mdtMemberRef:
952 GetDescFromMemberRef(
953 pModule, MemberDefOrRef, &pMD, &pFD, pTypeContext, strictMetadataChecks, &th);
954
955 if (!pFD)
956 {
957 // The exception type and message preserved for compatibility
958 COMPlusThrow(kMissingFieldException, W("Arg_MissingFieldException"));
959 }
960 break;
961
962 default:
963 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
964 }
965
966 return pFD;
967}
968
969//*******************************************************************************
970BOOL MemberLoader::FM_PossibleToSkipMethod(FM_Flags flags)
971{
972 LIMITED_METHOD_CONTRACT;
973
974 return ((flags & FM_SpecialVirtualMask) || (flags & FM_SpecialAccessMask));
975}
976
977//*******************************************************************************
978BOOL MemberLoader::FM_ShouldSkipMethod(DWORD dwAttrs, FM_Flags flags)
979{
980 LIMITED_METHOD_CONTRACT;
981
982 BOOL retVal = FALSE;
983
984 // If we have any special selection flags, then we need to check a little deeper.
985 if (flags & FM_SpecialVirtualMask)
986 {
987 if (((flags & FM_ExcludeVirtual) && IsMdVirtual(dwAttrs)) ||
988 ((flags & FM_ExcludeNonVirtual) && !IsMdVirtual(dwAttrs)))
989 {
990 retVal = TRUE;
991 }
992 }
993
994 // This makes for quick shifting in determining if an access mask bit matches
995 static_assert_no_msg((FM_ExcludePrivateScope >> 0x4) == 0x1);
996
997 if (flags & FM_SpecialAccessMask)
998 {
999 DWORD dwAccess = dwAttrs & mdMemberAccessMask;
1000 if ((1 << dwAccess) & ((DWORD)(flags & FM_SpecialAccessMask) >> 0x4))
1001 {
1002 retVal = TRUE;
1003 }
1004 }
1005
1006 // Ensure that this function is kept in sync with FM_PossibleToSkipMethod
1007 CONSISTENCY_CHECK(FM_PossibleToSkipMethod(flags) || !retVal);
1008
1009 return retVal;
1010}
1011
1012//*******************************************************************************
1013// Given a signature, and a method declared on a class or on a parent of a class,
1014// find out if the signature matches the method.
1015//
1016// In the normal non-generic case, we can simply perform a signature check,
1017// but with generics, we need to have a properly set up Substitution, so that
1018// we have a correct set of types to compare with. The idea is that either the current
1019// EEClass matches up with the methoddesc, or a parent EEClass will match up.
1020BOOL CompareMethodSigWithCorrectSubstitution(
1021 PCCOR_SIGNATURE pSignature,
1022 DWORD cSignature,
1023 Module* pModule,
1024 MethodDesc *pCurDeclMD,
1025 const Substitution *pDefSubst,
1026 MethodTable *pCurMT
1027 )
1028{
1029 CONTRACTL
1030 {
1031 THROWS;
1032 GC_TRIGGERS;
1033 MODE_ANY;
1034 INJECT_FAULT(COMPlusThrowOM());
1035 }
1036 CONTRACTL_END
1037
1038 MethodTable *pCurDeclMT = pCurDeclMD->GetMethodTable();
1039 BOOL fNeedsSubstitutionUpdateDueToInstantiationDifferences = pCurDeclMT->HasInstantiation() && pCurDeclMT != pCurMT->GetCanonicalMethodTable();
1040 if (!fNeedsSubstitutionUpdateDueToInstantiationDifferences)
1041 {
1042 PCCOR_SIGNATURE pCurMethodSig;
1043 DWORD cCurMethodSig;
1044
1045 pCurDeclMD->GetSig(&pCurMethodSig, &cCurMethodSig);
1046 return MetaSig::CompareMethodSigs(pSignature, cSignature, pModule, NULL, pCurMethodSig,
1047 cCurMethodSig, pCurDeclMD->GetModule(), pDefSubst);
1048 }
1049 else
1050 {
1051 MethodTable *pParentMT = pCurMT->GetParentMethodTable();
1052 if (pParentMT != NULL)
1053 {
1054 Substitution subst2 = pCurMT->GetSubstitutionForParent(pDefSubst);
1055
1056 return CompareMethodSigWithCorrectSubstitution(pSignature, cSignature, pModule, pCurDeclMD, &subst2, pParentMT);
1057 }
1058 return FALSE;
1059 }
1060}
1061
1062//*******************************************************************************
1063// Finds a method by name and signature, where scope is the scope in which the
1064// signature is defined.
1065MethodDesc *
1066MemberLoader::FindMethod(
1067 MethodTable * pMT,
1068 LPCUTF8 pszName,
1069 PCCOR_SIGNATURE pSignature, DWORD cSignature,
1070 Module* pModule,
1071 FM_Flags flags, // = FM_Default
1072 const Substitution *pDefSubst) // = NULL
1073{
1074
1075 CONTRACT (MethodDesc *) {
1076 THROWS;
1077 GC_TRIGGERS;
1078 INJECT_FAULT(COMPlusThrowOM(););
1079 MODE_ANY;
1080 } CONTRACT_END;
1081
1082 // Retrieve the right comparition function to use.
1083 UTF8StringCompareFuncPtr StrCompFunc = FM_GetStrCompFunc(flags);
1084
1085 SString targetName(SString::Utf8Literal, pszName);
1086 ULONG targetNameHash = targetName.HashCaseInsensitive();
1087
1088 // Statistically it's most likely for a method to be found in non-vtable portion of this class's members, then in the
1089 // vtable of this class's declared members, then in the inherited portion of the vtable, so we search backwards.
1090
1091 // For value classes, if it's a value class method, we want to return the duplicated MethodDesc, not the one in the vtable
1092 // section. We'll find the one in the duplicate section before the one in the vtable section, so we're ok.
1093
1094 // Search non-vtable portion of this class first
1095
1096 MethodTable::MethodIterator it(pMT);
1097
1098 // Move the iterator to the appropriate starting point. It is imporant to search from the end
1099 // because hide-by-sig methods found in child types must be matched before the methods they
1100 // may be hiding in parent types.
1101 it.MoveToEnd();
1102
1103 // Iterate through the methods of the current type searching for a match.
1104 for (; it.IsValid(); it.Prev())
1105 {
1106 MethodDesc *pCurDeclMD = it.GetDeclMethodDesc();
1107#ifdef _DEBUG
1108 MethodTable *pCurDeclMT = pCurDeclMD->GetMethodTable();
1109 CONSISTENCY_CHECK(!pMT->IsInterface() || pCurDeclMT == pMT->GetCanonicalMethodTable());
1110#endif
1111
1112 if (FM_PossibleToSkipMethod(flags) && FM_ShouldSkipMethod(pCurDeclMD->GetAttrs(), flags))
1113 {
1114 continue;
1115 }
1116
1117 if ((flags & FM_IgnoreName) != 0
1118 ||
1119 (pCurDeclMD->MightHaveName(targetNameHash)
1120 // This is done last since it is the most expensive of the IF statement.
1121 && StrCompFunc(pszName, pCurDeclMD->GetName()) == 0)
1122 )
1123 {
1124 if (CompareMethodSigWithCorrectSubstitution(pSignature, cSignature, pModule, pCurDeclMD, pDefSubst, pMT))
1125 {
1126 RETURN pCurDeclMD;
1127 }
1128 }
1129 }
1130
1131
1132 // No inheritance on value types or interfaces
1133 if (pMT->IsValueType() || pMT->IsInterface())
1134 {
1135 RETURN NULL;
1136 }
1137
1138 // Recurse up the hierarchy if the method was not found.
1139 //<TODO>@todo: This routine might be factored slightly to improve perf.</TODO>
1140 CONSISTENCY_CHECK(pMT->CheckLoadLevel(CLASS_LOAD_APPROXPARENTS));
1141
1142 MethodTable *pParentMT = pMT->GetParentMethodTable();
1143 if (pParentMT != NULL)
1144 {
1145 Substitution subst2 = pMT->GetSubstitutionForParent(pDefSubst);
1146
1147 MethodDesc *md = MemberLoader::FindMethod(pParentMT,
1148 pszName, pSignature, cSignature, pModule, flags, &subst2);
1149
1150 // Don't inherit constructors from parent classes. It is important to forbid this,
1151 // because the JIT needs to get the class handle from the memberRef, and when the
1152 // constructor is inherited, the JIT will get the class handle for the parent class
1153 // (and not allocate enough space, etc.). See bug #50035 for details.
1154 if (md)
1155 {
1156 if (IsMdInstanceInitializer(md->GetAttrs(), pszName))
1157 {
1158 md = NULL;
1159 }
1160 }
1161
1162 RETURN md;
1163 }
1164
1165 RETURN NULL;
1166}
1167
1168//*******************************************************************************
1169// This will return the MethodDesc that implements the interface method <pInterface,slotNum>.
1170MethodDesc *
1171MemberLoader::FindMethodForInterfaceSlot(MethodTable * pMT, MethodTable *pInterface, WORD slotNum)
1172{
1173 CONTRACTL {
1174 THROWS;
1175 GC_TRIGGERS;
1176 PRECONDITION(CheckPointer(pInterface));
1177 PRECONDITION(pInterface->IsInterface());
1178 PRECONDITION(slotNum < pInterface->GetNumVirtuals());
1179 } CONTRACTL_END;
1180
1181 MethodDesc *pMDRet = NULL;
1182
1183 DispatchSlot ds(pMT->FindDispatchSlot(pInterface->GetTypeID(), (UINT32)slotNum));
1184 if (!ds.IsNull()) {
1185 pMDRet = ds.GetMethodDesc();
1186 }
1187
1188 CONSISTENCY_CHECK(CheckPointer(pMDRet));
1189 return pMDRet;
1190}
1191
1192//*******************************************************************************
1193MethodDesc *
1194MemberLoader::FindMethod(MethodTable * pMT, LPCUTF8 pwzName, LPHARDCODEDMETASIG pwzSignature, FM_Flags flags)
1195 {
1196 CONTRACTL {
1197 THROWS;
1198 GC_TRIGGERS;
1199 INJECT_FAULT(COMPlusThrowOM(););
1200 MODE_ANY;
1201 } CONTRACTL_END;
1202
1203 Signature sig = MscorlibBinder::GetSignature(pwzSignature);
1204
1205 return FindMethod(pMT, pwzName, sig.GetRawSig(), sig.GetRawSigLen(), MscorlibBinder::GetModule(), flags);
1206}
1207
1208//*******************************************************************************
1209MethodDesc *
1210MemberLoader::FindMethod(MethodTable * pMT, mdMethodDef mb)
1211{
1212 CONTRACTL {
1213 THROWS;
1214 GC_TRIGGERS;
1215 INJECT_FAULT(COMPlusThrowOM(););
1216 MODE_ANY;
1217 } CONTRACTL_END;
1218
1219 // We have the EEClass (this) and so lets just look this up in the ridmap.
1220 MethodDesc *pMD = NULL;
1221 Module *pModule = pMT->GetModule();
1222 PREFIX_ASSUME(pModule != NULL);
1223
1224 if (TypeFromToken(mb) == mdtMemberRef)
1225 pMD = pModule->LookupMemberRefAsMethod(mb);
1226 else
1227 pMD = pModule->LookupMethodDef(mb);
1228
1229 if (pMD != NULL)
1230 pMD->CheckRestore();
1231
1232 return pMD;
1233}
1234
1235//*******************************************************************************
1236MethodDesc *
1237MemberLoader::FindMethodByName(MethodTable * pMT, LPCUTF8 pszName, FM_Flags flags)
1238{
1239 CONTRACTL {
1240 THROWS;
1241 GC_TRIGGERS;
1242 INJECT_FAULT(COMPlusThrowOM(););
1243 PRECONDITION(!pMT->IsArray());
1244 MODE_ANY;
1245 } CONTRACTL_END;
1246
1247 // Caching of MethodDescs (impl and decl) for MethodTable slots provided significant
1248 // performance gain in some reflection emit scenarios.
1249 MethodTable::AllowMethodDataCaching();
1250
1251 // Retrieve the right comparison function to use.
1252 UTF8StringCompareFuncPtr StrCompFunc = FM_GetStrCompFunc(flags);
1253
1254 SString targetName(SString::Utf8, pszName);
1255 ULONG targetNameHash = targetName.HashCaseInsensitive();
1256
1257 // Scan all classes in the hierarchy, starting at the current class and
1258 // moving back up towards the base.
1259 while (pMT != NULL)
1260 {
1261 MethodDesc *pRetMD = NULL;
1262
1263 // Iterate through the methods searching for a match.
1264 MethodTable::MethodIterator it(pMT);
1265 it.MoveToEnd();
1266 for (; it.IsValid(); it.Prev())
1267 {
1268 MethodDesc *pCurMD = it.GetDeclMethodDesc();
1269
1270 if (pCurMD != NULL)
1271 {
1272 // If we're working from the end of the vtable, we'll cover all the non-virtuals
1273 // first, and so if we're supposed to ignore virtuals (see setting of the flag
1274 // below) then we can just break out of the loop and go to the parent.
1275 if ((flags & FM_ExcludeVirtual) && pCurMD->IsVirtual())
1276 {
1277 break;
1278 }
1279
1280 if (FM_PossibleToSkipMethod(flags) && FM_ShouldSkipMethod(pCurMD->GetAttrs(), flags))
1281 {
1282 continue;
1283 }
1284
1285 if (pCurMD->MightHaveName(targetNameHash) && StrCompFunc(pszName, pCurMD->GetNameOnNonArrayClass()) == 0)
1286 {
1287 if (pRetMD != NULL)
1288 {
1289 _ASSERTE(flags & FM_Unique);
1290
1291 // Found another method of this name but FM_Unique was given.
1292 return NULL;
1293 }
1294
1295 pRetMD = it.GetMethodDesc();
1296 pRetMD->CheckRestore();
1297
1298 // Let's always finish iterating through this MT for FM_Unique to reveal overloads, i.e.
1299 // methods with the same name. Returning the first/last method of the given name
1300 // may in some cases work but it depends on the vtable order which is something we
1301 // do not want. It can be easily broken by a seemingly unrelated change.
1302 if (!(flags & FM_Unique))
1303 return pRetMD;
1304 }
1305 }
1306 }
1307
1308 if (pRetMD != NULL)
1309 return pRetMD;
1310
1311 // Check the parent type for a matching method.
1312 pMT = pMT->GetParentMethodTable();
1313
1314 // There is no need to check virtuals for parent types, since by definition they have the same name.
1315 //
1316 // Warning: This is not entirely true as virtuals can be overriden explicitly regardless of their name.
1317 // We should be fine though as long as we do not use this code to find arbitrary user-defined methods.
1318 flags = (FM_Flags)(flags | FM_ExcludeVirtual);
1319 }
1320
1321 return NULL;
1322}
1323
1324//*******************************************************************************
1325MethodDesc *
1326MemberLoader::FindPropertyMethod(MethodTable * pMT, LPCUTF8 pszName, EnumPropertyMethods Method, FM_Flags flags)
1327{
1328 CONTRACTL {
1329 THROWS;
1330 GC_TRIGGERS;
1331 INJECT_FAULT(COMPlusThrowOM(););
1332 MODE_ANY;
1333 PRECONDITION(Method < 2);
1334 } CONTRACTL_END;
1335
1336 // The format strings for the getter and setter. These must stay in synch with the
1337 // EnumPropertyMethods enum defined in class.h
1338 static const LPCUTF8 aFormatStrings[] =
1339 {
1340 "get_%s",
1341 "set_%s"
1342 };
1343
1344 CQuickBytes qbMethName;
1345 size_t len = strlen(pszName) + strlen(aFormatStrings[Method]) + 1;
1346 LPUTF8 strMethName = (LPUTF8) qbMethName.AllocThrows(len);
1347 sprintf_s(strMethName, len, aFormatStrings[Method], pszName);
1348
1349 return FindMethodByName(pMT, strMethName, flags);
1350}
1351
1352//*******************************************************************************
1353MethodDesc *
1354MemberLoader::FindEventMethod(MethodTable * pMT, LPCUTF8 pszName, EnumEventMethods Method, FM_Flags flags)
1355 {
1356 CONTRACTL {
1357 THROWS;
1358 GC_TRIGGERS;
1359 INJECT_FAULT(COMPlusThrowOM(););
1360 MODE_ANY;
1361 PRECONDITION(Method < 3);
1362 } CONTRACTL_END;
1363
1364 // The format strings for the getter and setter. These must stay in synch with the
1365 // EnumPropertyMethods enum defined in class.h
1366 static const LPCUTF8 aFormatStrings[] =
1367 {
1368 "add_%s",
1369 "remove_%s",
1370 "raise_%s"
1371 };
1372
1373 CQuickBytes qbMethName;
1374 size_t len = strlen(pszName) + strlen(aFormatStrings[Method]) + 1;
1375 LPUTF8 strMethName = (LPUTF8) qbMethName.AllocThrows(len);
1376 sprintf_s(strMethName, len, aFormatStrings[Method], pszName);
1377
1378 return FindMethodByName(pMT, strMethName, flags);
1379}
1380
1381//*******************************************************************************
1382MethodDesc *
1383MemberLoader::FindConstructor(MethodTable * pMT, LPHARDCODEDMETASIG pwzSignature)
1384{
1385 CONTRACTL
1386 {
1387 THROWS;
1388 GC_TRIGGERS;
1389 INJECT_FAULT(COMPlusThrowOM(););
1390 MODE_ANY;
1391 }
1392 CONTRACTL_END
1393
1394 Signature sig = MscorlibBinder::GetSignature(pwzSignature);
1395
1396 return FindConstructor(pMT, sig.GetRawSig(), sig.GetRawSigLen(), MscorlibBinder::GetModule());
1397}
1398
1399//*******************************************************************************
1400MethodDesc *
1401MemberLoader::FindConstructor(MethodTable * pMT, PCCOR_SIGNATURE pSignature,DWORD cSignature, Module* pModule)
1402{
1403 CONTRACTL
1404 {
1405 THROWS;
1406 GC_TRIGGERS;
1407 INJECT_FAULT(COMPlusThrowOM(););
1408 MODE_ANY;
1409 }
1410 CONTRACTL_END
1411
1412 // Array classes don't have metadata
1413 if (pMT->IsArray())
1414 return NULL;
1415
1416 MethodTable::MethodIterator it(pMT);
1417
1418 for (it.MoveTo(it.GetNumVirtuals()); it.IsValid(); it.Next())
1419 {
1420 _ASSERTE(!it.IsVirtual());
1421
1422 MethodDesc *pCurMethod = it.GetMethodDesc();
1423 if (pCurMethod == NULL)
1424 {
1425 continue;
1426 }
1427
1428 // Don't want class initializers.
1429 if (pCurMethod->IsStatic())
1430 {
1431 continue;
1432 }
1433
1434 DWORD dwCurMethodAttrs = pCurMethod->GetAttrs();
1435 if (!IsMdRTSpecialName(dwCurMethodAttrs))
1436 {
1437 continue;
1438 }
1439
1440 // Find only the constructor for for this object
1441 _ASSERTE(pCurMethod->GetMethodTable() == pMT->GetCanonicalMethodTable());
1442
1443 PCCOR_SIGNATURE pCurMethodSig;
1444 DWORD cCurMethodSig;
1445 pCurMethod->GetSig(&pCurMethodSig, &cCurMethodSig);
1446
1447 if (MetaSig::CompareMethodSigs(pSignature, cSignature, pModule, NULL, pCurMethodSig, cCurMethodSig, pCurMethod->GetModule(), NULL))
1448 {
1449 return pCurMethod;
1450 }
1451 }
1452
1453 return NULL;
1454}
1455
1456#endif // DACCESS_COMPILE
1457
1458FieldDesc *
1459MemberLoader::FindField(MethodTable * pMT, LPCUTF8 pszName, PCCOR_SIGNATURE pSignature, DWORD cSignature, Module* pModule, BOOL bCaseSensitive)
1460{
1461 CONTRACTL
1462 {
1463 THROWS;
1464 GC_TRIGGERS;
1465 INJECT_FAULT(COMPlusThrowOM(););
1466 MODE_ANY;
1467 }
1468 CONTRACTL_END
1469
1470 DWORD i;
1471 DWORD dwFieldDescsToScan;
1472 IMDInternalImport *pInternalImport = pMT->GetMDImport(); // All explicitly declared fields in this class will have the same scope
1473
1474 CONSISTENCY_CHECK(pMT->CheckLoadLevel(CLASS_LOAD_APPROXPARENTS));
1475
1476 // Retrieve the right comparition function to use.
1477 UTF8StringCompareFuncPtr StrCompFunc = bCaseSensitive ? strcmp : stricmpUTF8;
1478
1479 // Array classes don't have fields, and don't have metadata
1480 if (pMT->IsArray())
1481 return NULL;
1482
1483 SString targetName(SString::Utf8Literal, pszName);
1484 ULONG targetNameHash = targetName.HashCaseInsensitive();
1485
1486 EEClass * pClass = pMT->GetClass();
1487 MethodTable *pParentMT = pMT->GetParentMethodTable();
1488
1489 // Scan the FieldDescs of this class
1490 if (pParentMT != NULL)
1491 dwFieldDescsToScan = pClass->GetNumInstanceFields() - pParentMT->GetNumInstanceFields() + pClass->GetNumStaticFields();
1492 else
1493 dwFieldDescsToScan = pClass->GetNumInstanceFields() + pClass->GetNumStaticFields();
1494
1495 PTR_FieldDesc pFieldDescList = pClass->GetFieldDescList();
1496
1497 for (i = 0; i < dwFieldDescsToScan; i++)
1498 {
1499 LPCUTF8 szMemberName;
1500 FieldDesc * pFD = &pFieldDescList[i];
1501 PREFIX_ASSUME(pFD!=NULL);
1502 mdFieldDef mdField = pFD->GetMemberDef();
1503
1504 // Check is valid FieldDesc, and not some random memory
1505 INDEBUGIMPL(pFD->GetApproxEnclosingMethodTable()->SanityCheck());
1506
1507 if (!pFD->MightHaveName(targetNameHash))
1508 {
1509 continue;
1510 }
1511
1512 IfFailThrow(pInternalImport->GetNameOfFieldDef(mdField, &szMemberName));
1513
1514 if (StrCompFunc(szMemberName, pszName) != 0)
1515 {
1516 continue;
1517 }
1518
1519 if (pSignature != NULL)
1520 {
1521 PCCOR_SIGNATURE pMemberSig;
1522 DWORD cMemberSig;
1523
1524 IfFailThrow(pInternalImport->GetSigOfFieldDef(mdField, &cMemberSig, &pMemberSig));
1525
1526 if (!MetaSig::CompareFieldSigs(
1527 pMemberSig,
1528 cMemberSig,
1529 pMT->GetModule(),
1530 pSignature,
1531 cSignature,
1532 pModule))
1533 {
1534 continue;
1535 }
1536 }
1537
1538 return pFD;
1539 }
1540
1541 return NULL;
1542}
1543