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// COM+ Data Field Abstraction
7//
8
9
10#ifndef _FIELD_H_
11#define _FIELD_H_
12
13#include "excep.h"
14
15// Temporary values stored in FieldDesc m_dwOffset during loading
16// The high 5 bits must be zero (because in field.h we steal them for other uses), so we must choose values > 0
17#define FIELD_OFFSET_MAX ((1<<27)-1)
18#define FIELD_OFFSET_UNPLACED FIELD_OFFSET_MAX
19#define FIELD_OFFSET_UNPLACED_GC_PTR (FIELD_OFFSET_MAX-1)
20#define FIELD_OFFSET_VALUE_CLASS (FIELD_OFFSET_MAX-2)
21#define FIELD_OFFSET_NOT_REAL_FIELD (FIELD_OFFSET_MAX-3)
22
23// Offset to indicate an EnC added field. They don't have offsets as aren't placed in the object.
24#define FIELD_OFFSET_NEW_ENC (FIELD_OFFSET_MAX-4)
25#define FIELD_OFFSET_BIG_RVA (FIELD_OFFSET_MAX-5)
26#define FIELD_OFFSET_LAST_REAL_OFFSET (FIELD_OFFSET_MAX-6) // real fields have to be smaller than this
27
28
29//
30// This describes a field - one of this is allocated for every field, so don't make this structure any larger.
31//
32// @GENERICS:
33// Field descriptors for fields in instantiated types may be shared between compatible instantiations
34// Hence for reflection it's necessary to pair a field desc with the exact owning type handle
35class FieldDesc
36{
37 friend class MethodTableBuilder;
38#ifdef DACCESS_COMPILE
39 friend class NativeImageDumper;
40#endif
41
42 protected:
43 RelativePointer<PTR_MethodTable> m_pMTOfEnclosingClass; // This is used to hold the log2 of the field size temporarily during class loading. Yuck.
44
45 // See also: FieldDesc::InitializeFrom method
46
47#if defined(DACCESS_COMPILE)
48 union { //create a union so I can get the correct offset for ClrDump.
49 unsigned m_dword1;
50 struct {
51#endif
52 // Note that we may store other information in the high bits if available --
53 // see enum_packedMBLayout and m_requiresFullMbValue for details.
54 unsigned m_mb : 24;
55
56 // 8 bits...
57 unsigned m_isStatic : 1;
58 unsigned m_isThreadLocal : 1;
59 unsigned m_isRVA : 1;
60 unsigned m_prot : 3;
61 // Does this field's mb require all 24 bits
62 unsigned m_requiresFullMbValue : 1;
63#if defined(DACCESS_COMPILE)
64 };
65 };
66#endif
67
68#if defined(DACCESS_COMPILE)
69 union { //create a union so I can get the correct offset for ClrDump
70 unsigned m_dword2;
71 struct {
72#endif
73 // Note: this has been as low as 22 bits in the past & seemed to be OK.
74 // we can steal some more bits here if we need them.
75 unsigned m_dwOffset : 27;
76 unsigned m_type : 5;
77#if defined(DACCESS_COMPILE)
78 };
79 };
80#endif
81
82#ifdef _DEBUG
83 LPUTF8 m_debugName;
84#endif
85
86public:
87 // Allocated by special heap means, don't construct me
88 FieldDesc() =delete;
89
90#ifndef DACCESS_COMPILE
91 void InitializeFrom(const FieldDesc& sourceField, MethodTable *pMT)
92 {
93 m_pMTOfEnclosingClass.SetValue(pMT);
94
95 m_mb = sourceField.m_mb;
96 m_isStatic = sourceField.m_isStatic;
97 m_isThreadLocal = sourceField.m_isThreadLocal;
98 m_isRVA = sourceField.m_isRVA;
99 m_prot = sourceField.m_prot;
100 m_requiresFullMbValue = sourceField.m_requiresFullMbValue;
101
102 m_dwOffset = sourceField.m_dwOffset;
103 m_type = sourceField.m_type;
104
105#ifdef _DEBUG
106 m_debugName = sourceField.m_debugName;
107#endif // _DEBUG
108 }
109#endif // !DACCESS_COMPILE
110
111#ifdef _DEBUG
112 inline LPUTF8 GetDebugName()
113 {
114 LIMITED_METHOD_CONTRACT;
115 return m_debugName;
116 }
117#endif // _DEBUG
118
119#ifndef DACCESS_COMPILE
120 // This should be called. It was added so that Reflection
121 // can create FieldDesc's for the static primitive fields that aren't
122 // stored with the EEClass.
123 void SetMethodTable(MethodTable* mt)
124 {
125 LIMITED_METHOD_CONTRACT;
126 m_pMTOfEnclosingClass.SetValue(mt);
127 }
128#endif
129
130 VOID Init(mdFieldDef mb,
131 CorElementType FieldType,
132 DWORD dwMemberAttrs,
133 BOOL fIsStatic,
134 BOOL fIsRVA,
135 BOOL fIsThreadLocal,
136 LPCSTR pszFieldName);
137
138 enum {
139 enum_packedMbLayout_MbMask = 0x01FFFF,
140 enum_packedMbLayout_NameHashMask = 0xFE0000
141 };
142
143 void SetMemberDef(mdFieldDef mb)
144 {
145 WRAPPER_NO_CONTRACT;
146
147 // Check if we have to avoid using the packed mb layout
148 if (RidFromToken(mb) > enum_packedMbLayout_MbMask)
149 {
150 m_requiresFullMbValue = 1;
151 }
152
153 // Set only the portion of m_mb we are using
154 if (!m_requiresFullMbValue)
155 {
156 m_mb &= ~enum_packedMbLayout_MbMask;
157 m_mb |= RidFromToken(mb);
158 }
159 else
160 {
161 m_mb = RidFromToken(mb);
162 }
163 }
164
165 mdFieldDef GetMemberDef() const
166 {
167 LIMITED_METHOD_DAC_CONTRACT;
168
169 // Check if this FieldDesc is using the packed mb layout
170 if (!m_requiresFullMbValue)
171 {
172 return TokenFromRid(m_mb & enum_packedMbLayout_MbMask, mdtFieldDef);
173 }
174
175 return TokenFromRid(m_mb, mdtFieldDef);
176 }
177
178 CorElementType GetFieldType()
179 {
180 LIMITED_METHOD_DAC_CONTRACT;
181
182 // Set in code:FieldDesc.Init which in turn is called from
183 // code:MethodTableBuilder.InitializeFieldDescs#InitCall which in turn calls
184 // code:MethodTableBuilder.InitializeFieldDescs#FieldDescTypeMorph
185 return (CorElementType) m_type;
186 }
187
188 DWORD GetFieldProtection()
189 {
190 LIMITED_METHOD_CONTRACT;
191
192 // Set in code:FieldDesc.Init which in turn is called from code:MethodTableBuilder::InitializeFieldDescs#InitCall
193 return m_prot;
194 }
195
196 // Please only use this in a path that you have already guarenteed
197 // the assert is true
198 DWORD GetOffsetUnsafe()
199 {
200 LIMITED_METHOD_CONTRACT;
201
202 g_IBCLogger.LogFieldDescsAccess(this);
203 _ASSERTE(m_dwOffset <= FIELD_OFFSET_LAST_REAL_OFFSET);
204 return m_dwOffset;
205 }
206
207 DWORD GetOffset()
208 {
209 LIMITED_METHOD_DAC_CONTRACT;
210 g_IBCLogger.LogFieldDescsAccess(this);
211 return GetOffset_NoLogging();
212 }
213
214 // During class load m_pMTOfEnclosingClass has the field size in it, so it has to use this version of
215 // GetOffset during that time
216 DWORD GetOffset_NoLogging()
217 {
218 LIMITED_METHOD_DAC_CONTRACT;
219
220 // Note FieldDescs are no longer on "hot" paths so the optimized code here
221 // does not look necessary.
222
223 if (m_dwOffset != FIELD_OFFSET_BIG_RVA) {
224 // Assert that the big RVA case handling doesn't get out of sync
225 // with the normal RVA case.
226#ifdef _DEBUG
227 // The OutOfLine_BigRVAOffset() can't be correctly evaluated during the time
228 // that we repurposed m_pMTOfEnclosingClass for holding the field size
229 // I don't see any good way to determine when this is so hurray for
230 // heuristics!
231 //
232 // As of 4/11/2012 I could repro this by turning on the COMPLUS log and
233 // the LOG() at line methodtablebuilder.cpp:7845
234 // MethodTableBuilder::PlaceRegularStaticFields() calls GetOffset_NoLogging()
235 if((DWORD)(DWORD_PTR&)m_pMTOfEnclosingClass > 16)
236 {
237 _ASSERTE(!this->IsRVA() || (m_dwOffset == OutOfLine_BigRVAOffset()));
238 }
239#endif
240 return m_dwOffset;
241 }
242
243 return OutOfLine_BigRVAOffset();
244 }
245
246 DWORD OutOfLine_BigRVAOffset()
247 {
248 LIMITED_METHOD_DAC_CONTRACT;
249
250 DWORD rva;
251
252 // <NICE>I'm discarding a potential error here. According to the code in MDInternalRO.cpp,
253 // we won't get an error if we initially found the RVA. So I'm going to just
254 // assert it never happens.
255 //
256 // This is a small sin, but I don't see a good alternative. --cwb.</NICE>
257 HRESULT hr;
258 hr = GetMDImport()->GetFieldRVA(GetMemberDef(), &rva);
259 _ASSERTE(SUCCEEDED(hr));
260 return rva;
261 }
262
263 HRESULT SetOffset(DWORD dwOffset)
264 {
265 LIMITED_METHOD_CONTRACT;
266
267 //
268 // value class fields must be aligned to pointer-sized boundaries
269 //
270 //
271 // This is commented out because it isn't valid in all cases.
272 // This is still here because it is useful for finding alignment
273 // problems on IA64.
274 //
275 //_ASSERTE((dwOffset > FIELD_OFFSET_LAST_REAL_OFFSET) ||
276 // (ELEMENT_TYPE_VALUETYPE != GetFieldType()) ||
277 // (IS_ALIGNED(dwOffset, sizeof(void*))));
278
279 m_dwOffset = dwOffset;
280 return((dwOffset > FIELD_OFFSET_LAST_REAL_OFFSET) ? COR_E_TYPELOAD : S_OK);
281 }
282
283 // Okay, we've stolen too many bits from FieldDescs. In the RVA case, there's no
284 // reason to believe they will be limited to 22 bits. So use a sentinel for the
285 // huge cases, and recover them from metadata on-demand.
286 void SetOffsetRVA(DWORD dwOffset)
287 {
288 LIMITED_METHOD_CONTRACT;
289
290 m_dwOffset = (dwOffset > FIELD_OFFSET_LAST_REAL_OFFSET)
291 ? FIELD_OFFSET_BIG_RVA
292 : dwOffset;
293 }
294
295 DWORD IsStatic() const
296 {
297 LIMITED_METHOD_DAC_CONTRACT;
298
299 return m_isStatic;
300 }
301
302 BOOL IsSpecialStatic()
303 {
304 LIMITED_METHOD_CONTRACT;
305
306 return m_isStatic && (m_isRVA || m_isThreadLocal
307 );
308 }
309
310 BOOL IsRVA() const // Has an explicit RVA associated with it
311 {
312 LIMITED_METHOD_DAC_CONTRACT;
313
314 return m_isRVA;
315 }
316
317 BOOL IsThreadStatic() const // Static relative to a thread
318 {
319 LIMITED_METHOD_DAC_CONTRACT;
320
321 return m_isThreadLocal;
322 }
323
324 // Indicate that this field was added by EnC
325 // Must only be called on instances of EnCFieldDesc
326 void SetEnCNew()
327 {
328 WRAPPER_NO_CONTRACT;
329
330 // EnC added fields don't live in the actual object, so don't have a real offset
331 SetOffset(FIELD_OFFSET_NEW_ENC);
332 }
333
334 // Was this field added by EnC?
335 // If this is true, then this object is an instance of EnCFieldDesc
336 BOOL IsEnCNew()
337 {
338 LIMITED_METHOD_DAC_CONTRACT;
339
340 // EnC added fields don't have a real offset
341 return m_dwOffset == FIELD_OFFSET_NEW_ENC;
342 }
343
344 BOOL IsByValue()
345 {
346 LIMITED_METHOD_DAC_CONTRACT;
347
348 return GetFieldType() == ELEMENT_TYPE_VALUETYPE;
349 }
350
351 BOOL IsPrimitive()
352 {
353 LIMITED_METHOD_DAC_CONTRACT;
354
355 return (CorIsPrimitiveType(GetFieldType()) != FALSE);
356 }
357
358 BOOL IsObjRef();
359
360#ifdef FEATURE_PREJIT
361 void SaveContents(DataImage *image);
362 void Fixup(DataImage *image);
363#endif // FEATURE_PREJIT
364
365 UINT LoadSize();
366
367 // Return -1 if the type isn't loaded yet (i.e. if LookupFieldTypeHandle() would return null)
368 UINT GetSize();
369
370 // These routines encapsulate the operation of getting and setting
371 // fields.
372 void GetInstanceField(OBJECTREF o, VOID * pOutVal);
373 void SetInstanceField(OBJECTREF o, const VOID * pInVal);
374
375 void* GetInstanceAddress(OBJECTREF o);
376
377 // Get the address of a field within object 'o'
378 PTR_VOID GetAddress(PTR_VOID o);
379
380 PTR_VOID GetAddressNoThrowNoGC(PTR_VOID o);
381 void* GetAddressGuaranteedInHeap(void *o);
382
383 void* GetValuePtr(OBJECTREF o);
384 VOID SetValuePtr(OBJECTREF o, void* pValue);
385 DWORD GetValue32(OBJECTREF o);
386 VOID SetValue32(OBJECTREF o, DWORD dwValue);
387 OBJECTREF GetRefValue(OBJECTREF o);
388 VOID SetRefValue(OBJECTREF o, OBJECTREF orValue);
389 USHORT GetValue16(OBJECTREF o);
390 VOID SetValue16(OBJECTREF o, DWORD dwValue);
391 BYTE GetValue8(OBJECTREF o);
392 VOID SetValue8(OBJECTREF o, DWORD dwValue);
393 __int64 GetValue64(OBJECTREF o);
394 VOID SetValue64(OBJECTREF o, __int64 value);
395
396 PTR_MethodTable GetApproxEnclosingMethodTable_NoLogging()
397 {
398 LIMITED_METHOD_DAC_CONTRACT;
399 return m_pMTOfEnclosingClass.GetValue(PTR_HOST_MEMBER_TADDR(FieldDesc, this, m_pMTOfEnclosingClass));
400 }
401
402 PTR_MethodTable GetApproxEnclosingMethodTable()
403 {
404 LIMITED_METHOD_DAC_CONTRACT;
405 g_IBCLogger.LogFieldDescsAccess(this);
406 return GetApproxEnclosingMethodTable_NoLogging();
407 }
408
409 PTR_MethodTable GetEnclosingMethodTable()
410 {
411 LIMITED_METHOD_DAC_CONTRACT;
412 _ASSERTE(!IsSharedByGenericInstantiations());
413 return GetApproxEnclosingMethodTable();
414 }
415
416 // FieldDesc can be shared between generic instantiations. So List<String>._items
417 // is really the same as List<__Canon>._items. Hence, the FieldDesc itself
418 // cannot know the exact enclosing type. You need to provide the exact owner
419 // like List<String> or a subtype like MyInheritedList<String>.
420 MethodTable * GetExactDeclaringType(MethodTable * ownerOrSubType);
421
422 BOOL IsSharedByGenericInstantiations()
423 {
424 LIMITED_METHOD_DAC_CONTRACT;
425 return (!IsStatic()) && GetApproxEnclosingMethodTable()->IsSharedByGenericInstantiations();
426 }
427
428 BOOL IsFieldOfValueType()
429 {
430 WRAPPER_NO_CONTRACT;
431 return GetApproxEnclosingMethodTable()->IsValueType();
432 }
433
434 DWORD GetNumGenericClassArgs()
435 {
436 WRAPPER_NO_CONTRACT;
437 return GetApproxEnclosingMethodTable()->GetNumGenericArgs();
438 }
439
440 PTR_BYTE GetBaseInDomainLocalModule(DomainLocalModule * pLocalModule)
441 {
442 WRAPPER_NO_CONTRACT;
443
444 if (GetFieldType() == ELEMENT_TYPE_CLASS || GetFieldType() == ELEMENT_TYPE_VALUETYPE)
445 {
446 return pLocalModule->GetGCStaticsBasePointer(GetEnclosingMethodTable());
447 }
448 else
449 {
450 return pLocalModule->GetNonGCStaticsBasePointer(GetEnclosingMethodTable());
451 }
452 }
453
454#ifndef DACCESS_COMPILE
455 PTR_BYTE GetBase()
456 {
457 CONTRACTL
458 {
459 THROWS;
460 GC_TRIGGERS;
461 INJECT_FAULT(COMPlusThrowOM());
462 }
463 CONTRACTL_END
464
465 MethodTable *pMT = GetEnclosingMethodTable();
466
467 return GetBaseInDomainLocalModule(pMT->GetDomainLocalModule());
468 }
469
470#endif //!DACCESS_COMPILE
471
472 PTR_BYTE GetBaseInDomain(AppDomain * appDomain)
473 {
474 CONTRACTL
475 {
476 NOTHROW;
477 GC_NOTRIGGER;
478 }
479 CONTRACTL_END;
480
481 Module *pModule = GetEnclosingMethodTable()->GetModuleForStatics();
482 if (pModule == NULL)
483 return NULL;
484
485 DomainLocalModule *pLocalModule = pModule->GetDomainLocalModule(appDomain);
486 if (pLocalModule == NULL)
487 return NULL;
488
489 return GetBaseInDomainLocalModule(pLocalModule);
490 }
491
492 // returns the address of the field
493 void* GetStaticAddress(void *base);
494
495 // In all cases except Value classes, the AddressHandle is
496 // simply the address of the static. For the case of value
497 // types, however, it is the address of OBJECTREF that holds
498 // the boxed value used to hold the value type. This is needed
499 // because the OBJECTREF moves, and the JIT needs to embed something
500 // in the code that does not move. Thus the jit has to
501 // dereference and unbox before the access.
502 PTR_VOID GetStaticAddressHandle(PTR_VOID base);
503
504#ifndef DACCESS_COMPILE
505 OBJECTREF GetStaticOBJECTREF()
506 {
507 WRAPPER_NO_CONTRACT;
508 return *(OBJECTREF *)GetCurrentStaticAddress();
509 }
510
511 VOID SetStaticOBJECTREF(OBJECTREF objRef)
512 {
513 CONTRACTL
514 {
515 THROWS;
516 GC_TRIGGERS;
517 MODE_COOPERATIVE;
518 INJECT_FAULT(COMPlusThrowOM());
519 }
520 CONTRACTL_END
521
522 GCPROTECT_BEGIN(objRef);
523 OBJECTREF *pObjRef = (OBJECTREF *)GetCurrentStaticAddress();
524 SetObjectReference(pObjRef, objRef, GetAppDomain());
525 GCPROTECT_END();
526 }
527
528 void* GetStaticValuePtr()
529 {
530 WRAPPER_NO_CONTRACT;
531 return *(void**)GetCurrentStaticAddress();
532 }
533
534 VOID SetStaticValuePtr(void *value)
535 {
536 WRAPPER_NO_CONTRACT;
537 *(void**)GetCurrentStaticAddress() = value;
538 }
539
540 DWORD GetStaticValue32()
541 {
542 WRAPPER_NO_CONTRACT;
543 return *(DWORD*)GetCurrentStaticAddress();
544 }
545
546 VOID SetStaticValue32(DWORD dwValue)
547 {
548 WRAPPER_NO_CONTRACT;
549 *(DWORD*)GetCurrentStaticAddress() = dwValue;
550 }
551
552 USHORT GetStaticValue16()
553 {
554 WRAPPER_NO_CONTRACT;
555 return *(USHORT*)GetCurrentStaticAddress();
556 }
557
558 VOID SetStaticValue16(DWORD dwValue)
559 {
560 WRAPPER_NO_CONTRACT;
561 *(USHORT*)GetCurrentStaticAddress() = (USHORT)dwValue;
562 }
563
564 BYTE GetStaticValue8()
565 {
566 WRAPPER_NO_CONTRACT;
567 return *(BYTE*)GetCurrentStaticAddress();
568 }
569
570 VOID SetStaticValue8(DWORD dwValue)
571 {
572 WRAPPER_NO_CONTRACT;
573 *(BYTE*)GetCurrentStaticAddress() = (BYTE)dwValue;
574 }
575
576 __int64 GetStaticValue64()
577 {
578 WRAPPER_NO_CONTRACT;
579 return *(__int64*)GetCurrentStaticAddress();
580 }
581
582 VOID SetStaticValue64(__int64 qwValue)
583 {
584 WRAPPER_NO_CONTRACT;
585 *(__int64*)GetCurrentStaticAddress() = qwValue;
586 }
587
588 void* GetCurrentStaticAddress()
589 {
590 CONTRACTL
591 {
592 THROWS;
593 GC_TRIGGERS;
594 MODE_COOPERATIVE;
595 INJECT_FAULT(COMPlusThrowOM());
596 }
597 CONTRACTL_END
598
599 _ASSERTE(IsStatic());
600
601 if (IsThreadStatic())
602 {
603 return Thread::GetStaticFieldAddress(this);
604 }
605 else {
606 PTR_BYTE base = 0;
607 if (!IsRVA()) // for RVA the base is ignored
608 base = GetBase();
609 return GetStaticAddress((void *)dac_cast<TADDR>(base));
610 }
611 }
612
613 VOID CheckRunClassInitThrowing()
614 {
615 CONTRACTL
616 {
617 THROWS;
618 GC_TRIGGERS;
619 INJECT_FAULT(COMPlusThrowOM());
620 }
621 CONTRACTL_END;
622
623 GetEnclosingMethodTable()->CheckRunClassInitThrowing();
624 }
625#endif //DACCESS_COMPILE
626
627 Module *GetModule()
628 {
629 LIMITED_METHOD_DAC_CONTRACT;
630
631 return GetApproxEnclosingMethodTable()->GetModule();
632 }
633
634 BOOL IsZapped()
635 {
636 WRAPPER_NO_CONTRACT;
637
638 // Field Desc's are currently always saved into the same module as their
639 // corresponding method table.
640 return GetApproxEnclosingMethodTable()->IsZapped();
641 }
642
643 Module *GetLoaderModule()
644 {
645 WRAPPER_NO_CONTRACT;
646
647 // Field Desc's are currently always saved into the same module as their
648 // corresponding method table.
649 return GetApproxEnclosingMethodTable()->GetLoaderModule();
650 }
651
652 void GetSig(PCCOR_SIGNATURE *ppSig, DWORD *pcSig)
653 {
654 CONTRACTL
655 {
656 NOTHROW;
657 GC_NOTRIGGER;
658 MODE_ANY;
659 SO_TOLERANT;
660 }
661 CONTRACTL_END
662
663 if (FAILED(GetMDImport()->GetSigOfFieldDef(GetMemberDef(), pcSig, ppSig)))
664 { // Class loader already asked for signature, so this should always succeed (unless there's a
665 // bug or a new code path)
666 _ASSERTE(!"If this ever fires, then this method should return HRESULT");
667 *ppSig = NULL;
668 *pcSig = 0;
669 }
670 }
671
672 SigPointer GetSigPointer()
673 {
674 WRAPPER_NO_CONTRACT;
675
676 PCCOR_SIGNATURE pSig;
677 DWORD cSig;
678
679 GetSig(&pSig, &cSig);
680
681 return SigPointer(pSig, cSig);
682 }
683
684 // This is slow (uses MetaData), don't use it!
685 LPCUTF8 GetName()
686 {
687 CONTRACTL
688 {
689 THROWS;
690 GC_NOTRIGGER;
691 MODE_ANY;
692 }
693 CONTRACTL_END
694
695 LPCSTR szName;
696 IfFailThrow(GetMDImport()->GetNameOfFieldDef(GetMemberDef(), &szName));
697 _ASSERTE(szName != NULL);
698 return szName;
699 }
700 // This is slow (uses MetaData), don't use it!
701 __checkReturn
702 HRESULT GetName_NoThrow(LPCUTF8 *pszName)
703 {
704 CONTRACTL
705 {
706 NOTHROW;
707 GC_NOTRIGGER;
708 MODE_ANY;
709 SO_TOLERANT;
710 }
711 CONTRACTL_END
712
713 return GetMDImport()->GetNameOfFieldDef(GetMemberDef(), pszName);
714 }
715
716 void PrecomputeNameHash();
717 BOOL MightHaveName(ULONG nameHashValue);
718
719 // <TODO>@TODO: </TODO>This is slow, don't use it!
720 DWORD GetAttributes()
721 {
722 CONTRACTL
723 {
724 NOTHROW;
725 GC_NOTRIGGER;
726 MODE_ANY;
727 SO_TOLERANT;
728 }
729 CONTRACTL_END
730
731 DWORD dwAttributes;
732 if (FAILED(GetMDImport()->GetFieldDefProps(GetMemberDef(), &dwAttributes)))
733 { // Class loader already asked for attributes, so this should always succeed (unless there's a
734 // bug or a new code path)
735 _ASSERTE(!"If this ever fires, then this method should return HRESULT");
736 return 0;
737 }
738 return dwAttributes;
739 }
740
741 // Mini-Helpers
742 DWORD IsPublic()
743 {
744 WRAPPER_NO_CONTRACT;
745
746 return IsFdPublic(GetFieldProtection());
747 }
748
749 DWORD IsProtected()
750 {
751 WRAPPER_NO_CONTRACT;
752 return IsFdFamily(GetFieldProtection());
753 }
754
755 DWORD IsPrivate()
756 {
757 WRAPPER_NO_CONTRACT;
758
759 return IsFdPrivate(GetFieldProtection());
760 }
761
762 IMDInternalImport *GetMDImport()
763 {
764 LIMITED_METHOD_DAC_CONTRACT;
765
766 return GetModule()->GetMDImport();
767 }
768
769#ifndef DACCESS_COMPILE
770 IMetaDataImport *GetRWImporter()
771 {
772 WRAPPER_NO_CONTRACT;
773
774 return GetModule()->GetRWImporter();
775 }
776#endif // DACCESS_COMPILE
777
778 TypeHandle LookupFieldTypeHandle(ClassLoadLevel level = CLASS_LOADED, BOOL dropGenericArgumentLevel = FALSE);
779
780 TypeHandle LookupApproxFieldTypeHandle()
781 {
782 WRAPPER_NO_CONTRACT;
783 return LookupFieldTypeHandle(CLASS_LOAD_APPROXPARENTS, TRUE);
784 }
785
786 // Instance FieldDesc can be shared between generic instantiations. So List<String>._items
787 // is really the same as List<__Canon>._items. Hence, the FieldDesc itself
788 // cannot know the exact field type. This function returns the approximate field type.
789 // For eg. this will return "__Canon[]" for List<String>._items.
790 TypeHandle GetFieldTypeHandleThrowing(ClassLoadLevel level = CLASS_LOADED, BOOL dropGenericArgumentLevel = FALSE);
791
792 TypeHandle GetApproxFieldTypeHandleThrowing()
793 {
794 WRAPPER_NO_CONTRACT;
795 return GetFieldTypeHandleThrowing(CLASS_LOAD_APPROXPARENTS, TRUE);
796 }
797
798 // Given a type handle of an object and a method that comes from some
799 // superclass of the class of that object, find the instantiation of
800 // that superclass, i.e. the class instantiation which will be relevant
801 // to interpreting the signature of the method. The type handle of
802 // the object does not need to be given in all circumstances, in
803 // particular it is only needed for FieldDescs pFD that
804 // return true for pFD->GetApproxEnclosingMethodTable()->IsSharedByGenericInstantiations().
805 // In other cases it is allowed to be null and will be ignored.
806 //
807 // Will return NULL if the field is not in a generic class.
808 Instantiation GetExactClassInstantiation(TypeHandle possibleObjType);
809
810 // Instance FieldDesc can be shared between generic instantiations. So List<String>._items
811 // is really the same as List<__Canon>._items. Hence, the FieldDesc itself
812 // cannot know the exact field type. You need to specify the owner
813 // like List<String> in order to get the exact type which would be "String[]"
814 TypeHandle GetExactFieldType(TypeHandle owner);
815
816#ifdef DACCESS_COMPILE
817 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
818 {
819 SUPPORTS_DAC;
820 DAC_ENUM_DTHIS();
821 }
822#endif
823
824#ifndef DACCESS_COMPILE
825 REFLECTFIELDREF GetStubFieldInfo();
826#endif
827};
828
829#endif // _FIELD_H_
830
831