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// File: typedesc.h
6//
7
8
9//
10
11//
12// ============================================================================
13
14
15#ifndef TYPEDESC_H
16#define TYPEDESC_H
17#include <specstrings.h>
18
19class TypeHandleList;
20
21/*************************************************************************/
22/* TypeDesc is a discriminated union of all types that can not be directly
23 represented by a simple MethodTable*. The discrimintor of the union at the present
24 time is the CorElementType numeration. The subclass of TypeDesc are
25 the possible variants of the union.
26
27
28 ParamTypeDescs only include byref, array and pointer types. They do NOT
29 include instantaitions of generic types, which are represented by MethodTables.
30*/
31
32
33typedef DPTR(class TypeDesc) PTR_TypeDesc;
34
35class TypeDesc
36{
37public:
38#ifdef DACCESS_COMPILE
39 friend class NativeImageDumper;
40#endif
41#ifndef DACCESS_COMPILE
42 TypeDesc(CorElementType type) {
43 LIMITED_METHOD_CONTRACT;
44
45 m_typeAndFlags = type;
46 }
47#endif
48
49 // This is the ELEMENT_TYPE* that would be used in the type sig for this type
50 // For enums this is the uderlying type
51 inline CorElementType GetInternalCorElementType() {
52 LIMITED_METHOD_DAC_CONTRACT;
53
54 return (CorElementType) (m_typeAndFlags & 0xff);
55 }
56
57 // Get the exact parent (superclass) of this type
58 TypeHandle GetParent();
59
60 // Returns the name of the array. Note that it returns
61 // the length of the returned string
62 static void ConstructName(CorElementType kind,
63 TypeHandle param,
64 int rank,
65 SString &ssBuff);
66
67 void GetName(SString &ssBuf);
68
69 //-------------------------------------------------------------------
70 // CASTING
71 //
72 // There are two variants of the "CanCastTo" method:
73 //
74 // CanCastTo
75 // - restore encoded pointers on demand
76 // - might throw, might trigger GC
77 // - return type is boolean (FALSE = cannot cast, TRUE = can cast)
78 //
79 // CanCastToNoGC
80 // - do not restore encoded pointers on demand
81 // - does not throw, does not trigger GC
82 // - return type is three-valued (CanCast, CannotCast, MaybeCast)
83 // - MaybeCast indicates that the test tripped on an encoded pointer
84 // so the caller should now call CanCastTo if it cares
85 //
86
87 BOOL CanCastTo(TypeHandle type, TypeHandlePairList *pVisited);
88 TypeHandle::CastResult CanCastToNoGC(TypeHandle type);
89
90 static BOOL CanCastParam(TypeHandle fromParam, TypeHandle toParam, TypeHandlePairList *pVisited);
91 static TypeHandle::CastResult CanCastParamNoGC(TypeHandle fromParam, TypeHandle toParam);
92
93#ifndef DACCESS_COMPILE
94 BOOL IsEquivalentTo(TypeHandle type COMMA_INDEBUG(TypeHandlePairList *pVisited));
95#endif
96
97 // BYREF
98 BOOL IsByRef() { // BYREFS are often treated specially
99 WRAPPER_NO_CONTRACT;
100
101 return(GetInternalCorElementType() == ELEMENT_TYPE_BYREF);
102 }
103
104 // PTR
105 BOOL IsPointer() {
106 WRAPPER_NO_CONTRACT;
107
108 return(GetInternalCorElementType() == ELEMENT_TYPE_PTR);
109 }
110
111 // ARRAY, SZARRAY
112 BOOL IsArray();
113
114 // VAR, MVAR
115 BOOL IsGenericVariable();
116
117 // ELEMENT_TYPE_FNPTR
118 BOOL IsFnPtr();
119
120 // VALUETYPE
121 BOOL IsNativeValueType();
122
123 // Is actually ParamTypeDesc (ARRAY, SZARRAY, BYREF, PTR)
124 BOOL HasTypeParam();
125
126#ifdef FEATURE_PREJIT
127 void Save(DataImage *image);
128 void Fixup(DataImage *image);
129
130 BOOL NeedsRestore(DataImage *image)
131 {
132 WRAPPER_NO_CONTRACT;
133 return ComputeNeedsRestore(image, NULL);
134 }
135
136 BOOL ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited);
137#endif
138
139 void DoRestoreTypeKey();
140 void Restore();
141 BOOL IsRestored();
142 BOOL IsRestored_NoLogging();
143 void SetIsRestored();
144
145 inline BOOL HasUnrestoredTypeKey() const
146 {
147 LIMITED_METHOD_CONTRACT;
148 SUPPORTS_DAC;
149
150 return (m_typeAndFlags & TypeDesc::enum_flag_UnrestoredTypeKey) != 0;
151 }
152
153 BOOL HasTypeEquivalence() const
154 {
155 LIMITED_METHOD_CONTRACT;
156 return (m_typeAndFlags & TypeDesc::enum_flag_HasTypeEquivalence) != 0;
157 }
158
159 BOOL IsFullyLoaded() const
160 {
161 LIMITED_METHOD_CONTRACT;
162
163 return (m_typeAndFlags & TypeDesc::enum_flag_IsNotFullyLoaded) == 0;
164 }
165
166 VOID SetIsFullyLoaded()
167 {
168 LIMITED_METHOD_CONTRACT;
169 FastInterlockAnd(&m_typeAndFlags, ~TypeDesc::enum_flag_IsNotFullyLoaded);
170 }
171
172 ClassLoadLevel GetLoadLevel();
173
174 void DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel level,
175 DFLPendingList *pPending, BOOL *pfBailed, const InstantiationContext *pInstContext);
176
177 // The module that defined the underlying type
178 PTR_Module GetModule();
179
180 // The ngen'ed module where this type-desc lives
181 PTR_Module GetZapModule();
182
183 // The module where this type lives for the purposes of loading and prejitting
184 // See ComputeLoaderModule for more information
185 PTR_Module GetLoaderModule();
186
187 // The assembly that defined this type (== GetModule()->GetAssembly())
188 Assembly* GetAssembly();
189
190 PTR_MethodTable GetMethodTable(); // only meaningful for ParamTypeDesc
191 TypeHandle GetTypeParam(); // only meaningful for ParamTypeDesc
192 Instantiation GetClassOrArrayInstantiation(); // only meaningful for ParamTypeDesc; see above
193
194 TypeHandle GetBaseTypeParam(); // only allowed for ParamTypeDesc, helper method used to avoid recursion
195
196 // Note that if the TypeDesc, e.g. a function pointer type, involves parts that may
197 // come from either a SharedDomain or an AppDomain then special rules apply to GetDomain.
198 // It returns the SharedDomain if all the
199 // constituent parts of the type are SharedDomain (i.e. domain-neutral),
200 // and returns an AppDomain if any of the parts are from an AppDomain,
201 // i.e. are domain-bound. If any of the parts are domain-bound
202 // then they will all belong to the same domain.
203 PTR_BaseDomain GetDomain();
204
205 PTR_LoaderAllocator GetLoaderAllocator()
206 {
207 SUPPORTS_DAC;
208
209 return GetLoaderModule()->GetLoaderAllocator();
210 }
211
212 protected:
213 // See methodtable.h for details of the flags with the same name there
214 enum
215 {
216 enum_flag_NeedsRestore = 0x00000100, // Only used during ngen
217 enum_flag_PreRestored = 0x00000200, // Only used during ngen
218 enum_flag_Unrestored = 0x00000400,
219 enum_flag_UnrestoredTypeKey = 0x00000800,
220 enum_flag_IsNotFullyLoaded = 0x00001000,
221 enum_flag_DependenciesLoaded = 0x00002000,
222 enum_flag_HasTypeEquivalence = 0x00004000
223 };
224 //
225 // Low-order 8 bits of this flag are used to store the CorElementType, which
226 // discriminates what kind of TypeDesc we are
227 //
228 // The remaining bits are available for flags
229 //
230 DWORD m_typeAndFlags;
231};
232
233
234/*************************************************************************/
235// This variant is used for parameterized types that have exactly one argument
236// type. This includes arrays, byrefs, pointers.
237
238typedef DPTR(class ParamTypeDesc) PTR_ParamTypeDesc;
239
240
241class ParamTypeDesc : public TypeDesc {
242 friend class TypeDesc;
243 friend class JIT_TrialAlloc;
244 friend class CheckAsmOffsets;
245#ifdef DACCESS_COMPILE
246 friend class NativeImageDumper;
247#endif
248
249public:
250#ifndef DACCESS_COMPILE
251 ParamTypeDesc(CorElementType type, MethodTable* pMT, TypeHandle arg)
252 : TypeDesc(type), m_Arg(arg), m_hExposedClassObject(0) {
253
254 LIMITED_METHOD_CONTRACT;
255
256 m_TemplateMT.SetValueMaybeNull(pMT);
257
258 // ParamTypeDescs start out life not fully loaded
259 m_typeAndFlags |= TypeDesc::enum_flag_IsNotFullyLoaded;
260
261 // Param type descs can only be equivalent if their constituent bits are equivalent.
262 if (arg.HasTypeEquivalence())
263 {
264 m_typeAndFlags |= TypeDesc::enum_flag_HasTypeEquivalence;
265 }
266
267 INDEBUGIMPL(Verify());
268 }
269#endif
270
271 INDEBUGIMPL(BOOL Verify();)
272
273 OBJECTREF GetManagedClassObject();
274
275 OBJECTREF GetManagedClassObjectIfExists()
276 {
277 CONTRACTL
278 {
279 NOTHROW;
280 GC_NOTRIGGER;
281 MODE_COOPERATIVE;
282 }
283 CONTRACTL_END;
284
285 OBJECTREF objRet = NULL;
286 GET_LOADERHANDLE_VALUE_FAST(GetLoaderAllocator(), m_hExposedClassObject, &objRet);
287 return objRet;
288 }
289 OBJECTREF GetManagedClassObjectFast()
290 {
291 LIMITED_METHOD_CONTRACT;
292
293 OBJECTREF objRet = NULL;
294 LoaderAllocator::GetHandleValueFast(m_hExposedClassObject, &objRet);
295 return objRet;
296 }
297
298 TypeHandle GetModifiedType()
299 {
300 LIMITED_METHOD_CONTRACT;
301
302 return m_Arg;
303 }
304
305 TypeHandle GetTypeParam();
306
307#ifdef FEATURE_PREJIT
308 void Save(DataImage *image);
309 void Fixup(DataImage *image);
310 BOOL ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited);
311#endif
312
313 BOOL OwnsTemplateMethodTable();
314
315#ifdef DACCESS_COMPILE
316 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
317#endif
318
319 friend class StubLinkerCPU;
320
321#ifdef FEATURE_ARRAYSTUB_AS_IL
322 friend class ArrayOpLinker;
323#endif
324protected:
325 PTR_MethodTable GetTemplateMethodTableInternal() {
326 WRAPPER_NO_CONTRACT;
327 return ReadPointerMaybeNull(this, &ParamTypeDesc::m_TemplateMT);
328 }
329
330 // the m_typeAndFlags field in TypeDesc tell what kind of parameterized type we have
331 RelativeFixupPointer<PTR_MethodTable> m_TemplateMT; // The shared method table, some variants do not use this field (it is null)
332 TypeHandle m_Arg; // The type that is being modified
333 LOADERHANDLE m_hExposedClassObject; // handle back to the internal reflection Type object
334};
335
336
337/*************************************************************************/
338/* An ArrayTypeDesc represents a Array of some pointer type. */
339
340class ArrayTypeDesc : public ParamTypeDesc
341{
342#ifdef DACCESS_COMPILE
343 friend class NativeImageDumper;
344#endif
345public:
346#ifndef DACCESS_COMPILE
347 ArrayTypeDesc(MethodTable* arrayMT, TypeHandle elementType) :
348 ParamTypeDesc(arrayMT->IsMultiDimArray() ? ELEMENT_TYPE_ARRAY : ELEMENT_TYPE_SZARRAY, arrayMT, elementType)
349#ifdef FEATURE_COMINTEROP
350 , m_pCCWTemplate(NULL)
351#endif // FEATURE_COMINTEROP
352 {
353 STATIC_CONTRACT_SO_TOLERANT;
354 WRAPPER_NO_CONTRACT;
355 INDEBUG(Verify());
356 }
357
358//private: TypeHandle m_Arg; // The type that is being modified
359
360
361 // placement new operator
362 void* operator new(size_t size, void* spot) { return (spot); }
363
364#endif
365
366 TypeHandle GetArrayElementTypeHandle() {
367 WRAPPER_NO_CONTRACT;
368 SUPPORTS_DAC;
369 return GetTypeParam();
370 }
371
372 unsigned GetRank() {
373 WRAPPER_NO_CONTRACT;
374 SUPPORTS_DAC;
375
376 if (GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY)
377 return 1;
378 else
379 return dac_cast<PTR_ArrayClass>(GetMethodTable()->GetClass())->GetRank();
380 }
381
382 MethodTable* GetParent()
383 {
384 WRAPPER_NO_CONTRACT;
385
386 _ASSERTE(!m_TemplateMT.IsNull());
387 _ASSERTE(GetTemplateMethodTableInternal()->IsArray());
388 _ASSERTE(GetTemplateMethodTableInternal()->ParentEquals(g_pArrayClass));
389
390 return g_pArrayClass;
391 }
392
393#ifdef FEATURE_COMINTEROP
394 ComCallWrapperTemplate *GetComCallWrapperTemplate()
395 {
396 LIMITED_METHOD_CONTRACT;
397 return m_pCCWTemplate;
398 }
399
400 BOOL SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate)
401 {
402 CONTRACTL
403 {
404 THROWS;
405 GC_NOTRIGGER;
406 MODE_ANY;
407 }
408 CONTRACTL_END;
409
410 TypeHandle th(this);
411 g_IBCLogger.LogTypeMethodTableWriteableAccess(&th);
412
413 return (InterlockedCompareExchangeT(EnsureWritablePages(&m_pCCWTemplate), pTemplate, NULL) == NULL);
414 }
415#endif // FEATURE_COMINTEROP
416
417 INDEBUG(BOOL Verify();)
418
419#ifdef FEATURE_PREJIT
420 void Fixup(DataImage *image);
421#endif
422
423 PTR_MethodTable GetTemplateMethodTable() {
424 WRAPPER_NO_CONTRACT;
425 PTR_MethodTable ptrTemplateMT = GetTemplateMethodTableInternal();
426 _ASSERTE(ptrTemplateMT->IsArray());
427 return ptrTemplateMT;
428 }
429
430 TADDR GetTemplateMethodTableMaybeTagged() {
431 WRAPPER_NO_CONTRACT;
432 return m_TemplateMT.GetValueMaybeTagged(dac_cast<TADDR>(this) + offsetof(ArrayTypeDesc, m_TemplateMT));
433 }
434
435#ifdef FEATURE_COMINTEROP
436 ComCallWrapperTemplate *m_pCCWTemplate;
437#endif // FEATURE_COMINTEROP
438};
439
440/*************************************************************************/
441// These are for verification of generic code and reflection over generic code.
442// Each TypeVarTypeDesc represents a class or method type variable, as specified by a GenericParam entry.
443// The type variables are tied back to the class or method that *defines* them.
444// This is done through typedef or methoddef tokens.
445
446class TypeVarTypeDesc : public TypeDesc
447{
448#ifdef DACCESS_COMPILE
449 friend class NativeImageDumper;
450#endif
451public:
452
453#ifndef DACCESS_COMPILE
454
455 TypeVarTypeDesc(PTR_Module pModule, mdToken typeOrMethodDef, unsigned int index, mdGenericParam token) :
456 TypeDesc(TypeFromToken(typeOrMethodDef) == mdtTypeDef ? ELEMENT_TYPE_VAR : ELEMENT_TYPE_MVAR)
457 {
458 CONTRACTL
459 {
460 NOTHROW;
461 GC_NOTRIGGER;
462 PRECONDITION(CheckPointer(pModule));
463 PRECONDITION(TypeFromToken(typeOrMethodDef) == mdtTypeDef || TypeFromToken(typeOrMethodDef) == mdtMethodDef);
464 PRECONDITION(index >= 0);
465 PRECONDITION(TypeFromToken(token) == mdtGenericParam);
466 }
467 CONTRACTL_END;
468
469 m_pModule.SetValue(pModule);
470 m_typeOrMethodDef = typeOrMethodDef;
471 m_token = token;
472 m_index = index;
473 m_hExposedClassObject = 0;
474 m_constraints = NULL;
475 m_numConstraints = (DWORD)-1;
476 }
477#endif // #ifndef DACCESS_COMPILE
478
479 // placement new operator
480 void* operator new(size_t size, void* spot) { LIMITED_METHOD_CONTRACT; return (spot); }
481
482 PTR_Module GetModule()
483 {
484 LIMITED_METHOD_CONTRACT;
485 SUPPORTS_DAC;
486
487 return ReadPointer(this, &TypeVarTypeDesc::m_pModule);
488 }
489
490 unsigned int GetIndex()
491 {
492 LIMITED_METHOD_CONTRACT;
493 SUPPORTS_DAC;
494 return m_index;
495 }
496
497 mdGenericParam GetToken()
498 {
499 LIMITED_METHOD_CONTRACT;
500 SUPPORTS_DAC;
501 return m_token;
502 }
503
504 mdToken GetTypeOrMethodDef()
505 {
506 LIMITED_METHOD_CONTRACT;
507 SUPPORTS_DAC;
508 return m_typeOrMethodDef;
509 }
510
511 OBJECTREF GetManagedClassObject();
512 OBJECTREF GetManagedClassObjectIfExists()
513 {
514 CONTRACTL
515 {
516 NOTHROW;
517 GC_NOTRIGGER;
518 MODE_COOPERATIVE;
519 }
520 CONTRACTL_END;
521
522 OBJECTREF objRet = NULL;
523 GET_LOADERHANDLE_VALUE_FAST(GetLoaderAllocator(), m_hExposedClassObject, &objRet);
524 return objRet;
525 }
526 OBJECTREF GetManagedClassObjectFast()
527 {
528 LIMITED_METHOD_CONTRACT;
529
530 OBJECTREF objRet = NULL;
531 LoaderAllocator::GetHandleValueFast(m_hExposedClassObject, &objRet);
532 return objRet;
533 }
534
535 // Load the owning type. Note that the result is not guaranteed to be full loaded
536 MethodDesc * LoadOwnerMethod();
537 TypeHandle LoadOwnerType();
538
539 BOOL ConstraintsLoaded() { LIMITED_METHOD_CONTRACT; return m_numConstraints != (DWORD)-1; }
540
541 // Return NULL if no constraints are specified
542 // Return an array of type handles if constraints are specified,
543 // with the number of constraints returned in pNumConstraints
544 TypeHandle* GetCachedConstraints(DWORD *pNumConstraints);
545 TypeHandle* GetConstraints(DWORD *pNumConstraints, ClassLoadLevel level = CLASS_LOADED);
546
547 // Load the constraints if not already loaded
548 void LoadConstraints(ClassLoadLevel level = CLASS_LOADED);
549
550 // Check the constraints on this type parameter hold in the supplied context for the supplied type
551 BOOL SatisfiesConstraints(SigTypeContext *pTypeContext, TypeHandle thArg,
552 const InstantiationContext *pInstContext = NULL);
553
554 // Check whether the constraints on this type force it to be a reference type (i.e. it is impossible
555 // to instantiate it with a value type).
556 BOOL ConstrainedAsObjRef();
557
558 // Check whether the constraints on this type force it to be a value type (i.e. it is impossible to
559 // instantiate it with a reference type).
560 BOOL ConstrainedAsValueType();
561
562#ifdef FEATURE_PREJIT
563 void Save(DataImage *image);
564 void Fixup(DataImage *image);
565#endif // FEATURE_PREJIT
566
567#ifdef DACCESS_COMPILE
568 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
569#endif
570
571protected:
572 BOOL ConstrainedAsObjRefHelper();
573
574 // Module containing the generic definition, also the loader module for this type desc
575 RelativePointer<PTR_Module> m_pModule;
576
577 // Declaring type or method
578 mdToken m_typeOrMethodDef;
579
580 // Constraints, determined on first call to GetConstraints
581 Volatile<DWORD> m_numConstraints; // -1 until number has been determined
582 PTR_TypeHandle m_constraints;
583
584 // slot index back to the internal reflection Type object
585 LOADERHANDLE m_hExposedClassObject;
586
587 // token for GenericParam entry
588 mdGenericParam m_token;
589
590 // index within declaring type or method, numbered from zero
591 unsigned int m_index;
592};
593
594/*************************************************************************/
595/* represents a function type. */
596
597typedef SPTR(class FnPtrTypeDesc) PTR_FnPtrTypeDesc;
598
599class FnPtrTypeDesc : public TypeDesc
600{
601#ifdef DACCESS_COMPILE
602 friend class NativeImageDumper;
603#endif
604
605public:
606#ifndef DACCESS_COMPILE
607 FnPtrTypeDesc(BYTE callConv, DWORD numArgs, TypeHandle * retAndArgTypes)
608 : TypeDesc(ELEMENT_TYPE_FNPTR), m_NumArgs(numArgs), m_CallConv(callConv)
609 {
610 LIMITED_METHOD_CONTRACT;
611 for (DWORD i = 0; i <= numArgs; i++)
612 {
613 m_RetAndArgTypes[i] = retAndArgTypes[i];
614 }
615 }
616#endif //!DACCESS_COMPILE
617
618 DWORD GetNumArgs()
619 {
620 LIMITED_METHOD_CONTRACT;
621 SUPPORTS_DAC;
622 return m_NumArgs;
623 }
624
625 BYTE GetCallConv()
626 {
627 LIMITED_METHOD_CONTRACT;
628 SUPPORTS_DAC;
629 _ASSERTE(FitsIn<BYTE>(m_CallConv));
630 return static_cast<BYTE>(m_CallConv);
631 }
632
633 // Return a pointer to the types of the signature, return type followed by argument types
634 // The type handles are guaranteed to be fixed up
635 TypeHandle * GetRetAndArgTypes();
636 // As above, but const version
637 const TypeHandle * GetRetAndArgTypes() const
638 {
639 WRAPPER_NO_CONTRACT;
640 return const_cast<FnPtrTypeDesc *>(this)->GetRetAndArgTypes();
641 }
642
643 // As above, but the type handles might be zap-encodings that need fixing up explicitly
644 PTR_TypeHandle GetRetAndArgTypesPointer()
645 {
646 LIMITED_METHOD_CONTRACT;
647 SUPPORTS_DAC;
648
649 return PTR_TypeHandle(m_RetAndArgTypes);
650 }
651
652#ifndef DACCESS_COMPILE
653 // Returns TRUE if all return and argument types are externally visible.
654 BOOL IsExternallyVisible() const;
655#endif //DACCESS_COMPILE
656
657#ifdef FEATURE_PREJIT
658 void Save(DataImage *image);
659 void Fixup(DataImage *image);
660#endif //FEATURE_PREJIT
661
662#ifdef DACCESS_COMPILE
663 static ULONG32 DacSize(TADDR addr)
664 {
665 DWORD numArgs = *PTR_DWORD(addr + offsetof(FnPtrTypeDesc, m_NumArgs));
666 return (offsetof(FnPtrTypeDesc, m_RetAndArgTypes) +
667 (numArgs * sizeof(TypeHandle)));
668 }
669
670 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
671#endif //DACCESS_COMPILE
672
673protected:
674 // Number of arguments
675 DWORD m_NumArgs;
676
677 // Calling convention (actually just a single byte)
678 DWORD m_CallConv;
679
680 // Return type first, then argument types
681 TypeHandle m_RetAndArgTypes[1];
682}; // class FnPtrTypeDesc
683
684#endif // TYPEDESC_H
685