From ef1e2ab328087c61a6878c1e84f4fc5d710aebce Mon Sep 17 00:00:00 2001 From: dotnet-bot Date: Fri, 30 Jan 2015 14:14:42 -0800 Subject: Initial commit to populate CoreCLR repo [tfs-changeset: 1407945] --- src/vm/field.h | 1004 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1004 insertions(+) create mode 100644 src/vm/field.h (limited to 'src/vm/field.h') diff --git a/src/vm/field.h b/src/vm/field.h new file mode 100644 index 0000000000..a278c4d12c --- /dev/null +++ b/src/vm/field.h @@ -0,0 +1,1004 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// +// COM+ Data Field Abstraction +// + + +#ifndef _FIELD_H_ +#define _FIELD_H_ + +#ifndef BINDER +#include "objecthandle.h" +#include "excep.h" +#else // BINDER +#include "methodtable.h" +#endif // BINDER + +// Temporary values stored in FieldDesc m_dwOffset during loading +// The high 5 bits must be zero (because in field.h we steal them for other uses), so we must choose values > 0 +#define FIELD_OFFSET_MAX ((1<<27)-1) +#define FIELD_OFFSET_UNPLACED FIELD_OFFSET_MAX +#define FIELD_OFFSET_UNPLACED_GC_PTR (FIELD_OFFSET_MAX-1) +#define FIELD_OFFSET_VALUE_CLASS (FIELD_OFFSET_MAX-2) +#define FIELD_OFFSET_NOT_REAL_FIELD (FIELD_OFFSET_MAX-3) + +// Offset to indicate an EnC added field. They don't have offsets as aren't placed in the object. +#define FIELD_OFFSET_NEW_ENC (FIELD_OFFSET_MAX-4) +#define FIELD_OFFSET_BIG_RVA (FIELD_OFFSET_MAX-5) +#define FIELD_OFFSET_LAST_REAL_OFFSET (FIELD_OFFSET_MAX-6) // real fields have to be smaller than this + + +// +// This describes a field - one of this is allocated for every field, so don't make this structure any larger. +// +// @GENERICS: +// Field descriptors for fields in instantiated types may be shared between compatible instantiations +// Hence for reflection it's necessary to pair a field desc with the exact owning type handle +class FieldDesc +{ + friend class MethodTableBuilder; +#ifdef BINDER + friend class MdilModule; +#endif // BINDER +#ifdef DACCESS_COMPILE + friend class NativeImageDumper; +#endif + + protected: + RelativePointer m_pMTOfEnclosingClass; // This is used to hold the log2 of the field size temporarily during class loading. Yuck. + +#if defined(DACCESS_COMPILE) + union { //create a union so I can get the correct offset for ClrDump. + unsigned m_dword1; + struct { +#endif + // Note that we may store other information in the high bits if available -- + // see enum_packedMBLayout and m_requiresFullMbValue for details. + unsigned m_mb : 24; + + // 8 bits... + unsigned m_isStatic : 1; + unsigned m_isThreadLocal : 1; +#ifdef FEATURE_REMOTING + unsigned m_isContextLocal : 1; +#endif + unsigned m_isRVA : 1; + unsigned m_prot : 3; + // Does this field's mb require all 24 bits + unsigned m_requiresFullMbValue : 1; +#if defined(DACCESS_COMPILE) + }; + }; +#endif + +#if defined(DACCESS_COMPILE) + union { //create a union so I can get the correct offset for ClrDump + unsigned m_dword2; + struct { +#endif + // Note: this has been as low as 22 bits in the past & seemed to be OK. + // we can steal some more bits here if we need them. + unsigned m_dwOffset : 27; + unsigned m_type : 5; +#if defined(DACCESS_COMPILE) + }; + }; +#endif + +#ifdef _DEBUG + struct { + unsigned m_isDangerousAppDomainAgileField : 1; + }; + LPUTF8 m_debugName; +#endif + + // Allocated by special heap means, don't construct me + FieldDesc() {}; + +public: +#ifdef BINDER + // We will need these to implement pseudoinstructions COPY_STRUCT, + // PUSH_STRUCT (versionable struct support). + // They are implemented via a side hash table in MdilModule + DWORD GetFieldValueTypeToken(); + void SetFieldValueTypeToken(DWORD valueTypeToken); + MethodTable *GetFieldFullType(); + void SetFieldFullType(MethodTable *mt); +#endif + +#ifdef _DEBUG + inline LPUTF8 GetDebugName() + { + LIMITED_METHOD_CONTRACT; + return m_debugName; + } +#endif // _DEBUG + +#ifndef DACCESS_COMPILE + // This should be called. It was added so that Reflection + // can create FieldDesc's for the static primitive fields that aren't + // stored with the EEClass. + void SetMethodTable(MethodTable* mt) + { + LIMITED_METHOD_CONTRACT; + m_pMTOfEnclosingClass.SetValue(mt); + } +#endif + + VOID Init(mdFieldDef mb, + CorElementType FieldType, + DWORD dwMemberAttrs, + BOOL fIsStatic, + BOOL fIsRVA, + BOOL fIsThreadLocal, + BOOL fIsContextLocal, + LPCSTR pszFieldName); + + enum { + enum_packedMbLayout_MbMask = 0x01FFFF, + enum_packedMbLayout_NameHashMask = 0xFE0000 + }; + + void SetMemberDef(mdFieldDef mb) + { + WRAPPER_NO_CONTRACT; + + // Check if we have to avoid using the packed mb layout + if (RidFromToken(mb) > enum_packedMbLayout_MbMask) + { + m_requiresFullMbValue = 1; + } + + // Set only the portion of m_mb we are using + if (!m_requiresFullMbValue) + { + m_mb &= ~enum_packedMbLayout_MbMask; + m_mb |= RidFromToken(mb); + } + else + { + m_mb = RidFromToken(mb); + } + } + + mdFieldDef GetMemberDef() const + { + LIMITED_METHOD_DAC_CONTRACT; + + // Check if this FieldDesc is using the packed mb layout + if (!m_requiresFullMbValue) + { + return TokenFromRid(m_mb & enum_packedMbLayout_MbMask, mdtFieldDef); + } + + return TokenFromRid(m_mb, mdtFieldDef); + } + + CorElementType GetFieldType() + { + LIMITED_METHOD_DAC_CONTRACT; + + // Set in code:FieldDesc.Init which in turn is called from + // code:MethodTableBuilder.InitializeFieldDescs#InitCall which in turn calls + // code:MethodTableBuilder.InitializeFieldDescs#FieldDescTypeMorph + return (CorElementType) m_type; + } +#ifdef BINDER + void SetFieldType(CorElementType type) + { + + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + + // Set in code:FieldDesc.Init which in turn is called from + // code:MethodTableBuilder.InitializeFieldDescs#InitCall which in turn calls + // code:MethodTableBuilder.InitializeFieldDescs#FieldDescTypeMorph + m_type = type; + } +#endif + + DWORD GetFieldProtection() + { + LIMITED_METHOD_CONTRACT; + + // Set in code:FieldDesc.Init which in turn is called from code:MethodTableBuilder::InitializeFieldDescs#InitCall + return m_prot; + } + + // Please only use this in a path that you have already guarenteed + // the assert is true + DWORD GetOffsetUnsafe() + { + LIMITED_METHOD_CONTRACT; + + g_IBCLogger.LogFieldDescsAccess(this); + _ASSERTE(m_dwOffset <= FIELD_OFFSET_LAST_REAL_OFFSET); + return m_dwOffset; + } + + DWORD GetOffset() + { + LIMITED_METHOD_DAC_CONTRACT; + + g_IBCLogger.LogFieldDescsAccess(this); + return GetOffset_NoLogging(); + } + + // During class load m_pMTOfEnclosingClass has the field size in it, so it has to use this version of + // GetOffset during that time + DWORD GetOffset_NoLogging() + { + LIMITED_METHOD_DAC_CONTRACT; + + // Note FieldDescs are no longer on "hot" paths so the optimized code here + // does not look necessary. + + if (m_dwOffset != FIELD_OFFSET_BIG_RVA) { + // Assert that the big RVA case handling doesn't get out of sync + // with the normal RVA case. +#ifdef _DEBUG + // The OutOfLine_BigRVAOffset() can't be correctly evaluated during the time + // that we repurposed m_pMTOfEnclosingClass for holding the field size + // I don't see any good way to determine when this is so hurray for + // heuristics! + // + // As of 4/11/2012 I could repro this by turning on the COMPLUS log and + // the LOG() at line methodtablebuilder.cpp:7845 + // MethodTableBuilder::PlaceRegularStaticFields() calls GetOffset_NoLogging() + if((DWORD)(DWORD_PTR&)m_pMTOfEnclosingClass > 16) + { + _ASSERTE(!this->IsRVA() || (m_dwOffset == OutOfLine_BigRVAOffset())); + } +#endif + return m_dwOffset; + } + + return OutOfLine_BigRVAOffset(); + } + + DWORD OutOfLine_BigRVAOffset() + { + LIMITED_METHOD_DAC_CONTRACT; + + DWORD rva; + +#ifndef BINDER + // I'm discarding a potential error here. According to the code in MDInternalRO.cpp, + // we won't get an error if we initially found the RVA. So I'm going to just + // assert it never happens. + // + // This is a small sin, but I don't see a good alternative. --cwb. + HRESULT hr; + hr = GetMDImport()->GetFieldRVA(GetMemberDef(), &rva); + _ASSERTE(SUCCEEDED(hr)); +#else // BINDER + BOOL fSucceeded = GetRVAOffsetForFieldDesc(this, &rva); + assert(fSucceeded); +#endif // BINDER + return rva; + } + + HRESULT SetOffset(DWORD dwOffset) + { + LIMITED_METHOD_CONTRACT; + + // + // value class fields must be aligned to pointer-sized boundaries + // + // + // This is commented out because it isn't valid in all cases. + // This is still here because it is useful for finding alignment + // problems on IA64. + // + //_ASSERTE((dwOffset > FIELD_OFFSET_LAST_REAL_OFFSET) || + // (ELEMENT_TYPE_VALUETYPE != GetFieldType()) || + // (IS_ALIGNED(dwOffset, sizeof(void*)))); + + m_dwOffset = dwOffset; + return((dwOffset > FIELD_OFFSET_LAST_REAL_OFFSET) ? COR_E_TYPELOAD : S_OK); + } + + // Okay, we've stolen too many bits from FieldDescs. In the RVA case, there's no + // reason to believe they will be limited to 22 bits. So use a sentinel for the + // huge cases, and recover them from metadata on-demand. + void SetOffsetRVA(DWORD dwOffset) + { + LIMITED_METHOD_CONTRACT; + + m_dwOffset = (dwOffset > FIELD_OFFSET_LAST_REAL_OFFSET) + ? FIELD_OFFSET_BIG_RVA + : dwOffset; +#ifdef BINDER + StoreRVAOffsetForFieldDesc(this, dwOffset); +#endif + } + +#ifndef BINDER + BOOL IsILOnlyRVAField() + { + WRAPPER_NO_CONTRACT; + return (IsRVA() && GetModule()->GetFile()->IsILOnly()); + } +#endif // !BINDER + + DWORD IsStatic() const + { + LIMITED_METHOD_DAC_CONTRACT; + + return m_isStatic; + } + + BOOL IsSpecialStatic() + { + LIMITED_METHOD_CONTRACT; + + return m_isStatic && (m_isRVA || m_isThreadLocal +#ifdef FEATURE_REMOTING + || m_isContextLocal +#endif + ); + } + +#if defined(CHECK_APP_DOMAIN_LEAKS) || defined(_DEBUG) + BOOL IsDangerousAppDomainAgileField() + { + LIMITED_METHOD_CONTRACT; + + return m_isDangerousAppDomainAgileField; + } + + void SetDangerousAppDomainAgileField() + { + LIMITED_METHOD_CONTRACT; + + m_isDangerousAppDomainAgileField = TRUE; + } +#endif + + BOOL IsRVA() const // Has an explicit RVA associated with it + { + LIMITED_METHOD_DAC_CONTRACT; + + return m_isRVA; + } + + BOOL IsThreadStatic() const // Static relative to a thread + { + LIMITED_METHOD_DAC_CONTRACT; + + return m_isThreadLocal; + } + + BOOL IsContextStatic() const // Static relative to a context + { + LIMITED_METHOD_DAC_CONTRACT; + +#ifdef FEATURE_REMOTING + return m_isContextLocal; +#else + return FALSE; +#endif + } + + // Indicate that this field was added by EnC + // Must only be called on instances of EnCFieldDesc + void SetEnCNew() + { + WRAPPER_NO_CONTRACT; + + // EnC added fields don't live in the actual object, so don't have a real offset + SetOffset(FIELD_OFFSET_NEW_ENC); + } + + // Was this field added by EnC? + // If this is true, then this object is an instance of EnCFieldDesc + BOOL IsEnCNew() + { + LIMITED_METHOD_DAC_CONTRACT; + + // EnC added fields don't have a real offset + return m_dwOffset == FIELD_OFFSET_NEW_ENC; + } + + BOOL IsByValue() + { + LIMITED_METHOD_DAC_CONTRACT; + + return GetFieldType() == ELEMENT_TYPE_VALUETYPE; + } + + BOOL IsPrimitive() + { + LIMITED_METHOD_DAC_CONTRACT; + + return (CorIsPrimitiveType(GetFieldType()) != FALSE); + } + + BOOL IsObjRef(); + +#ifdef FEATURE_PREJIT + void SaveContents(DataImage *image); + void Fixup(DataImage *image); +#endif // FEATURE_PREJIT + + UINT LoadSize(); + + // Return -1 if the type isn't loaded yet (i.e. if LookupFieldTypeHandle() would return null) + UINT GetSize(); + + // These routines encapsulate the operation of getting and setting + // fields. + void GetInstanceField(OBJECTREF o, VOID * pOutVal); + void SetInstanceField(OBJECTREF o, const VOID * pInVal); + + void* GetInstanceAddress(OBJECTREF o); + + // Get the address of a field within object 'o' + PTR_VOID GetAddress(PTR_VOID o); + + PTR_VOID GetAddressNoThrowNoGC(PTR_VOID o); + void* GetAddressGuaranteedInHeap(void *o); + + void* GetValuePtr(OBJECTREF o); + VOID SetValuePtr(OBJECTREF o, void* pValue); + DWORD GetValue32(OBJECTREF o); + VOID SetValue32(OBJECTREF o, DWORD dwValue); + OBJECTREF GetRefValue(OBJECTREF o); + VOID SetRefValue(OBJECTREF o, OBJECTREF orValue); + USHORT GetValue16(OBJECTREF o); + VOID SetValue16(OBJECTREF o, DWORD dwValue); + BYTE GetValue8(OBJECTREF o); + VOID SetValue8(OBJECTREF o, DWORD dwValue); + __int64 GetValue64(OBJECTREF o); + VOID SetValue64(OBJECTREF o, __int64 value); + + PTR_MethodTable GetApproxEnclosingMethodTable_NoLogging() + { + LIMITED_METHOD_DAC_CONTRACT; + return m_pMTOfEnclosingClass.GetValue(PTR_HOST_MEMBER_TADDR(FieldDesc, this, m_pMTOfEnclosingClass)); + } + + PTR_MethodTable GetApproxEnclosingMethodTable() + { + LIMITED_METHOD_DAC_CONTRACT; + g_IBCLogger.LogFieldDescsAccess(this); + return GetApproxEnclosingMethodTable_NoLogging(); + } + + PTR_MethodTable GetEnclosingMethodTable() + { + LIMITED_METHOD_DAC_CONTRACT; + _ASSERTE(!IsSharedByGenericInstantiations()); + return GetApproxEnclosingMethodTable(); + } + + // FieldDesc can be shared between generic instantiations. So List._items + // is really the same as List<__Canon>._items. Hence, the FieldDesc itself + // cannot know the exact enclosing type. You need to provide the exact owner + // like List or a subtype like MyInheritedList. + MethodTable * GetExactDeclaringType(MethodTable * ownerOrSubType); + + BOOL IsSharedByGenericInstantiations() + { + LIMITED_METHOD_DAC_CONTRACT; +#ifndef BINDER + return (!IsStatic()) && GetApproxEnclosingMethodTable()->IsSharedByGenericInstantiations(); +#else // BINDER + return FALSE; +#endif // BINDER + } + + BOOL IsFieldOfValueType() + { + WRAPPER_NO_CONTRACT; + return GetApproxEnclosingMethodTable()->IsValueType(); + } + + DWORD GetNumGenericClassArgs() + { + WRAPPER_NO_CONTRACT; + return GetApproxEnclosingMethodTable()->GetNumGenericArgs(); + } + + +#ifndef BINDER + + PTR_BYTE GetBaseInDomainLocalModule(DomainLocalModule * pLocalModule) + { + WRAPPER_NO_CONTRACT; + + if (GetFieldType() == ELEMENT_TYPE_CLASS || GetFieldType() == ELEMENT_TYPE_VALUETYPE) + { + return pLocalModule->GetGCStaticsBasePointer(GetEnclosingMethodTable()); + } + else + { + return pLocalModule->GetNonGCStaticsBasePointer(GetEnclosingMethodTable()); + } + } + +#ifndef DACCESS_COMPILE + PTR_BYTE GetBase() + { + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + MethodTable *pMT = GetEnclosingMethodTable(); + + return GetBaseInDomainLocalModule(pMT->GetDomainLocalModule()); + } + +#endif //!DACCESS_COMPILE + + PTR_BYTE GetBaseInDomain(AppDomain * appDomain) + { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + } + CONTRACTL_END; + + Module *pModule = GetEnclosingMethodTable()->GetModuleForStatics(); + if (pModule == NULL) + return NULL; + + DomainLocalModule *pLocalModule = pModule->GetDomainLocalModule(appDomain); + if (pLocalModule == NULL) + return NULL; + + return GetBaseInDomainLocalModule(pLocalModule); + } + + // returns the address of the field + void* GetStaticAddress(void *base); + + // In all cases except Value classes, the AddressHandle is + // simply the address of the static. For the case of value + // types, however, it is the address of OBJECTREF that holds + // the boxed value used to hold the value type. This is needed + // because the OBJECTREF moves, and the JIT needs to embed something + // in the code that does not move. Thus the jit has to + // dereference and unbox before the access. + PTR_VOID GetStaticAddressHandle(PTR_VOID base); + +#ifndef DACCESS_COMPILE + OBJECTREF GetStaticOBJECTREF() + { + WRAPPER_NO_CONTRACT; + return *(OBJECTREF *)GetCurrentStaticAddress(); + } + + VOID SetStaticOBJECTREF(OBJECTREF objRef) + { + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + GCPROTECT_BEGIN(objRef); + OBJECTREF *pObjRef = (OBJECTREF *)GetCurrentStaticAddress(); + SetObjectReference(pObjRef, objRef, GetAppDomain()); + GCPROTECT_END(); + } + + void* GetStaticValuePtr() + { + WRAPPER_NO_CONTRACT; + return *(void**)GetCurrentStaticAddress(); + } + + VOID SetStaticValuePtr(void *value) + { + WRAPPER_NO_CONTRACT; + *(void**)GetCurrentStaticAddress() = value; + } + + DWORD GetStaticValue32() + { + WRAPPER_NO_CONTRACT; + return *(DWORD*)GetCurrentStaticAddress(); + } + + VOID SetStaticValue32(DWORD dwValue) + { + WRAPPER_NO_CONTRACT; + *(DWORD*)GetCurrentStaticAddress() = dwValue; + } + + USHORT GetStaticValue16() + { + WRAPPER_NO_CONTRACT; + return *(USHORT*)GetCurrentStaticAddress(); + } + + VOID SetStaticValue16(DWORD dwValue) + { + WRAPPER_NO_CONTRACT; + *(USHORT*)GetCurrentStaticAddress() = (USHORT)dwValue; + } + + BYTE GetStaticValue8() + { + WRAPPER_NO_CONTRACT; + return *(BYTE*)GetCurrentStaticAddress(); + } + + VOID SetStaticValue8(DWORD dwValue) + { + WRAPPER_NO_CONTRACT; + *(BYTE*)GetCurrentStaticAddress() = (BYTE)dwValue; + } + + __int64 GetStaticValue64() + { + WRAPPER_NO_CONTRACT; + return *(__int64*)GetCurrentStaticAddress(); + } + + VOID SetStaticValue64(__int64 qwValue) + { + WRAPPER_NO_CONTRACT; + *(__int64*)GetCurrentStaticAddress() = qwValue; + } + + void* GetCurrentStaticAddress() + { + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + _ASSERTE(IsStatic()); + +#ifdef FEATURE_REMOTING + if (IsContextStatic()) + return Context::GetStaticFieldAddress(this); + else +#endif + if (IsThreadStatic()) + { + return Thread::GetStaticFieldAddress(this); + } + else { + PTR_BYTE base = 0; + if (!IsRVA()) // for RVA the base is ignored + base = GetBase(); + return GetStaticAddress((void *)dac_cast(base)); + } + } + + VOID CheckRunClassInitThrowing() + { + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END; + + GetEnclosingMethodTable()->CheckRunClassInitThrowing(); + } +#endif //DACCESS_COMPILE +#endif // !BINDER + +#ifdef BINDER + MdilModule *GetModule() + { + WRAPPER_NO_CONTRACT; + + return GetApproxEnclosingMethodTable()->GetModule(); + } + + MdilModule *GetLoaderModule() + { + WRAPPER_NO_CONTRACT; + + // Field Desc's are currently always saved into the same module as their + // corresponding method table. + return GetApproxEnclosingMethodTable()->GetLoaderModule(); + } +#else //!BINDER + Module *GetModule() + { + LIMITED_METHOD_DAC_CONTRACT; + + return GetApproxEnclosingMethodTable()->GetModule(); + } + + BOOL IsZapped() + { + WRAPPER_NO_CONTRACT; + + // Field Desc's are currently always saved into the same module as their + // corresponding method table. + return GetApproxEnclosingMethodTable()->IsZapped(); + } + + Module *GetLoaderModule() + { + WRAPPER_NO_CONTRACT; + + // Field Desc's are currently always saved into the same module as their + // corresponding method table. + return GetApproxEnclosingMethodTable()->GetLoaderModule(); + } + + void GetSig(PCCOR_SIGNATURE *ppSig, DWORD *pcSig) + { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + } + CONTRACTL_END + + if (FAILED(GetMDImport()->GetSigOfFieldDef(GetMemberDef(), pcSig, ppSig))) + { // Class loader already asked for signature, so this should always succeed (unless there's a + // bug or a new code path) + _ASSERTE(!"If this ever fires, then this method should return HRESULT"); + *ppSig = NULL; + *pcSig = 0; + } + } + + SigPointer GetSigPointer() + { + WRAPPER_NO_CONTRACT; + + PCCOR_SIGNATURE pSig; + DWORD cSig; + + GetSig(&pSig, &cSig); + + return SigPointer(pSig, cSig); + } + + // This is slow (uses MetaData), don't use it! + LPCUTF8 GetName() + { + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END + + LPCSTR szName; + IfFailThrow(GetMDImport()->GetNameOfFieldDef(GetMemberDef(), &szName)); + _ASSERTE(szName != NULL); + return szName; + } + // This is slow (uses MetaData), don't use it! + __checkReturn + HRESULT GetName_NoThrow(LPCUTF8 *pszName) + { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + } + CONTRACTL_END + + return GetMDImport()->GetNameOfFieldDef(GetMemberDef(), pszName); + } + + void PrecomputeNameHash(); + BOOL MightHaveName(ULONG nameHashValue); + + // @TODO: This is slow, don't use it! + DWORD GetAttributes() + { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + } + CONTRACTL_END + + DWORD dwAttributes; + if (FAILED(GetMDImport()->GetFieldDefProps(GetMemberDef(), &dwAttributes))) + { // Class loader already asked for attributes, so this should always succeed (unless there's a + // bug or a new code path) + _ASSERTE(!"If this ever fires, then this method should return HRESULT"); + return 0; + } + return dwAttributes; + } + + // Mini-Helpers + DWORD IsPublic() + { + WRAPPER_NO_CONTRACT; + + return IsFdPublic(GetFieldProtection()); + } + + DWORD IsProtected() + { + WRAPPER_NO_CONTRACT; + return IsFdFamily(GetFieldProtection()); + } + + DWORD IsPrivate() + { + WRAPPER_NO_CONTRACT; + + return IsFdPrivate(GetFieldProtection()); + } + + BOOL IsNotSerialized() + { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SO_TOLERANT; + MODE_ANY; + } + CONTRACTL_END; + + MethodTable *pMT = GetApproxEnclosingMethodTable(); + if (pMT->IsSerializable() && !IsStatic()) + return pMT->IsFieldNotSerialized(pMT->GetIndexForFieldDesc(this)); + return IsFdNotSerialized(GetAttributes()); + } + + // Only safe to call this for non-static fields on serializable types. + BOOL IsOptionallySerialized() + { + WRAPPER_NO_CONTRACT; + + _ASSERTE(!IsStatic() && GetApproxEnclosingMethodTable()->IsSerializable()); + + MethodTable *pMT = GetApproxEnclosingMethodTable(); + return pMT->IsFieldOptionallySerialized(pMT->GetIndexForFieldDesc(this)); + } + + IMDInternalImport *GetMDImport() + { + LIMITED_METHOD_DAC_CONTRACT; + + return GetModule()->GetMDImport(); + } + +#ifndef DACCESS_COMPILE + IMetaDataImport *GetRWImporter() + { + WRAPPER_NO_CONTRACT; + + return GetModule()->GetRWImporter(); + } +#endif // DACCESS_COMPILE + + TypeHandle LookupFieldTypeHandle(ClassLoadLevel level = CLASS_LOADED, BOOL dropGenericArgumentLevel = FALSE); + + TypeHandle LookupApproxFieldTypeHandle() + { + WRAPPER_NO_CONTRACT; + return LookupFieldTypeHandle(CLASS_LOAD_APPROXPARENTS, TRUE); + } + + // Instance FieldDesc can be shared between generic instantiations. So List._items + // is really the same as List<__Canon>._items. Hence, the FieldDesc itself + // cannot know the exact field type. This function returns the approximate field type. + // For eg. this will return "__Canon[]" for List._items. + TypeHandle GetFieldTypeHandleThrowing(ClassLoadLevel level = CLASS_LOADED, BOOL dropGenericArgumentLevel = FALSE); + + TypeHandle GetApproxFieldTypeHandleThrowing() + { + WRAPPER_NO_CONTRACT; + return GetFieldTypeHandleThrowing(CLASS_LOAD_APPROXPARENTS, TRUE); + } +#endif // !BINDER + + // Given a type handle of an object and a method that comes from some + // superclass of the class of that object, find the instantiation of + // that superclass, i.e. the class instantiation which will be relevant + // to interpreting the signature of the method. The type handle of + // the object does not need to be given in all circumstances, in + // particular it is only needed for FieldDescs pFD that + // return true for pFD->GetApproxEnclosingMethodTable()->IsSharedByGenericInstantiations(). + // In other cases it is allowed to be null and will be ignored. + // + // Will return NULL if the field is not in a generic class. + Instantiation GetExactClassInstantiation(TypeHandle possibleObjType); + + // Instance FieldDesc can be shared between generic instantiations. So List._items + // is really the same as List<__Canon>._items. Hence, the FieldDesc itself + // cannot know the exact field type. You need to specify the owner + // like List in order to get the exact type which would be "String[]" + TypeHandle GetExactFieldType(TypeHandle owner); + +#ifdef DACCESS_COMPILE + void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) + { + SUPPORTS_DAC; + DAC_ENUM_DTHIS(); + } +#endif + +#ifndef DACCESS_COMPILE + REFLECTFIELDREF GetStubFieldInfo(); +#endif +}; + +#ifdef BINDER +inline VOID FieldDesc::Init(mdFieldDef mb, CorElementType FieldType, DWORD dwMemberAttrs, BOOL fIsStatic, BOOL fIsRVA, BOOL fIsThreadLocal, BOOL fIsContextLocal, LPCSTR pszFieldName) +{ + + LIMITED_METHOD_CONTRACT; + + // We allow only a subset of field types here - all objects must be set to TYPE_CLASS + // By-value classes are ELEMENT_TYPE_VALUETYPE + _ASSERTE( + FieldType == ELEMENT_TYPE_I1 || + FieldType == ELEMENT_TYPE_BOOLEAN || + FieldType == ELEMENT_TYPE_U1 || + FieldType == ELEMENT_TYPE_I2 || + FieldType == ELEMENT_TYPE_U2 || + FieldType == ELEMENT_TYPE_CHAR || + FieldType == ELEMENT_TYPE_I4 || + FieldType == ELEMENT_TYPE_U4 || + FieldType == ELEMENT_TYPE_I8 || + FieldType == ELEMENT_TYPE_I || + FieldType == ELEMENT_TYPE_U || + FieldType == ELEMENT_TYPE_U8 || + FieldType == ELEMENT_TYPE_R4 || + FieldType == ELEMENT_TYPE_R8 || + FieldType == ELEMENT_TYPE_CLASS || + FieldType == ELEMENT_TYPE_VALUETYPE || + FieldType == ELEMENT_TYPE_PTR || + FieldType == ELEMENT_TYPE_FNPTR + ); + _ASSERTE(fIsStatic || (!fIsRVA && !fIsThreadLocal && !fIsContextLocal)); + _ASSERTE(fIsRVA + fIsThreadLocal + fIsContextLocal <= 1); + + m_mb = RidFromToken(mb); + m_type = FieldType; + m_prot = fdFieldAccessMask & dwMemberAttrs; + m_isStatic = fIsStatic != 0; + m_isRVA = fIsRVA != 0; + m_isThreadLocal = fIsThreadLocal != 0; +#ifdef FEATURE_REMOTING + m_isContextLocal = fIsContextLocal != 0; +#endif + +#ifdef _DEBUG + m_isDangerousAppDomainAgileField = 0; + m_debugName = (LPUTF8)pszFieldName; +#endif + _ASSERTE(GetMemberDef() == mb); // no truncation + _ASSERTE(GetFieldType() == FieldType); + _ASSERTE(GetFieldProtection() == (fdFieldAccessMask & dwMemberAttrs)); + _ASSERTE((BOOL) IsStatic() == (fIsStatic != 0)); +} +#endif // BINDER + +#endif // _FIELD_H_ + -- cgit v1.2.3