// 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 * | * +-- code:StringBufferObject - StringBuffer instance layout. * | * +-- 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:AppDomainBaseObject - The base object for the class AppDomain * | * +-- code:AssemblyBaseObject - The base object for the class Assembly * | * +-- code:ContextBaseObject - base object for class Context * * * 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 Context; class CtxStaticData; class DomainAssembly; class AssemblyNative; class WaitHandleNative; class ArgDestination; struct RCW; #if CHECK_APP_DOMAIN_LEAKS class Object; class SetAppDomainAgilePendingTable { public: SetAppDomainAgilePendingTable (); ~SetAppDomainAgilePendingTable (); void PushReference (Object *pObject) { STATIC_CONTRACT_THROWS; STATIC_CONTRACT_GC_NOTRIGGER; PendingEntry entry; entry.pObject = pObject; m_Stack.Push(entry); } void PushParent (Object *pObject) { STATIC_CONTRACT_THROWS; STATIC_CONTRACT_GC_NOTRIGGER; PendingEntry entry; entry.pObject = (Object*)((size_t)pObject | 1); m_Stack.Push(entry); } Object *GetPendingObject (bool *pfReturnedToParent) { STATIC_CONTRACT_THROWS; STATIC_CONTRACT_GC_NOTRIGGER; if (!m_Stack.Count()) return NULL; PendingEntry *pPending = m_Stack.Pop(); *pfReturnedToParent = pPending->fMarked != 0; return (Object*)((size_t)pPending->pObject & ~1); } private: union PendingEntry { Object *pObject; // Indicates whether the current thread set BIT_SBLK_AGILE_IN_PROGRESS // on the object. Entries without this flag set are unexplored // objects. size_t fMarked:1; }; CStackArray m_Stack; }; #endif //CHECK_APP_DOMAIN_LEAKS // // The generational GC requires that every object be at least 12 bytes // in size. #define MIN_OBJECT_SIZE (2*sizeof(BYTE*) + sizeof(ObjHeader)) #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) { LIMITED_METHOD_CONTRACT; m_pMethTab = pMT; } VOID SetMethodTableForLargeObject(MethodTable *pMT) { // 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); } #endif //!DACCESS_COMPILE // An object might be a proxy of some sort, with a thunking VTable. If so, we can // advance to the true method table or class. BOOL IsTransparentProxy() { LIMITED_METHOD_CONTRACT; return FALSE; } #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)); } MethodTable *GetTrueMethodTable(); 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(); } ADIndex GetAppDomainIndex(); // Get app domain of object, or NULL if it is agile AppDomain *GetAppDomain(); #ifndef DACCESS_COMPILE // Set app domain of object to current domain. void SetAppDomain() { WRAPPER_NO_CONTRACT; SetAppDomain(::GetAppDomain()); } BOOL SetAppDomainNoThrow(); #endif // Set app domain of object to given domain - it can only be set once void SetAppDomain(AppDomain *pDomain); #ifdef _DEBUG #ifndef DACCESS_COMPILE // For SO-tolerance contract violation purposes, define these DEBUG_ versions to identify // the codepaths to SetAppDomain that are called only from DEBUG code. void DEBUG_SetAppDomain() { WRAPPER_NO_CONTRACT; DEBUG_SetAppDomain(::GetAppDomain()); } #endif //!DACCESS_COMPILE void DEBUG_SetAppDomain(AppDomain *pDomain); #endif //_DEBUG #if CHECK_APP_DOMAIN_LEAKS // Mark object as app domain agile BOOL SetAppDomainAgile(BOOL raiseAssert=TRUE, SetAppDomainAgilePendingTable *pTable = NULL); BOOL TrySetAppDomainAgile(BOOL raiseAssert=TRUE); // Mark sync block as app domain agile void SetSyncBlockAppDomainAgile(); // Check if object is app domain agile BOOL IsAppDomainAgile(); // Check if object is app domain agile BOOL IsAppDomainAgileRaw() { WRAPPER_NO_CONTRACT; SyncBlock *psb = PassiveGetSyncBlock(); return (psb && psb->IsAppDomainAgile()); } BOOL IsCheckedForAppDomainAgile() { WRAPPER_NO_CONTRACT; SyncBlock *psb = PassiveGetSyncBlock(); return (psb && psb->IsCheckedForAppDomainAgile()); } void SetIsCheckedForAppDomainAgile() { WRAPPER_NO_CONTRACT; SyncBlock *psb = PassiveGetSyncBlock(); if (psb) psb->SetIsCheckedForAppDomainAgile(); } // Check object to see if it is usable in the current domain BOOL CheckAppDomain() { WRAPPER_NO_CONTRACT; return CheckAppDomain(::GetAppDomain()); } //Check object to see if it is usable in the given domain BOOL CheckAppDomain(AppDomain *pDomain); // Check if the object's type is app domain agile BOOL IsTypeAppDomainAgile(); // Check if the object's type is conditionally app domain agile BOOL IsTypeCheckAppDomainAgile(); // Check if the object's type is naturally app domain agile BOOL IsTypeTypesafeAppDomainAgile(); // Check if the object's type is possibly app domain agile BOOL IsTypeNeverAppDomainAgile(); // Validate object & fields to see that it's usable from the current app domain BOOL ValidateAppDomain() { WRAPPER_NO_CONTRACT; return ValidateAppDomain(::GetAppDomain()); } // Validate object & fields to see that it's usable from any app domain BOOL ValidateAppDomainAgile() { WRAPPER_NO_CONTRACT; return ValidateAppDomain(NULL); } // Validate object & fields to see that it's usable from the given app domain (or null for agile) BOOL ValidateAppDomain(AppDomain *pAppDomain); // Validate fields to see that they are usable from the object's app domain // (or from any domain if the object is agile) BOOL ValidateAppDomainFields() { WRAPPER_NO_CONTRACT; return ValidateAppDomainFields(GetAppDomain()); } // Validate fields to see that they are usable from the given app domain (or null for agile) BOOL ValidateAppDomainFields(AppDomain *pAppDomain); // Validate a value type's fields to see that it's usable from the current app domain static BOOL ValidateValueTypeAppDomain(MethodTable *pMT, void *base, BOOL raiseAssert = TRUE) { WRAPPER_NO_CONTRACT; return ValidateValueTypeAppDomain(pMT, base, ::GetAppDomain(), raiseAssert); } // Validate a value type's fields to see that it's usable from any app domain static BOOL ValidateValueTypeAppDomainAgile(MethodTable *pMT, void *base, BOOL raiseAssert = TRUE) { WRAPPER_NO_CONTRACT; return ValidateValueTypeAppDomain(pMT, base, NULL, raiseAssert); } // Validate a value type's fields to see that it's usable from the given app domain (or null for agile) static BOOL ValidateValueTypeAppDomain(MethodTable *pMT, void *base, AppDomain *pAppDomain, BOOL raiseAssert = TRUE); // Call when we are assigning this object to a dangerous field // in an object in a given app domain (or agile if null) BOOL AssignAppDomain(AppDomain *pAppDomain, BOOL raiseAssert = TRUE); BOOL TryAssignAppDomain(AppDomain *pAppDomain, BOOL raiseAssert = TRUE); // Call when we are assigning to a dangerous value type field // in an object in a given app domain (or agile if null) static BOOL AssignValueTypeAppDomain(MethodTable *pMT, void *base, AppDomain *pAppDomain, BOOL raiseAssert = TRUE); #endif // CHECK_APP_DOMAIN_LEAKS // 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); } 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); #if CHECK_APP_DOMAIN_LEAKS friend class ObjHeader; BOOL SetFieldsAgile(BOOL raiseAssert = TRUE, SetAppDomainAgilePendingTable *pTable = NULL); static BOOL SetClassFieldsAgile(MethodTable *pMT, void *base, BOOL baseIsVT, BOOL raiseAssert = TRUE, SetAppDomainAgilePendingTable *pTable = NULL); static BOOL ValidateClassFields(MethodTable *pMT, void *base, BOOL baseIsVT, AppDomain *pAppDomain, BOOL raiseAssert = TRUE); BOOL SetAppDomainAgileWorker(BOOL raiseAssert, SetAppDomainAgilePendingTable *pTable); BOOL ShouldCheckAppDomainAgile(BOOL raiseAssert, BOOL *pfResult); #endif }; /* * Object ref setting routines. You must use these to do * proper write barrier support, as well as app domain * leak checking. * * Note that the AppDomain parameter is the app domain affinity * of the object containing the field or value class. It should * be NULL if the containing object is app domain agile. Note that * you typically get this value by calling obj->GetAppDomain() on * the containing object. */ // 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); #if CHECK_APP_DOMAIN_LEAKS void SetObjectReferenceChecked(OBJECTREF *dst,OBJECTREF ref, AppDomain *pAppDomain); void CopyValueClassChecked(void* dest, void* src, MethodTable *pMT, AppDomain *pAppDomain); void CopyValueClassArgChecked(ArgDestination *argDest, void* src, MethodTable *pMT, AppDomain *pAppDomain, int destOffset); #define SetObjectReference(_d,_r,_a) SetObjectReferenceChecked(_d, _r, _a) #define CopyValueClass(_d,_s,_m,_a) CopyValueClassChecked(_d,_s,_m,_a) #define CopyValueClassArg(_d,_s,_m,_a,_o) CopyValueClassArgChecked(_d,_s,_m,_a,_o) #else #define SetObjectReference(_d,_r,_a) SetObjectReferenceUnchecked(_d, _r) #define CopyValueClass(_d,_s,_m,_a) CopyValueClassUnchecked(_d,_s,_m) #define CopyValueClassArg(_d,_s,_m,_a,_o) CopyValueClassArgUnchecked(_d,_s,_m,_o) #endif #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 AllocateArrayEx(TypeHandle arrayClass, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap DEBUG_ARG(BOOL bDontSetAppDomain)); friend OBJECTREF FastAllocatePrimitiveArray(MethodTable* arrayType, DWORD cElements, BOOL bAllocateInLargeHeap); friend FCDECL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size); friend FCDECL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE typeHnd_, 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 _WIN64 DWORD pad; #endif // _WIN64 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; // 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; #if CHECK_APP_DOMAIN_LEAKS pMT = GetGCSafeMethodTable(); #else pMT = GetMethodTable(); #endif //CHECK_APP_DOMAIN_LEAKS _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); }; // // 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(TypeHandle arrayClass, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap); friend class JIT_TrialAlloc; friend class CheckAsmOffsets; public: TypeHandle GetArrayElementTypeHandle() { LIMITED_METHOD_CONTRACT; return GetMethodTable()->GetApproxArrayElementTypeHandle(); } static SIZE_T GetDataOffset() { LIMITED_METHOD_CONTRACT; return offsetof(PtrArray, m_Array); } void SetAt(SIZE_T i, OBJECTREF ref) { CONTRACTL { NOTHROW; GC_NOTRIGGER; SO_TOLERANT; MODE_COOPERATIVE; } CONTRACTL_END; _ASSERTE(i < GetNumComponents()); SetObjectReference(m_Array + i, ref, GetAppDomain()); } 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]; }; /* 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 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(PTRArray) PTR_PTRArray; class StringObject; #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 CHARARRAYREF; typedef REF PTRARRAYREF; // Warning: Use PtrArray only for single dimensional arrays, not multidim arrays. typedef REF STRINGREF; #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_CHARArray CHARARRAYREF; typedef PTR_PTRArray PTRARRAYREF; // Warning: Use PtrArray only for single dimensional arrays, not multidim arrays. typedef PTR_StringObject STRINGREF; #endif // USE_CHECKED_OBJECTREFS #include /* * StringObject * * Special String implementation for performance. * * m_StringLength - Length of string in number of WCHARs * m_Characters - 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 #ifdef _MSC_VER #pragma warning(disable : 4200) // disable zero-sized array warning #endif 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_Characters[0]; // GC will see a StringObject like this: // DWORD m_StringLength // WCHAR m_Characters[0] // DWORD m_OptionalPadding (this is an optional field and will appear based on need) 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 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_Characters) ); } WCHAR* GetBuffer(DWORD *pdwSize) { LIMITED_METHOD_CONTRACT; _ASSERTE((this != nullptr) && pdwSize); *pdwSize = GetStringLength(); return GetBuffer(); } WCHAR* GetBufferNullable() { LIMITED_METHOD_CONTRACT; return( (this == nullptr) ? nullptr : (WCHAR*)( dac_cast(this) + offsetof(StringObject, m_Characters) ) ); } 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_Characters)); } 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(); static STRINGREF __stdcall StringInitCharHelper(LPCSTR pszSource, int length); 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 INT32 FastCompareStringHelper(DWORD* strAChars, INT32 countA, DWORD* strBChars, INT32 countB); 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; SO_TOLERANT; } 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; SO_TOLERANT; } CONTRACTL_END; INDEBUG(TypeCheck()); m_typeHandle = type; } void SetKeepAlive(OBJECTREF keepalive) { CONTRACTL { NOTHROW; MODE_COOPERATIVE; GC_NOTRIGGER; SO_TOLERANT; } CONTRACTL_END; INDEBUG(TypeCheck()); SetObjectReference(&m_keepalive, keepalive, GetAppDomain()); } TypeHandle GetType() { CONTRACTL { NOTHROW; MODE_COOPERATIVE; GC_NOTRIGGER; SO_TOLERANT; } CONTRACTL_END; INDEBUG(TypeCheck()); return m_typeHandle; } }; // 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, GetAppDomain()); } 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, GetAppDomain()); } 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, GetAppDomain()); } }; 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 PermissionListSetObject: public Object { friend class MscorlibBinder; private: OBJECTREF _firstPermSetTriple; OBJECTREF _permSetTriples; public: BOOL IsEmpty() { LIMITED_METHOD_CONTRACT; return (_firstPermSetTriple == NULL && _permSetTriples == NULL ); } }; #ifdef USE_CHECKED_OBJECTREFS typedef REF PERMISSIONLISTSETREF; #else typedef PermissionListSetObject* PERMISSIONLISTSETREF; #endif #define SYNCCTXPROPS_REQUIRESWAITNOTIFICATION 0x1 // Keep in sync with SynchronizationContext.cs SynchronizationContextFlags 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. INT32 _props; public: BOOL IsWaitNotificationRequired() { LIMITED_METHOD_CONTRACT; if ((_props & SYNCCTXPROPS_REQUIRESWAITNOTIFICATION) != 0) return TRUE; return FALSE; } }; 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; CLR_BOOL _useUserOverride; 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; OBJECTREF m_Name; OBJECTREF m_Delegate; #ifdef IO_CANCELLATION_ENABLED OBJECTREF m_CancellationSignals; #endif 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; CLR_BOOL m_ExecutionContextBelongsToCurrentScope; #ifdef _DEBUG CLR_BOOL m_ForbidExecutionContextMutation; #endif 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 SetObjectReferenceUnchecked( (OBJECTREF *)&m_ThreadStartArg, newThreadStartArg); } OBJECTREF GetDelegate() { LIMITED_METHOD_CONTRACT; return m_Delegate; } void SetDelegate(OBJECTREF delegate); CULTUREINFOBASEREF GetCurrentUserCulture(); CULTUREINFOBASEREF GetCurrentUICulture(); OBJECTREF GetManagedThreadCulture(BOOL bUICulture); void ResetManagedThreadCulture(BOOL bUICulture); void ResetCurrentUserCulture(); void ResetCurrentUICulture(); 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 ResetCulture() { LIMITED_METHOD_CONTRACT; ResetCurrentUserCulture(); ResetCurrentUICulture(); } 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 { }; // ContextBaseObject // This class is the base class for Contexts // class ContextBaseObject : public Object { friend class Context; 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. OBJECTREF m_ctxProps; // array of name-value pairs of properties OBJECTREF m_dphCtx; // dynamic property holder OBJECTREF m_localDataStore; // context local store OBJECTREF m_serverContextChain; // server context sink chain OBJECTREF m_clientContextChain; // client context sink chain OBJECTREF m_exposedAppDomain; //appDomain ?? PTRARRAYREF m_ctxStatics; // holder for context relative statics Context* m_internalContext; // Pointer to the VM context INT32 _ctxID; INT32 _ctxFlags; INT32 _numCtxProps; // current count of properties INT32 _ctxStaticsCurrentBucket; INT32 _ctxStaticsFreeIndex; protected: ContextBaseObject() { LIMITED_METHOD_CONTRACT; } ~ContextBaseObject() { LIMITED_METHOD_CONTRACT; } public: void SetInternalContext(Context* pCtx) { LIMITED_METHOD_CONTRACT; // either transitioning from NULL to non-NULL or vice versa. // But not setting NULL to NULL or non-NULL to non-NULL. _ASSERTE((m_internalContext == NULL) != (pCtx == NULL)); m_internalContext = pCtx; } Context* GetInternalContext() { LIMITED_METHOD_CONTRACT; return m_internalContext; } OBJECTREF GetExposedDomain() { return m_exposedAppDomain; } OBJECTREF SetExposedDomain(OBJECTREF newDomain) { LIMITED_METHOD_CONTRACT; OBJECTREF oldDomain = m_exposedAppDomain; SetObjectReference( (OBJECTREF *)&m_exposedAppDomain, newDomain, GetAppDomain() ); return oldDomain; } PTRARRAYREF GetContextStaticsHolder() { LIMITED_METHOD_CONTRACT; SUPPORTS_DAC; // The code that needs this should have faulted it in by now! _ASSERTE(m_ctxStatics != NULL); return m_ctxStatics; } }; typedef DPTR(ContextBaseObject) PTR_ContextBaseObject; // AppDomainBaseObject // This class is the base class for application domains // class AppDomainBaseObject : public MarshalByRefObjectBaseObject { friend class AppDomain; 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_pDomainManager; // AppDomainManager for host settings. OBJECTREF m_LocalStore; OBJECTREF m_FusionTable; OBJECTREF m_pSecurityIdentity; // Evidence associated with this domain OBJECTREF m_pPolicies; // Array of context policies associated with this domain OBJECTREF m_pAssemblyEventHandler; // Delegate for 'loading assembly' event OBJECTREF m_pTypeEventHandler; // Delegate for 'resolve type' event OBJECTREF m_pResourceEventHandler; // Delegate for 'resolve resource' event OBJECTREF m_pAsmResolveEventHandler; // Delegate for 'resolve assembly' event OBJECTREF m_pApplicationTrust; // App ApplicationTrust. OBJECTREF m_pProcessExitEventHandler; // Delegate for 'process exit' event. Only used in Default appdomain. OBJECTREF m_pDomainUnloadEventHandler; // Delegate for 'about to unload domain' event OBJECTREF m_pUnhandledExceptionEventHandler; // Delegate for 'unhandled exception' event OBJECTREF m_compatFlags; OBJECTREF m_pFirstChanceExceptionHandler; // Delegate for 'FirstChance Exception' event AppDomain* m_pDomain; // Pointer to the BaseDomain Structure CLR_BOOL m_bHasSetPolicy; // SetDomainPolicy has been called for this domain CLR_BOOL m_bIsFastFullTrustDomain; // We know for sure that this is a homogeneous full trust domain. CLR_BOOL m_compatFlagsInitialized; protected: AppDomainBaseObject() { LIMITED_METHOD_CONTRACT; } ~AppDomainBaseObject() { LIMITED_METHOD_CONTRACT; } public: void SetDomain(AppDomain* p) { LIMITED_METHOD_CONTRACT; m_pDomain = p; } AppDomain* GetDomain() { LIMITED_METHOD_CONTRACT; return m_pDomain; } OBJECTREF GetSecurityIdentity() { LIMITED_METHOD_CONTRACT; return m_pSecurityIdentity; } OBJECTREF GetAppDomainManager() { LIMITED_METHOD_CONTRACT; return m_pDomainManager; } OBJECTREF GetApplicationTrust() { LIMITED_METHOD_CONTRACT; return m_pApplicationTrust; } BOOL GetIsFastFullTrustDomain() { LIMITED_METHOD_CONTRACT; return !!m_bIsFastFullTrustDomain; } // Ref needs to be a PTRARRAYREF void SetPolicies(OBJECTREF ref) { WRAPPER_NO_CONTRACT; SetObjectReference(&m_pPolicies, ref, m_pDomain ); } BOOL HasSetPolicy() { LIMITED_METHOD_CONTRACT; return m_bHasSetPolicy; } // Returns the reference to the delegate of the first chance exception notification handler OBJECTREF GetFirstChanceExceptionNotificationHandler() { LIMITED_METHOD_CONTRACT; return m_pFirstChanceExceptionHandler; } }; // The managed definition of AppDomainSetup is in BCL\System\AppDomainSetup.cs class AppDomainSetupObject : public Object { friend class MscorlibBinder; protected: PTRARRAYREF m_Entries; STRINGREF m_AppBase; OBJECTREF m_AppDomainInitializer; PTRARRAYREF m_AppDomainInitializerArguments; STRINGREF m_ApplicationTrust; I1ARRAYREF m_ConfigurationBytes; STRINGREF m_AppDomainManagerAssembly; STRINGREF m_AppDomainManagerType; OBJECTREF m_CompatFlags; STRINGREF m_TargetFrameworkName; INT32 m_LoaderOptimization; #ifdef FEATURE_COMINTEROP CLR_BOOL m_DisableInterfaceCache; #endif // FEATURE_COMINTEROP CLR_BOOL m_CheckedForTargetFrameworkName; #ifdef FEATURE_RANDOMIZED_STRING_HASHING CLR_BOOL m_UseRandomizedStringHashing; #endif protected: AppDomainSetupObject() { LIMITED_METHOD_CONTRACT; } ~AppDomainSetupObject() { LIMITED_METHOD_CONTRACT; } public: #ifdef FEATURE_RANDOMIZED_STRING_HASHING BOOL UseRandomizedStringHashing() { LIMITED_METHOD_CONTRACT; return (BOOL) m_UseRandomizedStringHashing; } #endif // FEATURE_RANDOMIZED_STRING_HASHING }; typedef DPTR(AppDomainSetupObject) PTR_AppDomainSetupObject; #ifdef USE_CHECKED_OBJECTREFS typedef REF APPDOMAINSETUPREF; #else typedef AppDomainSetupObject* APPDOMAINSETUPREF; #endif // 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 #ifdef FEATURE_APPX UINT32 m_flags; #endif 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; SetObjectReferenceUnchecked(&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)) // 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 m_pSimpleName; U1ARRAYREF m_pPublicKey; U1ARRAYREF m_pPublicKeyToken; OBJECTREF m_pCultureInfo; OBJECTREF m_pCodeBase; OBJECTREF m_pVersion; OBJECTREF m_StrongNameKeyPair; OBJECTREF m_siInfo; U1ARRAYREF m_HashForControl; DWORD m_HashAlgorithm; DWORD m_HashAlgorithmForControl; DWORD m_VersionCompatibility; DWORD m_Flags; protected: AssemblyNameBaseObject() { LIMITED_METHOD_CONTRACT; } ~AssemblyNameBaseObject() { LIMITED_METHOD_CONTRACT; } public: OBJECTREF GetSimpleName() { LIMITED_METHOD_CONTRACT; return m_pSimpleName; } U1ARRAYREF GetPublicKey() { LIMITED_METHOD_CONTRACT; return m_pPublicKey; } U1ARRAYREF GetPublicKeyToken() { LIMITED_METHOD_CONTRACT; return m_pPublicKeyToken; } OBJECTREF GetStrongNameKeyPair() { LIMITED_METHOD_CONTRACT; return m_StrongNameKeyPair; } OBJECTREF GetCultureInfo() { LIMITED_METHOD_CONTRACT; return m_pCultureInfo; } OBJECTREF GetAssemblyCodeBase() { LIMITED_METHOD_CONTRACT; return m_pCodeBase; } OBJECTREF GetVersion() { LIMITED_METHOD_CONTRACT; return m_pVersion; } DWORD GetAssemblyHashAlgorithm() { LIMITED_METHOD_CONTRACT; return m_HashAlgorithm; } DWORD GetFlags() { LIMITED_METHOD_CONTRACT; return m_Flags; } U1ARRAYREF GetHashForControl() { LIMITED_METHOD_CONTRACT; return m_HashForControl;} DWORD GetHashAlgorithmForControl() { LIMITED_METHOD_CONTRACT; return m_HashAlgorithmForControl; } }; // 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; } }; // FrameSecurityDescriptorBaseObject // This class is the base class for the frame security descriptor // class FrameSecurityDescriptorBaseObject : 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_assertions; // imperative OBJECTREF m_denials; // imperative OBJECTREF m_restriction; // imperative OBJECTREF m_DeclarativeAssertions; OBJECTREF m_DeclarativeDenials; OBJECTREF m_DeclarativeRestrictions; CLR_BOOL m_assertFT; CLR_BOOL m_assertAllPossible; CLR_BOOL m_declSecComputed; protected: FrameSecurityDescriptorBaseObject() {LIMITED_METHOD_CONTRACT;} ~FrameSecurityDescriptorBaseObject() {LIMITED_METHOD_CONTRACT;} public: INT32 GetOverridesCount() { LIMITED_METHOD_CONTRACT; INT32 ret =0; if (m_restriction != NULL) ret++; if (m_denials != NULL) ret++; if (m_DeclarativeDenials != NULL) ret++; if (m_DeclarativeRestrictions != NULL) ret++; return ret; } INT32 GetAssertCount() { LIMITED_METHOD_CONTRACT; INT32 ret =0; if (m_assertions != NULL || m_DeclarativeAssertions != NULL || HasAssertAllPossible()) ret++; return ret; } BOOL HasAssertFT() { LIMITED_METHOD_CONTRACT; return m_assertFT; } BOOL IsDeclSecComputed() { LIMITED_METHOD_CONTRACT; return m_declSecComputed; } BOOL HasAssertAllPossible() { LIMITED_METHOD_CONTRACT; return m_assertAllPossible; } OBJECTREF GetImperativeAssertions() { LIMITED_METHOD_CONTRACT; return m_assertions; } OBJECTREF GetDeclarativeAssertions() { LIMITED_METHOD_CONTRACT; return m_DeclarativeAssertions; } OBJECTREF GetImperativeDenials() { LIMITED_METHOD_CONTRACT; return m_denials; } OBJECTREF GetDeclarativeDenials() { LIMITED_METHOD_CONTRACT; return m_DeclarativeDenials; } OBJECTREF GetImperativeRestrictions() { LIMITED_METHOD_CONTRACT; return m_restriction; } OBJECTREF GetDeclarativeRestrictions() { LIMITED_METHOD_CONTRACT; return m_DeclarativeRestrictions; } void SetImperativeAssertions(OBJECTREF assertRef) { LIMITED_METHOD_CONTRACT; SetObjectReference(&m_assertions, assertRef, this->GetAppDomain()); } void SetDeclarativeAssertions(OBJECTREF assertRef) { LIMITED_METHOD_CONTRACT; SetObjectReference(&m_DeclarativeAssertions, assertRef, this->GetAppDomain()); } void SetImperativeDenials(OBJECTREF denialRef) { LIMITED_METHOD_CONTRACT; SetObjectReference(&m_denials, denialRef, this->GetAppDomain()); } void SetDeclarativeDenials(OBJECTREF denialRef) { LIMITED_METHOD_CONTRACT; SetObjectReference(&m_DeclarativeDenials, denialRef, this->GetAppDomain()); } void SetImperativeRestrictions(OBJECTREF restrictRef) { LIMITED_METHOD_CONTRACT; SetObjectReference(&m_restriction, restrictRef, this->GetAppDomain()); } void SetDeclarativeRestrictions(OBJECTREF restrictRef) { LIMITED_METHOD_CONTRACT; SetObjectReference(&m_DeclarativeRestrictions, restrictRef, this->GetAppDomain()); } void SetAssertAllPossible(BOOL assertAllPossible) { LIMITED_METHOD_CONTRACT; m_assertAllPossible = !!assertAllPossible; } void SetAssertFT(BOOL assertFT) { LIMITED_METHOD_CONTRACT; m_assertFT = !!assertFT; } void SetDeclSecComputed(BOOL declSec) { LIMITED_METHOD_CONTRACT; m_declSecComputed = !!declSec; } }; 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 APPDOMAINREF; typedef REF MARSHALBYREFOBJECTBASEREF; typedef REF CONTEXTBASEREF; typedef REF ASSEMBLYREF; typedef REF ASSEMBLYNAMEREF; typedef REF VERSIONREF; typedef REF FRAMESECDESCREF; 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_AppDomainBaseObject APPDOMAINREF; typedef PTR_AssemblyBaseObject ASSEMBLYREF; typedef PTR_AssemblyNameBaseObject ASSEMBLYNAMEREF; typedef PTR_ContextBaseObject CONTEXTBASEREF; #ifndef DACCESS_COMPILE typedef MarshalByRefObjectBaseObject* MARSHALBYREFOBJECTBASEREF; typedef VersionBaseObject* VERSIONREF; typedef FrameSecurityDescriptorBaseObject* FRAMESECDESCREF; 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); class TransparentProxyObject : public Object { friend class MscorlibBinder; friend class CheckAsmOffsets; public: MethodTable * GetMethodTableBeingProxied() { LIMITED_METHOD_CONTRACT; return _pMT; } void SetMethodTableBeingProxied(MethodTable * pMT) { LIMITED_METHOD_CONTRACT; _pMT = pMT; } MethodTable * GetInterfaceMethodTable() { LIMITED_METHOD_CONTRACT; return _pInterfaceMT; } void SetInterfaceMethodTable(MethodTable * pInterfaceMT) { LIMITED_METHOD_CONTRACT; _pInterfaceMT = pInterfaceMT; } void * GetStub() { LIMITED_METHOD_CONTRACT; return _stub; } void SetStub(void * pStub) { LIMITED_METHOD_CONTRACT; _stub = pStub; } OBJECTREF GetStubData() { LIMITED_METHOD_CONTRACT; return _stubData; } void SetStubData(OBJECTREF stubData) { LIMITED_METHOD_CONTRACT; SetObjectReference(&_stubData, stubData, GetAppDomain()); } OBJECTREF GetRealProxy() { LIMITED_METHOD_CONTRACT; return _rp; } void SetRealProxy(OBJECTREF realProxy) { LIMITED_METHOD_CONTRACT; SetObjectReference(&_rp, realProxy, GetAppDomain()); } static int GetOffsetOfRP() { LIMITED_METHOD_CONTRACT; return offsetof(TransparentProxyObject, _rp); } protected: TransparentProxyObject() {LIMITED_METHOD_CONTRACT;}; // don't instantiate this class directly ~TransparentProxyObject(){LIMITED_METHOD_CONTRACT;}; private: OBJECTREF _rp; OBJECTREF _stubData; MethodTable* _pMT; MethodTable* _pInterfaceMT; void* _stub; }; #ifdef USE_CHECKED_OBJECTREFS typedef REF TRANSPARENTPROXYREF; #else typedef TransparentProxyObject* TRANSPARENTPROXYREF; #endif class RealProxyObject : public Object { friend class MscorlibBinder; public: DWORD GetOptFlags() { LIMITED_METHOD_CONTRACT; return _optFlags; } VOID SetOptFlags(DWORD flags) { LIMITED_METHOD_CONTRACT; _optFlags = flags; } DWORD GetDomainID() { LIMITED_METHOD_CONTRACT; return _domainID; } TRANSPARENTPROXYREF GetTransparentProxy() { LIMITED_METHOD_CONTRACT; return (TRANSPARENTPROXYREF&)_tp; } void SetTransparentProxy(TRANSPARENTPROXYREF tp) { LIMITED_METHOD_CONTRACT; SetObjectReference(&_tp, (OBJECTREF)tp, GetAppDomain()); } static int GetOffsetOfIdentity() { LIMITED_METHOD_CONTRACT; return offsetof(RealProxyObject, _identity); } static int GetOffsetOfServerObject() { LIMITED_METHOD_CONTRACT; return offsetof(RealProxyObject, _serverObject); } static int GetOffsetOfServerIdentity() { LIMITED_METHOD_CONTRACT; return offsetof(RealProxyObject, _srvIdentity); } protected: RealProxyObject() { LIMITED_METHOD_CONTRACT; }; // don't instantiate this class directly ~RealProxyObject(){ LIMITED_METHOD_CONTRACT; }; private: OBJECTREF _tp; OBJECTREF _identity; OBJECTREF _serverObject; DWORD _flags; DWORD _optFlags; DWORD _domainID; OBJECTHANDLE _srvIdentity; }; #ifdef USE_CHECKED_OBJECTREFS typedef REF REALPROXYREF; #else typedef RealProxyObject* REALPROXYREF; #endif #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 StringBufferObject; #ifdef USE_CHECKED_OBJECTREFS typedef REF STRINGBUFFERREF; #else // USE_CHECKED_OBJECTREFS typedef StringBufferObject * STRINGBUFFERREF; #endif // USE_CHECKED_OBJECTREFS // // StringBufferObject // // Note that the "copy on write" bit is buried within the implementation // of the object in order to make the implementation smaller. // class StringBufferObject : public Object { friend class MscorlibBinder; private: CHARARRAYREF m_ChunkChars; StringBufferObject *m_ChunkPrevious; UINT32 m_ChunkLength; UINT32 m_ChunkOffset; INT32 m_MaxCapacity; WCHAR* GetBuffer() { LIMITED_METHOD_CONTRACT; return (WCHAR *)m_ChunkChars->GetDirectPointerToNonObjectElements(); } // This function assumes that requiredLength will be less // than the max capacity of the StringBufferObject DWORD GetAllocationLength(DWORD dwRequiredLength) { LIMITED_METHOD_CONTRACT; _ASSERTE((INT32)dwRequiredLength <= m_MaxCapacity); DWORD dwCurrentLength = GetArrayLength(); // round the current length to the nearest multiple of 2 // that is >= the required length if(dwCurrentLength < dwRequiredLength) { dwCurrentLength = (dwRequiredLength + 1) & ~1; } return dwCurrentLength; } protected: StringBufferObject() { LIMITED_METHOD_CONTRACT; }; ~StringBufferObject() { LIMITED_METHOD_CONTRACT; }; public: INT32 GetMaxCapacity() { return m_MaxCapacity; } DWORD GetArrayLength() { LIMITED_METHOD_CONTRACT; _ASSERTE(m_ChunkChars); return m_ChunkOffset + m_ChunkChars->GetNumComponents(); } // Given an ANSI string, use it to replace the StringBufferObject's internal buffer VOID ReplaceBufferWithAnsi(CHARARRAYREF *newArrayRef, __in CHAR *newChars, DWORD dwNewCapacity) { #ifndef DACCESS_COMPILE SetObjectReference((OBJECTREF *)&m_ChunkChars, (OBJECTREF)(*newArrayRef), GetAppDomain()); #endif //!DACCESS_COMPILE WCHAR *thisChars = GetBuffer(); // NOTE: This call to MultiByte also writes out the null terminator // which is currently part of the String representation. INT32 ncWritten = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, newChars, -1, (LPWSTR)thisChars, dwNewCapacity+1); if (ncWritten == 0) { // Normally, we'd throw an exception if the string couldn't be converted. // In this particular case, we paper over it instead. The reason is // that most likely reason a P/Invoke-called api returned a // poison string is that the api failed for some reason, and hence // exercised its right to leave the buffer in a poison state. // Because P/Invoke cannot discover if an api failed, it cannot // know to ignore the buffer on the out marshaling path. // Because normal P/Invoke procedure is for the caller to check error // codes manually, we don't want to throw an exception on him. // We certainly don't want to randomly throw or not throw based on the // nondeterministic contents of a buffer passed to a failing api. *thisChars = W('\0'); ncWritten++; } m_ChunkOffset = 0; m_ChunkLength = ncWritten-1; m_ChunkPrevious = NULL; } // Given a Unicode string, use it to replace the StringBufferObject's internal buffer VOID ReplaceBuffer(CHARARRAYREF *newArrayRef, __in_ecount(dwNewCapacity) WCHAR *newChars, DWORD dwNewCapacity) { CONTRACTL { NOTHROW; GC_NOTRIGGER; SO_TOLERANT; MODE_COOPERATIVE; } CONTRACTL_END; #ifndef DACCESS_COMPILE SetObjectReference((OBJECTREF *)&m_ChunkChars, (OBJECTREF)(*newArrayRef), GetAppDomain()); #endif //!DACCESS_COMPILE WCHAR *thisChars = GetBuffer(); memcpyNoGCRefs(thisChars, newChars, sizeof(WCHAR)*dwNewCapacity); thisChars[dwNewCapacity] = W('\0'); m_ChunkLength = dwNewCapacity; m_ChunkPrevious = NULL; m_ChunkOffset = 0; } static void ReplaceBuffer(STRINGBUFFERREF *thisRef, __in_ecount(newLength) WCHAR *newBuffer, INT32 newLength); static void ReplaceBufferAnsi(STRINGBUFFERREF *thisRef, __in_ecount(newCapacity) CHAR *newBuffer, INT32 newCapacity); static INT32 LocalIndexOfString(__in_ecount(strLength) WCHAR *base, __in_ecount(patternLength) WCHAR *search, int strLength, int patternLength, int startPos); }; 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. #ifdef _DEBUG STRINGREF m_debugStackTrace; // Where we allocated this SafeHandle #endif 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; } BOOL OwnsHandle() const { LIMITED_METHOD_CONTRACT; return m_ownsHandle; } static size_t GetHandleOffset() { LIMITED_METHOD_CONTRACT; return offsetof(SafeHandle, m_handle); } void AddRef(); void Release(bool fDispose = false); void Dispose(); void SetHandle(LPVOID handle); static FCDECL1(void, DisposeNative, SafeHandle* refThisUNSAFE); static FCDECL1(void, Finalize, SafeHandle* refThisUNSAFE); static FCDECL1(void, SetHandleAsInvalid, SafeHandle* refThisUNSAFE); static FCDECL2(void, DangerousAddRef, SafeHandle* refThisUNSAFE, CLR_BOOL *pfSuccess); static FCDECL1(void, DangerousRelease, SafeHandle* refThisUNSAFE); }; // SAFEHANDLEREF defined above because CompressedStackObject needs it 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. #ifdef _DEBUG STRINGREF m_debugStackTrace; // Where we allocated this CriticalHandle #endif 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); }; class ReflectClassBaseObject; class SafeBuffer : SafeHandle { private: size_t m_numBytes; public: static FCDECL1(UINT, SizeOfType, ReflectClassBaseObject* typeUNSAFE); static FCDECL1(UINT, AlignedSizeOfType, ReflectClassBaseObject* typeUNSAFE); static FCDECL3_IVI(void, PtrToStructure, BYTE* ptr, FC_TypedByRef structure, UINT32 sizeofT); static FCDECL3_VII(void, StructureToPtr, FC_TypedByRef structure, BYTE* ptr, UINT32 sizeofT); }; #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 WaitHandleNative; friend class MscorlibBinder; public: __inline LPVOID GetWaitHandle() {LIMITED_METHOD_CONTRACT; return m_handle;} __inline SAFEHANDLEREF GetSafeHandle() {LIMITED_METHOD_CONTRACT; return m_safeHandle;} private: SAFEHANDLEREF m_safeHandle; LPVOID m_handle; CLR_BOOL m_hasThreadAffinity; }; #ifdef USE_CHECKED_OBJECTREFS typedef REF WAITHANDLEREF; #else // USE_CHECKED_OBJECTREFS typedef WaitHandleBase* WAITHANDLEREF; #endif // USE_CHECKED_OBJECTREFS // This class corresponds to FileStreamAsyncResult on the managed side. class AsyncResultBase :public Object { friend class MscorlibBinder; public: WAITHANDLEREF GetWaitHandle() { LIMITED_METHOD_CONTRACT; return _waitHandle;} void SetErrorCode(int errcode) { LIMITED_METHOD_CONTRACT; _errorCode = errcode;} void SetNumBytes(int numBytes) { LIMITED_METHOD_CONTRACT; _numBytes = numBytes;} void SetIsComplete() { LIMITED_METHOD_CONTRACT; _isComplete = TRUE; } void SetCompletedAsynchronously() { LIMITED_METHOD_CONTRACT; _completedSynchronously = FALSE; } // README: // If you modify the order of these fields, make sure to update the definition in // BCL for this object. private: OBJECTREF _userCallback; OBJECTREF _userStateObject; WAITHANDLEREF _waitHandle; SAFEHANDLEREF _fileHandle; // For cancellation. LPOVERLAPPED _overlapped; int _EndXxxCalled; // Whether we've called EndXxx already. int _numBytes; // number of bytes read OR written int _errorCode; int _numBufferedBytes; CLR_BOOL _isWrite; // Whether this is a read or a write CLR_BOOL _isComplete; CLR_BOOL _completedSynchronously; // Which thread called callback }; #ifdef USE_CHECKED_OBJECTREFS typedef REF ASYNCRESULTREF; #else // USE_CHECKED_OBJECTREFS typedef AsyncResultBase* ASYNCRESULTREF; #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, GetAppDomain()); } 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, GetAppDomain()); } 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, GetAppDomain()); } // 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; }; #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; SO_TOLERANT; 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); void AppendSkipLast(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); StackTraceArray & operator=(StackTraceArray const & rhs) { WRAPPER_NO_CONTRACT; StackTraceArray copy(rhs); this->Swap(copy); return *this; } 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; SetObjectReferenceUnchecked(&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, GetAppDomain()); } 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, GetAppDomain()); } STRINGREF GetMessage() { LIMITED_METHOD_DAC_CONTRACT; return _message; } void SetStackTraceString(STRINGREF stackTraceString) { WRAPPER_NO_CONTRACT; SetObjectReference((OBJECTREF*)&_stackTraceString, (OBJECTREF)stackTraceString, GetAppDomain()); } 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, GetAppDomain()); } void SetSource(STRINGREF source) { WRAPPER_NO_CONTRACT; SetObjectReference((OBJECTREF*)&_source, (OBJECTREF)source, GetAppDomain()); } void ClearStackTraceForThrow() { WRAPPER_NO_CONTRACT; SetObjectReferenceUnchecked((OBJECTREF*)&_remoteStackTraceString, NULL); SetObjectReferenceUnchecked((OBJECTREF*)&_stackTrace, NULL); SetObjectReferenceUnchecked((OBJECTREF*)&_stackTraceString, NULL); } void ClearStackTracePreservingRemoteStackTrace() { WRAPPER_NO_CONTRACT; SetObjectReferenceUnchecked((OBJECTREF*)&_stackTrace, NULL); SetObjectReferenceUnchecked((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, GetAppDomain()); } // 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: STRINGREF _className; //Needed for serialization. OBJECTREF _exceptionMethod; //Needed for serialization. STRINGREF _exceptionMethodString; //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. IN_WIN64(void* _xptrs;) IN_WIN64(UINT_PTR _ipForWatsonBuckets;) // Contains the IP of exception for watson bucketing INT32 _remoteStackIndex; INT32 _HResult; IN_WIN32(void* _xptrs;) INT32 _xcode; IN_WIN32(UINT_PTR _ipForWatsonBuckets;) // Contains the IP of exception for watson bucketing }; // 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 IN_WIN64(INT32 _Kind;) STRINGREF _UserMessage; STRINGREF _Condition; IN_WIN32(INT32 _Kind;) }; #include "poppack.h" #ifdef USE_CHECKED_OBJECTREFS typedef REF CONTRACTEXCEPTIONREF; #else // USE_CHECKED_OBJECTREFS typedef PTR_ContractExceptionObject CONTRACTEXCEPTIONREF; #endif // USE_CHECKED_OBJECTREFS class NumberFormatInfo: public Object { public: // C++ data members // Corresponding data member in NumberFormatInfo.cs // Also update mscorlib.h when you add/remove fields I4ARRAYREF cNumberGroup; // numberGroupSize I4ARRAYREF cCurrencyGroup; // currencyGroupSize I4ARRAYREF cPercentGroup; // percentGroupSize STRINGREF sPositive; // positiveSign STRINGREF sNegative; // negativeSign STRINGREF sNumberDecimal; // numberDecimalSeparator STRINGREF sNumberGroup; // numberGroupSeparator STRINGREF sCurrencyGroup; // currencyDecimalSeparator STRINGREF sCurrencyDecimal; // currencyGroupSeparator STRINGREF sCurrency; // currencySymbol STRINGREF sNaN; // nanSymbol STRINGREF sPositiveInfinity; // positiveInfinitySymbol STRINGREF sNegativeInfinity; // negativeInfinitySymbol STRINGREF sPercentDecimal; // percentDecimalSeparator STRINGREF sPercentGroup; // percentGroupSeparator STRINGREF sPercent; // percentSymbol STRINGREF sPerMille; // perMilleSymbol PTRARRAYREF sNativeDigits; // nativeDigits (a string array) INT32 cNumberDecimals; // numberDecimalDigits INT32 cCurrencyDecimals; // currencyDecimalDigits INT32 cPosCurrencyFormat; // positiveCurrencyFormat INT32 cNegCurrencyFormat; // negativeCurrencyFormat INT32 cNegativeNumberFormat; // negativeNumberFormat INT32 cPositivePercentFormat; // positivePercentFormat INT32 cNegativePercentFormat; // negativePercentFormat INT32 cPercentDecimals; // percentDecimalDigits INT32 iDigitSubstitution; // digitSubstitution CLR_BOOL bIsReadOnly; // Is this NumberFormatInfo ReadOnly? CLR_BOOL bIsInvariant; // Is this the NumberFormatInfo for the Invariant Culture? }; typedef NumberFormatInfo * NUMFMTREF; //=============================================================================== // #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 #endif // _OBJECT_H_