Fix module override for recursive generic signatures (#24707)
[platform/upstream/coreclr.git] / src / vm / siginfo.hpp
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 // siginfo.hpp
6 //
7
8
9 #ifndef _H_SIGINFO
10 #define _H_SIGINFO
11
12
13 #include "util.hpp"
14 #include "vars.hpp"
15 #include "clsload.hpp"
16 #include "sigparser.h"
17 #include "zapsig.h"
18 #include "threads.h"
19
20 #include "eecontract.h"
21 #include "typectxt.h"
22
23 //---------------------------------------------------------------------------------------
24 // These macros define how arguments are mapped to the stack in the managed calling convention.
25 // We assume to be walking a method's signature left-to-right, in the virtual calling convention.
26 // See MethodDesc::Call for details on this virtual calling convention.
27 // These macros tell us whether the arguments we see as we proceed with the signature walk are mapped
28 //   to increasing or decreasing stack addresses. This is valid only for arguments that go on the stack.
29 //---------------------------------------------------------------------------------------
30 #if defined(_TARGET_X86_)
31 #define STACK_GROWS_DOWN_ON_ARGS_WALK
32 #else
33 #define STACK_GROWS_UP_ON_ARGS_WALK
34 #endif
35
36 BOOL IsTypeRefOrDef(LPCSTR szClassName, Module *pModule, mdToken token);
37
38 struct ElementTypeInfo {
39 #ifdef _DEBUG
40     int            m_elementType;
41 #endif
42     int            m_cbSize;
43     CorInfoGCType  m_gc         : 3;
44     int            m_enregister : 1;
45 };
46 extern const ElementTypeInfo gElementTypeInfo[];
47
48 unsigned GetSizeForCorElementType(CorElementType etyp);
49 const ElementTypeInfo* GetElementTypeInfo(CorElementType etyp);
50
51 class SigBuilder;
52 class ArgDestination;
53
54 typedef const struct HardCodedMetaSig *LPHARDCODEDMETASIG;
55
56 //@GENERICS: flags returned from IsPolyType indicating the presence or absence of class and
57 // method type parameters in a type whose instantiation cannot be determined at JIT-compile time
58 enum VarKind
59 {
60   hasNoVars = 0x0000,
61   hasClassVar = 0x0001,
62   hasMethodVar = 0x0002,
63   hasSharableClassVar = 0x0004,
64   hasSharableMethodVar = 0x0008,
65   hasAnyVarsMask = 0x0003,
66   hasSharableVarsMask = 0x000c
67 };
68
69 //---------------------------------------------------------------------------------------
70
71 struct ScanContext;
72 typedef void promote_func(PTR_PTR_Object, ScanContext*, uint32_t);
73 typedef void promote_carefully_func(promote_func*, PTR_PTR_Object, ScanContext*, uint32_t);
74
75 void PromoteCarefully(promote_func   fn,
76                       PTR_PTR_Object obj, 
77                       ScanContext*   sc, 
78                       uint32_t       flags = GC_CALL_INTERIOR);
79
80 class LoaderAllocator;
81 void GcReportLoaderAllocator(promote_func* fn, ScanContext* sc, LoaderAllocator *pLoaderAllocator);
82
83 //---------------------------------------------------------------------------------------
84 // 
85 // Encapsulates how compressed integers and typeref tokens are encoded into
86 // a bytestream.
87 //
88 // As you use this class please understand the implicit normalizations 
89 // on the CorElementType's returned by the various methods, especially
90 // for variable types (e.g. !0 in generic signatures), string types
91 // (i.e. E_T_STRING), object types (E_T_OBJECT), constructed types 
92 // (e.g. List<int>) and enums.
93 // 
94 class SigPointer : public SigParser
95 {
96     friend class MetaSig;
97
98 public:
99     // Constructor.
100     SigPointer() { LIMITED_METHOD_DAC_CONTRACT; }
101     
102     // Copy constructor.
103     SigPointer(const SigPointer & sig) : SigParser(sig)
104     {
105         WRAPPER_NO_CONTRACT;
106     }
107
108     SigPointer(const SigParser & sig) : SigParser(sig)
109     {
110         WRAPPER_NO_CONTRACT;
111     }
112
113     // Signature from a pointer. INSECURE!!!
114     // WARNING: Should not be used as it is insecure, because we do not have size of the signature and 
115     // therefore we can read behind the end of buffer/file.
116     FORCEINLINE 
117     SigPointer(PCCOR_SIGNATURE ptr) : SigParser(ptr)
118     {
119         WRAPPER_NO_CONTRACT;
120     }
121     
122     // Signature from a pointer and size.
123     FORCEINLINE 
124     SigPointer(PCCOR_SIGNATURE ptr, DWORD len) : SigParser(ptr, len)
125     {
126         WRAPPER_NO_CONTRACT;
127     }
128
129
130     //=========================================================================
131     // The RAW interface for reading signatures.  You see exactly the signature,
132     // apart from custom modifiers which for historical reasons tend to get eaten.
133     //
134     // DO NOT USE THESE METHODS UNLESS YOU'RE TOTALLY SURE YOU WANT
135     // THE RAW signature.  You nearly always want GetElemTypeClosed() or 
136     // PeekElemTypeClosed() or one of the MetaSig functions.  See the notes above.
137     // These functions will return E_T_INTERNAL, E_T_VAR, E_T_MVAR and such
138     // so the caller must be able to deal with those
139     //=========================================================================
140
141
142         void ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, BOOL bSkipCustomModifier = TRUE);
143         void ConvertToInternalSignature(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, BOOL bSkipCustomModifier = TRUE);
144
145
146     //=========================================================================
147     // The CLOSED interface for reading signatures.  With the following
148     // methods you see the signature "as if" all type variables are 
149     // replaced by the given instantiations.  However, no type loads happen.
150     //
151     // In general this is what you want to use if the signature may include
152     // generic type variables.  Even if you know it doesn't you can always
153     // pass in NULL for the instantiations and put a comment to that effect.
154     //
155     // The CLOSED api also hides E_T_INTERNAL by return E_T_CLASS or E_T_VALUETYPE
156     // appropriately (as directed by the TypeHandle following E_T_INTERNAL)
157     //=========================================================================
158
159         // The CorElementTypes returned correspond
160         // to those returned by TypeHandle::GetSignatureCorElementType.
161         CorElementType PeekElemTypeClosed(Module *pModule, const SigTypeContext *pTypeContext) const;
162
163         //------------------------------------------------------------------------
164         // Fetch the token for a CLASS, VALUETYPE or GENRICINST, or a type
165         // variable instantiatied to be one of these, taking into account
166         // the given instantiations.
167         //
168         // SigPointer should be in a position that satisfies
169         //  ptr.PeekElemTypeClosed(pTypeContext) = ELEMENT_TYPE_VALUETYPE
170         //
171         // A type ref or def is returned.  For an instantiated generic struct
172         // this will return the token for the generic class, e.g. for a signature
173         // for "struct Pair<int,int>" this will return a token for "Pair".
174         //
175         // The token will only make sense in the context of the module where 
176         // the signature occurs.
177         //
178         // WARNING: This api will return a mdTokenNil for a E_T_VALUETYPE obtained
179         //          from a E_T_INTERNAL, as the token is meaningless in that case
180         //          Users of this api must be prepared to deal with a null token
181         //------------------------------------------------------------------------
182         mdTypeRef PeekValueTypeTokenClosed(Module *pModule, const SigTypeContext *pTypeContext, Module **ppModuleOfToken) const;
183
184
185     //=========================================================================
186     // The INTERNAL-NORMALIZED interface for reading signatures.  You see 
187     // information concerning the signature, but taking into account normalizations
188     // performed for layout of data, e.g. enums and one-field VCs.
189     //=========================================================================
190
191         // The CorElementTypes returned correspond
192         // to those returned by TypeHandle::GetInternalCorElementType.
193         CorElementType PeekElemTypeNormalized(Module* pModule, const SigTypeContext *pTypeContext, TypeHandle * pthValueType = NULL) const;
194
195         //------------------------------------------------------------------------
196         // Assumes that the SigPointer points to the start of an element type.
197         // Returns size of that element in bytes. This is the minimum size that a
198         // field of this type would occupy inside an object. 
199         //------------------------------------------------------------------------
200         UINT SizeOf(Module* pModule, const SigTypeContext *pTypeContext) const;
201     
202 private:
203
204         // SigPointer should be just after E_T_VAR or E_T_MVAR
205         TypeHandle GetTypeVariable(CorElementType et,const SigTypeContext *pTypeContext);
206         TypeHandle GetTypeVariableThrowing(Module *pModule, 
207                                            CorElementType et,
208                                            ClassLoader::LoadTypesFlag fLoadTypes,
209                                            const SigTypeContext *pTypeContext);
210
211         // Parse type following E_T_GENERICINST
212         TypeHandle GetGenericInstType(Module *        pModule,
213                                       ClassLoader::LoadTypesFlag = ClassLoader::LoadTypes,
214                                       ClassLoadLevel level = CLASS_LOADED,
215                                       const ZapSig::Context *pZapSigContext = NULL);
216
217 public:
218
219         //------------------------------------------------------------------------
220         // Assuming that the SigPointer points the start if an element type.
221         // Use SigTypeContext to fill in any  type parameters
222         //
223         // Also advance the pointer to after the element type.
224         //------------------------------------------------------------------------
225
226         // OBSOLETE - Use GetTypeHandleThrowing()
227         TypeHandle GetTypeHandleNT(Module* pModule,
228                                    const SigTypeContext *pTypeContext) const;
229
230         // pTypeContext indicates how to instantiate any generic type parameters we come 
231         // However, first we implicitly apply the substitution pSubst to the metadata if pSubst is supplied.
232         // That is, if the metadata contains a type variable "!0" then we first look up
233         // !0 in pSubst to produce another item of metdata and continue processing.  
234         // If pSubst is empty then we look up !0 in the pTypeContext to produce a final
235         // type handle.  If any of these are out of range we throw an exception.
236         //
237         // The level is the level to which the result type will be loaded (see classloadlevel.h)
238         // If dropGenericArgumentLevel is TRUE, and the metadata represents an instantiated generic type,
239         // then generic arguments to the generic type will be loaded one level lower. (This is used by the
240         // class loader to avoid looping on definitions such as class C : D<C>)
241         //   
242         // If dropGenericArgumentLevel is TRUE and
243         // level=CLASS_LOAD_APPROXPARENTS, then the instantiated
244         // generic type is "approximated" in the following way: 
245         // - for generic interfaces, the generic type (uninstantiated) is returned 
246         // - for other generic instantiations, System.Object is used in place of any reference types
247         //   occurring in the type arguments 
248         // This semantics is used by the class loader to load tricky recursive definitions in phases
249         // (e.g. class C : D<C>, or struct S : I<S>)
250         TypeHandle GetTypeHandleThrowing(Module* pModule,
251                                          const SigTypeContext *pTypeContext, 
252                                          ClassLoader::LoadTypesFlag fLoadTypes = ClassLoader::LoadTypes,
253                                          ClassLoadLevel level = CLASS_LOADED,
254                                          BOOL dropGenericArgumentLevel = FALSE,
255                                          const Substitution *pSubst = NULL,
256                                          const ZapSig::Context *pZapSigContext = NULL) const;
257
258 public:
259         //------------------------------------------------------------------------
260         // Does this type contain class or method type parameters whose instantiation cannot
261         // be determined at JIT-compile time from the instantiations in the method context? 
262         // Return a combination of hasClassVar and hasMethodVar flags.
263         //
264         // Example: class C<A,B> containing instance method m<T,U>
265         // Suppose that the method context is C<float,string>::m<double,object>
266         // Then the type Dict<!0,!!0> is considered to have *no* "polymorphic" type parameters because 
267         // !0 is known to be float and !!0 is known to be double
268         // But Dict<!1,!!1> has polymorphic class *and* method type parameters because both
269         // !1=string and !!1=object are reference types and so code using these can be shared with
270         // other reference instantiations.
271         //------------------------------------------------------------------------
272         VarKind IsPolyType(const SigTypeContext *pTypeContext) const;
273
274         //------------------------------------------------------------------------
275         // Tests if the element type is a System.String. Accepts
276         // either ELEMENT_TYPE_STRING or ELEMENT_TYPE_CLASS encoding.
277         //------------------------------------------------------------------------
278         BOOL IsStringType(Module* pModule, const SigTypeContext *pTypeContext) const;
279         BOOL IsStringTypeThrowing(Module* pModule, const SigTypeContext *pTypeContext) const;
280
281 private:
282         BOOL IsStringTypeHelper(Module* pModule, const SigTypeContext* pTypeContext, BOOL fThrow) const;
283
284 public:
285
286
287         //------------------------------------------------------------------------
288         // Tests if the element class name is szClassName. 
289         //------------------------------------------------------------------------
290         BOOL IsClass(Module* pModule, LPCUTF8 szClassName, const SigTypeContext *pTypeContext = NULL) const;
291         BOOL IsClassThrowing(Module* pModule, LPCUTF8 szClassName, const SigTypeContext *pTypeContext = NULL) const;
292
293 private:
294         BOOL IsClassHelper(Module* pModule, LPCUTF8 szClassName, const SigTypeContext* pTypeContext, BOOL fThrow) const;
295
296 public:
297         //------------------------------------------------------------------------
298         // Tests for the existence of a custom modifier
299         //------------------------------------------------------------------------
300         BOOL HasCustomModifier(Module *pModule, LPCSTR szModName, CorElementType cmodtype) const;
301
302         //------------------------------------------------------------------------
303         // Tests for ELEMENT_TYPE_CLASS or ELEMENT_TYPE_VALUETYPE followed by a TypeDef,
304         // and returns the TypeDef
305         //------------------------------------------------------------------------
306         BOOL IsTypeDef(mdTypeDef* pTypeDef) const;
307
308 };  // class SigPointer
309
310 // forward declarations needed for the friends declared in Signature
311 struct FrameInfo;
312 struct VASigCookie;
313 #if defined(DACCESS_COMPILE)
314 class  DacDbiInterfaceImpl;
315 #endif // DACCESS_COMPILE
316
317 //---------------------------------------------------------------------------------------
318 //
319 // Currently, PCCOR_SIGNATURE is used all over the runtime to represent a signature, which is just 
320 // an array of bytes.  The problem with PCCOR_SIGNATURE is that it doesn't tell you the length of 
321 // the signature (i.e. the number of bytes in the array).  This is particularly troublesome for DAC, 
322 // which needs to know how much memory to grab from out of process.  This class is an encapsulation 
323 // over PCCOR_SIGNATURE AND the length of the signature it points to.
324 //
325 // Notes:
326 //    This class is meant to be read-only.  Moreover, preferrably we should never read the raw 
327 //    PCCOR_SIGNATURE pointer directly, but there are likely some cases where it is inevitable.
328 //    We should keep these to a minimum.
329 //
330 //    We should move over to Signature instead of PCCOR_SIGNATURE.  
331 //
332 //    To get a Signature, you can create one yourself by using a constructor.  However, it's recommended 
333 //    that you check whether the Signature should be constructed at a lower level.  For example, instead of 
334 //    creating a Signature in FramedMethodFrame::PromoteCallerStackWalker(), we should add a member function
335 //    to MethodDesc to return a Signature.
336 //
337
338 class Signature
339 {
340 public:
341     // create an empty Signature
342     Signature();
343
344     // this is the primary constructor
345     Signature(PCCOR_SIGNATURE pSig,
346               DWORD           cbSig);
347
348     // check whether the signature is empty, i.e. have a NULL PCCOR_SIGNATURE
349     BOOL IsEmpty() const;
350
351     // create a SigParser from the signature
352     SigParser CreateSigParser() const;
353
354     // create a SigPointer from the signature
355     SigPointer CreateSigPointer() const;
356
357     // pretty print the signature
358     void PrettyPrint(const CHAR *        pszMethodName,
359                      CQuickBytes *       pqbOut,
360                      IMDInternalImport * pIMDI) const;
361
362     // retrieve the raw PCCOR_SIGNATURE pointer
363     PCCOR_SIGNATURE GetRawSig() const;
364
365     // retrieve the length of the signature
366     DWORD           GetRawSigLen() const;
367
368 private:
369     PCCOR_SIGNATURE m_pSig;
370     DWORD           m_cbSig;
371 };  // class Signature
372
373
374 #ifdef _DEBUG
375 #define MAX_CACHED_SIG_SIZE     3       // To excercize non-cached code path
376 #else
377 #define MAX_CACHED_SIG_SIZE     15
378 #endif
379
380
381 //---------------------------------------------------------------------------------------
382 // 
383 // A substitution represents the composition of several formal type instantiations
384 // It is used when matching formal signatures across the inheritance hierarchy.
385 //
386 // It has the form of a linked list:
387 //   [mod_1, <inst_1>] ->
388 //   [mod_2, <inst_2>] ->
389 //   ...
390 //   [mod_n, <inst_n>]
391 //
392 // Here the types in <inst_1> must be resolved in the scope of module mod_1 but
393 // may contain type variables instantiated by <inst_2>
394 // ...
395 // and the types in <inst_(n-1)> must be resolved in the scope of mould mod_(n-1) but
396 // may contain type variables instantiated by <inst_n>
397 //
398 // Any type variables in <inst_n> are treated as "free".
399 // 
400 class Substitution
401 {
402 private:
403     Module *             m_pModule; // Module in which instantiation lives (needed to resolve typerefs)
404     SigPointer           m_sigInst;
405     const Substitution * m_pNext;
406
407 public:
408     Substitution()
409     { 
410         LIMITED_METHOD_CONTRACT;
411         m_pModule = NULL; 
412         m_pNext = NULL;
413     }
414     
415     Substitution(
416         Module *             pModuleArg, 
417         const SigPointer &   sigInst, 
418         const Substitution * pNextSubstitution)
419     { 
420         LIMITED_METHOD_CONTRACT;
421         m_pModule = pModuleArg; 
422         m_sigInst = sigInst;
423         m_pNext = pNextSubstitution;
424     }
425
426     Substitution(
427         mdToken              parentTypeDefOrRefOrSpec, 
428         Module *             pModuleArg, 
429         const Substitution * nextArg);
430     
431     Substitution(const Substitution & subst)
432     { 
433         LIMITED_METHOD_CONTRACT;
434         m_pModule = subst.m_pModule; 
435         m_sigInst = subst.m_sigInst;
436         m_pNext = subst.m_pNext;
437     }
438     void DeleteChain();
439
440     Module * GetModule() const { LIMITED_METHOD_DAC_CONTRACT; return m_pModule; }
441     const Substitution * GetNext() const { LIMITED_METHOD_DAC_CONTRACT; return m_pNext; }
442     const SigPointer & GetInst() const { LIMITED_METHOD_DAC_CONTRACT; return m_sigInst; }
443     DWORD GetLength() const;
444     
445     void CopyToArray(Substitution * pTarget /* must have type Substitution[GetLength()] */ ) const;
446
447 };  // class Substitution
448
449 //---------------------------------------------------------------------------------------
450 // 
451 // Linked list that records what tokens are currently being compared for equivalence. This prevents
452 // infinite recursion when types refer to each other in a cycle, e.g. a delegate that takes itself as
453 // a parameter or a struct that declares a field of itself (illegal but we don't know at this point).
454 // 
455 class TokenPairList
456 {
457 public:
458     // Chain using this constructor when comparing two typedefs for equivalence.
459     TokenPairList(mdToken token1, Module *pModule1, mdToken token2, Module *pModule2, TokenPairList *pNext)
460         : m_token1(token1), m_token2(token2),
461           m_pModule1(pModule1), m_pModule2(pModule2),
462           m_bInTypeEquivalenceForbiddenScope(pNext == NULL ? FALSE : pNext->m_bInTypeEquivalenceForbiddenScope),
463           m_pNext(pNext)
464     { LIMITED_METHOD_CONTRACT; }
465
466     static BOOL Exists(TokenPairList *pList, mdToken token1, Module *pModule1, mdToken token2, Module *pModule2)
467     {
468         LIMITED_METHOD_CONTRACT;
469         while (pList != NULL)
470         {
471             if (pList->m_token1 == token1 && pList->m_pModule1 == pModule1 &&
472                 pList->m_token2 == token2 && pList->m_pModule2 == pModule2)
473                 return TRUE;
474
475             if (pList->m_token1 == token2 && pList->m_pModule1 == pModule2 &&
476                 pList->m_token2 == token1 && pList->m_pModule2 == pModule1)
477                 return TRUE;
478
479             pList = pList->m_pNext;
480         }
481         return FALSE;
482     }
483
484     static BOOL InTypeEquivalenceForbiddenScope(TokenPairList *pList)
485     {
486         return (pList == NULL ? FALSE : pList->m_bInTypeEquivalenceForbiddenScope);
487     }
488
489     // Chain using this method when comparing type specs.
490     static TokenPairList AdjustForTypeSpec(TokenPairList *pTemplate, Module *pTypeSpecModule, PCCOR_SIGNATURE pTypeSpecSig, DWORD cbTypeSpecSig);
491     static TokenPairList AdjustForTypeEquivalenceForbiddenScope(TokenPairList *pTemplate);
492
493 private:
494     TokenPairList(TokenPairList *pTemplate)
495         : m_token1(pTemplate ? pTemplate->m_token1 : mdTokenNil),
496           m_token2(pTemplate ? pTemplate->m_token2 : mdTokenNil),
497           m_pModule1(pTemplate ? pTemplate->m_pModule1 : NULL),
498           m_pModule2(pTemplate ? pTemplate->m_pModule2 : NULL),
499           m_bInTypeEquivalenceForbiddenScope(pTemplate ? pTemplate->m_bInTypeEquivalenceForbiddenScope : FALSE),
500           m_pNext(pTemplate ? pTemplate->m_pNext : NULL)
501     { LIMITED_METHOD_CONTRACT; }
502
503     mdToken m_token1, m_token2;
504     Module *m_pModule1, *m_pModule2;
505     BOOL m_bInTypeEquivalenceForbiddenScope;
506     TokenPairList *m_pNext;
507 };  // class TokenPairList
508
509 //---------------------------------------------------------------------------------------
510 // 
511 class MetaSig
512 {
513     public:
514         enum MetaSigKind { 
515             sigMember, 
516             sigLocalVars,
517             sigField,
518             };
519
520         //------------------------------------------------------------------
521         // Common init used by other constructors
522         //------------------------------------------------------------------
523         void Init(PCCOR_SIGNATURE szMetaSig,
524                 DWORD cbMetaSig,
525                 Module* pModule, 
526                 const SigTypeContext *pTypeContext, 
527                 MetaSigKind kind = sigMember);
528
529         //------------------------------------------------------------------
530         // Constructor. Warning: Does NOT make a copy of szMetaSig.
531         //
532         // The instantiations are used to fill in type variables on calls
533         // to PeekArg, GetReturnType, GetNextArg, GetTypeHandle, GetRetTypeHandle and
534         // so on.  
535         //
536         // Please make sure you know what you're doing by leaving classInst and methodInst to default NULL
537         // Are you sure the signature cannot contain type parameters (E_T_VAR, E_T_MVAR)?
538         //------------------------------------------------------------------
539         MetaSig(PCCOR_SIGNATURE szMetaSig, 
540                 DWORD cbMetaSig,
541                 Module* pModule, 
542                 const SigTypeContext *pTypeContext, 
543                 MetaSigKind kind = sigMember)
544         {
545             WRAPPER_NO_CONTRACT;
546             Init(szMetaSig, cbMetaSig, pModule, pTypeContext, kind);
547         }
548
549         // this is just a variation of the previous constructor to ease the transition to Signature
550         MetaSig(const Signature &      signature,
551                 Module               * pModule, 
552                 const SigTypeContext * pTypeContext, 
553                 MetaSigKind            kind = sigMember)
554         {
555             WRAPPER_NO_CONTRACT;
556             Init(signature.GetRawSig(), signature.GetRawSigLen(), pModule, pTypeContext, kind);
557         }
558
559         // The following create MetaSigs for parsing the signature of the given method.  
560         // They are identical except that they give slightly different 
561         // type contexts.  (Note the type context will only be relevant if we 
562         // are parsing a method on an array type or on a generic type.)
563         // See TypeCtxt.h for more details.
564         // If declaringType is omitted then a *representative* instantiation may be obtained from pMD or pFD
565         MetaSig(MethodDesc *pMD, TypeHandle declaringType = TypeHandle());
566         MetaSig(MethodDesc *pMD, Instantiation classInst, Instantiation methodInst);
567
568         MetaSig(FieldDesc *pFD, TypeHandle declaringType = TypeHandle());
569
570         // Used to avoid touching metadata for mscorlib methods.  Nb. only use for non-generic methods.
571         MetaSig(BinderMethodID id);
572
573         MetaSig(LPHARDCODEDMETASIG pwzMetaSig);
574
575         //------------------------------------------------------------------
576         // Returns type of current argument index. Returns ELEMENT_TYPE_END
577         // if already past end of arguments.
578         //------------------------------------------------------------------
579         CorElementType PeekArg() const;
580
581         //------------------------------------------------------------------
582         // Returns type of current argument index. Returns ELEMENT_TYPE_END
583         // if already past end of arguments.
584         //------------------------------------------------------------------
585         CorElementType PeekArgNormalized(TypeHandle * pthValueType = NULL) const;
586
587         //------------------------------------------------------------------
588         // Returns type of current argument, then advances the argument
589         // index. Returns ELEMENT_TYPE_END if already past end of arguments.
590         // This method updates m_pLastType
591         //------------------------------------------------------------------
592         CorElementType NextArg();
593
594         //------------------------------------------------------------------
595         // Advance the argument index. Can be used with GetArgProps() to
596         // to iterate when you do not have a valid type context.
597         // This method updates m_pLastType
598         //------------------------------------------------------------------
599         void SkipArg();
600
601         //------------------------------------------------------------------
602         // Returns a read-only SigPointer for the m_pLastType set by one
603         // of NextArg() or SkipArg()
604         // This allows extracting more information for complex types.
605         //------------------------------------------------------------------
606         const SigPointer & GetArgProps() const
607         {
608             LIMITED_METHOD_CONTRACT;
609             return m_pLastType;
610         }
611
612         //------------------------------------------------------------------
613         // Returns a read-only SigPointer for the return type.
614         // This allows extracting more information for complex types.
615         //------------------------------------------------------------------
616         const SigPointer & GetReturnProps() const
617         {
618             LIMITED_METHOD_CONTRACT;
619             return m_pRetType;
620         }
621
622
623         //------------------------------------------------------------------------
624         // Returns # of arguments. Does not count the return value.
625         // Does not count the "this" argument (which is not reflected om the
626         // sig.) 64-bit arguments are counted as one argument.
627         //------------------------------------------------------------------------
628         UINT NumFixedArgs()
629         {
630             LIMITED_METHOD_DAC_CONTRACT;
631             return m_nArgs;
632         }
633         
634         //----------------------------------------------------------
635         // Returns the calling convention (see IMAGE_CEE_CS_CALLCONV_*
636         // defines in cor.h) - throws.
637         //----------------------------------------------------------
638         static BYTE GetCallingConvention(
639             Module          *pModule, 
640             const Signature &signature)
641         {
642             CONTRACTL
643             {
644                 THROWS;
645                 GC_NOTRIGGER;
646                 MODE_ANY;
647                 SUPPORTS_DAC;
648             }
649             CONTRACTL_END
650             
651             PCCOR_SIGNATURE pSig = signature.GetRawSig();
652             
653             if (signature.GetRawSigLen() < 1)
654             {
655                 ThrowHR(COR_E_BADIMAGEFORMAT);
656             }
657             return (BYTE)(IMAGE_CEE_CS_CALLCONV_MASK & CorSigUncompressCallingConv(/*modifies*/pSig));
658         }
659         
660         //----------------------------------------------------------
661         // Returns the calling convention (see IMAGE_CEE_CS_CALLCONV_*
662         // defines in cor.h) - doesn't throw.
663         //----------------------------------------------------------
664         __checkReturn 
665         static HRESULT GetCallingConvention_NoThrow(
666             Module          *pModule, 
667             const Signature &signature, 
668             BYTE            *pbCallingConvention)
669         {
670             CONTRACTL
671             {
672                 NOTHROW;
673                 GC_NOTRIGGER;
674                 MODE_ANY;
675                 SUPPORTS_DAC;
676             }
677             CONTRACTL_END
678             
679             PCCOR_SIGNATURE pSig = signature.GetRawSig();
680             
681             if (signature.GetRawSigLen() < 1)
682             {
683                 *pbCallingConvention = 0;
684                 return COR_E_BADIMAGEFORMAT;
685             }
686             *pbCallingConvention = (BYTE)(IMAGE_CEE_CS_CALLCONV_MASK & CorSigUncompressCallingConv(/*modifies*/pSig));
687             return S_OK;
688         }
689         
690         //----------------------------------------------------------
691         // Returns the calling convention (see IMAGE_CEE_CS_CALLCONV_*
692         // defines in cor.h)
693         //----------------------------------------------------------
694         BYTE GetCallingConvention()
695         {
696             LIMITED_METHOD_CONTRACT;
697             SUPPORTS_DAC;
698             return m_CallConv & IMAGE_CEE_CS_CALLCONV_MASK; 
699         }
700
701         //----------------------------------------------------------
702         // Returns the calling convention & flags (see IMAGE_CEE_CS_CALLCONV_*
703         // defines in cor.h)
704         //----------------------------------------------------------
705         BYTE GetCallingConventionInfo()
706         {
707             LIMITED_METHOD_DAC_CONTRACT;
708
709             return m_CallConv;
710         }
711
712         //----------------------------------------------------------
713         // Has a 'this' pointer?
714         //----------------------------------------------------------
715         BOOL HasThis()
716         {
717             LIMITED_METHOD_CONTRACT;
718
719             return m_CallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS;
720         }  
721
722         //----------------------------------------------------------
723         // Has a explicit 'this' pointer?
724         //----------------------------------------------------------
725         BOOL HasExplicitThis()
726         {
727             LIMITED_METHOD_CONTRACT;
728
729             return m_CallConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS;
730         }  
731                 
732         //----------------------------------------------------------
733         // Is a generic method with explicit arity?
734         //----------------------------------------------------------
735         BOOL IsGenericMethod()
736         {
737             LIMITED_METHOD_CONTRACT;
738             return m_CallConv & IMAGE_CEE_CS_CALLCONV_GENERIC;
739         }  
740         
741         //----------------------------------------------------------
742         // Is vararg?
743         //----------------------------------------------------------
744         BOOL IsVarArg()
745         {
746             WRAPPER_NO_CONTRACT;
747             SUPPORTS_DAC;
748             return GetCallingConvention() == IMAGE_CEE_CS_CALLCONV_VARARG;
749         }
750         
751         //----------------------------------------------------------
752         // Is vararg?
753         //----------------------------------------------------------
754         static BOOL IsVarArg(Module *pModule, const Signature &signature)
755         {
756             CONTRACTL
757             {
758                 NOTHROW;
759                 GC_NOTRIGGER;
760                 MODE_ANY;
761                 SUPPORTS_DAC;
762             }
763             CONTRACTL_END
764             
765             HRESULT hr;
766             BYTE    nCallingConvention;
767             
768             hr = GetCallingConvention_NoThrow(pModule, signature, &nCallingConvention);
769             if (FAILED(hr))
770             {   // Invalid signatures are not VarArg
771                 return FALSE;
772             }
773             return nCallingConvention == IMAGE_CEE_CS_CALLCONV_VARARG;
774         }
775         
776         Module* GetModule() const
777         {
778             LIMITED_METHOD_DAC_CONTRACT;
779             
780             return m_pModule;
781         }
782         
783         //----------------------------------------------------------
784         // Returns the unmanaged calling convention.
785         //----------------------------------------------------------
786         static BOOL GetUnmanagedCallingConvention(Module *pModule, PCCOR_SIGNATURE pSig, ULONG cSig, CorPinvokeMap *pPinvokeMapOut);
787
788         //------------------------------------------------------------------
789         // Like NextArg, but return only normalized type (enums flattned to 
790         // underlying type ...
791         //------------------------------------------------------------------
792         CorElementType 
793         NextArgNormalized(TypeHandle * pthValueType = NULL)
794         {
795             CONTRACTL
796             {
797                 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
798                 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
799                 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
800                 MODE_ANY;
801                 SUPPORTS_DAC;
802             }
803             CONTRACTL_END
804
805             m_pLastType = m_pWalk;
806             if (m_iCurArg == m_nArgs)
807             {
808                 return ELEMENT_TYPE_END;
809             }
810             else
811             {
812                 m_iCurArg++;
813                 CorElementType mt = m_pWalk.PeekElemTypeNormalized(m_pModule, &m_typeContext, pthValueType);
814                 // We should not hit ELEMENT_TYPE_END in the middle of the signature
815                 if (mt == ELEMENT_TYPE_END)
816                 {
817                     THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, (Module *)NULL);
818                 }
819                 IfFailThrowBF(m_pWalk.SkipExactlyOne(), BFA_BAD_SIGNATURE, (Module *)NULL);
820                 return mt;
821             }
822         } // NextArgNormalized
823
824         // Tests if the return type is an object ref.  Loads types
825         // if needed (though it shouldn't really need to)
826         BOOL IsObjectRefReturnType();
827
828         //------------------------------------------------------------------------
829         // Compute element size from CorElementType and optional valuetype.
830         //------------------------------------------------------------------------
831         static UINT GetElemSize(CorElementType etype, TypeHandle thValueType);
832
833         UINT GetReturnTypeSize() 
834         {    
835             WRAPPER_NO_CONTRACT;
836             SUPPORTS_DAC;
837             return m_pRetType.SizeOf(m_pModule, &m_typeContext);
838         }
839
840         //------------------------------------------------------------------
841         // Perform type-specific GC promotion on the value (based upon the
842         // last type retrieved by NextArg()).
843         //------------------------------------------------------------------
844         VOID GcScanRoots(ArgDestination *pValue, promote_func *fn,
845                          ScanContext* sc, promote_carefully_func *fnc = NULL);
846
847         //------------------------------------------------------------------
848         // Is the return type 64 bit?
849         //------------------------------------------------------------------
850         BOOL Is64BitReturn() const
851         {
852             WRAPPER_NO_CONTRACT;
853             CorElementType rt = GetReturnTypeNormalized();
854             return (rt == ELEMENT_TYPE_I8 || rt == ELEMENT_TYPE_U8 || rt == ELEMENT_TYPE_R8);
855         }
856
857         //------------------------------------------------------------------
858         // Is the return type floating point?
859         //------------------------------------------------------------------
860         BOOL HasFPReturn()
861         {
862             WRAPPER_NO_CONTRACT;
863             CorElementType rt = GetReturnTypeNormalized();
864             return (rt == ELEMENT_TYPE_R4 || rt == ELEMENT_TYPE_R8);
865         }
866
867         //------------------------------------------------------------------
868         // reset: goto start pos
869         //------------------------------------------------------------------
870         VOID Reset();
871
872         //------------------------------------------------------------------
873         // current position of the arg iterator
874         //------------------------------------------------------------------
875         UINT GetArgNum()
876         {
877             LIMITED_METHOD_CONTRACT;
878             return m_iCurArg;
879         }
880
881         //------------------------------------------------------------------
882         // Returns CorElementType of return value, taking into account
883         // any instantiations due to generics.  Does not load types.
884         // Does not return normalized type.
885         //------------------------------------------------------------------
886         CorElementType GetReturnType() const;
887
888         BOOL IsReturnTypeVoid() const;
889
890         CorElementType GetReturnTypeNormalized(TypeHandle * pthValueType = NULL) const;
891
892         //------------------------------------------------------------------
893         // used to treat some sigs as special case vararg
894         // used by calli to unmanaged target
895         //------------------------------------------------------------------
896         BOOL IsTreatAsVarArg()
897         {
898             LIMITED_METHOD_DAC_CONTRACT;
899             
900             return (m_flags & TREAT_AS_VARARG);
901         }
902
903         //------------------------------------------------------------------
904         // Determines if the current argument is System/String.
905         // Caller must determine first that the argument type is 
906         // ELEMENT_TYPE_CLASS or ELEMENT_TYPE_STRING.  This may be used during
907         // GC.
908         //------------------------------------------------------------------
909         BOOL IsStringType() const;
910
911         //------------------------------------------------------------------
912         // Determines if the current argument is a particular class.
913         // Caller must determine first that the argument type 
914         // is ELEMENT_TYPE_CLASS.
915         //------------------------------------------------------------------
916         BOOL IsClass(LPCUTF8 szClassName) const;
917
918
919         //------------------------------------------------------------------
920         // This method will return a TypeHandle for the last argument
921         // examined.
922         // If NextArg() returns ELEMENT_TYPE_BYREF, you can also call GetByRefType()
923         // to get to the underlying type of the byref
924         //------------------------------------------------------------------
925         TypeHandle GetLastTypeHandleNT() const
926         {
927              WRAPPER_NO_CONTRACT;
928              return m_pLastType.GetTypeHandleNT(m_pModule, &m_typeContext);
929         }
930
931         //------------------------------------------------------------------
932         // This method will return a TypeHandle for the last argument
933         // examined.
934         // If NextArg() returns ELEMENT_TYPE_BYREF, you can also call GetByRefType()
935         // to get to the underlying type of the byref
936         //------------------------------------------------------------------
937         TypeHandle GetLastTypeHandleThrowing(ClassLoader::LoadTypesFlag fLoadTypes = ClassLoader::LoadTypes,
938                                              ClassLoadLevel level = CLASS_LOADED,
939                                              BOOL dropGenericArgumentLevel = FALSE) const
940         {
941              WRAPPER_NO_CONTRACT;
942              return m_pLastType.GetTypeHandleThrowing(m_pModule, &m_typeContext, fLoadTypes, 
943                                                       level, dropGenericArgumentLevel);
944         }
945
946         //------------------------------------------------------------------
947         // Returns the TypeHandle for the return type of the signature
948         //------------------------------------------------------------------
949         TypeHandle GetRetTypeHandleNT() const
950         {
951              WRAPPER_NO_CONTRACT;
952              return m_pRetType.GetTypeHandleNT(m_pModule, &m_typeContext);
953         }
954
955         TypeHandle GetRetTypeHandleThrowing(ClassLoader::LoadTypesFlag fLoadTypes = ClassLoader::LoadTypes,
956                                             ClassLoadLevel level = CLASS_LOADED) const
957         {
958              WRAPPER_NO_CONTRACT;
959              return m_pRetType.GetTypeHandleThrowing(m_pModule, &m_typeContext, fLoadTypes, level);
960         }
961
962         //------------------------------------------------------------------
963         // Returns the base type of the byref type of the last argument examined
964         // which needs to have been ELEMENT_TYPE_BYREF.
965         // For object references, the class being accessed byref is also returned in *pTy.
966         // eg. for "int32 &",            return value = ELEMENT_TYPE_I4,    *pTy= ???
967         //     for "System.Exception &", return value = ELEMENT_TYPE_CLASS, *pTy=System.Exception
968         // Note that byref to byref is not allowed, and so the return value
969         // can never be ELEMENT_TYPE_BYREF.
970         //------------------------------------------------------------------
971         CorElementType GetByRefType(TypeHandle* pTy) const;
972
973         // Compare types in two signatures, first applying
974         // - optional substitutions pSubst1 and pSubst2
975         //   to class type parameters (E_T_VAR) in the respective signatures
976         static 
977         BOOL 
978         CompareElementType(
979             PCCOR_SIGNATURE &    pSig1, 
980             PCCOR_SIGNATURE &    pSig2, 
981             PCCOR_SIGNATURE      pEndSig1, 
982             PCCOR_SIGNATURE      pEndSig2, 
983             Module *             pModule1, 
984             Module *             pModule2, 
985             const Substitution * pSubst1, 
986             const Substitution * pSubst2, 
987             TokenPairList *      pVisited = NULL);
988
989
990
991         // If pTypeDef1 is C<...> and pTypeDef2 is C<...> (for possibly different instantiations)
992         // then check C<!0, ... !n> @ pSubst1 == C<!0, ..., !n> @ pSubst2, i.e.
993         // that the head type (C) is the same and that when the head type is treated
994         // as an uninstantiated type definition and we apply each of the substitutions 
995         // then the same type results.  This effectively checks that the two substitutions
996         // are equivalent.
997         static BOOL CompareTypeDefsUnderSubstitutions(MethodTable *pTypeDef1,          MethodTable *pTypeDef2,
998                                                       const Substitution*   pSubst1,   const Substitution*   pSubst2,
999                                                       TokenPairList *pVisited = NULL);
1000
1001
1002         // Compare two complete method signatures, first applying optional substitutions pSubst1 and pSubst2
1003         // to class type parameters (E_T_VAR) in the respective signatures
1004         static BOOL CompareMethodSigs(
1005             PCCOR_SIGNATURE pSig1, 
1006             DWORD       cSig1, 
1007             Module*     pModule1, 
1008             const Substitution* pSubst1,
1009             PCCOR_SIGNATURE pSig2, 
1010             DWORD       cSig2, 
1011             Module*     pModule2,
1012             const Substitution* pSubst2,
1013             TokenPairList *pVisited = NULL
1014         );
1015
1016         // Nonthrowing version of CompareMethodSigs
1017         //
1018         //   Return S_OK if they match
1019         //          S_FALSE if they don't match
1020         //          FAILED  if OOM or some other blocking error
1021         //
1022         static HRESULT CompareMethodSigsNT(
1023             PCCOR_SIGNATURE pSig1, 
1024             DWORD       cSig1, 
1025             Module*     pModule1, 
1026             const Substitution* pSubst1,
1027             PCCOR_SIGNATURE pSig2, 
1028             DWORD       cSig2, 
1029             Module*     pModule2,
1030             const Substitution* pSubst2,
1031             TokenPairList *pVisited = NULL
1032         );
1033
1034         static BOOL CompareFieldSigs(
1035             PCCOR_SIGNATURE pSig1, 
1036             DWORD       cSig1, 
1037             Module*     pModule1, 
1038             PCCOR_SIGNATURE pSig2, 
1039             DWORD       cSig2, 
1040             Module*     pModule2,
1041             TokenPairList *pVisited = NULL
1042         );
1043
1044         static BOOL CompareMethodSigs(MetaSig &msig1,
1045                                       MetaSig &msig2,
1046                                       BOOL ignoreCallconv);
1047
1048         // Is each set of constraints on the implementing method's type parameters a subset
1049         // of the corresponding set of constraints on the declared method's type parameters,
1050         // given a subsitution for the latter's (class) type parameters.
1051         // This is used by the class loader to verify type safety of method overriding and interface implementation.
1052         static BOOL CompareMethodConstraints(const Substitution *pSubst1,
1053                                              Module *pModule1, 
1054                                              mdMethodDef tok1, //implementing method
1055                                              const Substitution *pSubst2,
1056                                              Module *pModule2,
1057                                              mdMethodDef tok2); //declared method
1058
1059 private:
1060         static BOOL CompareVariableConstraints(const Substitution *pSubst1,
1061                                                Module *pModule1, mdGenericParam tok1, //overriding
1062                                                const Substitution *pSubst2,
1063                                                Module *pModule2, mdGenericParam tok2); //overridden
1064
1065         static BOOL CompareTypeDefOrRefOrSpec(Module *pModule1, mdToken tok1,
1066                                               const Substitution *pSubst1,
1067                                               Module *pModule2, mdToken tok2,
1068                                               const Substitution *pSubst2,
1069                                               TokenPairList *pVisited);
1070         static BOOL CompareTypeSpecToToken(mdTypeSpec tk1,
1071                                            mdToken tk2,
1072                                            Module *pModule1,
1073                                            Module *pModule2,
1074                                            const Substitution *pSubst1,
1075                                            TokenPairList *pVisited);
1076
1077         static BOOL CompareElementTypeToToken(PCCOR_SIGNATURE &pSig1,
1078                                              PCCOR_SIGNATURE pEndSig1, // end of sig1
1079                                              mdToken         tk2,
1080                                              Module*         pModule1,
1081                                              Module*         pModule2,
1082                                              const Substitution*   pSubst1,
1083                                              TokenPairList *pVisited);
1084
1085 public:
1086
1087         //------------------------------------------------------------------
1088         // Ensures that all the value types in the sig are loaded. This
1089         // should be called on sig's that have value types before they
1090         // are passed to Call(). This ensures that value classes will not
1091         // be loaded during the operation to determine the size of the
1092         // stack. Thus preventing the resulting GC hole.
1093         //------------------------------------------------------------------
1094         static void EnsureSigValueTypesLoaded(MethodDesc *pMD);
1095
1096         // this walks the sig and checks to see if all  types in the sig can be loaded
1097         static void CheckSigTypesCanBeLoaded(MethodDesc *pMD);
1098         
1099         const SigTypeContext *GetSigTypeContext() const { LIMITED_METHOD_CONTRACT; return &m_typeContext; }
1100
1101         // Disallow copy constructor.
1102         MetaSig(MetaSig *pSig);
1103
1104         void SetHasParamTypeArg()
1105         {
1106             LIMITED_METHOD_CONTRACT;
1107             m_CallConv |= CORINFO_CALLCONV_PARAMTYPE;
1108         }
1109
1110         void SetTreatAsVarArg()
1111         {
1112             LIMITED_METHOD_CONTRACT;
1113             m_flags |= TREAT_AS_VARARG;
1114         }
1115
1116
1117     // These are protected because Reflection subclasses Metasig
1118     protected:
1119
1120         enum MetaSigFlags
1121         {
1122             SIG_RET_TYPE_INITTED    = 0x01,
1123             TREAT_AS_VARARG         = 0x02,     // used to treat some sigs as special case vararg
1124                                                 // used by calli to unmanaged target
1125         };
1126
1127         Module*      m_pModule;
1128         SigTypeContext m_typeContext;   // Instantiation for type parameters
1129
1130         SigPointer   m_pStart;
1131         SigPointer   m_pWalk;
1132         SigPointer   m_pLastType;
1133         SigPointer   m_pRetType;
1134         UINT32       m_nArgs;
1135         UINT32       m_iCurArg;
1136
1137         // The following are cached so we don't the signature
1138         //  multiple times
1139
1140         CorElementType  m_corNormalizedRetType;
1141         BYTE            m_flags;
1142         BYTE            m_CallConv;
1143 };  // class MetaSig
1144
1145
1146 BOOL IsTypeRefOrDef(LPCSTR szClassName, Module *pModule, mdToken token);
1147
1148 #if defined(FEATURE_TYPEEQUIVALENCE) && !defined(DACCESS_COMPILE)
1149
1150 // A helper struct representing data stored in the TypeIdentifierAttribute.
1151 struct TypeIdentifierData
1152 {
1153     TypeIdentifierData() : m_cbScope(0), m_pchScope(NULL), m_cbIdentifierNamespace(0), m_pchIdentifierNamespace(NULL),
1154                            m_cbIdentifierName(0), m_pchIdentifierName(NULL) {}
1155
1156     HRESULT Init(Module *pModule, mdToken tk);
1157     BOOL IsEqual(const TypeIdentifierData & data) const;
1158     
1159 private:
1160     SIZE_T  m_cbScope;
1161     LPCUTF8 m_pchScope;
1162     SIZE_T  m_cbIdentifierNamespace;
1163     LPCUTF8 m_pchIdentifierNamespace;
1164     SIZE_T  m_cbIdentifierName;
1165     LPCUTF8 m_pchIdentifierName;
1166 };
1167
1168 #endif // FEATURE_TYPEEQUIVALENCE && !DACCESS_COMPILE
1169
1170 // fResolved is TRUE when one of the tokens is a resolved TypeRef. This is used to restrict
1171 // type equivalence checks for value types.
1172 BOOL CompareTypeTokens(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModule2, TokenPairList *pVisited = NULL);
1173
1174 // Nonthrowing version of CompareTypeTokens.
1175 //
1176 //   Return S_OK if they match
1177 //          S_FALSE if they don't match
1178 //          FAILED  if OOM or some other blocking error
1179 //
1180 HRESULT  CompareTypeTokensNT(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModule2);
1181
1182 // TRUE if the two TypeDefs have the same layout and field marshal information.
1183 BOOL CompareTypeLayout(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModule2);
1184 BOOL CompareTypeDefsForEquivalence(mdToken tk1, mdToken tk2, Module *pModule1, Module *pModule2, TokenPairList *pVisited);
1185 BOOL IsTypeDefEquivalent(mdToken tk, Module *pModule);
1186 BOOL IsTypeDefExternallyVisible(mdToken tk, Module *pModule, DWORD dwAttrs);
1187
1188 void ReportPointersFromValueType(promote_func *fn, ScanContext *sc, PTR_MethodTable pMT, PTR_VOID pSrc);
1189
1190 #endif /* _H_SIGINFO */