// 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. // // OBJECT.H // // Definitions of a Com+ Object // // See code:EEStartup#TableOfContents for overview #ifndef _OBJECT_H_ #define _OBJECT_H_ #include "util.hpp" #include "syncblk.h" #include "gcdesc.h" #include "specialstatics.h" #include "sstring.h" #include "daccess.h" #include "fcall.h" extern "C" void __fastcall ZeroMemoryInGCHeap(void*, size_t); void ErectWriteBarrierForMT(MethodTable **dst, MethodTable *ref); /* #ObjectModel * COM+ Internal Object Model * * * Object - This is the common base part to all COM+ objects * | it contains the MethodTable pointer and the * | sync block index, which is at a negative offset * | * +-- code:StringObject - String objects are specialized objects for string * | storage/retrieval for higher performance (UCS-2 / UTF-16 data) * | * +-- code:Utf8StringObject - String objects are specialized objects for string * | storage/retrieval for higher performance (UTF-8 data) * | * +-- BaseObjectWithCachedData - Object Plus one object field for caching. * | | * | +- ReflectClassBaseObject - The base object for the RuntimeType class * | +- ReflectMethodObject - The base object for the RuntimeMethodInfo class * | +- ReflectFieldObject - The base object for the RtFieldInfo class * | * +-- code:ArrayBase - Base portion of all arrays * | | * | +- I1Array - Base type arrays * | | I2Array * | | ... * | | * | +- PtrArray - Array of OBJECTREFs, different than base arrays because of pObjectClass * | * +-- code:AssemblyBaseObject - The base object for the class Assembly * * * PLEASE NOTE THE FOLLOWING WHEN ADDING A NEW OBJECT TYPE: * * The size of the object in the heap must be able to be computed * very, very quickly for GC purposes. Restrictions on the layout * of the object guarantee this is possible. * * Any object that inherits from Object must be able to * compute its complete size by using the first 4 bytes of * the object following the Object part and constants * reachable from the MethodTable... * * The formula used for this calculation is: * MT->GetBaseSize() + ((OBJECTTYPEREF->GetSizeField() * MT->GetComponentSize()) * * So for Object, since this is of fixed size, the ComponentSize is 0, which makes the right side * of the equation above equal to 0 no matter what the value of GetSizeField(), so the size is just the base size. * */ // // @TODO: #define COW 0x04 // @TODO: MOO, MOO - no, not bovine, really Copy On Write bit for StringBuffer, requires 8 byte align MT // @TODL: which we don't have yet class MethodTable; class Thread; class BaseDomain; class Assembly; class DomainAssembly; class AssemblyNative; class WaitHandleNative; class ArgDestination; struct RCW; #ifdef _TARGET_64BIT_ #define OBJHEADER_SIZE (sizeof(DWORD) /* m_alignpad */ + sizeof(DWORD) /* m_SyncBlockValue */) #else #define OBJHEADER_SIZE sizeof(DWORD) /* m_SyncBlockValue */ #endif #define OBJECT_SIZE TARGET_POINTER_SIZE /* m_pMethTab */ #define OBJECT_BASESIZE (OBJHEADER_SIZE + OBJECT_SIZE) #ifdef _TARGET_64BIT_ #define ARRAYBASE_SIZE (OBJECT_SIZE /* m_pMethTab */ + sizeof(DWORD) /* m_NumComponents */ + sizeof(DWORD) /* pad */) #else #define ARRAYBASE_SIZE (OBJECT_SIZE /* m_pMethTab */ + sizeof(DWORD) /* m_NumComponents */) #endif #define ARRAYBASE_BASESIZE (OBJHEADER_SIZE + ARRAYBASE_SIZE) // // The generational GC requires that every object be at least 12 bytes // in size. #define MIN_OBJECT_SIZE (2*TARGET_POINTER_SIZE + OBJHEADER_SIZE) #define PTRALIGNCONST (DATA_ALIGNMENT-1) #ifndef PtrAlign #define PtrAlign(size) \ ((size + PTRALIGNCONST) & (~PTRALIGNCONST)) #endif //!PtrAlign // code:Object is the respesentation of an managed object on the GC heap. // // See code:#ObjectModel for some important subclasses of code:Object // // The only fields mandated by all objects are // // * a pointer to the code:MethodTable at offset 0 // * a poiner to a code:ObjHeader at a negative offset. This is often zero. It holds information that // any addition information that we might need to attach to arbitrary objects. // class Object { protected: PTR_MethodTable m_pMethTab; protected: Object() { LIMITED_METHOD_CONTRACT; }; ~Object() { LIMITED_METHOD_CONTRACT; }; public: MethodTable *RawGetMethodTable() const { return m_pMethTab; } #ifndef DACCESS_COMPILE void RawSetMethodTable(MethodTable *pMT) { LIMITED_METHOD_CONTRACT; m_pMethTab = pMT; } VOID SetMethodTable(MethodTable *pMT DEBUG_ARG(BOOL bAllowArray = FALSE)) { LIMITED_METHOD_CONTRACT; m_pMethTab = pMT; #ifdef _DEBUG if (!bAllowArray) { AssertNotArray(); } #endif // _DEBUG } VOID SetMethodTableForLargeObject(MethodTable *pMT DEBUG_ARG(BOOL bAllowArray = FALSE)) { // This function must be used if the allocation occurs on the large object heap, and the method table might be a collectible type WRAPPER_NO_CONTRACT; ErectWriteBarrierForMT(&m_pMethTab, pMT); #ifdef _DEBUG if (!bAllowArray) { AssertNotArray(); } #endif // _DEBUG } #endif //!DACCESS_COMPILE #define MARKED_BIT 0x1 PTR_MethodTable GetMethodTable() const { LIMITED_METHOD_DAC_CONTRACT; #ifndef DACCESS_COMPILE // We should always use GetGCSafeMethodTable() if we're running during a GC. // If the mark bit is set then we're running during a GC _ASSERTE((dac_cast(m_pMethTab) & MARKED_BIT) == 0); return m_pMethTab; #else //DACCESS_COMPILE //@dbgtodo dharvey Make this a type which supports bitwise and operations //when available return PTR_MethodTable((dac_cast(m_pMethTab)) & (~MARKED_BIT)); #endif //DACCESS_COMPILE } DPTR(PTR_MethodTable) GetMethodTablePtr() const { LIMITED_METHOD_CONTRACT; return dac_cast(PTR_HOST_MEMBER_TADDR(Object, this, m_pMethTab)); } TypeHandle GetTypeHandle(); TypeHandle GetTrueTypeHandle(); // Methods used to determine if an object supports a given interface. static BOOL SupportsInterface(OBJECTREF pObj, MethodTable *pInterfaceMT); inline DWORD GetNumComponents(); inline SIZE_T GetSize(); CGCDesc* GetSlotMap() { WRAPPER_NO_CONTRACT; return( CGCDesc::GetCGCDescFromMT(GetMethodTable())); } // Sync Block & Synchronization services // Access the ObjHeader which is at a negative offset on the object (because of // cache lines) PTR_ObjHeader GetHeader() { LIMITED_METHOD_DAC_CONTRACT; return dac_cast(this) - 1; } // Get the current address of the object (works for debug refs, too.) PTR_BYTE GetAddress() { LIMITED_METHOD_DAC_CONTRACT; return dac_cast(this); } #ifdef _DEBUG // TRUE if the header has a real SyncBlockIndex (i.e. it has an entry in the // SyncTable, though it doesn't necessarily have an entry in the SyncBlockCache) BOOL HasEmptySyncBlockInfo() { WRAPPER_NO_CONTRACT; return GetHeader()->HasEmptySyncBlockInfo(); } #endif // retrieve or allocate a sync block for this object SyncBlock *GetSyncBlock() { WRAPPER_NO_CONTRACT; return GetHeader()->GetSyncBlock(); } DWORD GetSyncBlockIndex() { WRAPPER_NO_CONTRACT; return GetHeader()->GetSyncBlockIndex(); } // 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. BOOL ValidateObjectWithPossibleAV(); // Validate an object ref out of the Promote routine in the GC void ValidatePromote(ScanContext *sc, DWORD flags); // Validate an object ref out of the VerifyHeap routine in the GC void ValidateHeap(Object *from, BOOL bDeep=TRUE); PTR_SyncBlock PassiveGetSyncBlock() { LIMITED_METHOD_DAC_CONTRACT; return GetHeader()->PassiveGetSyncBlock(); } static DWORD ComputeHashCode(); #ifndef DACCESS_COMPILE INT32 GetHashCodeEx(); #endif // #ifndef DACCESS_COMPILE // Synchronization #ifndef DACCESS_COMPILE void EnterObjMonitor() { WRAPPER_NO_CONTRACT; GetHeader()->EnterObjMonitor(); } BOOL TryEnterObjMonitor(INT32 timeOut = 0) { WRAPPER_NO_CONTRACT; return GetHeader()->TryEnterObjMonitor(timeOut); } bool TryEnterObjMonitorSpinHelper(); FORCEINLINE AwareLock::EnterHelperResult EnterObjMonitorHelper(Thread* pCurThread) { WRAPPER_NO_CONTRACT; return GetHeader()->EnterObjMonitorHelper(pCurThread); } FORCEINLINE AwareLock::EnterHelperResult EnterObjMonitorHelperSpin(Thread* pCurThread) { WRAPPER_NO_CONTRACT; return GetHeader()->EnterObjMonitorHelperSpin(pCurThread); } BOOL LeaveObjMonitor() { WRAPPER_NO_CONTRACT; return GetHeader()->LeaveObjMonitor(); } // should be called only from unwind code; used in the // case where EnterObjMonitor failed to allocate the // sync-object. BOOL LeaveObjMonitorAtException() { WRAPPER_NO_CONTRACT; return GetHeader()->LeaveObjMonitorAtException(); } FORCEINLINE AwareLock::LeaveHelperAction LeaveObjMonitorHelper(Thread* pCurThread) { WRAPPER_NO_CONTRACT; return GetHeader()->LeaveObjMonitorHelper(pCurThread); } // Returns TRUE if the lock is owned and FALSE otherwise // threadId is set to the ID (Thread::GetThreadId()) of the thread which owns the lock // acquisitionCount is set to the number of times the lock needs to be released before // it is unowned BOOL GetThreadOwningMonitorLock(DWORD *pThreadId, DWORD *pAcquisitionCount) { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return GetHeader()->GetThreadOwningMonitorLock(pThreadId, pAcquisitionCount); } #endif // #ifndef DACCESS_COMPILE BOOL Wait(INT32 timeOut, BOOL exitContext) { WRAPPER_NO_CONTRACT; return GetHeader()->Wait(timeOut, exitContext); } void Pulse() { WRAPPER_NO_CONTRACT; GetHeader()->Pulse(); } void PulseAll() { WRAPPER_NO_CONTRACT; GetHeader()->PulseAll(); } PTR_VOID UnBox(); // if it is a value class, get the pointer to the first field PTR_BYTE GetData(void) { LIMITED_METHOD_CONTRACT; SUPPORTS_DAC; return dac_cast(this) + sizeof(Object); } static UINT GetOffsetOfFirstField() { LIMITED_METHOD_CONTRACT; return sizeof(Object); } DWORD GetOffset32(DWORD dwOffset) { WRAPPER_NO_CONTRACT; return * PTR_DWORD(GetData() + dwOffset); } USHORT GetOffset16(DWORD dwOffset) { WRAPPER_NO_CONTRACT; return * PTR_USHORT(GetData() + dwOffset); } BYTE GetOffset8(DWORD dwOffset) { WRAPPER_NO_CONTRACT; return * PTR_BYTE(GetData() + dwOffset); } __int64 GetOffset64(DWORD dwOffset) { WRAPPER_NO_CONTRACT; return (__int64) * PTR_ULONG64(GetData() + dwOffset); } void *GetPtrOffset(DWORD dwOffset) { WRAPPER_NO_CONTRACT; return (void *)(TADDR)*PTR_TADDR(GetData() + dwOffset); } #ifndef DACCESS_COMPILE void SetOffsetObjectRef(DWORD dwOffset, size_t dwValue); void SetOffsetPtr(DWORD dwOffset, LPVOID value) { WRAPPER_NO_CONTRACT; *(LPVOID *) &GetData()[dwOffset] = value; } void SetOffset32(DWORD dwOffset, DWORD dwValue) { WRAPPER_NO_CONTRACT; *(DWORD *) &GetData()[dwOffset] = dwValue; } void SetOffset16(DWORD dwOffset, DWORD dwValue) { WRAPPER_NO_CONTRACT; *(USHORT *) &GetData()[dwOffset] = (USHORT) dwValue; } void SetOffset8(DWORD dwOffset, DWORD dwValue) { WRAPPER_NO_CONTRACT; *(BYTE *) &GetData()[dwOffset] = (BYTE) dwValue; } void SetOffset64(DWORD dwOffset, __int64 qwValue) { WRAPPER_NO_CONTRACT; *(__int64 *) &GetData()[dwOffset] = qwValue; } #endif // #ifndef DACCESS_COMPILE VOID Validate(BOOL bDeep = TRUE, BOOL bVerifyNextHeader = TRUE, BOOL bVerifySyncBlock = TRUE); PTR_MethodTable GetGCSafeMethodTable() const { LIMITED_METHOD_CONTRACT; SUPPORTS_DAC; // lose GC marking bit and the reserved bit // A method table pointer should always be aligned. During GC we set the least // significant bit for marked objects, and the second to least significant // bit is reserved. So if we want the actual MT pointer during a GC // we must zero out the lowest 2 bits. return dac_cast((dac_cast(m_pMethTab)) & ~((UINT_PTR)3)); } // There are some cases where it is unsafe to get the type handle during a GC. // This occurs when the type has already been unloaded as part of an in-progress appdomain shutdown. TypeHandle GetGCSafeTypeHandleIfPossible() const; inline TypeHandle GetGCSafeTypeHandle() const; #ifdef DACCESS_COMPILE void EnumMemoryRegions(void); #endif private: VOID ValidateInner(BOOL bDeep, BOOL bVerifyNextHeader, BOOL bVerifySyncBlock); #ifdef _DEBUG void AssertNotArray() { if (m_pMethTab->IsArray()) { _ASSERTE(!"ArrayBase::SetArrayMethodTable/ArrayBase::SetArrayMethodTableForLargeObject should be used for arrays"); } } #endif // _DEBUG }; /* * Object ref setting routines. You must use these to do * proper write barrier support. */ // SetObjectReference sets an OBJECTREF field void SetObjectReferenceUnchecked(OBJECTREF *dst,OBJECTREF ref); #ifdef _DEBUG void EnableStressHeapHelper(); #endif //Used to clear the object reference inline void ClearObjectReference(OBJECTREF* dst) { LIMITED_METHOD_CONTRACT; *(void**)(dst) = NULL; } // CopyValueClass sets a value class field void STDCALL CopyValueClassUnchecked(void* dest, void* src, MethodTable *pMT); void STDCALL CopyValueClassArgUnchecked(ArgDestination *argDest, void* src, MethodTable *pMT, int destOffset); inline void InitValueClass(void *dest, MethodTable *pMT) { WRAPPER_NO_CONTRACT; ZeroMemoryInGCHeap(dest, pMT->GetNumInstanceFieldBytes()); } // Initialize value class argument void InitValueClassArg(ArgDestination *argDest, MethodTable *pMT); #define SetObjectReference(_d,_r) SetObjectReferenceUnchecked(_d, _r) #define CopyValueClass(_d,_s,_m) CopyValueClassUnchecked(_d,_s,_m) #define CopyValueClassArg(_d,_s,_m,_o) CopyValueClassArgUnchecked(_d,_s,_m,_o) #include // There are two basic kinds of array layouts in COM+ // ELEMENT_TYPE_ARRAY - a multidimensional array with lower bounds on the dims // ELMENNT_TYPE_SZARRAY - A zero based single dimensional array // // In addition the layout of an array in memory is also affected by // whether the method table is shared (eg in the case of arrays of object refs) // or not. In the shared case, the array has to hold the type handle of // the element type. // // ArrayBase encapuslates all of these details. In theory you should never // have to peek inside this abstraction // class ArrayBase : public Object { friend class GCHeap; friend class CObjectHeader; friend class Object; friend OBJECTREF AllocateSzArray(MethodTable *pArrayMT, INT32 length, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap); friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, GC_ALLOC_FLAGS flags, BOOL bAllocateInLargeHeap); friend FCDECL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size); friend FCDECL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size); friend class JIT_TrialAlloc; friend class CheckAsmOffsets; friend struct _DacGlobals; private: // This MUST be the first field, so that it directly follows Object. This is because // Object::GetSize() looks at m_NumComponents even though it may not be an array (the // values is shifted out if not an array, so it's ok). DWORD m_NumComponents; #ifdef _TARGET_64BIT_ DWORD pad; #endif // _TARGET_64BIT_ SVAL_DECL(INT32, s_arrayBoundsZero); // = 0 // What comes after this conceputally is: // TypeHandle elementType; Only present if the method table is shared among many types (arrays of pointers) // INT32 bounds[rank]; The bounds are only present for Multidimensional arrays // INT32 lowerBounds[rank]; Valid indexes are lowerBounds[i] <= index[i] < lowerBounds[i] + bounds[i] public: // Gets the unique type handle for this array object. // This will call the loader in don't-load mode - the allocator // always makes sure that the particular ArrayTypeDesc for this array // type is available before allocating any instances of this array type. inline TypeHandle GetTypeHandle() const; inline static TypeHandle GetTypeHandle(MethodTable * pMT); // Get the element type for the array, this works whether the the element // type is stored in the array or not inline TypeHandle GetArrayElementTypeHandle() const; // Get the CorElementType for the elements in the array. Avoids creating a TypeHandle inline CorElementType GetArrayElementType() const; inline unsigned GetRank() const; // Total element count for the array inline DWORD GetNumComponents() const; #ifndef DACCESS_COMPILE inline void SetArrayMethodTable(MethodTable *pArrayMT); inline void SetArrayMethodTableForLargeObject(MethodTable *pArrayMT); #endif // !DACCESS_COMPILE // Get pointer to elements, handles any number of dimensions PTR_BYTE GetDataPtr(BOOL inGC = FALSE) const { LIMITED_METHOD_CONTRACT; SUPPORTS_DAC; #ifdef _DEBUG #ifndef DACCESS_COMPILE EnableStressHeapHelper(); #endif #endif return dac_cast(this) + GetDataPtrOffset(inGC ? GetGCSafeMethodTable() : GetMethodTable()); } // The component size is actually 16-bit WORD, but this method is returning SIZE_T to ensure // that SIZE_T is used everywhere for object size computation. It is necessary to support // objects bigger than 2GB. SIZE_T GetComponentSize() const { WRAPPER_NO_CONTRACT; MethodTable * pMT; pMT = GetMethodTable(); _ASSERTE(pMT->HasComponentSize()); return pMT->RawGetComponentSize(); } // Note that this can be a multidimensional array of rank 1 // (for example if we had a 1-D array with lower bounds BOOL IsMultiDimArray() const { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return(GetMethodTable()->IsMultiDimArray()); } // Get pointer to the begining of the bounds (counts for each dim) // Works for any array type PTR_INT32 GetBoundsPtr() const { WRAPPER_NO_CONTRACT; MethodTable * pMT = GetMethodTable(); if (pMT->IsMultiDimArray()) { return dac_cast( dac_cast(this) + sizeof(*this)); } else { return dac_cast(PTR_HOST_MEMBER_TADDR(ArrayBase, this, m_NumComponents)); } } // Works for any array type PTR_INT32 GetLowerBoundsPtr() const { WRAPPER_NO_CONTRACT; if (IsMultiDimArray()) { // Lower bounds info is after total bounds info // and total bounds info has rank elements return GetBoundsPtr() + GetRank(); } else return dac_cast(GVAL_ADDR(s_arrayBoundsZero)); } static unsigned GetOffsetOfNumComponents() { LIMITED_METHOD_CONTRACT; return offsetof(ArrayBase, m_NumComponents); } inline static unsigned GetDataPtrOffset(MethodTable* pMT); inline static unsigned GetBoundsOffset(MethodTable* pMT); inline static unsigned GetLowerBoundsOffset(MethodTable* pMT); private: #ifndef DACCESS_COMPILE #ifdef _DEBUG void AssertArrayTypeDescLoaded(); #endif // _DEBUG #endif // !DACCESS_COMPILE }; // // Template used to build all the non-object // arrays of a single dimension // template < class KIND > class Array : public ArrayBase { public: typedef DPTR(KIND) PTR_KIND; typedef DPTR(const KIND) PTR_CKIND; KIND m_Array[1]; PTR_KIND GetDirectPointerToNonObjectElements() { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; // return m_Array; return PTR_KIND(GetDataPtr()); // This also handles arrays of dim 1 with lower bounds present } PTR_CKIND GetDirectConstPointerToNonObjectElements() const { WRAPPER_NO_CONTRACT; // return m_Array; return PTR_CKIND(GetDataPtr()); // This also handles arrays of dim 1 with lower bounds present } }; // Warning: Use PtrArray only for single dimensional arrays, not multidim arrays. class PtrArray : public ArrayBase { friend class GCHeap; friend class ClrDataAccess; friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, DWORD flags, BOOL bAllocateInLargeHeap); friend class JIT_TrialAlloc; friend class CheckAsmOffsets; public: TypeHandle GetArrayElementTypeHandle() { LIMITED_METHOD_CONTRACT; return GetMethodTable()->GetApproxArrayElementTypeHandle(); } PTR_OBJECTREF GetDataPtr() { LIMITED_METHOD_CONTRACT; SUPPORTS_DAC; return dac_cast(dac_cast(this) + GetDataOffset()); } static SIZE_T GetDataOffset() { LIMITED_METHOD_CONTRACT; return offsetof(PtrArray, m_Array); } void SetAt(SIZE_T i, OBJECTREF ref) { CONTRACTL { NOTHROW; GC_NOTRIGGER; MODE_COOPERATIVE; } CONTRACTL_END; _ASSERTE(i < GetNumComponents()); SetObjectReference(m_Array + i, ref); } void ClearAt(SIZE_T i) { WRAPPER_NO_CONTRACT; _ASSERTE(i < GetNumComponents()); ClearObjectReference(m_Array + i); } OBJECTREF GetAt(SIZE_T i) { LIMITED_METHOD_CONTRACT; SUPPORTS_DAC; _ASSERTE(i < GetNumComponents()); // DAC doesn't know the true size of this array // the compiler thinks it is size 1, but really it is size N hanging off the structure #ifndef DACCESS_COMPILE return m_Array[i]; #else TADDR arrayTargetAddress = dac_cast(this) + offsetof(PtrArray, m_Array); __ArrayDPtr targetArray = dac_cast< __ArrayDPtr >(arrayTargetAddress); return targetArray[i]; #endif } friend class StubLinkerCPU; #ifdef FEATURE_ARRAYSTUB_AS_IL friend class ArrayOpLinker; #endif public: OBJECTREF m_Array[1]; }; #define OFFSETOF__PtrArray__m_Array_ ARRAYBASE_SIZE /* a TypedByRef is a structure that is used to implement VB's BYREF variants. it is basically a tuple of an address of some data along with a TypeHandle that indicates the type of the address */ class TypedByRef { public: PTR_VOID data; TypeHandle type; }; typedef DPTR(TypedByRef) PTR_TypedByRef; typedef Array I1Array; typedef Array I2Array; typedef Array I4Array; typedef Array I8Array; typedef Array R4Array; typedef Array R8Array; typedef Array U1Array; typedef Array BOOLArray; typedef Array U2Array; typedef Array CHARArray; typedef Array U4Array; typedef Array U8Array; typedef Array UPTRArray; typedef PtrArray PTRArray; typedef DPTR(I1Array) PTR_I1Array; typedef DPTR(I2Array) PTR_I2Array; typedef DPTR(I4Array) PTR_I4Array; typedef DPTR(I8Array) PTR_I8Array; typedef DPTR(R4Array) PTR_R4Array; typedef DPTR(R8Array) PTR_R8Array; typedef DPTR(U1Array) PTR_U1Array; typedef DPTR(BOOLArray) PTR_BOOLArray; typedef DPTR(U2Array) PTR_U2Array; typedef DPTR(CHARArray) PTR_CHARArray; typedef DPTR(U4Array) PTR_U4Array; typedef DPTR(U8Array) PTR_U8Array; typedef DPTR(UPTRArray) PTR_UPTRArray; typedef DPTR(PTRArray) PTR_PTRArray; class StringObject; #ifdef FEATURE_UTF8STRING class Utf8StringObject; #endif // FEATURE_UTF8STRING #ifdef USE_CHECKED_OBJECTREFS typedef REF BASEARRAYREF; typedef REF I1ARRAYREF; typedef REF I2ARRAYREF; typedef REF I4ARRAYREF; typedef REF I8ARRAYREF; typedef REF R4ARRAYREF; typedef REF R8ARRAYREF; typedef REF U1ARRAYREF; typedef REF BOOLARRAYREF; typedef REF U2ARRAYREF; typedef REF U4ARRAYREF; typedef REF U8ARRAYREF; typedef REF UPTRARRAYREF; typedef REF CHARARRAYREF; typedef REF PTRARRAYREF; // Warning: Use PtrArray only for single dimensional arrays, not multidim arrays. typedef REF STRINGREF; #ifdef FEATURE_UTF8STRING typedef REF UTF8STRINGREF; #endif // FEATURE_UTF8STRING #else // USE_CHECKED_OBJECTREFS typedef PTR_ArrayBase BASEARRAYREF; typedef PTR_I1Array I1ARRAYREF; typedef PTR_I2Array I2ARRAYREF; typedef PTR_I4Array I4ARRAYREF; typedef PTR_I8Array I8ARRAYREF; typedef PTR_R4Array R4ARRAYREF; typedef PTR_R8Array R8ARRAYREF; typedef PTR_U1Array U1ARRAYREF; typedef PTR_BOOLArray BOOLARRAYREF; typedef PTR_U2Array U2ARRAYREF; typedef PTR_U4Array U4ARRAYREF; typedef PTR_U8Array U8ARRAYREF; typedef PTR_UPTRArray UPTRARRAYREF; typedef PTR_CHARArray CHARARRAYREF; typedef PTR_PTRArray PTRARRAYREF; // Warning: Use PtrArray only for single dimensional arrays, not multidim arrays. typedef PTR_StringObject STRINGREF; #ifdef FEATURE_UTF8STRING typedef PTR_Utf8StringObject UTF8STRINGREF; #endif // FEATURE_UTF8STRING #endif // USE_CHECKED_OBJECTREFS #include /* * StringObject * * Special String implementation for performance. * * m_StringLength - Length of string in number of WCHARs * m_FirstChar - The string buffer * */ /** * The high bit state can be one of three value: * STRING_STATE_HIGH_CHARS: We've examined the string and determined that it definitely has values greater than 0x80 * STRING_STATE_FAST_OPS: We've examined the string and determined that it definitely has no chars greater than 0x80 * STRING_STATE_UNDETERMINED: We've never examined this string. * We've also reserved another bit for future use. */ #define STRING_STATE_UNDETERMINED 0x00000000 #define STRING_STATE_HIGH_CHARS 0x40000000 #define STRING_STATE_FAST_OPS 0x80000000 #define STRING_STATE_SPECIAL_SORT 0xC0000000 class StringObject : public Object { #ifdef DACCESS_COMPILE friend class ClrDataAccess; #endif friend class GCHeap; friend class JIT_TrialAlloc; friend class CheckAsmOffsets; friend class COMString; private: DWORD m_StringLength; WCHAR m_FirstChar; public: VOID SetStringLength(DWORD len) { LIMITED_METHOD_CONTRACT; _ASSERTE(len >= 0); m_StringLength = len; } protected: StringObject() {LIMITED_METHOD_CONTRACT; } ~StringObject() {LIMITED_METHOD_CONTRACT; } public: static DWORD GetBaseSize(); static SIZE_T GetSize(DWORD stringLength); DWORD GetStringLength() { LIMITED_METHOD_DAC_CONTRACT; return( m_StringLength );} WCHAR* GetBuffer() { LIMITED_METHOD_CONTRACT; _ASSERTE(this != nullptr); return (WCHAR*)( dac_cast(this) + offsetof(StringObject, m_FirstChar) ); } DWORD GetHighCharState() { WRAPPER_NO_CONTRACT; DWORD ret = GetHeader()->GetBits() & (BIT_SBLK_STRING_HIGH_CHAR_MASK); return ret; } VOID SetHighCharState(DWORD value) { WRAPPER_NO_CONTRACT; _ASSERTE(value==STRING_STATE_HIGH_CHARS || value==STRING_STATE_FAST_OPS || value==STRING_STATE_UNDETERMINED || value==STRING_STATE_SPECIAL_SORT); // you need to clear the present state before going to a new state, but we'll allow multiple threads to set it to the same thing. _ASSERTE((GetHighCharState() == STRING_STATE_UNDETERMINED) || (GetHighCharState()==value)); static_assert_no_msg(BIT_SBLK_STRING_HAS_NO_HIGH_CHARS == STRING_STATE_FAST_OPS && STRING_STATE_HIGH_CHARS == BIT_SBLK_STRING_HIGH_CHARS_KNOWN && STRING_STATE_SPECIAL_SORT == BIT_SBLK_STRING_HAS_SPECIAL_SORT); GetHeader()->SetBit(value); } static UINT GetBufferOffset() { LIMITED_METHOD_DAC_CONTRACT; return (UINT)(offsetof(StringObject, m_FirstChar)); } static UINT GetStringLengthOffset() { LIMITED_METHOD_CONTRACT; return (UINT)(offsetof(StringObject, m_StringLength)); } VOID GetSString(SString &result) { WRAPPER_NO_CONTRACT; result.Set(GetBuffer(), GetStringLength()); } //======================================================================== // Creates a System.String object. All the functions that take a length // or a count of bytes will add the null terminator after length // characters. So this means that if you have a string that has 5 // characters and the null terminator you should pass in 5 and NOT 6. //======================================================================== static STRINGREF NewString(int length); static STRINGREF NewString(int length, BOOL bHasTrailByte); static STRINGREF NewString(const WCHAR *pwsz); static STRINGREF NewString(const WCHAR *pwsz, int length); static STRINGREF NewString(LPCUTF8 psz); static STRINGREF NewString(LPCUTF8 psz, int cBytes); static STRINGREF GetEmptyString(); static STRINGREF* GetEmptyStringRefPtr(); static STRINGREF* InitEmptyStringRefPtr(); DWORD InternalCheckHighChars(); BOOL HasTrailByte(); BOOL GetTrailByte(BYTE *bTrailByte); BOOL SetTrailByte(BYTE bTrailByte); static BOOL CaseInsensitiveCompHelper(__in_ecount(aLength) WCHAR * strA, __in_z INT8 * strB, int aLength, int bLength, int *result); #ifdef VERIFY_HEAP //has to use raw object to avoid recursive validation BOOL ValidateHighChars (); #endif //VERIFY_HEAP /*=================RefInterpretGetStringValuesDangerousForGC====================== **N.B.: This perfoms no range checking and relies on the caller to have done this. **Args: (IN)ref -- the String to be interpretted. ** (OUT)chars -- a pointer to the characters in the buffer. ** (OUT)length -- a pointer to the length of the buffer. **Returns: void. **Exceptions: None. ==============================================================================*/ // !!!! If you use this function, you have to be careful because chars is a pointer // !!!! to the data buffer of ref. If GC happens after this call, you need to make // !!!! sure that you have a pin handle on ref, or use GCPROTECT_BEGINPINNING on ref. void RefInterpretGetStringValuesDangerousForGC(__deref_out_ecount(*length + 1) WCHAR **chars, int *length) { WRAPPER_NO_CONTRACT; _ASSERTE(GetGCSafeMethodTable() == g_pStringClass); *length = GetStringLength(); *chars = GetBuffer(); #ifdef _DEBUG EnableStressHeapHelper(); #endif } private: static STRINGREF* EmptyStringRefPtr; }; //The first two macros are essentially the same. I just define both because //having both can make the code more readable. #define IS_FAST_SORT(state) (((state) == STRING_STATE_FAST_OPS)) #define IS_SLOW_SORT(state) (((state) != STRING_STATE_FAST_OPS)) //This macro should be used to determine things like indexing, casing, and encoding. #define IS_FAST_OPS_EXCEPT_SORT(state) (((state)==STRING_STATE_SPECIAL_SORT) || ((state)==STRING_STATE_FAST_OPS)) #define IS_ASCII(state) (((state)==STRING_STATE_SPECIAL_SORT) || ((state)==STRING_STATE_FAST_OPS)) #define IS_FAST_CASING(state) IS_ASCII(state) #define IS_FAST_INDEX(state) IS_ASCII(state) #define IS_STRING_STATE_UNDETERMINED(state) ((state)==STRING_STATE_UNDETERMINED) #define HAS_HIGH_CHARS(state) ((state)==STRING_STATE_HIGH_CHARS) /*================================GetEmptyString================================ **Get a reference to the empty string. If we haven't already gotten one, we **query the String class for a pointer to the empty string that we know was **created at startup. ** **Args: None **Returns: A STRINGREF to the EmptyString **Exceptions: None ==============================================================================*/ inline STRINGREF StringObject::GetEmptyString() { CONTRACTL { THROWS; MODE_COOPERATIVE; GC_TRIGGERS; } CONTRACTL_END; STRINGREF* refptr = EmptyStringRefPtr; //If we've never gotten a reference to the EmptyString, we need to go get one. if (refptr==NULL) { refptr = InitEmptyStringRefPtr(); } //We've already have a reference to the EmptyString, so we can just return it. return *refptr; } inline STRINGREF* StringObject::GetEmptyStringRefPtr() { CONTRACTL { THROWS; MODE_ANY; GC_TRIGGERS; } CONTRACTL_END; STRINGREF* refptr = EmptyStringRefPtr; //If we've never gotten a reference to the EmptyString, we need to go get one. if (refptr==NULL) { refptr = InitEmptyStringRefPtr(); } //We've already have a reference to the EmptyString, so we can just return it. return refptr; } // This is used to account for the remoting cache on RuntimeType, // RuntimeMethodInfo, and RtFieldInfo. class BaseObjectWithCachedData : public Object { }; // This is the Class version of the Reflection object. // A Class has adddition information. // For a ReflectClassBaseObject the m_pData is a pointer to a FieldDesc array that // contains all of the final static primitives if its defined. // m_cnt = the number of elements defined in the m_pData FieldDesc array. -1 means // this hasn't yet been defined. class ReflectClassBaseObject : public BaseObjectWithCachedData { friend class MscorlibBinder; protected: OBJECTREF m_keepalive; OBJECTREF m_cache; TypeHandle m_typeHandle; #ifdef _DEBUG void TypeCheck() { CONTRACTL { NOTHROW; MODE_COOPERATIVE; GC_NOTRIGGER; } CONTRACTL_END; MethodTable *pMT = GetMethodTable(); while (pMT != g_pRuntimeTypeClass && pMT != NULL) { pMT = pMT->GetParentMethodTable(); } _ASSERTE(pMT == g_pRuntimeTypeClass); } #endif // _DEBUG public: void SetType(TypeHandle type) { CONTRACTL { NOTHROW; MODE_COOPERATIVE; GC_NOTRIGGER; } CONTRACTL_END; INDEBUG(TypeCheck()); m_typeHandle = type; } void SetKeepAlive(OBJECTREF keepalive) { CONTRACTL { NOTHROW; MODE_COOPERATIVE; GC_NOTRIGGER; } CONTRACTL_END; INDEBUG(TypeCheck()); SetObjectReference(&m_keepalive, keepalive); } TypeHandle GetType() { CONTRACTL { NOTHROW; MODE_COOPERATIVE; GC_NOTRIGGER; } CONTRACTL_END; INDEBUG(TypeCheck()); return m_typeHandle; } }; #ifdef FEATURE_UTF8STRING class Utf8StringObject : public Object { #ifdef DACCESS_COMPILE friend class ClrDataAccess; #endif private: DWORD m_StringLength; BYTE m_FirstChar; public: VOID SetLength(DWORD len) { LIMITED_METHOD_CONTRACT; _ASSERTE(len >= 0); m_StringLength = len; } protected: Utf8StringObject() { LIMITED_METHOD_CONTRACT; } ~Utf8StringObject() { LIMITED_METHOD_CONTRACT; } public: /*=================RefInterpretGetStringValuesDangerousForGC====================== **N.B.: This perfoms no range checking and relies on the caller to have done this. **Args: (IN)ref -- the Utf8String to be interpretted. ** (OUT)chars -- a pointer to the characters in the buffer. ** (OUT)length -- a pointer to the length of the buffer. **Returns: void. **Exceptions: None. ==============================================================================*/ // !!!! If you use this function, you have to be careful because chars is a pointer // !!!! to the data buffer of ref. If GC happens after this call, you need to make // !!!! sure that you have a pin handle on ref, or use GCPROTECT_BEGINPINNING on ref. void RefInterpretGetStringValuesDangerousForGC(__deref_out_ecount(*length + 1) CHAR **chars, int *length) { WRAPPER_NO_CONTRACT; _ASSERTE(GetGCSafeMethodTable() == g_pUtf8StringClass); *length = GetStringLength(); *chars = GetBuffer(); #ifdef _DEBUG EnableStressHeapHelper(); #endif } DWORD GetStringLength() { LIMITED_METHOD_DAC_CONTRACT; return( m_StringLength );} CHAR* GetBuffer() { LIMITED_METHOD_CONTRACT; _ASSERTE(this != nullptr); return (CHAR*)( dac_cast(this) + offsetof(Utf8StringObject, m_FirstChar) ); } static DWORD GetBaseSize(); static SIZE_T GetSize(DWORD stringLength); }; #endif // FEATURE_UTF8STRING // This is the Method version of the Reflection object. // A Method has adddition information. // m_pMD - A pointer to the actual MethodDesc of the method. // m_object - a field that has a reference type in it. Used only for RuntimeMethodInfoStub to keep the real type alive. // This structure matches the structure up to the m_pMD for several different managed types. // (RuntimeConstructorInfo, RuntimeMethodInfo, and RuntimeMethodInfoStub). These types are unrelated in the type // system except that they all implement a particular interface. It is important that that interface is not attached to any // type that does not sufficiently match this data structure. class ReflectMethodObject : public BaseObjectWithCachedData { friend class MscorlibBinder; protected: OBJECTREF m_object; OBJECTREF m_empty1; OBJECTREF m_empty2; OBJECTREF m_empty3; OBJECTREF m_empty4; OBJECTREF m_empty5; OBJECTREF m_empty6; OBJECTREF m_empty7; MethodDesc * m_pMD; public: void SetMethod(MethodDesc *pMethod) { LIMITED_METHOD_CONTRACT; m_pMD = pMethod; } // This must only be called on instances of ReflectMethodObject that are actually RuntimeMethodInfoStub void SetKeepAlive(OBJECTREF keepalive) { WRAPPER_NO_CONTRACT; SetObjectReference(&m_object, keepalive); } MethodDesc *GetMethod() { LIMITED_METHOD_CONTRACT; return m_pMD; } }; // This is the Field version of the Reflection object. // A Method has adddition information. // m_pFD - A pointer to the actual MethodDesc of the method. // m_object - a field that has a reference type in it. Used only for RuntimeFieldInfoStub to keep the real type alive. // This structure matches the structure up to the m_pFD for several different managed types. // (RtFieldInfo and RuntimeFieldInfoStub). These types are unrelated in the type // system except that they all implement a particular interface. It is important that that interface is not attached to any // type that does not sufficiently match this data structure. class ReflectFieldObject : public BaseObjectWithCachedData { friend class MscorlibBinder; protected: OBJECTREF m_object; OBJECTREF m_empty1; INT32 m_empty2; OBJECTREF m_empty3; OBJECTREF m_empty4; FieldDesc * m_pFD; public: void SetField(FieldDesc *pField) { LIMITED_METHOD_CONTRACT; m_pFD = pField; } // This must only be called on instances of ReflectFieldObject that are actually RuntimeFieldInfoStub void SetKeepAlive(OBJECTREF keepalive) { WRAPPER_NO_CONTRACT; SetObjectReference(&m_object, keepalive); } FieldDesc *GetField() { LIMITED_METHOD_CONTRACT; return m_pFD; } }; // ReflectModuleBaseObject // This class is the base class for managed Module. // This class will connect the Object back to the underlying VM representation // m_ReflectClass -- This is the real Class that was used for reflection // This class was used to get at this object // m_pData -- this is a generic pointer which usually points CorModule // class ReflectModuleBaseObject : public Object { friend class MscorlibBinder; protected: // READ ME: // Modifying the order or fields of this object may require other changes to the // classlib class definition of this object. OBJECTREF m_runtimeType; OBJECTREF m_runtimeAssembly; void* m_ReflectClass; // Pointer to the ReflectClass structure Module* m_pData; // Pointer to the Module void* m_pGlobals; // Global values.... void* m_pGlobalsFlds; // Global Fields.... protected: ReflectModuleBaseObject() {LIMITED_METHOD_CONTRACT;} ~ReflectModuleBaseObject() {LIMITED_METHOD_CONTRACT;} public: void SetModule(Module* p) { LIMITED_METHOD_CONTRACT; m_pData = p; } Module* GetModule() { LIMITED_METHOD_CONTRACT; return m_pData; } void SetAssembly(OBJECTREF assembly) { WRAPPER_NO_CONTRACT; SetObjectReference(&m_runtimeAssembly, assembly); } }; NOINLINE ReflectModuleBaseObject* GetRuntimeModuleHelper(LPVOID __me, Module *pModule, OBJECTREF keepAlive); #define FC_RETURN_MODULE_OBJECT(pModule, refKeepAlive) FC_INNER_RETURN(ReflectModuleBaseObject*, GetRuntimeModuleHelper(__me, pModule, refKeepAlive)) class SafeHandle; #ifdef USE_CHECKED_OBJECTREFS typedef REF SAFEHANDLE; typedef REF SAFEHANDLEREF; #else // USE_CHECKED_OBJECTREFS typedef SafeHandle * SAFEHANDLE; typedef SafeHandle * SAFEHANDLEREF; #endif // USE_CHECKED_OBJECTREFS class ThreadBaseObject; class SynchronizationContextObject: public Object { friend class MscorlibBinder; private: // These field are also defined in the managed representation. (SecurityContext.cs)If you // add or change these field you must also change the managed code so that // it matches these. This is necessary so that the object is the proper // size. CLR_BOOL _requireWaitNotification; public: BOOL IsWaitNotificationRequired() const { LIMITED_METHOD_CONTRACT; return _requireWaitNotification; } }; typedef DPTR(class CultureInfoBaseObject) PTR_CultureInfoBaseObject; #ifdef USE_CHECKED_OBJECTREFS typedef REF SYNCHRONIZATIONCONTEXTREF; typedef REF EXECUTIONCONTEXTREF; typedef REF CULTUREINFOBASEREF; typedef REF ARRAYBASEREF; #else typedef SynchronizationContextObject* SYNCHRONIZATIONCONTEXTREF; typedef CultureInfoBaseObject* CULTUREINFOBASEREF; typedef PTR_ArrayBase ARRAYBASEREF; #endif // Note that the name must always be "" or "en-US". Other cases and nulls // aren't allowed (we already checked.) __inline bool IsCultureEnglishOrInvariant(LPCWSTR localeName) { LIMITED_METHOD_CONTRACT; if (localeName != NULL && (localeName[0] == W('\0') || wcscmp(localeName, W("en-US")) == 0)) { return true; } return false; } class CultureInfoBaseObject : public Object { friend class MscorlibBinder; private: OBJECTREF _compareInfo; OBJECTREF _textInfo; OBJECTREF _numInfo; OBJECTREF _dateTimeInfo; OBJECTREF _calendar; OBJECTREF _cultureData; OBJECTREF _consoleFallbackCulture; STRINGREF _name; // "real" name - en-US, de-DE_phoneb or fj-FJ STRINGREF _nonSortName; // name w/o sort info (de-DE for de-DE_phoneb) STRINGREF _sortName; // Sort only name (de-DE_phoneb, en-us for fj-fj (w/us sort) CULTUREINFOBASEREF _parent; CLR_BOOL _isReadOnly; CLR_BOOL _isInherited; public: CULTUREINFOBASEREF GetParent() { LIMITED_METHOD_CONTRACT; return _parent; }// GetParent STRINGREF GetName() { LIMITED_METHOD_CONTRACT; return _name; }// GetName }; // class CultureInfoBaseObject typedef DPTR(class ThreadBaseObject) PTR_ThreadBaseObject; class ThreadBaseObject : public Object { friend class ClrDataAccess; friend class ThreadNative; friend class MscorlibBinder; friend class Object; private: // These field are also defined in the managed representation. If you // add or change these field you must also change the managed code so that // it matches these. This is necessary so that the object is the proper // size. The order here must match that order which the loader will choose // when laying out the managed class. Note that the layouts are checked // at run time, not compile time. OBJECTREF m_ExecutionContext; OBJECTREF m_SynchronizationContext; STRINGREF m_Name; OBJECTREF m_Delegate; OBJECTREF m_ThreadStartArg; // The next field (m_InternalThread) is declared as IntPtr in the managed // definition of Thread. The loader will sort it next. // m_InternalThread is always valid -- unless the thread has finalized and been // resurrected. (The thread stopped running before it was finalized). Thread *m_InternalThread; INT32 m_Priority; //We need to cache the thread id in managed code for perf reasons. INT32 m_ManagedThreadId; protected: // the ctor and dtor can do no useful work. ThreadBaseObject() {LIMITED_METHOD_CONTRACT;}; ~ThreadBaseObject() {LIMITED_METHOD_CONTRACT;}; public: Thread *GetInternal() { LIMITED_METHOD_CONTRACT; return m_InternalThread; } void SetInternal(Thread *it); void ClearInternal(); INT32 GetManagedThreadId() { LIMITED_METHOD_CONTRACT; return m_ManagedThreadId; } void SetManagedThreadId(INT32 id) { LIMITED_METHOD_CONTRACT; m_ManagedThreadId = id; } OBJECTREF GetThreadStartArg() { LIMITED_METHOD_CONTRACT; return m_ThreadStartArg; } void SetThreadStartArg(OBJECTREF newThreadStartArg) { WRAPPER_NO_CONTRACT; _ASSERTE(newThreadStartArg == NULL); // Note: this is an unchecked assignment. We are cleaning out the ThreadStartArg field when // a thread starts so that ADU does not cause problems SetObjectReference( (OBJECTREF *)&m_ThreadStartArg, newThreadStartArg); } STRINGREF GetName() { LIMITED_METHOD_CONTRACT; return m_Name; } OBJECTREF GetDelegate() { LIMITED_METHOD_CONTRACT; return m_Delegate; } void SetDelegate(OBJECTREF delegate); OBJECTREF GetSynchronizationContext() { LIMITED_METHOD_CONTRACT; return m_SynchronizationContext; } // SetDelegate is our "constructor" for the pathway where the exposed object is // created first. InitExisting is our "constructor" for the pathway where an // existing physical thread is later exposed. void InitExisting(); void ResetName() { LIMITED_METHOD_CONTRACT; m_Name = NULL; } void SetPriority(INT32 priority) { LIMITED_METHOD_CONTRACT; m_Priority = priority; } INT32 GetPriority() const { LIMITED_METHOD_CONTRACT; return m_Priority; } }; // MarshalByRefObjectBaseObject // This class is the base class for MarshalByRefObject // class MarshalByRefObjectBaseObject : public Object { }; // AssemblyBaseObject // This class is the base class for assemblies // class AssemblyBaseObject : public Object { friend class Assembly; friend class MscorlibBinder; protected: // READ ME: // Modifying the order or fields of this object may require other changes to the // classlib class definition of this object. OBJECTREF m_pModuleEventHandler; // Delegate for 'resolve module' event STRINGREF m_fullname; // Slot for storing assemblies fullname OBJECTREF m_pSyncRoot; // Pointer to loader allocator to keep collectible types alive, and to serve as the syncroot for assembly building in ref.emit DomainAssembly* m_pAssembly; // Pointer to the Assembly Structure protected: AssemblyBaseObject() { LIMITED_METHOD_CONTRACT; } ~AssemblyBaseObject() { LIMITED_METHOD_CONTRACT; } public: void SetAssembly(DomainAssembly* p) { LIMITED_METHOD_CONTRACT; m_pAssembly = p; } DomainAssembly* GetDomainAssembly() { LIMITED_METHOD_CONTRACT; return m_pAssembly; } Assembly* GetAssembly(); void SetSyncRoot(OBJECTREF pSyncRoot) { WRAPPER_NO_CONTRACT; SetObjectReference(&m_pSyncRoot, pSyncRoot); } }; NOINLINE AssemblyBaseObject* GetRuntimeAssemblyHelper(LPVOID __me, DomainAssembly *pAssembly, OBJECTREF keepAlive); #define FC_RETURN_ASSEMBLY_OBJECT(pAssembly, refKeepAlive) FC_INNER_RETURN(AssemblyBaseObject*, GetRuntimeAssemblyHelper(__me, pAssembly, refKeepAlive)) // AssemblyLoadContextBaseObject // This class is the base class for AssemblyLoadContext // #if defined(_TARGET_X86_) && !defined(FEATURE_PAL) #include "pshpack4.h" #endif // defined(_TARGET_X86_) && !defined(FEATURE_PAL) class AssemblyLoadContextBaseObject : public Object { friend class MscorlibBinder; protected: // READ ME: // Modifying the order or fields of this object may require other changes to the // classlib class definition of this object. #ifdef _TARGET_64BIT_ OBJECTREF _unloadLock; OBJECTREF _resovlingUnmanagedDll; OBJECTREF _resolving; OBJECTREF _unloading; OBJECTREF _name; INT_PTR _nativeAssemblyLoadContext; int64_t _id; // On 64-bit platforms this is a value type so it is placed after references and pointers DWORD _state; CLR_BOOL _isCollectible; #else // _TARGET_64BIT_ int64_t _id; // On 32-bit platforms this 64-bit value type is larger than a pointer so JIT places it first OBJECTREF _unloadLock; OBJECTREF _resovlingUnmanagedDll; OBJECTREF _resolving; OBJECTREF _unloading; OBJECTREF _name; INT_PTR _nativeAssemblyLoadContext; DWORD _state; CLR_BOOL _isCollectible; #endif // _TARGET_64BIT_ protected: AssemblyLoadContextBaseObject() { LIMITED_METHOD_CONTRACT; } ~AssemblyLoadContextBaseObject() { LIMITED_METHOD_CONTRACT; } public: INT_PTR GetNativeAssemblyLoadContext() { LIMITED_METHOD_CONTRACT; return _nativeAssemblyLoadContext; } }; #if defined(_TARGET_X86_) && !defined(FEATURE_PAL) #include "poppack.h" #endif // defined(_TARGET_X86_) && !defined(FEATURE_PAL) // AssemblyNameBaseObject // This class is the base class for assembly names // class AssemblyNameBaseObject : public Object { friend class AssemblyNative; friend class AppDomainNative; friend class MscorlibBinder; protected: // READ ME: // Modifying the order or fields of this object may require other changes to the // classlib class definition of this object. OBJECTREF _name; U1ARRAYREF _publicKey; U1ARRAYREF _publicKeyToken; OBJECTREF _cultureInfo; OBJECTREF _codeBase; OBJECTREF _version; OBJECTREF _strongNameKeyPair; DWORD _hashAlgorithm; DWORD _versionCompatibility; DWORD _flags; protected: AssemblyNameBaseObject() { LIMITED_METHOD_CONTRACT; } ~AssemblyNameBaseObject() { LIMITED_METHOD_CONTRACT; } public: OBJECTREF GetSimpleName() { LIMITED_METHOD_CONTRACT; return _name; } U1ARRAYREF GetPublicKey() { LIMITED_METHOD_CONTRACT; return _publicKey; } U1ARRAYREF GetPublicKeyToken() { LIMITED_METHOD_CONTRACT; return _publicKeyToken; } OBJECTREF GetStrongNameKeyPair() { LIMITED_METHOD_CONTRACT; return _strongNameKeyPair; } OBJECTREF GetCultureInfo() { LIMITED_METHOD_CONTRACT; return _cultureInfo; } OBJECTREF GetAssemblyCodeBase() { LIMITED_METHOD_CONTRACT; return _codeBase; } OBJECTREF GetVersion() { LIMITED_METHOD_CONTRACT; return _version; } DWORD GetAssemblyHashAlgorithm() { LIMITED_METHOD_CONTRACT; return _hashAlgorithm; } DWORD GetFlags() { LIMITED_METHOD_CONTRACT; return _flags; } }; // VersionBaseObject // This class is the base class for versions // class VersionBaseObject : public Object { friend class MscorlibBinder; protected: // READ ME: // Modifying the order or fields of this object may require other changes to the // classlib class definition of this object. int m_Major; int m_Minor; int m_Build; int m_Revision; VersionBaseObject() {LIMITED_METHOD_CONTRACT;} ~VersionBaseObject() {LIMITED_METHOD_CONTRACT;} public: int GetMajor() { LIMITED_METHOD_CONTRACT; return m_Major; } int GetMinor() { LIMITED_METHOD_CONTRACT; return m_Minor; } int GetBuild() { LIMITED_METHOD_CONTRACT; return m_Build; } int GetRevision() { LIMITED_METHOD_CONTRACT; return m_Revision; } }; class WeakReferenceObject : public Object { public: Volatile m_Handle; }; #ifdef USE_CHECKED_OBJECTREFS typedef REF REFLECTMODULEBASEREF; typedef REF REFLECTCLASSBASEREF; typedef REF REFLECTMETHODREF; typedef REF REFLECTFIELDREF; typedef REF THREADBASEREF; typedef REF MARSHALBYREFOBJECTBASEREF; typedef REF ASSEMBLYREF; typedef REF ASSEMBLYLOADCONTEXTREF; typedef REF ASSEMBLYNAMEREF; typedef REF VERSIONREF; typedef REF WEAKREFERENCEREF; inline ARG_SLOT ObjToArgSlot(OBJECTREF objRef) { LIMITED_METHOD_CONTRACT; LPVOID v; v = OBJECTREFToObject(objRef); return (ARG_SLOT)(SIZE_T)v; } inline OBJECTREF ArgSlotToObj(ARG_SLOT i) { LIMITED_METHOD_CONTRACT; LPVOID v; v = (LPVOID)(SIZE_T)i; return ObjectToOBJECTREF ((Object*)v); } inline ARG_SLOT StringToArgSlot(STRINGREF sr) { LIMITED_METHOD_CONTRACT; LPVOID v; v = OBJECTREFToObject(sr); return (ARG_SLOT)(SIZE_T)v; } inline STRINGREF ArgSlotToString(ARG_SLOT s) { LIMITED_METHOD_CONTRACT; LPVOID v; v = (LPVOID)(SIZE_T)s; return ObjectToSTRINGREF ((StringObject*)v); } #else // USE_CHECKED_OBJECTREFS typedef PTR_ReflectModuleBaseObject REFLECTMODULEBASEREF; typedef PTR_ReflectClassBaseObject REFLECTCLASSBASEREF; typedef PTR_ReflectMethodObject REFLECTMETHODREF; typedef PTR_ReflectFieldObject REFLECTFIELDREF; typedef PTR_ThreadBaseObject THREADBASEREF; typedef PTR_AssemblyBaseObject ASSEMBLYREF; typedef PTR_AssemblyLoadContextBaseObject ASSEMBLYLOADCONTEXTREF; typedef PTR_AssemblyNameBaseObject ASSEMBLYNAMEREF; #ifndef DACCESS_COMPILE typedef MarshalByRefObjectBaseObject* MARSHALBYREFOBJECTBASEREF; typedef VersionBaseObject* VERSIONREF; typedef WeakReferenceObject* WEAKREFERENCEREF; #endif // #ifndef DACCESS_COMPILE #define ObjToArgSlot(objref) ((ARG_SLOT)(SIZE_T)(objref)) #define ArgSlotToObj(s) ((OBJECTREF)(SIZE_T)(s)) #define StringToArgSlot(objref) ((ARG_SLOT)(SIZE_T)(objref)) #define ArgSlotToString(s) ((STRINGREF)(SIZE_T)(s)) #endif //USE_CHECKED_OBJECTREFS #define PtrToArgSlot(ptr) ((ARG_SLOT)(SIZE_T)(ptr)) #define ArgSlotToPtr(s) ((LPVOID)(SIZE_T)(s)) #define BoolToArgSlot(b) ((ARG_SLOT)(CLR_BOOL)(!!(b))) #define ArgSlotToBool(s) ((BOOL)(s)) STRINGREF AllocateString(SString sstr); CHARARRAYREF AllocateCharArray(DWORD dwArrayLength); #ifdef FEATURE_COMINTEROP //------------------------------------------------------------- // class ComObject, Exposed class __ComObject // // //------------------------------------------------------------- class ComObject : public MarshalByRefObjectBaseObject { friend class MscorlibBinder; protected: ComObject() {LIMITED_METHOD_CONTRACT;}; // don't instantiate this class directly ~ComObject(){LIMITED_METHOD_CONTRACT;}; public: OBJECTREF m_ObjectToDataMap; //-------------------------------------------------------------------- // SupportsInterface static BOOL SupportsInterface(OBJECTREF oref, MethodTable* pIntfTable); //-------------------------------------------------------------------- // SupportsInterface static void ThrowInvalidCastException(OBJECTREF *pObj, MethodTable* pCastToMT); //----------------------------------------------------------------- // GetComIPFromRCW static IUnknown* GetComIPFromRCW(OBJECTREF *pObj, MethodTable* pIntfTable); //----------------------------------------------------------------- // GetComIPFromRCWThrowing static IUnknown* GetComIPFromRCWThrowing(OBJECTREF *pObj, MethodTable* pIntfTable); //----------------------------------------------------------- // create an empty ComObjectRef static OBJECTREF CreateComObjectRef(MethodTable* pMT); //----------------------------------------------------------- // Release all the data associated with the __ComObject. static void ReleaseAllData(OBJECTREF oref); //----------------------------------------------------------- // Redirection for ToString static FCDECL1(MethodDesc *, GetRedirectedToStringMD, Object *pThisUNSAFE); static FCDECL2(StringObject *, RedirectToString, Object *pThisUNSAFE, MethodDesc *pToStringMD); //----------------------------------------------------------- // Redirection for GetHashCode static FCDECL1(MethodDesc *, GetRedirectedGetHashCodeMD, Object *pThisUNSAFE); static FCDECL2(int, RedirectGetHashCode, Object *pThisUNSAFE, MethodDesc *pGetHashCodeMD); //----------------------------------------------------------- // Redirection for Equals static FCDECL1(MethodDesc *, GetRedirectedEqualsMD, Object *pThisUNSAFE); static FCDECL3(FC_BOOL_RET, RedirectEquals, Object *pThisUNSAFE, Object *pOtherUNSAFE, MethodDesc *pEqualsMD); }; #ifdef USE_CHECKED_OBJECTREFS typedef REF COMOBJECTREF; #else typedef ComObject* COMOBJECTREF; #endif //------------------------------------------------------------- // class UnknownWrapper, Exposed class UnknownWrapper // // //------------------------------------------------------------- class UnknownWrapper : public Object { protected: UnknownWrapper(UnknownWrapper &wrap) {LIMITED_METHOD_CONTRACT}; // dissalow copy construction. UnknownWrapper() {LIMITED_METHOD_CONTRACT;}; // don't instantiate this class directly ~UnknownWrapper() {LIMITED_METHOD_CONTRACT;}; OBJECTREF m_WrappedObject; public: OBJECTREF GetWrappedObject() { LIMITED_METHOD_CONTRACT; return m_WrappedObject; } void SetWrappedObject(OBJECTREF pWrappedObject) { LIMITED_METHOD_CONTRACT; m_WrappedObject = pWrappedObject; } }; #ifdef USE_CHECKED_OBJECTREFS typedef REF UNKNOWNWRAPPEROBJECTREF; #else typedef UnknownWrapper* UNKNOWNWRAPPEROBJECTREF; #endif //------------------------------------------------------------- // class DispatchWrapper, Exposed class DispatchWrapper // // //------------------------------------------------------------- class DispatchWrapper : public Object { protected: DispatchWrapper(DispatchWrapper &wrap) {LIMITED_METHOD_CONTRACT}; // dissalow copy construction. DispatchWrapper() {LIMITED_METHOD_CONTRACT;}; // don't instantiate this class directly ~DispatchWrapper() {LIMITED_METHOD_CONTRACT;}; OBJECTREF m_WrappedObject; public: OBJECTREF GetWrappedObject() { LIMITED_METHOD_CONTRACT; return m_WrappedObject; } void SetWrappedObject(OBJECTREF pWrappedObject) { LIMITED_METHOD_CONTRACT; m_WrappedObject = pWrappedObject; } }; #ifdef USE_CHECKED_OBJECTREFS typedef REF DISPATCHWRAPPEROBJECTREF; #else typedef DispatchWrapper* DISPATCHWRAPPEROBJECTREF; #endif //------------------------------------------------------------- // class VariantWrapper, Exposed class VARIANTWRAPPEROBJECTREF // // //------------------------------------------------------------- class VariantWrapper : public Object { protected: VariantWrapper(VariantWrapper &wrap) {LIMITED_METHOD_CONTRACT}; // dissalow copy construction. VariantWrapper() {LIMITED_METHOD_CONTRACT}; // don't instantiate this class directly ~VariantWrapper() {LIMITED_METHOD_CONTRACT}; OBJECTREF m_WrappedObject; public: OBJECTREF GetWrappedObject() { LIMITED_METHOD_CONTRACT; return m_WrappedObject; } void SetWrappedObject(OBJECTREF pWrappedObject) { LIMITED_METHOD_CONTRACT; m_WrappedObject = pWrappedObject; } }; #ifdef USE_CHECKED_OBJECTREFS typedef REF VARIANTWRAPPEROBJECTREF; #else typedef VariantWrapper* VARIANTWRAPPEROBJECTREF; #endif //------------------------------------------------------------- // class ErrorWrapper, Exposed class ErrorWrapper // // //------------------------------------------------------------- class ErrorWrapper : public Object { protected: ErrorWrapper(ErrorWrapper &wrap) {LIMITED_METHOD_CONTRACT}; // dissalow copy construction. ErrorWrapper() {LIMITED_METHOD_CONTRACT;}; // don't instantiate this class directly ~ErrorWrapper() {LIMITED_METHOD_CONTRACT;}; INT32 m_ErrorCode; public: INT32 GetErrorCode() { LIMITED_METHOD_CONTRACT; return m_ErrorCode; } void SetErrorCode(int ErrorCode) { LIMITED_METHOD_CONTRACT; m_ErrorCode = ErrorCode; } }; #ifdef USE_CHECKED_OBJECTREFS typedef REF ERRORWRAPPEROBJECTREF; #else typedef ErrorWrapper* ERRORWRAPPEROBJECTREF; #endif //------------------------------------------------------------- // class CurrencyWrapper, Exposed class CurrencyWrapper // // //------------------------------------------------------------- // Keep this in sync with code:MethodTableBuilder.CheckForSystemTypes where // alignment requirement of the managed System.Decimal structure is computed. #if !defined(ALIGN_ACCESS) && !defined(FEATURE_64BIT_ALIGNMENT) #include #endif // !ALIGN_ACCESS && !FEATURE_64BIT_ALIGNMENT class CurrencyWrapper : public Object { protected: CurrencyWrapper(CurrencyWrapper &wrap) {LIMITED_METHOD_CONTRACT}; // dissalow copy construction. CurrencyWrapper() {LIMITED_METHOD_CONTRACT;}; // don't instantiate this class directly ~CurrencyWrapper() {LIMITED_METHOD_CONTRACT;}; DECIMAL m_WrappedObject; public: DECIMAL GetWrappedObject() { LIMITED_METHOD_CONTRACT; return m_WrappedObject; } void SetWrappedObject(DECIMAL WrappedObj) { LIMITED_METHOD_CONTRACT; m_WrappedObject = WrappedObj; } }; #if !defined(ALIGN_ACCESS) && !defined(FEATURE_64BIT_ALIGNMENT) #include #endif // !ALIGN_ACCESS && !FEATURE_64BIT_ALIGNMENT #ifdef USE_CHECKED_OBJECTREFS typedef REF CURRENCYWRAPPEROBJECTREF; #else typedef CurrencyWrapper* CURRENCYWRAPPEROBJECTREF; #endif //------------------------------------------------------------- // class BStrWrapper, Exposed class BSTRWRAPPEROBJECTREF // // //------------------------------------------------------------- class BStrWrapper : public Object { protected: BStrWrapper(BStrWrapper &wrap) {LIMITED_METHOD_CONTRACT}; // dissalow copy construction. BStrWrapper() {LIMITED_METHOD_CONTRACT}; // don't instantiate this class directly ~BStrWrapper() {LIMITED_METHOD_CONTRACT}; STRINGREF m_WrappedObject; public: STRINGREF GetWrappedObject() { LIMITED_METHOD_CONTRACT; return m_WrappedObject; } void SetWrappedObject(STRINGREF pWrappedObject) { LIMITED_METHOD_CONTRACT; m_WrappedObject = pWrappedObject; } }; #ifdef USE_CHECKED_OBJECTREFS typedef REF BSTRWRAPPEROBJECTREF; #else typedef BStrWrapper* BSTRWRAPPEROBJECTREF; #endif #endif // FEATURE_COMINTEROP class SafeHandle : public Object { friend class MscorlibBinder; private: // READ ME: // Modifying the order or fields of this object may require // other changes to the classlib class definition of this // object or special handling when loading this system class. Volatile m_handle; Volatile m_state; // Combined ref count and closed/disposed state (for atomicity) Volatile m_ownsHandle; Volatile m_fullyInitialized; // Did constructor finish? // Describe the bits in the m_state field above. enum StateBits { SH_State_Closed = 0x00000001, SH_State_Disposed = 0x00000002, SH_State_RefCount = 0xfffffffc, SH_RefCountOne = 4, // Amount to increment state field to yield a ref count increment of 1 }; static WORD s_IsInvalidHandleMethodSlot; static WORD s_ReleaseHandleMethodSlot; static void RunReleaseMethod(SafeHandle* psh); BOOL IsFullyInitialized() const { LIMITED_METHOD_CONTRACT; return m_fullyInitialized; } public: static void Init(); // To use the SafeHandle from native, look at the SafeHandleHolder, which // will do the AddRef & Release for you. LPVOID GetHandle() const { LIMITED_METHOD_CONTRACT; _ASSERTE(((unsigned int) m_state) >= SH_RefCountOne); return m_handle; } void AddRef(); void Release(bool fDispose = false); void SetHandle(LPVOID handle); }; void AcquireSafeHandle(SAFEHANDLEREF* s); void ReleaseSafeHandle(SAFEHANDLEREF* s); typedef Holder SafeHandleHolder; class CriticalHandle : public Object { friend class MscorlibBinder; private: // READ ME: // Modifying the order or fields of this object may require // other changes to the classlib class definition of this // object or special handling when loading this system class. Volatile m_handle; Volatile m_isClosed; public: LPVOID GetHandle() const { LIMITED_METHOD_CONTRACT; return m_handle; } static size_t GetHandleOffset() { LIMITED_METHOD_CONTRACT; return offsetof(CriticalHandle, m_handle); } void SetHandle(LPVOID handle) { LIMITED_METHOD_CONTRACT; m_handle = handle; } static FCDECL1(void, FireCustomerDebugProbe, CriticalHandle* refThisUNSAFE); }; #ifdef USE_CHECKED_OBJECTREFS typedef REF CRITICALHANDLE; typedef REF CRITICALHANDLEREF; #else // USE_CHECKED_OBJECTREFS typedef CriticalHandle * CRITICALHANDLE; typedef CriticalHandle * CRITICALHANDLEREF; #endif // USE_CHECKED_OBJECTREFS // WaitHandleBase // Base class for WaitHandle class WaitHandleBase :public MarshalByRefObjectBaseObject { friend class MscorlibBinder; public: __inline LPVOID GetWaitHandle() { LIMITED_METHOD_CONTRACT; SAFEHANDLEREF safeHandle = (SAFEHANDLEREF)m_safeHandle.LoadWithoutBarrier(); return safeHandle != NULL ? safeHandle->GetHandle() : INVALID_HANDLE_VALUE; } __inline SAFEHANDLEREF GetSafeHandle() {LIMITED_METHOD_CONTRACT; return (SAFEHANDLEREF)m_safeHandle.LoadWithoutBarrier();} private: Volatile m_safeHandle; }; #ifdef USE_CHECKED_OBJECTREFS typedef REF WAITHANDLEREF; #else // USE_CHECKED_OBJECTREFS typedef WaitHandleBase* WAITHANDLEREF; #endif // USE_CHECKED_OBJECTREFS // This class corresponds to System.MulticastDelegate on the managed side. class DelegateObject : public Object { friend class CheckAsmOffsets; friend class MscorlibBinder; public: BOOL IsWrapperDelegate() { LIMITED_METHOD_CONTRACT; return _methodPtrAux == NULL; } OBJECTREF GetTarget() { LIMITED_METHOD_CONTRACT; return _target; } void SetTarget(OBJECTREF target) { WRAPPER_NO_CONTRACT; SetObjectReference(&_target, target); } static int GetOffsetOfTarget() { LIMITED_METHOD_CONTRACT; return offsetof(DelegateObject, _target); } PCODE GetMethodPtr() { LIMITED_METHOD_CONTRACT; return _methodPtr; } void SetMethodPtr(PCODE methodPtr) { LIMITED_METHOD_CONTRACT; _methodPtr = methodPtr; } static int GetOffsetOfMethodPtr() { LIMITED_METHOD_CONTRACT; return offsetof(DelegateObject, _methodPtr); } PCODE GetMethodPtrAux() { LIMITED_METHOD_CONTRACT; return _methodPtrAux; } void SetMethodPtrAux(PCODE methodPtrAux) { LIMITED_METHOD_CONTRACT; _methodPtrAux = methodPtrAux; } static int GetOffsetOfMethodPtrAux() { LIMITED_METHOD_CONTRACT; return offsetof(DelegateObject, _methodPtrAux); } OBJECTREF GetInvocationList() { LIMITED_METHOD_CONTRACT; return _invocationList; } void SetInvocationList(OBJECTREF invocationList) { WRAPPER_NO_CONTRACT; SetObjectReference(&_invocationList, invocationList); } static int GetOffsetOfInvocationList() { LIMITED_METHOD_CONTRACT; return offsetof(DelegateObject, _invocationList); } INT_PTR GetInvocationCount() { LIMITED_METHOD_CONTRACT; return _invocationCount; } void SetInvocationCount(INT_PTR invocationCount) { LIMITED_METHOD_CONTRACT; _invocationCount = invocationCount; } static int GetOffsetOfInvocationCount() { LIMITED_METHOD_CONTRACT; return offsetof(DelegateObject, _invocationCount); } void SetMethodBase(OBJECTREF newMethodBase) { LIMITED_METHOD_CONTRACT; SetObjectReference((OBJECTREF*)&_methodBase, newMethodBase); } // README: // If you modify the order of these fields, make sure to update the definition in // BCL for this object. private: // System.Delegate OBJECTREF _target; OBJECTREF _methodBase; PCODE _methodPtr; PCODE _methodPtrAux; // System.MulticastDelegate OBJECTREF _invocationList; INT_PTR _invocationCount; }; #define OFFSETOF__DelegateObject__target OBJECT_SIZE /* m_pMethTab */ #define OFFSETOF__DelegateObject__methodPtr (OFFSETOF__DelegateObject__target + TARGET_POINTER_SIZE /* _target */ + TARGET_POINTER_SIZE /* _methodBase */) #define OFFSETOF__DelegateObject__methodPtrAux (OFFSETOF__DelegateObject__methodPtr + TARGET_POINTER_SIZE /* _methodPtr */) #ifdef USE_CHECKED_OBJECTREFS typedef REF DELEGATEREF; #else // USE_CHECKED_OBJECTREFS typedef DelegateObject* DELEGATEREF; #endif // USE_CHECKED_OBJECTREFS struct StackTraceElement; class ClrDataAccess; typedef DPTR(StackTraceElement) PTR_StackTraceElement; class StackTraceArray { struct ArrayHeader { size_t m_size; Thread * m_thread; }; typedef DPTR(ArrayHeader) PTR_ArrayHeader; public: StackTraceArray() : m_array(static_cast(NULL)) { WRAPPER_NO_CONTRACT; } StackTraceArray(I1ARRAYREF array) : m_array(array) { LIMITED_METHOD_CONTRACT; } void Swap(StackTraceArray & rhs) { CONTRACTL { NOTHROW; GC_NOTRIGGER; MODE_COOPERATIVE; } CONTRACTL_END; SUPPORTS_DAC; I1ARRAYREF t = m_array; m_array = rhs.m_array; rhs.m_array = t; } size_t Size() const { WRAPPER_NO_CONTRACT; if (!m_array) return 0; else return GetSize(); } StackTraceElement const & operator[](size_t index) const; StackTraceElement & operator[](size_t index); void Append(StackTraceElement const * begin, StackTraceElement const * end); I1ARRAYREF Get() const { LIMITED_METHOD_DAC_CONTRACT; return m_array; } // Deep copies the array void CopyFrom(StackTraceArray const & src); private: StackTraceArray(StackTraceArray const & rhs) = delete; StackTraceArray & operator=(StackTraceArray const & rhs) = delete; void Grow(size_t size); void EnsureThreadAffinity(); void CheckState() const; size_t Capacity() const { WRAPPER_NO_CONTRACT; assert(!!m_array); return m_array->GetNumComponents(); } size_t GetSize() const { WRAPPER_NO_CONTRACT; return GetHeader()->m_size; } void SetSize(size_t size) { WRAPPER_NO_CONTRACT; GetHeader()->m_size = size; } Thread * GetObjectThread() const { WRAPPER_NO_CONTRACT; return GetHeader()->m_thread; } void SetObjectThread() { WRAPPER_NO_CONTRACT; GetHeader()->m_thread = GetThread(); } StackTraceElement const * GetData() const { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return dac_cast(GetRaw() + sizeof(ArrayHeader)); } PTR_StackTraceElement GetData() { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return dac_cast(GetRaw() + sizeof(ArrayHeader)); } I1 const * GetRaw() const { WRAPPER_NO_CONTRACT; assert(!!m_array); return const_cast(m_array)->GetDirectPointerToNonObjectElements(); } PTR_I1 GetRaw() { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; assert(!!m_array); return dac_cast(m_array->GetDirectPointerToNonObjectElements()); } ArrayHeader const * GetHeader() const { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return dac_cast(GetRaw()); } PTR_ArrayHeader GetHeader() { WRAPPER_NO_CONTRACT; SUPPORTS_DAC; return dac_cast(GetRaw()); } void SetArray(I1ARRAYREF const & arr) { LIMITED_METHOD_CONTRACT; m_array = arr; } private: // put only things here that can be protected with GCPROTECT I1ARRAYREF m_array; }; #ifdef FEATURE_COLLECTIBLE_TYPES class LoaderAllocatorScoutObject : public Object { friend class MscorlibBinder; friend class LoaderAllocatorObject; protected: LoaderAllocator * m_nativeLoaderAllocator; }; #ifdef USE_CHECKED_OBJECTREFS typedef REF LOADERALLOCATORSCOUTREF; #else // USE_CHECKED_OBJECTREFS typedef LoaderAllocatorScoutObject* LOADERALLOCATORSCOUTREF; #endif // USE_CHECKED_OBJECTREFS class LoaderAllocatorObject : public Object { friend class MscorlibBinder; public: PTRARRAYREF GetHandleTable() { LIMITED_METHOD_DAC_CONTRACT; return (PTRARRAYREF)m_pSlots; } void SetHandleTable(PTRARRAYREF handleTable) { LIMITED_METHOD_CONTRACT; SetObjectReference(&m_pSlots, (OBJECTREF)handleTable); } INT32 GetSlotsUsed() { LIMITED_METHOD_CONTRACT; return m_slotsUsed; } void SetSlotsUsed(INT32 newSlotsUsed) { LIMITED_METHOD_CONTRACT; m_slotsUsed = newSlotsUsed; } void SetNativeLoaderAllocator(LoaderAllocator * pLoaderAllocator) { LIMITED_METHOD_CONTRACT; m_pLoaderAllocatorScout->m_nativeLoaderAllocator = pLoaderAllocator; } // README: // If you modify the order of these fields, make sure to update the definition in // BCL for this object. protected: LOADERALLOCATORSCOUTREF m_pLoaderAllocatorScout; OBJECTREF m_pSlots; INT32 m_slotsUsed; OBJECTREF m_methodInstantiationsTable; }; #ifdef USE_CHECKED_OBJECTREFS typedef REF LOADERALLOCATORREF; #else // USE_CHECKED_OBJECTREFS typedef DPTR(LoaderAllocatorObject) PTR_LoaderAllocatorObject; typedef PTR_LoaderAllocatorObject LOADERALLOCATORREF; #endif // USE_CHECKED_OBJECTREFS #endif // FEATURE_COLLECTIBLE_TYPES #if !defined(DACCESS_COMPILE) // Define the lock used to access stacktrace from an exception object EXTERN_C SpinLock g_StackTraceArrayLock; #endif // !defined(DACCESS_COMPILE) // This class corresponds to Exception on the managed side. typedef DPTR(class ExceptionObject) PTR_ExceptionObject; #include "pshpack4.h" class ExceptionObject : public Object { friend class MscorlibBinder; public: void SetHResult(HRESULT hr) { LIMITED_METHOD_CONTRACT; _HResult = hr; } HRESULT GetHResult() { LIMITED_METHOD_CONTRACT; return _HResult; } void SetXCode(DWORD code) { LIMITED_METHOD_CONTRACT; _xcode = code; } DWORD GetXCode() { LIMITED_METHOD_CONTRACT; return _xcode; } void SetXPtrs(void* xptrs) { LIMITED_METHOD_CONTRACT; _xptrs = xptrs; } void* GetXPtrs() { LIMITED_METHOD_CONTRACT; return _xptrs; } void SetStackTrace(StackTraceArray const & stackTrace, PTRARRAYREF dynamicMethodArray); void SetNullStackTrace(); void GetStackTrace(StackTraceArray & stackTrace, PTRARRAYREF * outDynamicMethodArray = NULL) const; #ifdef DACCESS_COMPILE I1ARRAYREF GetStackTraceArrayObject() const { LIMITED_METHOD_DAC_CONTRACT; return _stackTrace; } #endif // DACCESS_COMPILE void SetInnerException(OBJECTREF innerException) { WRAPPER_NO_CONTRACT; SetObjectReference((OBJECTREF*)&_innerException, (OBJECTREF)innerException); } OBJECTREF GetInnerException() { LIMITED_METHOD_DAC_CONTRACT; return _innerException; } // Returns the innermost exception object - equivalent of the // managed System.Exception.GetBaseException method. OBJECTREF GetBaseException() { LIMITED_METHOD_CONTRACT; // Loop and get the innermost exception object OBJECTREF oInnerMostException = NULL; OBJECTREF oCurrent = NULL; oCurrent = _innerException; while(oCurrent != NULL) { oInnerMostException = oCurrent; oCurrent = ((ExceptionObject*)(Object *)OBJECTREFToObject(oCurrent))->GetInnerException(); } // return the innermost exception return oInnerMostException; } void SetMessage(STRINGREF message) { WRAPPER_NO_CONTRACT; SetObjectReference((OBJECTREF*)&_message, (OBJECTREF)message); } STRINGREF GetMessage() { LIMITED_METHOD_DAC_CONTRACT; return _message; } void SetStackTraceString(STRINGREF stackTraceString) { WRAPPER_NO_CONTRACT; SetObjectReference((OBJECTREF*)&_stackTraceString, (OBJECTREF)stackTraceString); } STRINGREF GetStackTraceString() { LIMITED_METHOD_DAC_CONTRACT; return _stackTraceString; } STRINGREF GetRemoteStackTraceString() { LIMITED_METHOD_DAC_CONTRACT; return _remoteStackTraceString; } void SetHelpURL(STRINGREF helpURL) { WRAPPER_NO_CONTRACT; SetObjectReference((OBJECTREF*)&_helpURL, (OBJECTREF)helpURL); } void SetSource(STRINGREF source) { WRAPPER_NO_CONTRACT; SetObjectReference((OBJECTREF*)&_source, (OBJECTREF)source); } void ClearStackTraceForThrow() { WRAPPER_NO_CONTRACT; SetObjectReference((OBJECTREF*)&_remoteStackTraceString, NULL); SetObjectReference((OBJECTREF*)&_stackTrace, NULL); SetObjectReference((OBJECTREF*)&_stackTraceString, NULL); } void ClearStackTracePreservingRemoteStackTrace() { WRAPPER_NO_CONTRACT; SetObjectReference((OBJECTREF*)&_stackTrace, NULL); SetObjectReference((OBJECTREF*)&_stackTraceString, NULL); } // This method will set the reference to the array // containing the watson bucket information (in byte[] form). void SetWatsonBucketReference(OBJECTREF oWatsonBucketArray) { WRAPPER_NO_CONTRACT; SetObjectReference((OBJECTREF*)&_watsonBuckets, (OBJECTREF)oWatsonBucketArray); } // This method will return the reference to the array // containing the watson buckets U1ARRAYREF GetWatsonBucketReference() { LIMITED_METHOD_CONTRACT; return _watsonBuckets; } // This method will return a BOOL to indicate if the // watson buckets are present or not. BOOL AreWatsonBucketsPresent() { LIMITED_METHOD_CONTRACT; return (_watsonBuckets != NULL)?TRUE:FALSE; } // This method will save the IP to be used for watson bucketing. void SetIPForWatsonBuckets(UINT_PTR ip) { LIMITED_METHOD_CONTRACT; _ipForWatsonBuckets = ip; } // This method will return a BOOL to indicate if Watson bucketing IP // is present (or not). BOOL IsIPForWatsonBucketsPresent() { LIMITED_METHOD_CONTRACT; return (_ipForWatsonBuckets != NULL); } // This method returns the IP for Watson Buckets. UINT_PTR GetIPForWatsonBuckets() { LIMITED_METHOD_CONTRACT; return _ipForWatsonBuckets; } // README: // If you modify the order of these fields, make sure to update the definition in // BCL for this object. private: OBJECTREF _exceptionMethod; //Needed for serialization. STRINGREF _message; OBJECTREF _data; OBJECTREF _innerException; STRINGREF _helpURL; I1ARRAYREF _stackTrace; U1ARRAYREF _watsonBuckets; STRINGREF _stackTraceString; //Needed for serialization. STRINGREF _remoteStackTraceString; PTRARRAYREF _dynamicMethods; STRINGREF _source; // Mainly used by VB. UINT_PTR _ipForWatsonBuckets; // Contains the IP of exception for watson bucketing void* _xptrs; INT32 _xcode; INT32 _HResult; }; // Defined in Contracts.cs enum ContractFailureKind { CONTRACT_FAILURE_PRECONDITION = 0, CONTRACT_FAILURE_POSTCONDITION, CONTRACT_FAILURE_POSTCONDITION_ON_EXCEPTION, CONTRACT_FAILURE_INVARIANT, CONTRACT_FAILURE_ASSERT, CONTRACT_FAILURE_ASSUME, }; typedef DPTR(class ContractExceptionObject) PTR_ContractExceptionObject; class ContractExceptionObject : public ExceptionObject { friend class MscorlibBinder; public: ContractFailureKind GetContractFailureKind() { LIMITED_METHOD_CONTRACT; return static_cast(_Kind); } private: // keep these in sync with ndp/clr/src/bcl/system/diagnostics/contracts/contractsbcl.cs STRINGREF _UserMessage; STRINGREF _Condition; INT32 _Kind; }; #include "poppack.h" #ifdef USE_CHECKED_OBJECTREFS typedef REF CONTRACTEXCEPTIONREF; #else // USE_CHECKED_OBJECTREFS typedef PTR_ContractExceptionObject CONTRACTEXCEPTIONREF; #endif // USE_CHECKED_OBJECTREFS //=============================================================================== // #NullableFeature // #NullableArchitecture // // In a nutshell it is counterintuitive to have a boxed Nullable, since a boxed // object already has a representation for null (the null pointer), and having // multiple representations for the 'not present' value just causes grief. Thus the // feature is build make Nullable box to a boxed (not boxed). // // We want to do this in a way that does not impact the perf of the runtime in the // non-nullable case. // // To do this we need to // * Modify the boxing helper code:JIT_Box (we don't need a special one because // the JIT inlines the common case, so this only gets call in uncommon cases) // * Make a new helper for the Unbox case (see code:JIT_Unbox_Nullable) // * Plumb the JIT to ask for what kind of Boxing helper is needed // (see code:CEEInfo.getBoxHelper, code:CEEInfo.getUnBoxHelper // * change all the places in the CLR where we box or unbox by hand, and force // them to use code:MethodTable.Box, and code:MethodTable.Unbox which in // turn call code:Nullable.Box and code:Nullable.UnBox, most of these // are in reflection, and remoting (passing and returning value types). // // #NullableVerification // // Sadly, the IL Verifier also needs to know about this change. Basically the 'box' // instruction returns a boxed(T) (not a boxed(Nullable)) for the purposes of // verfication. The JIT finds out what box returns by calling back to the EE with // the code:CEEInfo.getTypeForBox API. // // #NullableDebugging // // Sadly, because the debugger also does its own boxing 'by hand' for expression // evaluation inside visual studio, it measn that debuggers also need to be aware // of the fact that Nullable boxes to a boxed. It is the responcibility of // debuggers to follow this convention (which is why this is sad). // //=============================================================================== // Nullable represents the managed generic value type Nullable // // The runtime has special logic for this value class. When it is boxed // it becomes either null or a boxed T. Similarly a boxed T can be unboxed // either as a T (as normal), or as a Nullable // // See code:Nullable#NullableArchitecture for more. // class Nullable { Nullable(); // This is purposefully undefined. Do not make instances // of this class. public: static void CheckFieldOffsets(TypeHandle nullableType); static BOOL IsNullableType(TypeHandle nullableType); static BOOL IsNullableForType(TypeHandle nullableType, MethodTable* paramMT); static BOOL IsNullableForTypeNoGC(TypeHandle nullableType, MethodTable* paramMT); static OBJECTREF Box(void* src, MethodTable* nullable); static BOOL UnBox(void* dest, OBJECTREF boxedVal, MethodTable* destMT); static BOOL UnBoxNoGC(void* dest, OBJECTREF boxedVal, MethodTable* destMT); static BOOL UnBoxIntoArgNoGC(ArgDestination *argDest, OBJECTREF boxedVal, MethodTable* destMT); static void UnBoxNoCheck(void* dest, OBJECTREF boxedVal, MethodTable* destMT); static OBJECTREF BoxedNullableNull(TypeHandle nullableType) { return 0; } // if 'Obj' is a true boxed nullable, return the form we want (either null or a boxed T) static OBJECTREF NormalizeBox(OBJECTREF obj); static inline CLR_BOOL HasValue(void *src, MethodTable *nullableMT) { Nullable *nullable = (Nullable *)src; return *(nullable->HasValueAddr(nullableMT)); } static inline void *Value(void *src, MethodTable *nullableMT) { Nullable *nullable = (Nullable *)src; return nullable->ValueAddr(nullableMT); } private: static BOOL IsNullableForTypeHelper(MethodTable* nullableMT, MethodTable* paramMT); static BOOL IsNullableForTypeHelperNoGC(MethodTable* nullableMT, MethodTable* paramMT); CLR_BOOL* HasValueAddr(MethodTable* nullableMT); void* ValueAddr(MethodTable* nullableMT); }; #ifdef USE_CHECKED_OBJECTREFS typedef REF EXCEPTIONREF; #else // USE_CHECKED_OBJECTREFS typedef PTR_ExceptionObject EXCEPTIONREF; #endif // USE_CHECKED_OBJECTREFS class GCHeapHashObject : public Object { #ifdef DACCESS_COMPILE friend class ClrDataAccess; #endif friend class GCHeap; friend class JIT_TrialAlloc; friend class CheckAsmOffsets; friend class COMString; friend class MscorlibBinder; private: BASEARRAYREF _data; INT32 _count; INT32 _deletedCount; public: INT32 GetCount() { LIMITED_METHOD_CONTRACT; return _count; } void IncrementCount(bool replacingDeletedItem) { LIMITED_METHOD_CONTRACT; ++_count; if (replacingDeletedItem) --_deletedCount; } void DecrementCount(bool deletingItem) { LIMITED_METHOD_CONTRACT; --_count; if (deletingItem) ++_deletedCount; } INT32 GetDeletedCount() { LIMITED_METHOD_CONTRACT; return _deletedCount; } void SetDeletedCountToZero() { LIMITED_METHOD_CONTRACT; _deletedCount = 0; } INT32 GetCapacity() { LIMITED_METHOD_CONTRACT; if (_data == NULL) return 0; else return (_data->GetNumComponents()); } BASEARRAYREF GetData() { LIMITED_METHOD_CONTRACT; return _data; } void SetTable(BASEARRAYREF data) { STATIC_CONTRACT_NOTHROW; STATIC_CONTRACT_GC_NOTRIGGER; STATIC_CONTRACT_MODE_COOPERATIVE; SetObjectReference((OBJECTREF*)&_data, (OBJECTREF)data); } protected: GCHeapHashObject() {LIMITED_METHOD_CONTRACT; } ~GCHeapHashObject() {LIMITED_METHOD_CONTRACT; } }; typedef DPTR(GCHeapHashObject) PTR_GCHeapHashObject; #ifdef USE_CHECKED_OBJECTREFS typedef REF GCHEAPHASHOBJECTREF; #else // USE_CHECKED_OBJECTREFS typedef PTR_GCHeapHashObject GCHEAPHASHOBJECTREF; #endif // USE_CHECKED_OBJECTREFS class LAHashDependentHashTrackerObject : public Object { #ifdef DACCESS_COMPILE friend class ClrDataAccess; #endif friend class CheckAsmOffsets; friend class MscorlibBinder; private: OBJECTHANDLE _dependentHandle; LoaderAllocator* _loaderAllocator; public: bool IsLoaderAllocatorLive(); bool IsTrackerFor(LoaderAllocator *pLoaderAllocator) { if (pLoaderAllocator != _loaderAllocator) return false; return IsLoaderAllocatorLive(); } void GetDependentAndLoaderAllocator(OBJECTREF *pLoaderAllocatorRef, GCHEAPHASHOBJECTREF *pGCHeapHash); // Be careful with this. This isn't safe to use unless something is keeping the LoaderAllocator live, or there is no intention to dereference this pointer LoaderAllocator* GetLoaderAllocatorUnsafe() { return _loaderAllocator; } void Init(OBJECTHANDLE dependentHandle, LoaderAllocator* loaderAllocator) { LIMITED_METHOD_CONTRACT; _dependentHandle = dependentHandle; _loaderAllocator = loaderAllocator; } }; class LAHashKeyToTrackersObject : public Object { #ifdef DACCESS_COMPILE friend class ClrDataAccess; #endif friend class CheckAsmOffsets; friend class MscorlibBinder; public: // _trackerOrTrackerSet is either a reference to a LAHashDependentHashTracker, or to a GCHeapHash of LAHashDependentHashTracker objects. OBJECTREF _trackerOrTrackerSet; // _laLocalKeyValueStore holds an object that represents a Key value (which must always be valid for the lifetime of the // CrossLoaderAllocatorHeapHash, and the values which must also be valid for that entire lifetime. When a value might // have a shorter lifetime it is accessed through the _trackerOrTrackerSet variable, which allows access to hashtables which // are associated with that remote loaderallocator through a dependent handle, so that lifetime can be managed. OBJECTREF _laLocalKeyValueStore; }; typedef DPTR(LAHashDependentHashTrackerObject) PTR_LAHashDependentHashTrackerObject; typedef DPTR(LAHashKeyToTrackersObject) PTR_LAHashKeyToTrackersObject; #ifdef USE_CHECKED_OBJECTREFS typedef REF LAHASHDEPENDENTHASHTRACKERREF; typedef REF LAHASHKEYTOTRACKERSREF; #else // USE_CHECKED_OBJECTREFS typedef PTR_LAHashDependentHashTrackerObject LAHASHDEPENDENTHASHTRACKERREF; typedef PTR_LAHashKeyToTrackersObject LAHASHKEYTOTRACKERSREF; #endif // USE_CHECKED_OBJECTREFS #endif // _OBJECT_H_