| 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 | |