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