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 | |
6 | #ifndef _BINDERMODULE_H_ |
7 | #define _BINDERMODULE_H_ |
8 | |
9 | class DataImage; |
10 | class Module; |
11 | class MethodTable; |
12 | class MethodDesc; |
13 | class FieldDesc; |
14 | |
15 | typedef const struct HardCodedMetaSig *LPHARDCODEDMETASIG; |
16 | |
17 | // As hard-coded metasigs are constant data ordinarily it |
18 | // wouldn't be necessary to use PTR access. However, access |
19 | // through the Binder class requires it. |
20 | typedef DPTR(const struct HardCodedMetaSig) PTR_HARDCODEDMETASIG; |
21 | |
22 | struct HardCodedMetaSig |
23 | { |
24 | const BYTE* m_pMetaSig; // metasig prefixed with INT8 length: |
25 | // length > 0 - resolved, lenght < 0 - has unresolved type references |
26 | }; |
27 | |
28 | #define DEFINE_METASIG(body) extern const body |
29 | #define DEFINE_METASIG_T(body) extern body |
30 | #define METASIG_BODY(varname, types) HardCodedMetaSig gsig_ ## varname; |
31 | #include "metasig.h" |
32 | |
33 | // |
34 | // Use the Binder objects to avoid doing unnecessary name lookup |
35 | // (esp. in the prejit case) |
36 | // |
37 | // E.g. MscorlibBinder::GetClass(CLASS__APP_DOMAIN); |
38 | // |
39 | |
40 | // BinderClassIDs are of the form CLASS__XXX |
41 | |
42 | enum BinderClassID |
43 | { |
44 | #define TYPEINFO(e,ns,c,s,g,ia,ip,if,im,gv) CLASS__ ## e, |
45 | #include "cortypeinfo.h" |
46 | #undef TYPEINFO |
47 | |
48 | #define DEFINE_CLASS(i,n,s) CLASS__ ## i, |
49 | #include "mscorlib.h" |
50 | |
51 | CLASS__MSCORLIB_COUNT, |
52 | |
53 | // Aliases for element type classids |
54 | CLASS__NIL = CLASS__ELEMENT_TYPE_END, |
55 | CLASS__VOID = CLASS__ELEMENT_TYPE_VOID, |
56 | CLASS__BOOLEAN = CLASS__ELEMENT_TYPE_BOOLEAN, |
57 | CLASS__CHAR = CLASS__ELEMENT_TYPE_CHAR, |
58 | CLASS__BYTE = CLASS__ELEMENT_TYPE_U1, |
59 | CLASS__SBYTE = CLASS__ELEMENT_TYPE_I1, |
60 | CLASS__INT16 = CLASS__ELEMENT_TYPE_I2, |
61 | CLASS__UINT16 = CLASS__ELEMENT_TYPE_U2, |
62 | CLASS__INT32 = CLASS__ELEMENT_TYPE_I4, |
63 | CLASS__UINT32 = CLASS__ELEMENT_TYPE_U4, |
64 | CLASS__INT64 = CLASS__ELEMENT_TYPE_I8, |
65 | CLASS__UINT64 = CLASS__ELEMENT_TYPE_U8, |
66 | CLASS__SINGLE = CLASS__ELEMENT_TYPE_R4, |
67 | CLASS__DOUBLE = CLASS__ELEMENT_TYPE_R8, |
68 | CLASS__STRING = CLASS__ELEMENT_TYPE_STRING, |
69 | CLASS__TYPED_REFERENCE = CLASS__ELEMENT_TYPE_TYPEDBYREF, |
70 | CLASS__INTPTR = CLASS__ELEMENT_TYPE_I, |
71 | CLASS__UINTPTR = CLASS__ELEMENT_TYPE_U, |
72 | CLASS__OBJECT = CLASS__ELEMENT_TYPE_OBJECT |
73 | }; |
74 | |
75 | |
76 | // BinderMethodIDs are of the form METHOD__XXX__YYY, |
77 | // where X is the class and Y is the method |
78 | |
79 | enum BinderMethodID : int |
80 | { |
81 | METHOD__NIL = 0, |
82 | |
83 | #define DEFINE_METHOD(c,i,s,g) METHOD__ ## c ## __ ## i, |
84 | #include "mscorlib.h" |
85 | |
86 | METHOD__MSCORLIB_COUNT, |
87 | }; |
88 | |
89 | // BinderFieldIDs are of the form FIELD__XXX__YYY, |
90 | // where X is the class and Y is the field |
91 | |
92 | enum BinderFieldID |
93 | { |
94 | FIELD__NIL = 0, |
95 | |
96 | #define DEFINE_FIELD(c,i,s) FIELD__ ## c ## __ ## i, |
97 | #include "mscorlib.h" |
98 | |
99 | FIELD__MSCORLIB_COUNT, |
100 | }; |
101 | |
102 | struct MscorlibClassDescription |
103 | { |
104 | PTR_CSTR nameSpace; |
105 | PTR_CSTR name; |
106 | }; |
107 | |
108 | struct MscorlibMethodDescription |
109 | { |
110 | BinderClassID classID; |
111 | PTR_CSTR name; |
112 | PTR_HARDCODEDMETASIG sig; |
113 | }; |
114 | |
115 | struct MscorlibFieldDescription |
116 | { |
117 | BinderClassID classID; |
118 | PTR_CSTR name; |
119 | }; |
120 | |
121 | class MscorlibBinder |
122 | { |
123 | public: |
124 | #ifdef DACCESS_COMPILE |
125 | friend class NativeImageDumper; |
126 | #endif |
127 | |
128 | // |
129 | // Note that the frequently called methods are intentionally static to reduce code bloat. |
130 | // Instance methods would push the address of the global object at every callsite. |
131 | // |
132 | |
133 | static PTR_Module GetModule(); |
134 | |
135 | // |
136 | // Retrieve structures from ID. |
137 | // |
138 | // Note that none of the MscorlibBinder methods trigger static |
139 | // constructors. The JITed code takes care of triggering them. |
140 | // |
141 | static PTR_MethodTable GetClass(BinderClassID id); |
142 | static MethodDesc * GetMethod(BinderMethodID id); |
143 | static FieldDesc * GetField(BinderFieldID id); |
144 | |
145 | // |
146 | // A slighly faster version that assumes that the class was fetched |
147 | // by the binder earlier. |
148 | // |
149 | static PTR_MethodTable GetExistingClass(BinderClassID id); |
150 | static MethodDesc * GetExistingMethod(BinderMethodID id); |
151 | static FieldDesc * GetExistingField(BinderFieldID id); |
152 | |
153 | // |
154 | // Utilities for classes |
155 | // |
156 | static FORCEINLINE BOOL IsClass(MethodTable *pMT, BinderClassID id) |
157 | { |
158 | return dac_cast<TADDR>(GetClass(id)) == dac_cast<TADDR>(pMT); |
159 | } |
160 | |
161 | // Get the class only if it has been loaded already |
162 | static PTR_MethodTable GetClassIfExist(BinderClassID id); |
163 | |
164 | static LPCUTF8 GetClassNameSpace(BinderClassID id); |
165 | static LPCUTF8 GetClassName(BinderClassID id); |
166 | |
167 | // |
168 | // Utilities for methods |
169 | // |
170 | static LPCUTF8 GetMethodName(BinderMethodID id); |
171 | static LPHARDCODEDMETASIG GetMethodSig(BinderMethodID id); |
172 | |
173 | static Signature GetMethodSignature(BinderMethodID id) |
174 | { |
175 | WRAPPER_NO_CONTRACT; |
176 | return GetSignature(GetMethodSig(id)); |
177 | } |
178 | |
179 | // |
180 | // Utilities for fields |
181 | // |
182 | static LPCUTF8 GetFieldName(BinderFieldID id); |
183 | |
184 | static DWORD GetFieldOffset(BinderFieldID id); |
185 | |
186 | // |
187 | // Utilities for exceptions |
188 | // |
189 | |
190 | static MethodTable *GetException(RuntimeExceptionKind kind) |
191 | { |
192 | WRAPPER_NO_CONTRACT; |
193 | _ASSERTE(kind <= kLastExceptionInMscorlib); // Not supported for exceptions defined outside mscorlib. |
194 | BinderClassID id = (BinderClassID) (kind + CLASS__MSCORLIB_COUNT); |
195 | return GetClass(id); |
196 | } |
197 | |
198 | static BOOL IsException(MethodTable *pMT, RuntimeExceptionKind kind) |
199 | { |
200 | WRAPPER_NO_CONTRACT; |
201 | _ASSERTE(kind <= kLastExceptionInMscorlib); // Not supported for exceptions defined outside mscorlib. |
202 | BinderClassID id = (BinderClassID) (kind + CLASS__MSCORLIB_COUNT); |
203 | return dac_cast<TADDR>(GetClassIfExist(id)) == dac_cast<TADDR>(pMT); |
204 | } |
205 | |
206 | static LPCUTF8 GetExceptionName(RuntimeExceptionKind kind) |
207 | { |
208 | WRAPPER_NO_CONTRACT; |
209 | _ASSERTE(kind <= kLastExceptionInMscorlib); // Not supported for exceptions defined outside mscorlib. |
210 | BinderClassID id = (BinderClassID) (kind + CLASS__MSCORLIB_COUNT); |
211 | return GetClassName(id); |
212 | } |
213 | |
214 | // |
215 | // Utilities for signature element types |
216 | // |
217 | |
218 | static PTR_MethodTable GetElementType(CorElementType type) |
219 | { |
220 | LIMITED_METHOD_DAC_CONTRACT; |
221 | return GetExistingClass((BinderClassID) (type)); |
222 | } |
223 | |
224 | // This should be called during CLR initialization only |
225 | static PTR_MethodTable LoadPrimitiveType(CorElementType et); |
226 | |
227 | // Get the metasig, do a one-time conversion if necessary |
228 | static Signature GetSignature(LPHARDCODEDMETASIG pHardcodedSig); |
229 | static Signature GetTargetSignature(LPHARDCODEDMETASIG pHardcodedSig); |
230 | |
231 | // |
232 | // Static initialization |
233 | // |
234 | static void Startup(); |
235 | |
236 | // |
237 | // These are called by initialization code: |
238 | // |
239 | static void AttachModule(Module *pModule); |
240 | |
241 | #ifdef FEATURE_PREJIT |
242 | // |
243 | // Store the binding arrays to a prejit image |
244 | // so we don't have to do name lookup at runtime |
245 | // |
246 | void BindAll(); |
247 | void Save(DataImage *image); |
248 | void Fixup(DataImage *image); |
249 | #endif |
250 | |
251 | #ifdef _DEBUG |
252 | void Check(); |
253 | void CheckExtended(); |
254 | #endif |
255 | |
256 | #ifdef DACCESS_COMPILE |
257 | void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); |
258 | #endif |
259 | |
260 | private: |
261 | |
262 | // We have two different instances of the binder in crossgen. The instance local methods |
263 | // are used when it is necessary to differentiate between them. |
264 | PTR_MethodTable LookupClassLocal(BinderClassID id); |
265 | MethodDesc * LookupMethodLocal(BinderMethodID id); |
266 | FieldDesc * LookupFieldLocal(BinderFieldID id); |
267 | |
268 | PTR_MethodTable GetClassLocal(BinderClassID id); |
269 | MethodDesc * GetMethodLocal(BinderMethodID id); |
270 | FieldDesc * GetFieldLocal(BinderFieldID id); |
271 | |
272 | static PTR_MethodTable LookupClass(BinderClassID id); |
273 | static MethodDesc * LookupMethod(BinderMethodID id); |
274 | static FieldDesc * LookupField(BinderFieldID id); |
275 | |
276 | static PTR_MethodTable LookupClassIfExist(BinderClassID id); |
277 | |
278 | Signature GetSignatureLocal(LPHARDCODEDMETASIG pHardcodedSig); |
279 | |
280 | bool ConvertType(const BYTE*& pSig, SigBuilder * pSigBuilder); |
281 | void BuildConvertedSignature(const BYTE* pSig, SigBuilder * pSigBuilder); |
282 | const BYTE* ConvertSignature(LPHARDCODEDMETASIG pHardcodedSig, const BYTE* pSig); |
283 | |
284 | void SetDescriptions(Module * pModule, |
285 | const MscorlibClassDescription * pClassDescriptions, USHORT nClasses, |
286 | const MscorlibMethodDescription * pMethodDescriptions, USHORT nMethods, |
287 | const MscorlibFieldDescription * pFieldDescriptions, USHORT nFields); |
288 | |
289 | void AllocateTables(); |
290 | |
291 | #ifdef _DEBUG |
292 | static void TriggerGCUnderStress(); |
293 | #endif |
294 | |
295 | PTR_Module m_pModule; |
296 | |
297 | DPTR(PTR_MethodTable) m_pClasses; |
298 | DPTR(PTR_MethodDesc) m_pMethods; |
299 | DPTR(PTR_FieldDesc) m_pFields; |
300 | |
301 | // This is necessary to avoid embeding copy of the descriptions into mscordacwks |
302 | DPTR(const MscorlibClassDescription) m_classDescriptions; |
303 | DPTR(const MscorlibMethodDescription) m_methodDescriptions; |
304 | DPTR(const MscorlibFieldDescription) m_fieldDescriptions; |
305 | |
306 | USHORT m_cClasses; |
307 | USHORT m_cMethods; |
308 | USHORT m_cFields; |
309 | |
310 | static CrstStatic s_SigConvertCrst; |
311 | |
312 | #ifdef _DEBUG |
313 | |
314 | struct OffsetAndSizeCheck |
315 | { |
316 | PTR_CSTR classNameSpace; |
317 | PTR_CSTR className; |
318 | SIZE_T expectedClassSize; |
319 | |
320 | PTR_CSTR fieldName; |
321 | SIZE_T expectedFieldOffset; |
322 | SIZE_T expectedFieldSize; |
323 | }; |
324 | |
325 | static const OffsetAndSizeCheck OffsetsAndSizes[]; |
326 | |
327 | #endif |
328 | }; |
329 | |
330 | // |
331 | // Global bound modules: |
332 | // |
333 | |
334 | GVAL_DECL(MscorlibBinder, g_Mscorlib); |
335 | |
336 | FORCEINLINE PTR_MethodTable MscorlibBinder::GetClass(BinderClassID id) |
337 | { |
338 | CONTRACTL |
339 | { |
340 | THROWS; |
341 | GC_TRIGGERS; |
342 | INJECT_FAULT(ThrowOutOfMemory()); |
343 | |
344 | PRECONDITION(id != CLASS__NIL); |
345 | PRECONDITION((&g_Mscorlib)->m_cClasses > 0); // Make sure mscorlib has been loaded. |
346 | PRECONDITION(id <= (&g_Mscorlib)->m_cClasses); |
347 | } |
348 | CONTRACTL_END; |
349 | |
350 | // Force a GC here under stress because type loading could trigger GC nondeterminsticly |
351 | INDEBUG(TriggerGCUnderStress()); |
352 | |
353 | PTR_MethodTable pMT = VolatileLoad(&((&g_Mscorlib)->m_pClasses[id])); |
354 | if (pMT == NULL) |
355 | return LookupClass(id); |
356 | return pMT; |
357 | } |
358 | |
359 | FORCEINLINE MethodDesc * MscorlibBinder::GetMethod(BinderMethodID id) |
360 | { |
361 | CONTRACTL |
362 | { |
363 | THROWS; |
364 | GC_TRIGGERS; |
365 | INJECT_FAULT(ThrowOutOfMemory()); |
366 | |
367 | PRECONDITION(id != METHOD__NIL); |
368 | PRECONDITION(id <= (&g_Mscorlib)->m_cMethods); |
369 | } |
370 | CONTRACTL_END; |
371 | |
372 | // Force a GC here under stress because type loading could trigger GC nondeterminsticly |
373 | INDEBUG(TriggerGCUnderStress()); |
374 | |
375 | MethodDesc * pMD = VolatileLoad(&((&g_Mscorlib)->m_pMethods[id])); |
376 | if (pMD == NULL) |
377 | return LookupMethod(id); |
378 | return pMD; |
379 | } |
380 | |
381 | FORCEINLINE FieldDesc * MscorlibBinder::GetField(BinderFieldID id) |
382 | { |
383 | CONTRACTL |
384 | { |
385 | THROWS; |
386 | GC_TRIGGERS; |
387 | INJECT_FAULT(ThrowOutOfMemory()); |
388 | |
389 | PRECONDITION(id != FIELD__NIL); |
390 | PRECONDITION(id <= (&g_Mscorlib)->m_cFields); |
391 | } |
392 | CONTRACTL_END; |
393 | |
394 | // Force a GC here under stress because type loading could trigger GC nondeterminsticly |
395 | INDEBUG(TriggerGCUnderStress()); |
396 | |
397 | FieldDesc * pFD = VolatileLoad(&((&g_Mscorlib)->m_pFields[id])); |
398 | if (pFD == NULL) |
399 | return LookupField(id); |
400 | return pFD; |
401 | } |
402 | |
403 | FORCEINLINE PTR_MethodTable MscorlibBinder::GetExistingClass(BinderClassID id) |
404 | { |
405 | LIMITED_METHOD_DAC_CONTRACT; |
406 | PTR_MethodTable pMT = (&g_Mscorlib)->m_pClasses[id]; |
407 | _ASSERTE(pMT != NULL); |
408 | return pMT; |
409 | } |
410 | |
411 | FORCEINLINE MethodDesc * MscorlibBinder::GetExistingMethod(BinderMethodID id) |
412 | { |
413 | LIMITED_METHOD_DAC_CONTRACT; |
414 | MethodDesc * pMD = (&g_Mscorlib)->m_pMethods[id]; |
415 | _ASSERTE(pMD != NULL); |
416 | return pMD; |
417 | } |
418 | |
419 | FORCEINLINE FieldDesc * MscorlibBinder::GetExistingField(BinderFieldID id) |
420 | { |
421 | LIMITED_METHOD_DAC_CONTRACT; |
422 | FieldDesc * pFD = (&g_Mscorlib)->m_pFields[id]; |
423 | _ASSERTE(pFD != NULL); |
424 | return pFD; |
425 | } |
426 | |
427 | FORCEINLINE PTR_MethodTable MscorlibBinder::GetClassIfExist(BinderClassID id) |
428 | { |
429 | CONTRACTL |
430 | { |
431 | GC_NOTRIGGER; |
432 | NOTHROW; |
433 | FORBID_FAULT; |
434 | MODE_ANY; |
435 | |
436 | PRECONDITION(id != CLASS__NIL); |
437 | PRECONDITION(id <= (&g_Mscorlib)->m_cClasses); |
438 | } |
439 | CONTRACTL_END; |
440 | |
441 | PTR_MethodTable pMT = VolatileLoad(&((&g_Mscorlib)->m_pClasses[id])); |
442 | if (pMT == NULL) |
443 | return LookupClassIfExist(id); |
444 | return pMT; |
445 | } |
446 | |
447 | |
448 | FORCEINLINE PTR_Module MscorlibBinder::GetModule() |
449 | { |
450 | LIMITED_METHOD_DAC_CONTRACT; |
451 | PTR_Module pModule = (&g_Mscorlib)->m_pModule; |
452 | _ASSERTE(pModule != NULL); |
453 | return pModule; |
454 | } |
455 | |
456 | FORCEINLINE LPCUTF8 MscorlibBinder::GetClassNameSpace(BinderClassID id) |
457 | { |
458 | LIMITED_METHOD_CONTRACT; |
459 | |
460 | _ASSERTE(id != CLASS__NIL); |
461 | _ASSERTE(id <= (&g_Mscorlib)->m_cClasses); |
462 | return (&g_Mscorlib)->m_classDescriptions[id].nameSpace; |
463 | } |
464 | |
465 | FORCEINLINE LPCUTF8 MscorlibBinder::GetClassName(BinderClassID id) |
466 | { |
467 | LIMITED_METHOD_CONTRACT; |
468 | |
469 | _ASSERTE(id != CLASS__NIL); |
470 | _ASSERTE(id <= (&g_Mscorlib)->m_cClasses); |
471 | return (&g_Mscorlib)->m_classDescriptions[id].name; |
472 | } |
473 | |
474 | FORCEINLINE LPCUTF8 MscorlibBinder::GetMethodName(BinderMethodID id) |
475 | { |
476 | LIMITED_METHOD_CONTRACT; |
477 | |
478 | _ASSERTE(id != METHOD__NIL); |
479 | _ASSERTE(id <= (&g_Mscorlib)->m_cMethods); |
480 | return (&g_Mscorlib)->m_methodDescriptions[id-1].name; |
481 | } |
482 | |
483 | FORCEINLINE LPHARDCODEDMETASIG MscorlibBinder::GetMethodSig(BinderMethodID id) |
484 | { |
485 | LIMITED_METHOD_CONTRACT; |
486 | |
487 | _ASSERTE(id != METHOD__NIL); |
488 | _ASSERTE(id <= (&g_Mscorlib)->m_cMethods); |
489 | return (&g_Mscorlib)->m_methodDescriptions[id-1].sig; |
490 | } |
491 | |
492 | FORCEINLINE LPCUTF8 MscorlibBinder::GetFieldName(BinderFieldID id) |
493 | { |
494 | LIMITED_METHOD_CONTRACT; |
495 | |
496 | _ASSERTE(id != FIELD__NIL); |
497 | _ASSERTE(id <= (&g_Mscorlib)->m_cFields); |
498 | return (&g_Mscorlib)->m_fieldDescriptions[id-1].name; |
499 | } |
500 | |
501 | #endif // _BINDERMODULE_H_ |
502 | |