| 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 | // typectxt.h | 
| 6 | // | 
| 7 |  | 
| 8 | // | 
| 9 |  | 
| 10 | #ifndef _H_TYPECTXT | 
| 11 | #define _H_TYPECTXT | 
| 12 |  | 
| 13 | //------------------------------------------------------------------------ | 
| 14 | // A signature type context gives the information necessary to interpret  | 
| 15 | // the ELEMENT_TYPE_VAR and ELEMENT_TYPE_MVAR elements of a regular | 
| 16 | // metadata signature.  These are usually stack allocated at appropriate | 
| 17 | // points where the SigPointer objects are created, or are allocated | 
| 18 | // inside a MetaSig (which are themselves normally stack allocated) | 
| 19 | // | 
| 20 | // They are normally passed as "const SigTypeContext *". | 
| 21 | //------------------------------------------------------------------------ | 
| 22 |  | 
| 23 | class SigTypeContext | 
| 24 | { | 
| 25 | public: | 
| 26 |     // Store pointers first and DWORDs second to ensure good packing on 64-bit | 
| 27 |     Instantiation m_classInst; | 
| 28 |     Instantiation m_methodInst; | 
| 29 |  | 
| 30 |     // Default constructor for non-generic code | 
| 31 |     inline SigTypeContext() | 
| 32 |     { WRAPPER_NO_CONTRACT; InitTypeContext(this); } | 
| 33 |  | 
| 34 |  | 
| 35 |     // Initialize a type context given instantiations. | 
| 36 |     inline SigTypeContext(Instantiation classInst, Instantiation methodInst) | 
| 37 |     { WRAPPER_NO_CONTRACT; InitTypeContext(classInst, methodInst, this); } | 
| 38 |  | 
| 39 |  | 
| 40 |     // Initialize a type context from a MethodDesc.  If this is a MethodDesc that gets | 
| 41 |     // shared between generic instantiations (e.g. one being jitted by a code-sharing JIT) | 
| 42 |     // and a null declaring Type is passed then the type context will  | 
| 43 |     // be a representative context, not an exact one. | 
| 44 |     // This is sufficient for most purposes, e.g. GC and field layout, because | 
| 45 |     // these operations are "parametric", i.e. behave the same for all shared types. | 
| 46 |     // | 
| 47 |     // If declaringType is non-null, then the MethodDesc is assumed to be | 
| 48 |     // shared between generic classes, and the type handle is used to give the  | 
| 49 |     // exact type context.  The method should be one of the methods supported by the | 
| 50 |     // given type handle. | 
| 51 |     // | 
| 52 |     // If the method is a method in an array type then the type context will | 
| 53 |     // contain one item in the class instantiation corresponding to the  | 
| 54 |     // element type of the array. | 
| 55 |     // | 
| 56 |     // Finally, exactMethodInst should be specified if md might represent a generic method definition, | 
| 57 |     // as type parameters are not always available off the method desc for generic method definitions without | 
| 58 |     // forcing a load. Typically the caller will use MethodDesc::LoadMethodInstantiation. | 
| 59 |     inline SigTypeContext(MethodDesc *md)                  | 
| 60 |     { WRAPPER_NO_CONTRACT; InitTypeContext(md,this); } | 
| 61 |  | 
| 62 |     inline SigTypeContext(MethodDesc *md, TypeHandle declaringType)                                | 
| 63 |     { WRAPPER_NO_CONTRACT; InitTypeContext(md,declaringType,this); } | 
| 64 |  | 
| 65 |     inline SigTypeContext(MethodDesc *md, TypeHandle declaringType, Instantiation exactMethodInst) | 
| 66 |     { WRAPPER_NO_CONTRACT; InitTypeContext(md,declaringType,exactMethodInst,this); } | 
| 67 |  | 
| 68 |     // This is similar to the one above except that exact  | 
| 69 |     // instantiations are provided explicitly. | 
| 70 |     // This will only normally be used when the code is shared | 
| 71 |     // between generic instantiations and after fetching the  | 
| 72 |     // exact instantiations from the stack. | 
| 73 |     // | 
| 74 |     inline SigTypeContext(MethodDesc *md, Instantiation exactClassInst, Instantiation exactMethodInst)  | 
| 75 |     { WRAPPER_NO_CONTRACT; InitTypeContext(md,exactClassInst,exactMethodInst,this); } | 
| 76 |  | 
| 77 |     // Initialize a type context from a type handle.  This is used when  | 
| 78 |     // generating the type context for a | 
| 79 |     // any of the metadata in the class covered by the type handle apart from | 
| 80 |     // the metadata for any generic methods in the class. | 
| 81 |     // If the type handle satisfies th.IsNull() then the created type context | 
| 82 |     // will be empty. | 
| 83 |     inline SigTypeContext(TypeHandle th) | 
| 84 |     { WRAPPER_NO_CONTRACT; InitTypeContext(th,this); } | 
| 85 |  | 
| 86 |     inline SigTypeContext(FieldDesc *pFD, TypeHandle declaringType = TypeHandle()) | 
| 87 |     { WRAPPER_NO_CONTRACT; InitTypeContext(pFD,declaringType,this); } | 
| 88 |  | 
| 89 |     // Copy contructor - try not to use this.  The C++ compiler is not doing a good job | 
| 90 |     // of copy-constructor based code, and we've had perf regressions when using this too  | 
| 91 |     // much for this simple objects.  Use an explicit call to InitTypeContext instead, | 
| 92 |     // or use GetOptionalTypeContext. | 
| 93 |     inline SigTypeContext(const SigTypeContext &c) | 
| 94 |     { WRAPPER_NO_CONTRACT; InitTypeContext(&c,this); } | 
| 95 |  | 
| 96 |     // Copy contructor from a possibly-NULL pointer. | 
| 97 |     inline SigTypeContext(const SigTypeContext *c) | 
| 98 |     { WRAPPER_NO_CONTRACT; InitTypeContext(c,this); } | 
| 99 |  | 
| 100 |     static void InitTypeContext(MethodDesc *md, SigTypeContext *pRes); | 
| 101 |     static void InitTypeContext(MethodDesc *md, TypeHandle declaringType, SigTypeContext *pRes); | 
| 102 |     static void InitTypeContext(MethodDesc *md, TypeHandle declaringType, Instantiation exactMethodInst, SigTypeContext *pRes); | 
| 103 |     static void InitTypeContext(MethodDesc *md, Instantiation exactClassInst, Instantiation exactMethodInst, SigTypeContext *pRes); | 
| 104 |     static void InitTypeContext(TypeHandle th, SigTypeContext *pRes); | 
| 105 |     static void InitTypeContext(FieldDesc *pFD, TypeHandle declaringType, SigTypeContext *pRes); | 
| 106 |     inline static void InitTypeContext(Instantiation classInst, Instantiation methodInst, SigTypeContext *pRes); | 
| 107 |     inline static void InitTypeContext(SigTypeContext *); | 
| 108 |     inline static void InitTypeContext(const SigTypeContext *c, SigTypeContext *pRes); | 
| 109 |  | 
| 110 |     // These are allowed to return NULL if an empty type context is generated.  The NULL value | 
| 111 |     // can then be passed around to represent the empty type context. | 
| 112 |     // pRes must be non-null. | 
| 113 |     // pRes must initially be zero-initialized, e.g. by the default SigTypeContext constructor. | 
| 114 |     static const SigTypeContext * GetOptionalTypeContext(MethodDesc *md, TypeHandle declaringType, SigTypeContext *pRes); | 
| 115 |     static const SigTypeContext * GetOptionalTypeContext(TypeHandle th, SigTypeContext *pRes); | 
| 116 |  | 
| 117 |     // SigTypeContexts are used as part of keys for various data structures indiexed by instantiation | 
| 118 |     static BOOL Equal(const SigTypeContext *pCtx1, const SigTypeContext *pCtx2); | 
| 119 |     static BOOL IsValidTypeOnlyInstantiationOf(const SigTypeContext *pCtxTypicalMethodInstantiation, const SigTypeContext *pCtxTypeOnlyInstantiation); | 
| 120 |     BOOL IsEmpty() const { LIMITED_METHOD_CONTRACT; return m_classInst.IsEmpty() && m_methodInst.IsEmpty(); } | 
| 121 |  | 
| 122 | }; | 
| 123 |  | 
| 124 | inline void SigTypeContext::InitTypeContext(SigTypeContext *pRes) | 
| 125 | { | 
| 126 |     LIMITED_METHOD_DAC_CONTRACT; | 
| 127 | } | 
| 128 |  | 
| 129 | inline void SigTypeContext::InitTypeContext(Instantiation classInst, | 
| 130 |                                             Instantiation methodInst, | 
| 131 |                                             SigTypeContext *pRes) | 
| 132 | { | 
| 133 |     LIMITED_METHOD_CONTRACT; | 
| 134 |     pRes->m_classInst = classInst; | 
| 135 |     pRes->m_methodInst = methodInst; | 
| 136 | } | 
| 137 |  | 
| 138 |  | 
| 139 | // Copy contructor from a possibly-NULL pointer. | 
| 140 | inline void SigTypeContext::InitTypeContext(const SigTypeContext *c,SigTypeContext *pRes) | 
| 141 | { | 
| 142 |     LIMITED_METHOD_DAC_CONTRACT; | 
| 143 |     if (c) | 
| 144 |     { | 
| 145 |         pRes->m_classInst = c->m_classInst; | 
| 146 |         pRes->m_methodInst = c->m_methodInst; | 
| 147 |     } | 
| 148 |     else | 
| 149 |     { | 
| 150 |         pRes->m_classInst = Instantiation(); | 
| 151 |         pRes->m_methodInst = Instantiation(); | 
| 152 |     } | 
| 153 | } | 
| 154 |  | 
| 155 | //------------------------------------------------------------------------ | 
| 156 | // Encapsulates pointers to code:SigTypeContext and code:Substitution chain | 
| 157 | // that have been used to instantiate a generic type. The context is passed | 
| 158 | // as "const InstantiationContext *" from code:SigPointer.GetTypeHandleThrowing | 
| 159 | // down to code:TypeVarTypeDesc.SatisfiesConstraints where it is needed for | 
| 160 | // instantiating constraints attached to type arguments. | 
| 161 | //  | 
| 162 | // The reason why we need to pass these pointers down to the code that verifies | 
| 163 | // that constraints are satisified is the case when another type variable is | 
| 164 | // substituted for a type variable and this argument is constrained by a generic | 
| 165 | // type. In order to verify that constraints of the argument satisfy constraints | 
| 166 | // of the parameter, the argument constraints must be instantiated in the same | 
| 167 | // "instantiation context" as the original signature - and unfortunately this | 
| 168 | // context cannot be extracted from the rest of the information that we have | 
| 169 | // about the type that is being loaded. | 
| 170 | //  | 
| 171 | // See code:TypeVarTypeDesc.SatisfiesConstraints for more details and an | 
| 172 | // example scenario in which we are unable to verify constraints without this | 
| 173 | // context. | 
| 174 | //------------------------------------------------------------------------ | 
| 175 |  | 
| 176 | class InstantiationContext | 
| 177 | { | 
| 178 | public: | 
| 179 |     const SigTypeContext *m_pArgContext; | 
| 180 |     const Substitution *m_pSubstChain; | 
| 181 |  | 
| 182 |     inline InstantiationContext(const SigTypeContext *pArgContext = NULL, const Substitution *pSubstChain = NULL) | 
| 183 |     { | 
| 184 |         LIMITED_METHOD_DAC_CONTRACT; | 
| 185 |  | 
| 186 |         m_pArgContext = pArgContext; | 
| 187 |         m_pSubstChain = pSubstChain; | 
| 188 |     } | 
| 189 | }; | 
| 190 |  | 
| 191 | #endif | 
| 192 |  |