diff options
Diffstat (limited to 'src/vm/class.h')
-rw-r--r-- | src/vm/class.h | 2681 |
1 files changed, 2681 insertions, 0 deletions
diff --git a/src/vm/class.h b/src/vm/class.h new file mode 100644 index 0000000000..f19b9818ec --- /dev/null +++ b/src/vm/class.h @@ -0,0 +1,2681 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// ==++== +// +// + +// +// ==--== +// +// File: CLASS.H +// + + +// + +// +// NOTE: Even though EEClass is considered to contain cold data (relative to MethodTable), these data +// structures *are* touched (especially during startup as part of soft-binding). As a result, and given the +// number of EEClasses allocated for large assemblies, the size of this structure can have a direct impact on +// performance, especially startup performance. +// +// Given that the data itself is touched infrequently, we can trade off space reduction against cpu-usage to +// good effect here. A fair amount of work has gone into reducing the size of each EEClass instance (see +// EEClassOptionalFields and EEClassPackedFields) at the expense of somewhat more convoluted runtime access. +// +// Please consider this (and measure the impact of your changes against startup scenarios) before adding +// fields to EEClass or otherwise increasing its size. +// +// ============================================================================ + +#ifndef CLASS_H +#define CLASS_H + +/* + * Include Files + */ +#include "eecontract.h" +#include "argslot.h" +#include "vars.hpp" +#include "cor.h" +#include "clrex.h" +#include "hash.h" +#include "crst.h" +#include "objecthandle.h" +#include "cgensys.h" +#include "declsec.h" +#ifdef FEATURE_COMINTEROP +#include "stdinterfaces.h" +#endif +#include "slist.h" +#include "spinlock.h" +#include "typehandle.h" +#include "perfcounters.h" +#include "methodtable.h" +#include "eeconfig.h" +#include "typectxt.h" +#include "iterator_util.h" + +#ifdef FEATURE_COMINTEROP +#include "..\md\winmd\inc\adapter.h" +#endif +#include "packedfields.inl" +#include "array.h" +#define IBCLOG(x) g_IBCLogger.##x + +VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr); + +/* + * Macro definitions + */ +#define MAX_LOG2_PRIMITIVE_FIELD_SIZE 3 + +#define MAX_PRIMITIVE_FIELD_SIZE (1 << MAX_LOG2_PRIMITIVE_FIELD_SIZE) + +/* + * Forward declarations + */ +class AppDomain; +class ArrayClass; +class ArrayMethodDesc; +class Assembly; +class ClassLoader; +class DictionaryLayout; +class DomainLocalBlock; +class FCallMethodDesc; +class EEClass; +class EnCFieldDesc; +class FieldDesc; +class FieldMarshaler; +struct LayoutRawFieldInfo; +class MetaSig; +class MethodDesc; +class MethodDescChunk; +class MethodTable; +class Module; +struct ModuleCtorInfo; +class Object; +class Stub; +class Substitution; +class SystemDomain; +class TypeHandle; +class StackingAllocator; +class AllocMemTracker; +class InteropMethodTableSlotDataMap; +class LoadingEntry_LockHolder; +class DispatchMapBuilder; +class LoaderAllocator; +class ComCallWrapperTemplate; + +typedef DPTR(DictionaryLayout) PTR_DictionaryLayout; + + +//--------------------------------------------------------------------------------- +// Fields in an explicit-layout class present varying degrees of risk depending +// on how they overlap. +// +// Each level is a superset of the lower (in numerical value) level - i.e. +// all kVerifiable fields are also kLegal, but not vice-versa. +//--------------------------------------------------------------------------------- +class ExplicitFieldTrust +{ + public: + enum TrustLevel + { + // Note: order is important here - each guarantee also implicitly guarantees all promises + // made by values lower in number. + + // What's guaranteed. What the loader does. + //----- ----------------------- ------------------------------- + kNone = 0, // no guarantees at all - Type refuses to load at all. + kLegal = 1, // guarantees no objref <-> scalar overlap and no unaligned objref - Type loads but field access won't verify + kVerifiable = 2, // guarantees no objref <-> objref overlap and all guarantees above - Type loads and field access will verify + kNonOverLayed = 3, // guarantees no overlap at all and all guarantees above - Type loads, field access verifies and Equals() may be optimized if structure is tightly packed + + kMaxTrust = kNonOverLayed, + }; + +}; + +//---------------------------------------------------------------------------------------------- +// This class is a helper for HandleExplicitLayout. To make it harder to introduce security holes +// into this function, we will manage all updates to the class's trust level through the ExplicitClassTrust +// class. This abstraction enforces the rule that the overall class is only as trustworthy as +// the least trustworthy field. +//---------------------------------------------------------------------------------------------- +class ExplicitClassTrust : private ExplicitFieldTrust +{ + public: + ExplicitClassTrust() + { + LIMITED_METHOD_CONTRACT; + m_trust = kMaxTrust; // Yes, we start out with maximal trust. This reflects that explicit layout structures with no fields do represent no risk. + } + + VOID AddField(TrustLevel fieldTrust) + { + LIMITED_METHOD_CONTRACT; + m_trust = min(m_trust, fieldTrust); + } + + BOOL IsLegal() + { + LIMITED_METHOD_CONTRACT; + return m_trust >= kLegal; + } + + BOOL IsVerifiable() + { + LIMITED_METHOD_CONTRACT; + return m_trust >= kVerifiable; + } + + BOOL IsNonOverLayed() + { + LIMITED_METHOD_CONTRACT; + return m_trust >= kNonOverLayed; + } + + TrustLevel GetTrustLevel() + { + LIMITED_METHOD_CONTRACT; + return m_trust; + } + + private: + TrustLevel m_trust; +}; + +//---------------------------------------------------------------------------------------------- +// This class is a helper for HandleExplicitLayout. To make it harder to introduce security holes +// into this function, this class will collect trust information about individual fields to be later +// aggregated into the overall class level. +// +// This abstraction enforces the rule that all fields are presumed guilty until explicitly declared +// safe by calling SetTrust(). If you fail to call SetTrust before leaving the block, the destructor +// will automatically cause the entire class to be declared illegal (and you will get an assert +// telling you to fix this bug.) +//---------------------------------------------------------------------------------------------- +class ExplicitFieldTrustHolder : private ExplicitFieldTrust +{ + public: + ExplicitFieldTrustHolder(ExplicitClassTrust *pExplicitClassTrust) + { + LIMITED_METHOD_CONTRACT; + m_pExplicitClassTrust = pExplicitClassTrust; +#ifdef _DEBUG + m_trustDeclared = FALSE; +#endif + m_fieldTrust = kNone; + } + + VOID SetTrust(TrustLevel fieldTrust) + { + LIMITED_METHOD_CONTRACT; + + _ASSERTE(fieldTrust >= kNone && fieldTrust <= kMaxTrust); + _ASSERTE(!m_trustDeclared && "You should not set the trust value more than once."); + +#ifdef _DEBUG + m_trustDeclared = TRUE; +#endif + m_fieldTrust = fieldTrust; + } + + ~ExplicitFieldTrustHolder() + { + LIMITED_METHOD_CONTRACT; + // If no SetTrust() was ever called, we will default to kNone (i.e. declare the entire type + // illegal.) It'd be nice to assert here but since this case can be legitimately reached + // on exception unwind, we cannot. + m_pExplicitClassTrust->AddField(m_fieldTrust); + } + + + private: + ExplicitClassTrust* m_pExplicitClassTrust; + TrustLevel m_fieldTrust; +#ifdef _DEBUG + BOOL m_trustDeclared; // Debug flag to detect multiple Sets. (Which we treat as a bug as this shouldn't be necessary.) +#endif +}; + +//******************************************************************************* +// Enumerator to traverse the interface declarations of a type, automatically building +// a substitution chain on the stack. +class InterfaceImplEnum +{ + Module* m_pModule; + HENUMInternalHolder hEnumInterfaceImpl; + const Substitution *m_pSubstChain; + Substitution m_CurrSubst; + mdTypeDef m_CurrTok; +public: + InterfaceImplEnum(Module *pModule, mdTypeDef cl, const Substitution *pSubstChain) + : hEnumInterfaceImpl(pModule->GetMDImport()) + { + WRAPPER_NO_CONTRACT; + m_pModule = pModule; + hEnumInterfaceImpl.EnumInit(mdtInterfaceImpl, cl); + m_pSubstChain = pSubstChain; + } + + // Returns: + // S_OK ... if has next (TRUE) + // S_FALSE ... if does not have next (FALSE) + // error code. + HRESULT Next() + { + WRAPPER_NO_CONTRACT; + HRESULT hr; + mdInterfaceImpl ii; + if (!m_pModule->GetMDImport()->EnumNext(&hEnumInterfaceImpl, &ii)) + { + return S_FALSE; + } + + IfFailRet(m_pModule->GetMDImport()->GetTypeOfInterfaceImpl(ii, &m_CurrTok)); + m_CurrSubst = Substitution(m_CurrTok, m_pModule, m_pSubstChain); + return S_OK; + } + const Substitution *CurrentSubst() const { LIMITED_METHOD_CONTRACT; return &m_CurrSubst; } + mdTypeDef CurrentToken() const { LIMITED_METHOD_CONTRACT; return m_CurrTok; } +}; + +#ifdef FEATURE_COMINTEROP +// +// Class used to map MethodTable slot numbers to COM vtable slots numbers +// (either for calling a classic COM component or for constructing a classic COM +// vtable via which COM components can call managed classes). This structure is +// embedded in the EEClass but the mapping list itself is only allocated if the +// COM vtable is sparse. +// + +class SparseVTableMap +{ +public: +#ifdef DACCESS_COMPILE + friend class NativeImageDumper; +#endif + + SparseVTableMap(); + ~SparseVTableMap(); + + // First run through MT slots calling RecordGap wherever a gap in VT slots + // occurs. + void RecordGap(WORD StartMTSlot, WORD NumSkipSlots); + + // Then call FinalizeMapping to create the actual mapping list. + void FinalizeMapping(WORD TotalMTSlots); + + // Map MT to VT slot. + WORD LookupVTSlot(WORD MTSlot); + + // Retrieve the number of slots in the vtable (both empty and full). + WORD GetNumVTableSlots(); + + const void* GetMapList() + { + LIMITED_METHOD_CONTRACT; + return (void*)m_MapList; + } + +#ifdef FEATURE_PREJIT + // Methods to persist structure + void Save(DataImage *image); + void Fixup(DataImage *image); +#endif // FEATURE_PREJIT + +private: + + enum { MapGrow = 4 }; + + struct Entry + { + WORD m_Start; // Starting MT slot number + WORD m_Span; // # of consecutive slots that map linearly + WORD m_MapTo; // Starting VT slot number + }; + + Entry *m_MapList; // Pointer to array of Entry structures + WORD m_MapEntries; // Number of entries in above + WORD m_Allocated; // Number of entries allocated + + WORD m_LastUsed; // Index of last entry used in successful lookup + + WORD m_VTSlot; // Current VT slot number, used during list build + WORD m_MTSlot; // Current MT slot number, used during list build + + void AllocOrExpand(); // Allocate or expand the mapping list for a new entry +}; +#endif // FEATURE_COMINTEROP + +//======================================================================= +// Adjunct to the EEClass structure for classes w/ layout +//======================================================================= +class EEClassLayoutInfo +{ + static VOID CollectLayoutFieldMetadataThrowing( + mdTypeDef cl, // cl of the NStruct being loaded + BYTE packingSize, // packing size (from @dll.struct) + BYTE nlType, // nltype (from @dll.struct) +#ifdef FEATURE_COMINTEROP + BOOL isWinRT, // Is the type a WinRT type +#endif // FEATURE_COMINTEROP + BOOL fExplicitOffsets, // explicit offsets? + MethodTable *pParentMT, // the loaded superclass + ULONG cMembers, // total number of members (methods + fields) + HENUMInternal *phEnumField, // enumerator for field + Module* pModule, // Module that defines the scope, loader and heap (for allocate FieldMarshalers) + const SigTypeContext *pTypeContext, // Type parameters for NStruct being loaded + EEClassLayoutInfo *pEEClassLayoutInfoOut, // caller-allocated structure to fill in. + LayoutRawFieldInfo *pInfoArrayOut, // caller-allocated array to fill in. Needs room for cMember+1 elements + LoaderAllocator * pAllocator, + AllocMemTracker *pamTracker + ); + + + friend class ClassLoader; + friend class EEClass; + friend class MethodTableBuilder; +#ifdef DACCESS_COMPILE + friend class NativeImageDumper; +#endif + + private: + // size (in bytes) of fixed portion of NStruct. + UINT32 m_cbNativeSize; + UINT32 m_cbManagedSize; + + public: + // 1,2,4 or 8: this is equal to the largest of the alignment requirements + // of each of the EEClass's members. If the NStruct extends another NStruct, + // the base NStruct is treated as the first member for the purpose of + // this calculation. + BYTE m_LargestAlignmentRequirementOfAllMembers; + + // Post V1.0 addition: This is the equivalent of m_LargestAlignmentRequirementOfAllMember + // for the managed layout. + BYTE m_ManagedLargestAlignmentRequirementOfAllMembers; + + private: + enum { + // TRUE if the GC layout of the class is bit-for-bit identical + // to its unmanaged counterpart (i.e. no internal reference fields, + // no ansi-unicode char conversions required, etc.) Used to + // optimize marshaling. + e_BLITTABLE = 0x01, + // Post V1.0 addition: Is this type also sequential in managed memory? + e_MANAGED_SEQUENTIAL = 0x02, + // When a sequential/explicit type has no fields, it is conceptually + // zero-sized, but actually is 1 byte in length. This holds onto this + // fact and allows us to revert the 1 byte of padding when another + // explicit type inherits from this type. + e_ZERO_SIZED = 0x04, + // The size of the struct is explicitly specified in the meta-data. + e_HAS_EXPLICIT_SIZE = 0x08, +#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF +#ifdef FEATURE_HFA +#error Can't have FEATURE_HFA and FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF defined at the same time. +#endif // FEATURE_HFA + e_NATIVE_PASS_IN_REGISTERS = 0x10, // Flag wheter a native struct is passed in registers. +#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF +#ifdef FEATURE_HFA + // HFA type of the unmanaged layout + e_R4_HFA = 0x10, + e_R8_HFA = 0x20, +#endif + }; + + BYTE m_bFlags; + + // Packing size in bytes (1, 2, 4, 8 etc.) + BYTE m_cbPackingSize; + + // # of fields that are of the calltime-marshal variety. + UINT m_numCTMFields; + + // An array of FieldMarshaler data blocks, used to drive call-time + // marshaling of NStruct reference parameters. The number of elements + // equals m_numCTMFields. + FieldMarshaler *m_pFieldMarshalers; + + + public: + BOOL GetNativeSize() const + { + LIMITED_METHOD_CONTRACT; + return m_cbNativeSize; + } + + UINT32 GetManagedSize() const + { + LIMITED_METHOD_CONTRACT; + return m_cbManagedSize; + } + + + BYTE GetLargestAlignmentRequirementOfAllMembers() const + { + LIMITED_METHOD_CONTRACT; + return m_LargestAlignmentRequirementOfAllMembers; + } + + UINT GetNumCTMFields() const + { + LIMITED_METHOD_CONTRACT; + return m_numCTMFields; + } + + FieldMarshaler *GetFieldMarshalers() const + { + LIMITED_METHOD_CONTRACT; + return m_pFieldMarshalers; + } + + BOOL IsBlittable() const + { + LIMITED_METHOD_CONTRACT; + return (m_bFlags & e_BLITTABLE) == e_BLITTABLE; + } + + BOOL IsManagedSequential() const + { + LIMITED_METHOD_CONTRACT; + return (m_bFlags & e_MANAGED_SEQUENTIAL) == e_MANAGED_SEQUENTIAL; + } + + // If true, this says that the type was originally zero-sized + // and the native size was bumped up to one for similar behaviour + // to C++ structs. However, it is necessary to keep track of this + // so that we can ignore the one byte padding if other types derive + // from this type, that we can + BOOL IsZeroSized() const + { + LIMITED_METHOD_CONTRACT; + return (m_bFlags & e_ZERO_SIZED) == e_ZERO_SIZED; + } + + BOOL HasExplicitSize() const + { + LIMITED_METHOD_CONTRACT; + return (m_bFlags & e_HAS_EXPLICIT_SIZE) == e_HAS_EXPLICIT_SIZE; + } + + DWORD GetPackingSize() const + { + LIMITED_METHOD_CONTRACT; + return m_cbPackingSize; + } + +#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF + bool IsNativeStructPassedInRegisters() + { + LIMITED_METHOD_CONTRACT; + return (m_bFlags & e_NATIVE_PASS_IN_REGISTERS) != 0; + } +#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF + +#ifdef FEATURE_HFA + bool IsNativeHFA() + { + LIMITED_METHOD_CONTRACT; + return (m_bFlags & (e_R4_HFA | e_R8_HFA)) != 0; + } + + CorElementType GetNativeHFAType() + { + LIMITED_METHOD_CONTRACT; + if (IsNativeHFA()) + return (m_bFlags & e_R4_HFA) ? ELEMENT_TYPE_R4 : ELEMENT_TYPE_R8; + return ELEMENT_TYPE_END; + } +#endif + + private: + void SetIsBlittable(BOOL isBlittable) + { + LIMITED_METHOD_CONTRACT; + m_bFlags = isBlittable ? (m_bFlags | e_BLITTABLE) + : (m_bFlags & ~e_BLITTABLE); + } + + void SetIsManagedSequential(BOOL isManagedSequential) + { + LIMITED_METHOD_CONTRACT; + m_bFlags = isManagedSequential ? (m_bFlags | e_MANAGED_SEQUENTIAL) + : (m_bFlags & ~e_MANAGED_SEQUENTIAL); + } + + void SetIsZeroSized(BOOL isZeroSized) + { + LIMITED_METHOD_CONTRACT; + m_bFlags = isZeroSized ? (m_bFlags | e_ZERO_SIZED) + : (m_bFlags & ~e_ZERO_SIZED); + } + + void SetHasExplicitSize(BOOL hasExplicitSize) + { + LIMITED_METHOD_CONTRACT; + m_bFlags = hasExplicitSize ? (m_bFlags | e_HAS_EXPLICIT_SIZE) + : (m_bFlags & ~e_HAS_EXPLICIT_SIZE); + } + +#ifdef FEATURE_HFA + void SetNativeHFAType(CorElementType hfaType) + { + LIMITED_METHOD_CONTRACT; + m_bFlags |= (hfaType == ELEMENT_TYPE_R4) ? e_R4_HFA : e_R8_HFA; + } +#endif +#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF + void SetNativeStructPassedInRegisters() + { + LIMITED_METHOD_CONTRACT; + m_bFlags |= e_NATIVE_PASS_IN_REGISTERS; + } +#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF + +}; + + + +// +// This structure is used only when the classloader is building the interface map. Before the class +// is resolved, the EEClass contains an array of these, which are all interfaces *directly* declared +// for this class/interface by the metadata - inherited interfaces will not be present if they are +// not specifically declared. +// +// This structure is destroyed after resolving has completed. +// +typedef struct +{ + // The interface method table; for instantiated interfaces, this is the generic interface + MethodTable *m_pMethodTable; +} BuildingInterfaceInfo_t; + + +// +// We should not need to touch anything in here once the classes are all loaded, unless we +// are doing reflection. Try to avoid paging this data structure in. +// + +// Size of hash bitmap for method names +#define METHOD_HASH_BYTES 8 + +// Hash table size - prime number +#define METHOD_HASH_BITS 61 + + +// These are some macros for forming fully qualified class names for a class. +// These are abstracted so that we can decide later if a max length for a +// class name is acceptable. + +// It doesn't make any sense not to have a small but usually quite capable +// stack buffer to build class names into. Most class names that I can think +// of would fit in 128 characters, and that's a pretty small amount of stack +// to use in exchange for not having to new and delete the memory. +#define DEFAULT_NONSTACK_CLASSNAME_SIZE (MAX_CLASSNAME_LENGTH/4) + +#define DefineFullyQualifiedNameForClass() \ + ScratchBuffer<DEFAULT_NONSTACK_CLASSNAME_SIZE> _scratchbuffer_; \ + InlineSString<DEFAULT_NONSTACK_CLASSNAME_SIZE> _ssclsname_; + +#define DefineFullyQualifiedNameForClassOnStack() \ + ScratchBuffer<MAX_CLASSNAME_LENGTH> _scratchbuffer_; \ + InlineSString<MAX_CLASSNAME_LENGTH> _ssclsname_; + +#define DefineFullyQualifiedNameForClassW() \ + InlineSString<DEFAULT_NONSTACK_CLASSNAME_SIZE> _ssclsname_w_; + +#define DefineFullyQualifiedNameForClassWOnStack() \ + InlineSString<MAX_CLASSNAME_LENGTH> _ssclsname_w_; + +#define GetFullyQualifiedNameForClassNestedAware(pClass) \ + pClass->_GetFullyQualifiedNameForClassNestedAware(_ssclsname_).GetUTF8(_scratchbuffer_) + +#define GetFullyQualifiedNameForClassNestedAwareW(pClass) \ + pClass->_GetFullyQualifiedNameForClassNestedAware(_ssclsname_w_).GetUnicode() + +#define GetFullyQualifiedNameForClass(pClass) \ + pClass->_GetFullyQualifiedNameForClass(_ssclsname_).GetUTF8(_scratchbuffer_) + +#define GetFullyQualifiedNameForClassW(pClass) \ + pClass->_GetFullyQualifiedNameForClass(_ssclsname_w_).GetUnicode() + +#define GetFullyQualifiedNameForClassW_WinRT(pClass) \ + pClass->_GetFullyQualifiedNameForClass(_ssclsname_w_).GetUnicode() + +#define GetFullyQualifiedNameForClass_WinRT(pClass) \ + pClass->_GetFullyQualifiedNameForClass(_ssclsname_).GetUTF8(_scratchbuffer_) + +// Structure containing EEClass fields used by a minority of EEClass instances. This separation allows us to +// save memory and improve the density of accessed fields in the EEClasses themselves. This class is reached +// via the m_rpOptionalFields field EEClass (use the GetOptionalFields() accessor rather than the field +// itself). +class EEClassOptionalFields +{ + // All fields here are intentionally private. Use the corresponding accessor on EEClass instead (this + // makes it easier to add and remove fields from the optional section in the future). We make exceptions + // for MethodTableBuilder and NativeImageDumper, which need raw field-level access. + friend class EEClass; + friend class MethodTableBuilder; +#ifdef DACCESS_COMPILE + friend class NativeImageDumper; +#endif + + // + // GENERICS RELATED FIELDS. + // + + // If IsSharedByGenericInstantiations(), layout of handle dictionary for generic type + // (the last dictionary pointed to from PerInstInfo). Otherwise NULL. + PTR_DictionaryLayout m_pDictLayout; + + // Variance info for each type parameter (gpNonVariant, gpCovariant, or gpContravariant) + // If NULL, this type has no type parameters that are co/contravariant + BYTE* m_pVarianceInfo; + + // + // COM RELATED FIELDS. + // + +#ifdef FEATURE_COMINTEROP + SparseVTableMap *m_pSparseVTableMap; + + TypeHandle m_pCoClassForIntf; // @TODO: Coclass for an interface + +#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION + // Points to activation information if the type is an activatable COM/WinRT class. + ClassFactoryBase *m_pClassFactory; +#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION + + WinMDAdapter::RedirectedTypeIndex m_WinRTRedirectedTypeIndex; + +#endif // FEATURE_COMINTEROP + + // + // MISC FIELDS + // + + #define MODULE_NON_DYNAMIC_STATICS ((DWORD)-1) + DWORD m_cbModuleDynamicID; + + DWORD m_dwReliabilityContract; + + SecurityProperties m_SecProps; + +#if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) + // Number of eightBytes in the following arrays + int m_numberEightBytes; + // Classification of the eightBytes + SystemVClassificationType m_eightByteClassifications[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; + // Size of data the eightBytes + unsigned int m_eightByteSizes[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS]; +#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING + + // Set default values for optional fields. + inline void Init(); +}; +typedef DPTR(EEClassOptionalFields) PTR_EEClassOptionalFields; + +// +// Another mechanism used to reduce the size of the average EEClass instance is the notion of packed fields. +// This is based on the observation that EEClass has a large number of integer fields that typically contain +// small values and that are fixed once class layout has completed. We can compact these fields by discarding +// the leading zero bits (and for small values there'll be a lot of these) and packing the significant data +// into compact bitfields. This is a dynamic operation (the exact packing used depends on the exact data +// stored in the fields). +// +// The PackedDWORDFields<> class (defined in PackedFields.inl) encapsulates this. It takes one template +// parameter, the number of fields to pack, and provides operations to get and set those fields until we're +// happy with the values, at which point it will compact them for us. +// +// The packed fields themselves are stored at the end of the EEClass instance (or the LayoutEEClass or the +// DelegateEEClass etc.) so we can take advantage of the variable sized nature of the fields. We gain nothing for +// runtime allocated EEClasses (we have to allocate a maximally sized structure for the packed fields because +// we can't tell at the beginning of EEClass layout what the field values will be). But in the ngen scenario +// we can compact the fields just prior to saving and only store the portion of the EEClass that is relvant, +// helping us with our goal of packing all the EEClass instances together as tightly as possible. +// +// Since each packed field is now accessed via an array-like index, we give each of those indices a name with +// the enum below to make the code more readable. +// + +enum EEClassFieldId +{ + EEClass_Field_NumInstanceFields = 0, + EEClass_Field_NumMethods, + EEClass_Field_NumStaticFields, + EEClass_Field_NumHandleStatics, + EEClass_Field_NumBoxedStatics, + EEClass_Field_NonGCStaticFieldBytes, + EEClass_Field_NumThreadStaticFields, + EEClass_Field_NumHandleThreadStatics, + EEClass_Field_NumBoxedThreadStatics, + EEClass_Field_NonGCThreadStaticFieldBytes, + EEClass_Field_NumNonVirtualSlots, + EEClass_Field_COUNT +}; + +typedef PackedDWORDFields<EEClass_Field_COUNT> EEClassPackedFields; +typedef DPTR(EEClassPackedFields) PTR_EEClassPackedFields; + +//@GENERICS: +// For most types there is a one-to-one mapping between MethodTable* and EEClass* +// However this is not the case for instantiated types where code and representation +// are shared between compatible instantiations (e.g. List<string> and List<object>) +// Then a single EEClass structure is shared between multiple MethodTable structures +// Uninstantiated generic types (e.g. List) have their own EEClass and MethodTable, +// used (a) as a representative for the generic type itself, (b) for static fields and +// methods, which aren't present in the instantiations, and (c) to hold some information +// (e.g. formal instantiations of superclass and implemented interfaces) that is common +// to all instantiations and isn't stored in the EEClass structures for instantiated types +// +// +// ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE +// +// A word about EEClass vs. MethodTable +// ------------------------------------ +// +// At compile-time, we are happy to touch both MethodTable and EEClass. However, +// at runtime we want to restrict ourselves to the MethodTable. This is critical +// for common code paths, where we want to keep the EEClass out of our working +// set. For uncommon code paths, like throwing exceptions or strange Contexts +// issues, it's okay to access the EEClass. +// +// To this end, the TypeHandle (CLASS_HANDLE) abstraction is now based on the +// MethodTable pointer instead of the EEClass pointer. If you are writing a +// runtime helper that calls GetClass() to access the associated EEClass, please +// stop to wonder if you are making a mistake. +// +// ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE ** NOTE + + +// An code:EEClass is a representation of the part of a managed type that is not used very frequently (it is +// cold), and thus is segregated from the hot portion (which lives in code:MethodTable). As noted above an +// it is also the case that EEClass is SHARED among all instantiations of a generic type, so anything that +// is specific to a paritcular type can not live off the EEClass. +// +// From here you can get to +// code:MethodTable - The representation of the hot portion of a type. +// code:MethodDesc - The representation of a method +// code:FieldDesc - The representation of a field. +// +// EEClasses hold the following important fields +// * code:EEClass.m_pMethodTable - Points a MethodTable associated with +// * code:EEClass.m_pChunks - a list of code:MethodDescChunk which is simply a list of code:MethodDesc +// which represent the methods. +// * code:EEClass.m_pFieldDescList - a list of fields in the type. +// +class EEClass // DO NOT CREATE A NEW EEClass USING NEW! +{ + /************************************ + * FRIEND FUNCTIONS + ************************************/ + // DO NOT ADD FRIENDS UNLESS ABSOLUTELY NECESSARY + // USE ACCESSORS TO READ/WRITE private field members + + // To access bmt stuff + friend class MethodTable; + friend class MethodTableBuilder; + friend class FieldDesc; + friend class CheckAsmOffsets; + friend class ClrDataAccess; +#ifdef DACCESS_COMPILE + friend class NativeImageDumper; +#endif + + /************************************ + * PUBLIC INSTANCE METHODS + ************************************/ +public: + + DWORD IsSealed() + { + LIMITED_METHOD_CONTRACT; + return IsTdSealed(m_dwAttrClass); + } + + inline DWORD IsInterface() + { + WRAPPER_NO_CONTRACT; + return IsTdInterface(m_dwAttrClass); + } + + inline DWORD IsAbstract() + { + WRAPPER_NO_CONTRACT; + return IsTdAbstract(m_dwAttrClass); + } + + BOOL HasExplicitFieldOffsetLayout() + { + WRAPPER_NO_CONTRACT; + return IsTdExplicitLayout(GetAttrClass()) && HasLayout(); + } + + BOOL HasSequentialLayout() + { + WRAPPER_NO_CONTRACT; + return IsTdSequentialLayout(GetAttrClass()); + } + BOOL IsSerializable() + { + WRAPPER_NO_CONTRACT; + return IsTdSerializable(GetAttrClass()); + } + BOOL IsBeforeFieldInit() + { + WRAPPER_NO_CONTRACT; + return IsTdBeforeFieldInit(GetAttrClass()); + } + + DWORD GetProtection() + { + WRAPPER_NO_CONTRACT; + return (m_dwAttrClass & tdVisibilityMask); + } + + // class is blittable + BOOL IsBlittable(); + + // + // Security properties accessor methods + // + + inline BOOL RequiresLinktimeCheck() + { + WRAPPER_NO_CONTRACT; + PSecurityProperties psp = GetSecurityProperties(); + return psp && psp->RequiresLinktimeCheck(); + } + + inline BOOL RequiresLinkTimeCheckHostProtectionOnly() + { + WRAPPER_NO_CONTRACT; + PSecurityProperties psp = GetSecurityProperties(); + return psp && psp->RequiresLinkTimeCheckHostProtectionOnly(); + } + + inline BOOL RequiresInheritanceCheck() + { + WRAPPER_NO_CONTRACT; + PSecurityProperties psp = GetSecurityProperties(); + return psp && psp->RequiresInheritanceCheck(); + } + + inline BOOL RequiresCasInheritanceCheck() + { + WRAPPER_NO_CONTRACT; + PSecurityProperties psp = GetSecurityProperties(); + return psp && psp->RequiresCasInheritanceCheck(); + } + + inline BOOL RequiresNonCasInheritanceCheck() + { + WRAPPER_NO_CONTRACT; + PSecurityProperties psp = GetSecurityProperties(); + return psp && psp->RequiresNonCasInheritanceCheck(); + } + + +#ifndef DACCESS_COMPILE + void *operator new(size_t size, LoaderHeap* pHeap, AllocMemTracker *pamTracker); + void Destruct(MethodTable * pMT); + + static EEClass * CreateMinimalClass(LoaderHeap *pHeap, AllocMemTracker *pamTracker); +#endif // !DACCESS_COMPILE + +#ifdef EnC_SUPPORTED + // Add a new method to an already loaded type for EnC + static HRESULT AddMethod(MethodTable * pMT, mdMethodDef methodDef, RVA newRVA, MethodDesc **ppMethod); + + // Add a new field to an already loaded type for EnC + static HRESULT AddField(MethodTable * pMT, mdFieldDef fieldDesc, EnCFieldDesc **pAddedField); + static VOID FixupFieldDescForEnC(MethodTable * pMT, EnCFieldDesc *pFD, mdFieldDef fieldDef); +#endif // EnC_SUPPORTED + + inline DWORD IsComImport() + { + WRAPPER_NO_CONTRACT; + return IsTdImport(m_dwAttrClass); + } + +#ifdef FEATURE_PREJIT + DWORD GetSize(); + + void Save(DataImage *image, MethodTable *pMT); + void Fixup(DataImage *image, MethodTable *pMT); +#endif // FEATURE_PREJIT + + EEClassLayoutInfo *GetLayoutInfo(); + +#ifdef DACCESS_COMPILE + void EnumMemoryRegions(CLRDataEnumMemoryFlags flags, MethodTable *pMT); +#endif + + static CorElementType ComputeInternalCorElementTypeForValueType(MethodTable * pMT); + + /************************************ + * INSTANCE MEMBER VARIABLES + ************************************/ +#ifdef _DEBUG +public: + inline LPCUTF8 GetDebugClassName () + { + LIMITED_METHOD_CONTRACT; + return m_szDebugClassName; + } + inline void SetDebugClassName (LPCUTF8 szDebugClassName) + { + LIMITED_METHOD_CONTRACT; + m_szDebugClassName = szDebugClassName; + } + + /* + * Controls debugging breaks and output if a method class + * is mentioned in the registry ("BreakOnClassBuild") + * Method layout within this class can cause a debug + * break by setting "BreakOnMethodName". Not accessible + * outside the class. + */ + +#endif // _DEBUG + +#ifdef FEATURE_COMINTEROP + /* + * Used to map MethodTable slots to VTable slots + */ + inline SparseVTableMap* GetSparseCOMInteropVTableMap () + { + LIMITED_METHOD_CONTRACT; + return HasOptionalFields() ? GetOptionalFields()->m_pSparseVTableMap : NULL; + } + inline void SetSparseCOMInteropVTableMap (SparseVTableMap *map) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasOptionalFields()); + GetOptionalFields()->m_pSparseVTableMap = map; + } +#endif // FEATURE_COMINTEROP + +public: + /* + * Maintain back pointer to statcally hot portion of EEClass. + * For an EEClass representing multiple instantiations of a generic type, this is the method table + * for the first instantiation requested and is the only one containing entries for non-virtual instance methods + * (i.e. non-vtable entries). + */ + + // Note that EEClass structures may be shared between generic instantiations + // (see IsSharedByGenericInstantiations). In these cases EEClass::GetMethodTable + // will return the method table pointer corresponding to the "canonical" + // instantiation, as defined in typehandle.h. + // + inline MethodTable* GetMethodTable() + { + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + + return m_pMethodTable; + } + + // DO NOT ADD ANY ASSERTS TO THIS METHOD. + // DO NOT USE THIS METHOD. + // Yes folks, for better or worse the debugger pokes supposed object addresses + // to try to see if objects are valid, possibly firing an AccessViolation or worse, + // and then catches the AV and reports a failure to the debug client. This makes + // the debugger slightly more robust should any corrupted object references appear + // in a session. Thus it is "correct" behaviour for this to AV when used with + // an invalid object pointer, and incorrect behaviour for it to + // assert. + inline PTR_MethodTable GetMethodTableWithPossibleAV() + { + CANNOT_HAVE_CONTRACT; + SUPPORTS_DAC; + + return m_pMethodTable; + } +#ifndef DACCESS_COMPILE +#ifdef FEATURE_REMOTING + inline void SetMethodTableForTransparentProxy(MethodTable* pMT) + { + LIMITED_METHOD_CONTRACT; + // Transparent proxy class' true method table + // is replaced by a global thunk table + + _ASSERTE(pMT->IsTransparentProxy() && + m_pMethodTable->IsTransparentProxy()); + + IBCLOG(LogEEClassCOWTableAccess(GetMethodTable())); + + m_pMethodTable = pMT; + } +#endif + + inline void SetMethodTable(MethodTable* pMT) + { + LIMITED_METHOD_CONTRACT; + m_pMethodTable = pMT; + } +#endif // !DACCESS_COMPILE + + /* + * Number of fields in the class, including inherited fields. + * Does not include fields added from EnC. + */ + inline WORD GetNumInstanceFields() + { + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + return (WORD)GetPackableField(EEClass_Field_NumInstanceFields); + } + + inline void SetNumInstanceFields (WORD wNumInstanceFields) + { + LIMITED_METHOD_CONTRACT; + SetPackableField(EEClass_Field_NumInstanceFields, wNumInstanceFields); + } + + /* + * Number of static fields declared in this class. + * Implementation Note: Static values are laid out at the end of the MethodTable vtable. + */ + inline WORD GetNumStaticFields() + { + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + return (WORD)GetPackableField(EEClass_Field_NumStaticFields); + } + inline void SetNumStaticFields (WORD wNumStaticFields) + { + LIMITED_METHOD_CONTRACT; + SetPackableField(EEClass_Field_NumStaticFields, wNumStaticFields); + } + + inline WORD GetNumThreadStaticFields() + { + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + return (WORD)GetPackableField(EEClass_Field_NumThreadStaticFields); + } + + inline void SetNumThreadStaticFields (WORD wNumThreadStaticFields) + { + LIMITED_METHOD_CONTRACT; + SetPackableField(EEClass_Field_NumThreadStaticFields, wNumThreadStaticFields); + } + + // Statics are stored in a big chunk inside the module + + inline DWORD GetModuleDynamicID() + { + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + return HasOptionalFields() ? GetOptionalFields()->m_cbModuleDynamicID : MODULE_NON_DYNAMIC_STATICS; + } + + inline void SetModuleDynamicID(DWORD cbModuleDynamicID) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasOptionalFields()); + GetOptionalFields()->m_cbModuleDynamicID = cbModuleDynamicID; + } + + /* + * Difference between the InterfaceMap ptr and Vtable in the + * MethodTable used to indicate the number of static bytes + * Now interfaceMap ptr can be optional hence we store it here + */ + inline DWORD GetNonGCRegularStaticFieldBytes() + { + LIMITED_METHOD_CONTRACT; + return GetPackableField(EEClass_Field_NonGCStaticFieldBytes); + } + inline void SetNonGCRegularStaticFieldBytes (DWORD cbNonGCStaticFieldBytes) + { + LIMITED_METHOD_CONTRACT; + SetPackableField(EEClass_Field_NonGCStaticFieldBytes, cbNonGCStaticFieldBytes); + } + + inline DWORD GetNonGCThreadStaticFieldBytes() + { + LIMITED_METHOD_CONTRACT; + return GetPackableField(EEClass_Field_NonGCThreadStaticFieldBytes); + } + inline void SetNonGCThreadStaticFieldBytes (DWORD cbNonGCStaticFieldBytes) + { + LIMITED_METHOD_CONTRACT; + SetPackableField(EEClass_Field_NonGCThreadStaticFieldBytes, cbNonGCStaticFieldBytes); + } + + inline WORD GetNumNonVirtualSlots() + { + LIMITED_METHOD_CONTRACT; + return (WORD)GetPackableField(EEClass_Field_NumNonVirtualSlots); + } + inline void SetNumNonVirtualSlots(WORD wNumNonVirtualSlots) + { + LIMITED_METHOD_CONTRACT; + SetPackableField(EEClass_Field_NumNonVirtualSlots, wNumNonVirtualSlots); + } + + inline BOOL IsEquivalentType() + { + LIMITED_METHOD_CONTRACT; + return m_VMFlags & VMFLAG_IS_EQUIVALENT_TYPE; + } + +#ifdef FEATURE_COMINTEROP + inline void SetIsEquivalentType() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= VMFLAG_IS_EQUIVALENT_TYPE; + } +#endif + + /* + * Number of static handles allocated + */ + inline WORD GetNumHandleRegularStatics () + { + LIMITED_METHOD_CONTRACT; + return (WORD)GetPackableField(EEClass_Field_NumHandleStatics); + } + inline void SetNumHandleRegularStatics (WORD wNumHandleRegularStatics) + { + LIMITED_METHOD_CONTRACT; + SetPackableField(EEClass_Field_NumHandleStatics, wNumHandleRegularStatics); + } + + /* + * Number of static handles allocated for ThreadStatics + */ + inline WORD GetNumHandleThreadStatics () + { + LIMITED_METHOD_CONTRACT; + return (WORD)GetPackableField(EEClass_Field_NumHandleThreadStatics); + } + inline void SetNumHandleThreadStatics (WORD wNumHandleThreadStatics) + { + LIMITED_METHOD_CONTRACT; + SetPackableField(EEClass_Field_NumHandleThreadStatics, wNumHandleThreadStatics); + } + + /* + * Number of boxed statics allocated + */ + inline WORD GetNumBoxedRegularStatics () + { + LIMITED_METHOD_CONTRACT; + return (WORD)GetPackableField(EEClass_Field_NumBoxedStatics); + } + inline void SetNumBoxedRegularStatics (WORD wNumBoxedRegularStatics) + { + LIMITED_METHOD_CONTRACT; + SetPackableField(EEClass_Field_NumBoxedStatics, wNumBoxedRegularStatics); + } + + /* + * Number of boxed statics allocated for ThreadStatics + */ + inline WORD GetNumBoxedThreadStatics () + { + LIMITED_METHOD_CONTRACT; + return (WORD)GetPackableField(EEClass_Field_NumBoxedThreadStatics); + } + inline void SetNumBoxedThreadStatics (WORD wNumBoxedThreadStatics) + { + LIMITED_METHOD_CONTRACT; + SetPackableField(EEClass_Field_NumBoxedThreadStatics, wNumBoxedThreadStatics); + } + + /* + * Number of bytes to subract from code:MethodTable::GetBaseSize() to get the actual number of bytes + * of instance fields stored in the object on the GC heap. + */ + inline DWORD GetBaseSizePadding() + { + LIMITED_METHOD_DAC_CONTRACT; + return m_cbBaseSizePadding; + } + inline void SetBaseSizePadding(DWORD dwPadding) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(FitsIn<BYTE>(dwPadding)); + m_cbBaseSizePadding = static_cast<BYTE>(dwPadding); + } + + inline DWORD GetUnboxedNumInstanceFieldBytes() + { + DWORD cbBoxedSize = GetMethodTable()->GetNumInstanceFieldBytes(); + + _ASSERTE(GetMethodTable()->IsValueType() || GetMethodTable()->IsEnum()); + return cbBoxedSize; + } + + + /* + * Pointer to a list of FieldDescs declared in this class + * There are (m_wNumInstanceFields - GetParentClass()->m_wNumInstanceFields + m_wNumStaticFields) entries + * in this array + */ +#ifdef FEATURE_PREJIT + static DWORD FieldDescListSize(MethodTable * pMT); +#endif + + inline PTR_FieldDesc GetFieldDescList() + { + LIMITED_METHOD_DAC_CONTRACT; + // Careful about using this method. If it's possible that fields may have been added via EnC, then + // must use the FieldDescIterator as any fields added via EnC won't be in the raw list + return m_pFieldDescList.GetValueMaybeNull(PTR_HOST_MEMBER_TADDR(EEClass, this, m_pFieldDescList)); + } + + PTR_FieldDesc GetFieldDescByIndex(DWORD fieldIndex); + +#ifndef DACCESS_COMPILE + inline void SetFieldDescList (FieldDesc* pFieldDescList) + { + LIMITED_METHOD_CONTRACT; + m_pFieldDescList.SetValue(PTR_HOST_MEMBER_TADDR(EEClass, this, m_pFieldDescList), pFieldDescList); + } +#endif // !DACCESS_COMPILE + + inline WORD GetNumMethods() + { + LIMITED_METHOD_DAC_CONTRACT; + return (WORD)GetPackableField(EEClass_Field_NumMethods); + } + inline void SetNumMethods (WORD wNumMethods) + { + LIMITED_METHOD_CONTRACT; + SetPackableField(EEClass_Field_NumMethods, wNumMethods); + } + + /* + * Cached metadata for this class (GetTypeDefProps) + */ + inline DWORD GetAttrClass() + { + LIMITED_METHOD_CONTRACT; + return m_dwAttrClass; + } + inline void SetAttrClass (DWORD dwAttrClass) + { + LIMITED_METHOD_CONTRACT; + m_dwAttrClass = dwAttrClass; + } + + +#ifdef FEATURE_COMINTEROP + inline DWORD IsComClassInterface() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_HASCOCLASSATTRIB); + } + inline VOID SetIsComClassInterface() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= VMFLAG_HASCOCLASSATTRIB; + } + inline void SetComEventItfType() + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(IsInterface()); + m_VMFlags |= VMFLAG_COMEVENTITFMASK; + } + // class is a special COM event interface + inline BOOL IsComEventItfType() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_COMEVENTITFMASK); + } +#endif // FEATURE_COMINTEROP + +#ifdef _DEBUG + inline DWORD IsDestroyed() + { + LIMITED_METHOD_CONTRACT; + return (m_wAuxFlags & AUXFLAG_DESTROYED); + } +#endif + + inline BOOL IsCritical() + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasCriticalTransparentInfo()); + return (m_VMFlags & VMFLAG_TRANSPARENCY_MASK) != VMFLAG_TRANSPARENCY_TRANSPARENT + && !IsAllTransparent(); + } + + inline BOOL IsTreatAsSafe() + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasCriticalTransparentInfo()); + return (m_VMFlags & VMFLAG_TRANSPARENCY_MASK) == VMFLAG_TRANSPARENCY_ALLCRITICAL_TAS || + (m_VMFlags & VMFLAG_TRANSPARENCY_MASK) == VMFLAG_TRANSPARENCY_TAS_NOTCRITICAL +#ifndef FEATURE_CORECLR + || (m_VMFlags & VMFLAG_TRANSPARENCY_MASK) == VMFLAG_TRANSPARENCY_CRITICAL_TAS +#endif // !FEATURE_CORECLR; + ; + } + + inline BOOL IsAllTransparent() + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasCriticalTransparentInfo()); + return (m_VMFlags & VMFLAG_TRANSPARENCY_MASK) == VMFLAG_TRANSPARENCY_ALL_TRANSPARENT; + } + + inline BOOL IsAllCritical() + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasCriticalTransparentInfo()); + return (m_VMFlags & VMFLAG_TRANSPARENCY_MASK) == VMFLAG_TRANSPARENCY_ALLCRITICAL + || (m_VMFlags & VMFLAG_TRANSPARENCY_MASK) == VMFLAG_TRANSPARENCY_ALLCRITICAL_TAS; + } + + inline BOOL HasCriticalTransparentInfo() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_TRANSPARENCY_MASK) != VMFLAG_TRANSPARENCY_UNKNOWN; + } + + void SetCriticalTransparentInfo( +#ifndef FEATURE_CORECLR + BOOL fIsCritical, +#endif // !FEATURE_CORECLR + BOOL fIsTreatAsSafe, + BOOL fIsAllTransparent, + BOOL fIsAllCritical) + { + WRAPPER_NO_CONTRACT; + + // TAS wihtout critical doesn't make sense - although it was allowed in the v2 desktop model, + // so we need to allow it for compatibility reasons on the desktop. +#ifdef FEATURE_CORECLR + _ASSERTE(!fIsTreatAsSafe || fIsAllCritical); +#endif // FEATURE_CORECLR + + //if nothing is set, then we're transparent. + unsigned flags = VMFLAG_TRANSPARENCY_TRANSPARENT; + + if (fIsAllTransparent) + { + flags = VMFLAG_TRANSPARENCY_ALL_TRANSPARENT; + } + else if (fIsAllCritical) + { + flags = fIsTreatAsSafe ? VMFLAG_TRANSPARENCY_ALLCRITICAL_TAS : + VMFLAG_TRANSPARENCY_ALLCRITICAL; + } +#ifndef FEATURE_CORECLR + else if (fIsCritical) + { + flags = fIsTreatAsSafe ? VMFLAG_TRANSPARENCY_CRITICAL_TAS : + VMFLAG_TRANSPARENCY_CRITICAL; + } +#endif // !FEATURE_CORECLR + else + { + flags = fIsTreatAsSafe ? VMFLAG_TRANSPARENCY_TAS_NOTCRITICAL : + VMFLAG_TRANSPARENCY_TRANSPARENT; + } + + FastInterlockOr(EnsureWritablePages(&m_VMFlags), flags); + + _ASSERTE(HasCriticalTransparentInfo()); + } + inline DWORD IsUnsafeValueClass() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_UNSAFEVALUETYPE); + } + + +private: + inline void SetUnsafeValueClass() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= VMFLAG_UNSAFEVALUETYPE; + } + +public: + inline BOOL HasNoGuid() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_NO_GUID); + } + inline void SetHasNoGuid() + { + WRAPPER_NO_CONTRACT; + FastInterlockOr(EnsureWritablePages(&m_VMFlags), VMFLAG_NO_GUID); + } + +public: + + inline void SetDoesNotHaveSuppressUnmanagedCodeAccessAttr() + { + WRAPPER_NO_CONTRACT; + FastInterlockOr(EnsureWritablePages(&m_VMFlags),VMFLAG_NOSUPPRESSUNMGDCODEACCESS); + } + + inline BOOL HasSuppressUnmanagedCodeAccessAttr() + { + LIMITED_METHOD_CONTRACT; + return !(m_VMFlags & VMFLAG_NOSUPPRESSUNMGDCODEACCESS); + } + + inline BOOL HasRemotingProxyAttribute() + { + LIMITED_METHOD_CONTRACT; + return m_VMFlags & VMFLAG_REMOTING_PROXY_ATTRIBUTE; + } + inline void SetHasRemotingProxyAttribute() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= (DWORD)VMFLAG_REMOTING_PROXY_ATTRIBUTE; + } + inline BOOL IsAlign8Candidate() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_PREFER_ALIGN8); + } + inline void SetAlign8Candidate() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= VMFLAG_PREFER_ALIGN8; + } +#ifdef _DEBUG + inline void SetDestroyed() + { + LIMITED_METHOD_CONTRACT; + m_wAuxFlags |= AUXFLAG_DESTROYED; + } +#endif + inline void SetHasFixedAddressVTStatics() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= (DWORD) VMFLAG_FIXED_ADDRESS_VT_STATICS; + } +#ifdef FEATURE_COMINTEROP + void SetSparseForCOMInterop() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= (DWORD) VMFLAG_SPARSE_FOR_COMINTEROP; + } + inline void SetProjectedFromWinRT() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= (DWORD) VMFLAG_PROJECTED_FROM_WINRT; + } + inline void SetExportedToWinRT() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= (DWORD) VMFLAG_EXPORTED_TO_WINRT; + } + inline void SetMarshalingType(UINT32 mType) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(mType !=0); + _ASSERTE((m_VMFlags & VMFLAG_MARSHALINGTYPE_MASK) == 0); + switch(mType) + { + case 1: m_VMFlags |= VMFLAG_MARSHALINGTYPE_INHIBIT; + break; + case 2: m_VMFlags |= VMFLAG_MARSHALINGTYPE_FREETHREADED; + break; + case 3: m_VMFlags |= VMFLAG_MARSHALINGTYPE_STANDARD; + break; + default: + _ASSERTE(!"Invalid MarshalingBehaviorAttribute value"); + } + } +#endif // FEATURE_COMINTEROP + inline void SetHasLayout() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= (DWORD) VMFLAG_HASLAYOUT; //modified before the class is published + } + inline void SetHasOverLayedFields() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= VMFLAG_HASOVERLAYEDFIELDS; + } + inline void SetIsNested() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= VMFLAG_ISNESTED; + } + +#ifdef FEATURE_READYTORUN + inline BOOL HasLayoutDependsOnOtherModules() + { + LIMITED_METHOD_CONTRACT; + return m_VMFlags & VMFLAG_LAYOUT_DEPENDS_ON_OTHER_MODULES; + } + + inline void SetHasLayoutDependsOnOtherModules() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= VMFLAG_LAYOUT_DEPENDS_ON_OTHER_MODULES; + } +#endif + + // Is this delegate? Returns false for System.Delegate and System.MulticastDelegate. + inline BOOL IsDelegate() + { + LIMITED_METHOD_CONTRACT; + return m_VMFlags & VMFLAG_DELEGATE; + } + inline void SetIsDelegate() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= VMFLAG_DELEGATE; + } + + // This is only applicable to interfaces. This method does not + // provide correct information for non-interface types. + DWORD SomeMethodsRequireInheritanceCheck(); + void SetSomeMethodsRequireInheritanceCheck(); + + BOOL HasFixedAddressVTStatics() + { + LIMITED_METHOD_CONTRACT; + return m_VMFlags & VMFLAG_FIXED_ADDRESS_VT_STATICS; + } +#ifdef FEATURE_COMINTEROP + BOOL IsSparseForCOMInterop() + { + LIMITED_METHOD_CONTRACT; + return m_VMFlags & VMFLAG_SPARSE_FOR_COMINTEROP; + } + BOOL IsProjectedFromWinRT() + { + LIMITED_METHOD_DAC_CONTRACT; + return m_VMFlags & VMFLAG_PROJECTED_FROM_WINRT; + } + BOOL IsExportedToWinRT() + { + LIMITED_METHOD_CONTRACT; + return m_VMFlags & VMFLAG_EXPORTED_TO_WINRT; + } + BOOL IsMarshalingTypeSet() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_MARSHALINGTYPE_MASK); + } + BOOL IsMarshalingTypeFreeThreaded() + { + LIMITED_METHOD_CONTRACT; + return ((m_VMFlags & VMFLAG_MARSHALINGTYPE_MASK) == VMFLAG_MARSHALINGTYPE_FREETHREADED); + } + BOOL IsMarshalingTypeInhibit() + { + LIMITED_METHOD_CONTRACT; + return ((m_VMFlags & VMFLAG_MARSHALINGTYPE_MASK) == VMFLAG_MARSHALINGTYPE_INHIBIT); + } + BOOL IsMarshalingTypeStandard() + { + LIMITED_METHOD_CONTRACT; + return ((m_VMFlags & VMFLAG_MARSHALINGTYPE_MASK) == VMFLAG_MARSHALINGTYPE_STANDARD); + } +#endif // FEATURE_COMINTEROP + BOOL HasLayout() + { + LIMITED_METHOD_CONTRACT; + return m_VMFlags & VMFLAG_HASLAYOUT; + } + BOOL HasOverLayedField() + { + LIMITED_METHOD_CONTRACT; + return m_VMFlags & VMFLAG_HASOVERLAYEDFIELDS; + } + BOOL IsNested() + { + LIMITED_METHOD_CONTRACT; + return m_VMFlags & VMFLAG_ISNESTED; + } + BOOL HasFieldsWhichMustBeInited() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_HAS_FIELDS_WHICH_MUST_BE_INITED); + } + void SetHasFieldsWhichMustBeInited() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= (DWORD)VMFLAG_HAS_FIELDS_WHICH_MUST_BE_INITED; + } +#ifdef FEATURE_REMOTING + DWORD CannotBeBlittedByObjectCloner() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_CANNOT_BE_BLITTED_BY_OBJECT_CLONER); + } + void SetCannotBeBlittedByObjectCloner() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= (DWORD)VMFLAG_CANNOT_BE_BLITTED_BY_OBJECT_CLONER; + } +#else + void SetCannotBeBlittedByObjectCloner() + { + /* no op */ + } +#endif + DWORD HasNonPublicFields() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_HASNONPUBLICFIELDS); + } + void SetHasNonPublicFields() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= (DWORD)VMFLAG_HASNONPUBLICFIELDS; + } + DWORD IsNotTightlyPacked() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_NOT_TIGHTLY_PACKED); + } + void SetIsNotTightlyPacked() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= (DWORD)VMFLAG_NOT_TIGHTLY_PACKED; + } + DWORD ContainsMethodImpls() + { + LIMITED_METHOD_CONTRACT; + return (m_VMFlags & VMFLAG_CONTAINS_METHODIMPLS); + } + void SetContainsMethodImpls() + { + LIMITED_METHOD_CONTRACT; + m_VMFlags |= (DWORD)VMFLAG_CONTAINS_METHODIMPLS; + } + + + BOOL IsManagedSequential(); + + BOOL HasExplicitSize(); + + static void GetBestFitMapping(MethodTable * pMT, BOOL *pfBestFitMapping, BOOL *pfThrowOnUnmappableChar); + + /* + * Security attributes for the class are stored here. Do not update this field after the + * class is constructed without also updating the enum_flag_NoSecurityProperties on the + * methodtable. + */ + inline SecurityProperties* GetSecurityProperties() + { + LIMITED_METHOD_CONTRACT; + return HasOptionalFields() ? &GetOptionalFields()->m_SecProps : NULL; + } + + + /* + * The CorElementType for this class (most classes = ELEMENT_TYPE_CLASS) + */ +public: + // This is what would be used in the calling convention for this type. + CorElementType GetInternalCorElementType() + { + LIMITED_METHOD_DAC_CONTRACT; + + return CorElementType(m_NormType); + } + void SetInternalCorElementType (CorElementType _NormType) + { + LIMITED_METHOD_CONTRACT; + m_NormType = static_cast<BYTE>(_NormType); + } + + /* + * Chain of MethodDesc chunks for the MethodTable + */ +public: + inline PTR_MethodDescChunk GetChunks(); + +#ifndef DACCESS_COMPILE + inline void SetChunks (MethodDescChunk* pChunks) + { + LIMITED_METHOD_CONTRACT; + m_pChunks.SetValueMaybeNull(PTR_HOST_MEMBER_TADDR(EEClass, this, m_pChunks), pChunks); + } +#endif // !DACCESS_COMPILE + void AddChunk (MethodDescChunk* pNewChunk); + + void AddChunkIfItHasNotBeenAdded (MethodDescChunk* pNewChunk); + + inline PTR_GuidInfo GetGuidInfo() + { + LIMITED_METHOD_DAC_CONTRACT; + return m_pGuidInfo; + } + + inline void SetGuidInfo(GuidInfo* pGuidInfo) + { + WRAPPER_NO_CONTRACT; + #ifndef DACCESS_COMPILE + *EnsureWritablePages(&m_pGuidInfo) = pGuidInfo; + #endif // DACCESS_COMPILE + } + + // Cached class level reliability contract info, see ConstrainedExecutionRegion.cpp for details. + DWORD GetReliabilityContract(); + + inline void SetReliabilityContract(DWORD dwValue) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasOptionalFields()); + GetOptionalFields()->m_dwReliabilityContract = dwValue; + } + +#if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) + // Get number of eightbytes used by a struct passed in registers. + inline int GetNumberEightBytes() + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasOptionalFields()); + return GetOptionalFields()->m_numberEightBytes; + } + + // Get eightbyte classification for the eightbyte with the specified index. + inline SystemVClassificationType GetEightByteClassification(int index) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasOptionalFields()); + return GetOptionalFields()->m_eightByteClassifications[index]; + } + + // Get size of the data in the eightbyte with the specified index. + inline unsigned int GetEightByteSize(int index) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasOptionalFields()); + return GetOptionalFields()->m_eightByteSizes[index]; + } + + // Set the eightByte classification + inline void SetEightByteClassification(int eightByteCount, SystemVClassificationType *eightByteClassifications, unsigned int *eightByteSizes) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasOptionalFields()); + GetOptionalFields()->m_numberEightBytes = eightByteCount; + for (int i = 0; i < eightByteCount; i++) + { + GetOptionalFields()->m_eightByteClassifications[i] = eightByteClassifications[i]; + GetOptionalFields()->m_eightByteSizes[i] = eightByteSizes[i]; + } + } +#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING + +#ifdef FEATURE_COMINTEROP + inline TypeHandle GetCoClassForInterface() + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasOptionalFields()); + return GetOptionalFields()->m_pCoClassForIntf; + } + + inline void SetCoClassForInterface(TypeHandle th) + { + WRAPPER_NO_CONTRACT; + _ASSERTE(HasOptionalFields()); + *EnsureWritablePages(&GetOptionalFields()->m_pCoClassForIntf) = th; + } + + inline WinMDAdapter::RedirectedTypeIndex GetWinRTRedirectedTypeIndex() + { + LIMITED_METHOD_CONTRACT; + return HasOptionalFields() ? GetOptionalFields()->m_WinRTRedirectedTypeIndex + : WinMDAdapter::RedirectedTypeIndex_Invalid; + } + + inline void SetWinRTRedirectedTypeIndex(WinMDAdapter::RedirectedTypeIndex index) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasOptionalFields()); + _ASSERTE(index != WinMDAdapter::RedirectedTypeIndex_Invalid); + GetOptionalFields()->m_WinRTRedirectedTypeIndex = index; + } +#endif // FEATURE_COMINTEROP + + inline UINT32 GetNativeSize() + { + LIMITED_METHOD_DAC_CONTRACT; + return m_cbNativeSize; + } + static UINT32 GetOffsetOfNativeSize() + { + LIMITED_METHOD_CONTRACT; + return (UINT32)(offsetof(EEClass, m_cbNativeSize)); + } + void SetNativeSize(UINT32 nativeSize) + { + LIMITED_METHOD_CONTRACT; + m_cbNativeSize = nativeSize; + } +#ifdef FEATURE_COMINTEROP + OBJECTHANDLE GetOHDelegate() + { + LIMITED_METHOD_CONTRACT; + return m_ohDelegate; + } + void SetOHDelegate (OBJECTHANDLE _ohDelegate) + { + LIMITED_METHOD_CONTRACT; + m_ohDelegate = _ohDelegate; + } + // Set the COM interface type. + CorIfaceAttr GetComInterfaceType() + { + LIMITED_METHOD_CONTRACT; + return m_ComInterfaceType; + } + + void SetComInterfaceType(CorIfaceAttr ItfType) + { + WRAPPER_NO_CONTRACT; + _ASSERTE(IsInterface()); + EnsureWritablePages(this); + m_ComInterfaceType = ItfType; + } + + inline ComCallWrapperTemplate *GetComCallWrapperTemplate() + { + LIMITED_METHOD_CONTRACT; + return m_pccwTemplate; + } + inline BOOL SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate) + { + WRAPPER_NO_CONTRACT; + return (InterlockedCompareExchangeT(EnsureWritablePages(&m_pccwTemplate), pTemplate, NULL) == NULL); + } + +#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION + inline ClassFactoryBase *GetComClassFactory() + { + LIMITED_METHOD_CONTRACT; + return HasOptionalFields() ? GetOptionalFields()->m_pClassFactory : NULL; + } + inline BOOL SetComClassFactory(ClassFactoryBase *pFactory) + { + WRAPPER_NO_CONTRACT; + _ASSERTE(HasOptionalFields()); + return (InterlockedCompareExchangeT(EnsureWritablePages(&GetOptionalFields()->m_pClassFactory), pFactory, NULL) == NULL); + } +#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION +#endif // FEATURE_COMINTEROP + + +public: + PTR_DictionaryLayout GetDictionaryLayout() + { + SUPPORTS_DAC; + WRAPPER_NO_CONTRACT; + return HasOptionalFields() ? GetOptionalFields()->m_pDictLayout : NULL; + } + + void SetDictionaryLayout(PTR_DictionaryLayout pLayout) + { + SUPPORTS_DAC; + WRAPPER_NO_CONTRACT; + _ASSERTE(HasOptionalFields()); + GetOptionalFields()->m_pDictLayout = pLayout; + } + + static CorGenericParamAttr GetVarianceOfTypeParameter(BYTE * pbVarianceInfo, DWORD i) + { + LIMITED_METHOD_CONTRACT; + if (pbVarianceInfo == NULL) + return gpNonVariant; + else + return (CorGenericParamAttr) (pbVarianceInfo[i]); + } + + CorGenericParamAttr GetVarianceOfTypeParameter(DWORD i) + { + WRAPPER_NO_CONTRACT; + return GetVarianceOfTypeParameter(GetVarianceInfo(), i); + } + + BYTE* GetVarianceInfo() + { + LIMITED_METHOD_CONTRACT; + return HasOptionalFields() ? GetOptionalFields()->m_pVarianceInfo : NULL; + } + + void SetVarianceInfo(BYTE *pVarianceInfo) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasOptionalFields()); + GetOptionalFields()->m_pVarianceInfo = pVarianceInfo; + } + + // Check that a signature blob uses type parameters correctly + // in accordance with the variance annotations specified by this class + // The position parameter indicates the variance of the context we're in + // (result type is gpCovariant, argument types are gpContravariant, deeper in a signature + // we might be gpNonvariant e.g. in a pointer type or non-variant generic type) + static BOOL + CheckVarianceInSig( + DWORD numGenericArgs, + BYTE *pVarianceInfo, + Module * pModule, + SigPointer sp, + CorGenericParamAttr position); + +#if defined(CHECK_APP_DOMAIN_LEAKS) || defined(_DEBUG) +public: + enum{ + AUXFLAG_APP_DOMAIN_AGILE = 0x00000001, + AUXFLAG_CHECK_APP_DOMAIN_AGILE = 0x00000002, + AUXFLAG_APP_DOMAIN_AGILITY_DONE = 0x00000004, + AUXFLAG_DESTROYED = 0x00000008, // The Destruct() method has already been called on this class + }; + + inline DWORD GetAuxFlagsRaw() + { + LIMITED_METHOD_CONTRACT; + return m_wAuxFlags; + } + inline DWORD* GetAuxFlagsPtr() + { + LIMITED_METHOD_CONTRACT; + return (DWORD*)(&m_wAuxFlags); + } + inline void SetAuxFlags(DWORD flag) + { + LIMITED_METHOD_CONTRACT; + m_wAuxFlags |= (WORD)flag; + } + + // This flag is set (in a checked build only?) for classes whose + // instances are always app domain agile. This can + // be either because of type system guarantees or because + // the class is explicitly marked. + inline BOOL IsAppDomainAgile() + { + LIMITED_METHOD_CONTRACT; + return (m_wAuxFlags & AUXFLAG_APP_DOMAIN_AGILE); + } + inline void SetAppDomainAgile() + { + LIMITED_METHOD_CONTRACT; + m_wAuxFlags |= AUXFLAG_APP_DOMAIN_AGILE; + } + // This flag is set in a checked build for classes whose + // instances may be marked app domain agile, but agility + // isn't guaranteed by type safety. The JIT will compile + // in extra checks to field assignment on some fields + // in such a class. + inline BOOL IsCheckAppDomainAgile() + { + LIMITED_METHOD_CONTRACT; + return (m_wAuxFlags & AUXFLAG_CHECK_APP_DOMAIN_AGILE); + } + + inline void SetCheckAppDomainAgile() + { + LIMITED_METHOD_CONTRACT; + m_wAuxFlags |= AUXFLAG_CHECK_APP_DOMAIN_AGILE; + } + + // This flag is set in a checked build to indicate that the + // appdomain agility for a class had been set. This is used + // for debugging purposes to make sure that we don't allocate + // an object before the agility is set. + inline BOOL IsAppDomainAgilityDone() + { + LIMITED_METHOD_CONTRACT; + return (m_wAuxFlags & AUXFLAG_APP_DOMAIN_AGILITY_DONE); + } + inline void SetAppDomainAgilityDone() + { + LIMITED_METHOD_CONTRACT; + m_wAuxFlags |= AUXFLAG_APP_DOMAIN_AGILITY_DONE; + } + // + // This predicate checks whether or not the class is "naturally" + // app domain agile - that is: + // (1) it is in the system domain + // (2) all the fields are app domain agile + // (3) it has no finalizer + // + // Or, this also returns true for a proxy type which is allowed + // to have cross app domain refs. + // + inline BOOL IsTypesafeAppDomainAgile() + { + LIMITED_METHOD_CONTRACT; + return IsAppDomainAgile() && !IsCheckAppDomainAgile(); + } + // + // This predictate tests whether any instances are allowed + // to be app domain agile. + // + inline BOOL IsNeverAppDomainAgile() + { + LIMITED_METHOD_CONTRACT; + return !IsAppDomainAgile() && !IsCheckAppDomainAgile(); + } + static void SetAppDomainAgileAttribute(MethodTable * pMT); + + static void GetPredefinedAgility(Module *pModule, mdTypeDef td, BOOL *pfIsAgile, BOOL *pfIsCheckAgile); +#endif // defined(CHECK_APP_DOMAIN_LEAKS) || defined(_DEBUG) + + //------------------------------------------------------------- + // CONCRETE DATA LAYOUT + // + // Although accessed far less frequently than MethodTables, EEClasses are still + // pulled into working set, especially at startup. This has motivated several space + // optimizations in field layout where each is balanced against the need to access + // a particular field efficiently. + // + // Currently, the following strategy is used: + // + // - Any field that has a default value for the vast majority of EEClass instances + // should be stored in the EEClassOptionalFields (see header comment) + // + // - Any field that is nearly always a small positive integer and is infrequently + // accessed should be in the EEClassPackedFields (see header comment) + // + // If none of these categories apply - such as for always-meaningful pointer members or + // sets of flags - a full field is used. Please avoid adding such members if possible. + //------------------------------------------------------------- + + // @TODO: needed for asm code in cgenx86.cpp. Can this enum be private? + // + // Flags for m_VMFlags + // +public: + enum + { +#ifdef FEATURE_READYTORUN + VMFLAG_LAYOUT_DEPENDS_ON_OTHER_MODULES = 0x00000001, +#endif + VMFLAG_DELEGATE = 0x00000002, + + //Desktop + // -------------- + //Flag | All Transparent | Critical | All Critical | TreatAsSafe + //TRANSPARENT | 0 | 0 | 0 | 0 + //ALL_TRANSPARENT | 1 | 0 | 0 | 0 + //CRITICAL | 0 | 1 | 0 | 0 + //TAS_CRITICAL | 0 | 1 | 0 | 1 + //ALLCRITICAL | 0 | 0 | 1 | 0 + //ALLCRITICAL_TAS | 0 | 0 | 1 | 1 + //TAS_NOTCRITICAL | 0 | 0 | 0 | 1 + // + // + //On CoreCLR TAS implies Critical and "All Critical" and "Critical" are the same thing. + //CoreCLR + // -------------- + //Flag | All Transparent | Critical | TreatAsSafe + //TRANSPARENT | 0 | 0 | 0 + //ALL_TRANSPARENT | 1 | 0 | 0 + //CRITICAL | 0 | 1 | 0 + //TAS_CRITICAL | 0 | 1 | 1 + VMFLAG_TRANSPARENCY_MASK = 0x0000001c, + VMFLAG_TRANSPARENCY_UNKNOWN = 0x00000000, + VMFLAG_TRANSPARENCY_TRANSPARENT = 0x00000004, + VMFLAG_TRANSPARENCY_ALL_TRANSPARENT = 0x00000008, + VMFLAG_TRANSPARENCY_CRITICAL = 0x0000000c, + VMFLAG_TRANSPARENCY_CRITICAL_TAS = 0x00000010, + VMFLAG_TRANSPARENCY_ALLCRITICAL = 0x00000014, + VMFLAG_TRANSPARENCY_ALLCRITICAL_TAS = 0x00000018, + VMFLAG_TRANSPARENCY_TAS_NOTCRITICAL = 0x0000001c, + + VMFLAG_FIXED_ADDRESS_VT_STATICS = 0x00000020, // Value type Statics in this class will be pinned + VMFLAG_HASLAYOUT = 0x00000040, + VMFLAG_ISNESTED = 0x00000080, +#ifdef FEATURE_REMOTING + VMFLAG_CANNOT_BE_BLITTED_BY_OBJECT_CLONER = 0x00000100, // This class has GC type fields, or implements ISerializable or has non-Serializable fields +#endif + + VMFLAG_IS_EQUIVALENT_TYPE = 0x00000200, + + // OVERLAYED is used to detect whether Equals can safely optimize to a bit-compare across the structure. + VMFLAG_HASOVERLAYEDFIELDS = 0x00000400, + + // Set this if this class or its parent have instance fields which + // must be explicitly inited in a constructor (e.g. pointers of any + // kind, gc or native). + // + // Currently this is used by the verifier when verifying value classes + // - it's ok to use uninitialised value classes if there are no + // pointer fields in them. + VMFLAG_HAS_FIELDS_WHICH_MUST_BE_INITED = 0x00000800, + + VMFLAG_UNSAFEVALUETYPE = 0x00001000, + + VMFLAG_BESTFITMAPPING_INITED = 0x00002000, // VMFLAG_BESTFITMAPPING and VMFLAG_THROWONUNMAPPABLECHAR are valid only if this is set + VMFLAG_BESTFITMAPPING = 0x00004000, // BestFitMappingAttribute.Value + VMFLAG_THROWONUNMAPPABLECHAR = 0x00008000, // BestFitMappingAttribute.ThrowOnUnmappableChar + + VMFLAG_NOSUPPRESSUNMGDCODEACCESS = 0x00010000, + VMFLAG_NO_GUID = 0x00020000, + VMFLAG_HASNONPUBLICFIELDS = 0x00040000, + VMFLAG_REMOTING_PROXY_ATTRIBUTE = 0x00080000, + VMFLAG_CONTAINS_STACK_PTR = 0x00100000, + VMFLAG_PREFER_ALIGN8 = 0x00200000, // Would like to have 8-byte alignment + VMFLAG_METHODS_REQUIRE_INHERITANCE_CHECKS = 0x00400000, + +#ifdef FEATURE_COMINTEROP + VMFLAG_SPARSE_FOR_COMINTEROP = 0x00800000, + // interfaces may have a coclass attribute + VMFLAG_HASCOCLASSATTRIB = 0x01000000, + VMFLAG_COMEVENTITFMASK = 0x02000000, // class is a special COM event interface + VMFLAG_PROJECTED_FROM_WINRT = 0x04000000, + VMFLAG_EXPORTED_TO_WINRT = 0x08000000, +#endif // FEATURE_COMINTEROP + + // This one indicates that the fields of the valuetype are + // not tightly packed and is used to check whether we can + // do bit-equality on value types to implement ValueType::Equals. + // It is not valid for classes, and only matters if ContainsPointer + // is false. + VMFLAG_NOT_TIGHTLY_PACKED = 0x10000000, + + // True if methoddesc on this class have any real (non-interface) methodimpls + VMFLAG_CONTAINS_METHODIMPLS = 0x20000000, + +#ifdef FEATURE_COMINTEROP + VMFLAG_MARSHALINGTYPE_MASK = 0xc0000000, + + VMFLAG_MARSHALINGTYPE_INHIBIT = 0x40000000, + VMFLAG_MARSHALINGTYPE_FREETHREADED = 0x80000000, + VMFLAG_MARSHALINGTYPE_STANDARD = 0xc0000000, +#endif + }; + +public: + // C_ASSERTs in Jitinterface.cpp need this to be public to check the offset. + // Put it first so the offset rarely changes, which just reduces the number of times we have to fiddle + // with the offset. + PTR_GuidInfo m_pGuidInfo; // The cached guid inforation for interfaces. + +#ifdef _DEBUG +public: + LPCUTF8 m_szDebugClassName; + BOOL m_fDebuggingClass; +#endif + +private: + // Layout rest of fields below from largest to smallest to lessen the chance of wasting bytes with + // compiler injected padding (especially with the difference between pointers and DWORDs on 64-bit). + RelativePointer<PTR_EEClassOptionalFields> m_rpOptionalFields; + + // TODO: Remove this field. It is only used by SOS and object validation for stress. + PTR_MethodTable m_pMethodTable; + + RelativePointer<PTR_FieldDesc> m_pFieldDescList; + RelativePointer<PTR_MethodDescChunk> m_pChunks; + + union + { + // valid only if EEClass::IsBlittable() or EEClass::HasLayout() is true + UINT32 m_cbNativeSize; // size of fixed portion in bytes + +#ifdef FEATURE_COMINTEROP + // For COM+ wrapper objects that extend an unmanaged class, this field + // may contain a delegate to be called to allocate the aggregated + // unmanaged class (instead of using CoCreateInstance). + OBJECTHANDLE m_ohDelegate; + + // For interfaces this contains the COM interface type. + CorIfaceAttr m_ComInterfaceType; +#endif // FEATURE_COMINTEROP + }; + +#ifdef FEATURE_COMINTEROP + ComCallWrapperTemplate *m_pccwTemplate; // points to interop data structures used when this type is exposed to COM +#endif // FEATURE_COMINTEROP + + DWORD m_dwAttrClass; + DWORD m_VMFlags; + + /* + * We maintain some auxillary flags in DEBUG or CHECK_APP_DOMAIN_LEAKS builds, + * this frees up some bits in m_wVMFlags + */ +#if defined(CHECK_APP_DOMAIN_LEAKS) || defined(_DEBUG) + WORD m_wAuxFlags; +#endif + + // NOTE: Following BYTE fields are layed out together so they'll fit within the same DWORD for efficient + // structure packing. + BYTE m_NormType; + BYTE m_fFieldsArePacked; // TRUE iff fields pointed to by GetPackedFields() are in packed state + BYTE m_cbFixedEEClassFields; // Count of bytes of normal fields of this instance (EEClass, + // LayoutEEClass etc.). Doesn't count bytes of "packed" fields + BYTE m_cbBaseSizePadding; // How many bytes of padding are included in BaseSize + +public: + // EEClass optional field support. Whether a particular EEClass instance has optional fields is determined + // at class load time. The entire EEClassOptionalFields structure is allocated if the EEClass has need of + // one or more optional fields. + +#ifndef DACCESS_COMPILE + void AttachOptionalFields(EEClassOptionalFields *pFields) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(m_rpOptionalFields.IsNull()); + + m_rpOptionalFields.SetValue(pFields); + } +#endif // !DACCESS_COMPILE + + bool HasOptionalFields() + { + LIMITED_METHOD_DAC_CONTRACT; + return !m_rpOptionalFields.IsNull(); + } + + PTR_EEClassOptionalFields GetOptionalFields() + { + LIMITED_METHOD_DAC_CONTRACT; + return m_rpOptionalFields.GetValueMaybeNull(PTR_HOST_MEMBER_TADDR(EEClass, this, m_rpOptionalFields)); + } + +private: + // + // Support for packed fields. + // + + // Get pointer to the packed fields structure attached to this instance. + PTR_EEClassPackedFields GetPackedFields(); + + // Get the value of the given field. Works regardless of whether the field is currently in its packed or + // unpacked state. + DWORD GetPackableField(EEClassFieldId eField); + + // Set the value of the given field. The field *must* be in the unpacked state for this to be legal (in + // practice all packable fields must be initialized during class construction and from then on remain + // immutable). + void SetPackableField(EEClassFieldId eField, DWORD dwValue); + + //------------------------------------------------------------- + // END CONCRETE DATA LAYOUT + //------------------------------------------------------------- + + + + /************************************ + * PROTECTED METHODS + ************************************/ +protected: +#ifndef DACCESS_COMPILE + /* + * Constructor: prevent any other class from doing a new() + */ + EEClass(DWORD cbFixedEEClassFields); + + /* + * Destructor: prevent any other class from deleting + */ + ~EEClass() + { + LIMITED_METHOD_CONTRACT; + } +#endif // !DACCESS_COMPILE + +}; + +// -------------------------------------------------------------------------------------------- +template <typename Data> +class FixedCapacityStackingAllocatedUTF8StringHash +{ +public: + // Entry + struct HashEntry + { + HashEntry * m_pNext; // Next item with same bucketed hash value + DWORD m_dwHashValue; // Hash value + LPCUTF8 m_pKey; // String key + Data m_data; // Data + }; + + HashEntry ** m_pBuckets; // Pointer to first entry for each bucket + DWORD m_dwNumBuckets; + BYTE * m_pMemory; // Current pointer into preallocated memory for entries + BYTE * m_pMemoryStart; // Start pointer of pre-allocated memory fo entries + + INDEBUG(BYTE * m_pDebugEndMemory;) + + FixedCapacityStackingAllocatedUTF8StringHash() + : m_pMemoryStart(NULL) + { LIMITED_METHOD_CONTRACT; } + + static DWORD + GetHashCode( + LPCUTF8 szString) + { WRAPPER_NO_CONTRACT; return HashStringA(szString); } + + // Throws on error + void + Init( + DWORD dwMaxEntries, + StackingAllocator * pAllocator); + + // Insert new entry at head of list + void + Insert( + LPCUTF8 pszName, + const Data & data); + + // Return the first matching entry in the list, or NULL if there is no such entry + HashEntry * + Lookup( + LPCUTF8 pszName); + + // Return the next matching entry in the list, or NULL if there is no such entry. + HashEntry * + FindNext( + HashEntry * pEntry); +}; + + +//--------------------------------------------------------------------------------------- +// +class LayoutEEClass : public EEClass +{ +public: + EEClassLayoutInfo m_LayoutInfo; + +#ifndef DACCESS_COMPILE + LayoutEEClass() : EEClass(sizeof(LayoutEEClass)) + { + LIMITED_METHOD_CONTRACT; +#ifdef _DEBUG + FillMemory(&m_LayoutInfo, sizeof(m_LayoutInfo), 0xcc); +#endif + } +#endif // !DACCESS_COMPILE +}; + +class UMThunkMarshInfo; + +#ifdef FEATURE_COMINTEROP +struct ComPlusCallInfo; +#endif // FEATURE_COMINTEROP + +class DelegateEEClass : public EEClass +{ +public: + PTR_Stub m_pStaticCallStub; + PTR_Stub m_pInstRetBuffCallStub; + PTR_MethodDesc m_pInvokeMethod; + PTR_Stub m_pMultiCastInvokeStub; + UMThunkMarshInfo* m_pUMThunkMarshInfo; + PTR_MethodDesc m_pBeginInvokeMethod; + PTR_MethodDesc m_pEndInvokeMethod; + Volatile<PCODE> m_pMarshalStub; + +#ifdef FEATURE_COMINTEROP + ComPlusCallInfo *m_pComPlusCallInfo; +#endif // FEATURE_COMINTEROP + + // + // Ngened IL stub MethodDescs. Fixed up, wrapped with code:Stub, and installed to + // m_pMarshalStub (forward) or m_pUMThunkMarshInfo (reverse) when first needed. + // + MethodDesc* m_pForwardStubMD; // marshaling stub for calls to unmanaged code + MethodDesc* m_pReverseStubMD; // marshaling stub for calls from unmanaged code + +#ifndef DACCESS_COMPILE + DelegateEEClass() : EEClass(sizeof(DelegateEEClass)) + { + LIMITED_METHOD_CONTRACT; + // Note: Memory allocated on loader heap is zero filled + } + + // We need a LoaderHeap that lives at least as long as the DelegateEEClass, but ideally no longer + LoaderHeap *GetStubHeap(); +#endif // !DACCESS_COMPILE + +}; + + +typedef DPTR(ArrayClass) PTR_ArrayClass; + + +// Dynamically generated array class structure +class ArrayClass : public EEClass +{ +#ifdef FEATURE_PREJIT + friend void EEClass::Fixup(DataImage *image, MethodTable *pMethodTable); +#endif + + friend MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementType arrayKind, unsigned Rank, AllocMemTracker *pamTracker); + +#ifndef DACCESS_COMPILE + ArrayClass() : EEClass(sizeof(ArrayClass)) { LIMITED_METHOD_CONTRACT; } +#else + friend class NativeImageDumper; +#endif + +private: + + unsigned char m_rank; + CorElementType m_ElementType;// Cache of element type in m_ElementTypeHnd + +public: + DWORD GetRank() { + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + return m_rank; + } + void SetRank (unsigned Rank) { + LIMITED_METHOD_CONTRACT; + // The only code path calling this function is code:ClassLoader::CreateTypeHandleForTypeKey, which has + // checked the rank already. Assert that the rank is less than MAX_RANK and that it fits in one byte. + _ASSERTE((Rank <= MAX_RANK) && (Rank <= (unsigned char)(-1))); + m_rank = (unsigned char)Rank; + } + + CorElementType GetArrayElementType() { + LIMITED_METHOD_CONTRACT; + return m_ElementType; + } + void SetArrayElementType(CorElementType ElementType) { + LIMITED_METHOD_CONTRACT; + m_ElementType = ElementType; + } + + + // Allocate a new MethodDesc for the methods we add to this class + void InitArrayMethodDesc( + ArrayMethodDesc* pNewMD, + PCCOR_SIGNATURE pShortSig, + DWORD cShortSig, + DWORD dwVtableSlot, + LoaderAllocator *pLoaderAllocator, + AllocMemTracker *pamTracker); + + // Generate a short sig for an array accessor + VOID GenerateArrayAccessorCallSig(DWORD dwRank, + DWORD dwFuncType, // Load, store, or <init> + PCCOR_SIGNATURE *ppSig, // Generated signature + DWORD * pcSig, // Generated signature size + LoaderAllocator *pLoaderAllocator, + AllocMemTracker *pamTracker +#ifdef FEATURE_ARRAYSTUB_AS_IL + ,BOOL fForStubAsIL +#endif + ); + + +}; + +inline EEClassLayoutInfo *EEClass::GetLayoutInfo() +{ + LIMITED_METHOD_CONTRACT; + _ASSERTE(HasLayout()); + return &((LayoutEEClass *) this)->m_LayoutInfo; +} + +inline BOOL EEClass::IsBlittable() +{ + LIMITED_METHOD_CONTRACT; + + // Either we have an opaque bunch of bytes, or we have some fields that are + // all isomorphic and explicitly layed out. + return (HasLayout() && GetLayoutInfo()->IsBlittable()); +} + +inline BOOL EEClass::IsManagedSequential() +{ + LIMITED_METHOD_CONTRACT; + return HasLayout() && GetLayoutInfo()->IsManagedSequential(); +} + +inline BOOL EEClass::HasExplicitSize() +{ + LIMITED_METHOD_CONTRACT; + return HasLayout() && GetLayoutInfo()->HasExplicitSize(); +} + +//========================================================================== +// These routines manage the prestub (a bootstrapping stub that all +// FunctionDesc's are initialized with.) +//========================================================================== +VOID InitPreStubManager(); + +EXTERN_C void STDCALL ThePreStub(); + +inline PCODE GetPreStubEntryPoint() +{ + return GetEEFuncEntryPoint(ThePreStub); +} + +PCODE TheUMThunkPreStub(); + +PCODE TheVarargNDirectStub(BOOL hasRetBuffArg); + + + +// workaround: These classification bits need cleanup bad: for now, this gets around +// IJW setting both mdUnmanagedExport & mdPinvokeImpl on expored methods. +#define IsReallyMdPinvokeImpl(x) ( ((x) & mdPinvokeImpl) && !((x) & mdUnmanagedExport) ) + +// +// The MethodNameHash is a temporary loader structure which may be allocated if there are a large number of +// methods in a class, to quickly get from a method name to a MethodDesc (potentially a chain of MethodDescs). +// + +#define METH_NAME_CACHE_SIZE 5 +#define MAX_MISSES 3 + +#ifdef EnC_SUPPORTED + +struct EnCAddedFieldElement; + +#endif // EnC_SUPPORTED + + +// -------------------------------------------------------------------------------------------- +// For generic instantiations the FieldDescs stored for instance +// fields are approximate, not exact, i.e. they are representatives owned by +// canonical instantiation and they do not carry exact type information. +// This will not include EnC related fields. (See EncApproxFieldDescIterator for that) +class ApproxFieldDescIterator +{ +private: + int m_iteratorType; + PTR_FieldDesc m_pFieldDescList; + int m_currField; + int m_totalFields; + + public: + enum IteratorType { + INSTANCE_FIELDS = 0x1, + STATIC_FIELDS = 0x2, + ALL_FIELDS = (INSTANCE_FIELDS | STATIC_FIELDS) + }; + ApproxFieldDescIterator(); + ApproxFieldDescIterator(MethodTable *pMT, int iteratorType) + { + SUPPORTS_DAC; + Init(pMT, iteratorType); + } + void Init(MethodTable *pMT, int iteratorType); + PTR_FieldDesc Next(); + + int GetIteratorType() { + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + return m_iteratorType; + } + + int Count() { + LIMITED_METHOD_CONTRACT; + return m_totalFields; + } + int CountRemaining() { + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + return m_totalFields - m_currField - 1; + } +}; + +// +// DeepFieldDescIterator iterates over the entire +// set of fields available to a class, inherited or +// introduced. +// + +class DeepFieldDescIterator +{ +private: + ApproxFieldDescIterator m_fieldIter; + int m_numClasses; + int m_curClass; + MethodTable* m_classes[16]; + int m_deepTotalFields; + bool m_lastNextFromParentClass; + + bool NextClass(); + +public: + DeepFieldDescIterator() + { + LIMITED_METHOD_CONTRACT; + + m_numClasses = 0; + m_curClass = 0; + m_deepTotalFields = 0; + m_lastNextFromParentClass = false; + } + DeepFieldDescIterator(MethodTable* pMT, int iteratorType, + bool includeParents = true) + { + WRAPPER_NO_CONTRACT; + + Init(pMT, iteratorType, includeParents); + } + void Init(MethodTable* pMT, int iteratorType, + bool includeParents = true); + + FieldDesc* Next(); + + bool Skip(int numSkip); + + int Count() + { + LIMITED_METHOD_CONTRACT; + return m_deepTotalFields; + } + bool IsFieldFromParentClass() + { + LIMITED_METHOD_CONTRACT; + return m_lastNextFromParentClass; + } +}; + +#endif // !CLASS_H |