diff options
Diffstat (limited to 'src/vm/object.inl')
-rw-r--r-- | src/vm/object.inl | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/src/vm/object.inl b/src/vm/object.inl new file mode 100644 index 0000000000..5698321993 --- /dev/null +++ b/src/vm/object.inl @@ -0,0 +1,301 @@ +// 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.INL +// +// Definitions inline functions of a Com+ Object +// + + +#ifndef _OBJECT_INL_ +#define _OBJECT_INL_ + +#include "object.h" + +inline PTR_VOID Object::UnBox() // if it is a value class, get the pointer to the first field +{ + LIMITED_METHOD_DAC_CONTRACT; + _ASSERTE(GetMethodTable()->IsValueType()); + _ASSERTE(!Nullable::IsNullableType(TypeHandle(GetMethodTable()))); + + return dac_cast<PTR_BYTE>(this) + sizeof(*this); +} + +inline ADIndex Object::GetAppDomainIndex() +{ + WRAPPER_NO_CONTRACT; +#ifndef _DEBUG + // ok to cast to AppDomain because we know it's a real AppDomain if it's not shared + if (!GetGCSafeMethodTable()->IsDomainNeutral()) + return (dac_cast<PTR_AppDomain>(GetGCSafeMethodTable()->GetDomain())->GetIndex()); +#endif + return GetHeader()->GetAppDomainIndex(); +} + +inline DWORD Object::GetNumComponents() +{ + LIMITED_METHOD_DAC_CONTRACT; + // Yes, we may not even be an array, which means we are reading some of the object's memory - however, + // ComponentSize will multiply out this value. Therefore, m_NumComponents must be the first field in + // ArrayBase. + return dac_cast<PTR_ArrayBase>(this)->m_NumComponents; +} + +inline SIZE_T Object::GetSize() +{ + LIMITED_METHOD_DAC_CONTRACT; + + // mask the alignment bits because this methos is called during GC + MethodTable *mT = GetGCSafeMethodTable(); + + // strings have component size2, all other non-arrays should have 0 + _ASSERTE(( mT->GetComponentSize() <= 2) || mT->IsArray()); + + size_t s = mT->GetBaseSize(); + if (mT->HasComponentSize()) + s += (size_t)GetNumComponents() * mT->RawGetComponentSize(); + return s; +} + +__forceinline /*static*/ SIZE_T StringObject::GetSize(DWORD strLen) +{ + LIMITED_METHOD_DAC_CONTRACT; + + // Extra WCHAR for null terminator + return ObjSizeOf(StringObject) + sizeof(WCHAR) + strLen * sizeof(WCHAR); +} + +#ifdef DACCESS_COMPILE + +inline void Object::EnumMemoryRegions(void) +{ + SUPPORTS_DAC; + + PTR_MethodTable methodTable = GetGCSafeMethodTable(); + + TADDR ptr = dac_cast<TADDR>(this) - sizeof(ObjHeader); + SIZE_T size = sizeof(ObjHeader) + sizeof(Object); + + // If it is unsafe to touch the MethodTable so just enumerate + // the base object. + if (methodTable.IsValid()) + { + size = sizeof(ObjHeader) + GetSize(); + } + +#if defined (_DEBUG) + // Test hook: when testing on debug builds, we want an easy way to test that the following while + // correctly terminates in the face of ridiculous stuff from the target. + if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DumpGeneration_IntentionallyCorruptDataFromTarget) == 1) + { + // Pretend all objects are incredibly large. + size |= 0xf0000000; + } +#endif // defined (_DEBUG) + + // Unfortunately, DacEnumMemoryRegion takes only ULONG32 as size argument + while (size > 0) { + // Use 0x10000000 instead of MAX_ULONG32 so that the chunks stays aligned + SIZE_T chunk = min(size, 0x10000000); + // If for any reason we can't enumerate the memory, stop. This would generally mean + // that we have target corruption, or that the target is executing, etc. + if (!DacEnumMemoryRegion(ptr, chunk)) + break; + ptr += chunk; size -= chunk; + } + + // As an Object is very low-level don't propagate + // the enumeration to the MethodTable. +} + +#endif // #ifdef DACCESS_COMPILE + + +inline TypeHandle ArrayBase::GetTypeHandle() const +{ + WRAPPER_NO_CONTRACT; + return GetTypeHandle(GetMethodTable()); +} + +inline /* static */ TypeHandle ArrayBase::GetTypeHandle(MethodTable * pMT) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + FORBID_FAULT; + SO_TOLERANT; + SUPPORTS_DAC; + } + CONTRACTL_END + + _ASSERTE(pMT != NULL); + + // This ensures that we can always get the typehandle for an object in hand + // without triggering the noisy parts of the loader. + // + // The debugger can cause this routine to be called on an unmanaged thread + // so this really is important. + ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); + + CorElementType kind = pMT->GetInternalCorElementType(); + unsigned rank = pMT->GetRank(); + // Note that this load should always succeed because there is an invariant that + // if we have allocated an array object of type T then the ArrayTypeDesc + // for T[] is available and restored + + // @todo This should be turned into a probe with a hard SO when we have one + CONTRACT_VIOLATION(SOToleranceViolation); + // == FailIfNotLoadedOrNotRestored + TypeHandle arrayType = ClassLoader::LoadArrayTypeThrowing(pMT->GetApproxArrayElementTypeHandle(), kind, rank, ClassLoader::DontLoadTypes); + CONSISTENCY_CHECK(!arrayType.IsNull()); + return(arrayType); +} + + // Get the CorElementType for the elements in the array. Avoids creating a TypeHandle +inline CorElementType ArrayBase::GetArrayElementType() const +{ + WRAPPER_NO_CONTRACT; + return GetMethodTable()->GetArrayElementType(); +} + +inline unsigned ArrayBase::GetRank() const +{ + WRAPPER_NO_CONTRACT; + return GetMethodTable()->GetRank(); +} + +// Total element count for the array +inline DWORD ArrayBase::GetNumComponents() const +{ + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + return m_NumComponents; +} + +inline /* static */ unsigned ArrayBase::GetDataPtrOffset(MethodTable* pMT) +{ + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; +#if !defined(DACCESS_COMPILE) + _ASSERTE(pMT->IsArray()); +#endif // DACCESS_COMPILE + // The -sizeof(ObjHeader) is because of the sync block, which is before "this" + return pMT->GetBaseSize() - sizeof(ObjHeader); +} + +inline /* static */ unsigned ArrayBase::GetBoundsOffset(MethodTable* pMT) +{ + WRAPPER_NO_CONTRACT; + _ASSERTE(pMT->IsArray()); + if (!pMT->IsMultiDimArray()) + return(offsetof(ArrayBase, m_NumComponents)); + _ASSERTE(pMT->GetInternalCorElementType() == ELEMENT_TYPE_ARRAY); + return sizeof(ArrayBase); +} +inline /* static */ unsigned ArrayBase::GetLowerBoundsOffset(MethodTable* pMT) +{ + LIMITED_METHOD_CONTRACT; + _ASSERTE(pMT->IsArray()); + // There is no good offset for this for a SZARRAY. + _ASSERTE(pMT->GetInternalCorElementType() == ELEMENT_TYPE_ARRAY); + // Lower bounds info is after total bounds info + // and total bounds info has rank elements + return GetBoundsOffset(pMT) + + dac_cast<PTR_ArrayClass>(pMT->GetClass())->GetRank() * + sizeof(INT32); +} + +// Get the element type for the array, this works whether the the element +// type is stored in the array or not +inline TypeHandle ArrayBase::GetArrayElementTypeHandle() const +{ + STATIC_CONTRACT_SO_TOLERANT; + STATIC_CONTRACT_NOTHROW; + STATIC_CONTRACT_GC_NOTRIGGER; + STATIC_CONTRACT_FORBID_FAULT; + STATIC_CONTRACT_SUPPORTS_DAC; + + return GetGCSafeMethodTable()->GetApproxArrayElementTypeHandle(); +} + +//=============================================================================== +// Returns true if this pMT is Nullable<T> for T is equivalent to paramMT + +__forceinline BOOL Nullable::IsNullableForType(TypeHandle type, MethodTable* paramMT) +{ + if (type.IsTypeDesc()) + return FALSE; + if (!type.AsMethodTable()->HasInstantiation()) // shortcut, if it is not generic it can't be Nullable<T> + return FALSE; + return Nullable::IsNullableForTypeHelper(type.AsMethodTable(), paramMT); +} + +//=============================================================================== +// Returns true if this pMT is Nullable<T> for T == paramMT + +__forceinline BOOL Nullable::IsNullableForTypeNoGC(TypeHandle type, MethodTable* paramMT) +{ + if (type.IsTypeDesc()) + return FALSE; + if (!type.AsMethodTable()->HasInstantiation()) // shortcut, if it is not generic it can't be Nullable<T> + return FALSE; + return Nullable::IsNullableForTypeHelperNoGC(type.AsMethodTable(), paramMT); +} + +//=============================================================================== +// Returns true if this type is Nullable<T> for some T. + +inline BOOL Nullable::IsNullableType(TypeHandle type) +{ + WRAPPER_NO_CONTRACT; + SUPPORTS_DAC; + + if (type.IsTypeDesc()) + return FALSE; + + return type.AsMethodTable()->IsNullable(); +} + +inline TypeHandle Object::GetTypeHandle() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + FORBID_FAULT; + SO_TOLERANT; + SUPPORTS_DAC; + } + CONTRACTL_END + + _ASSERTE(m_pMethTab == GetGCSafeMethodTable()); + + if (m_pMethTab->IsArray()) + return (dac_cast<PTR_ArrayBase>(this))->GetTypeHandle(); + else + return TypeHandle(m_pMethTab); +} + +inline TypeHandle Object::GetGCSafeTypeHandle() const +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SO_TOLERANT; + MODE_ANY; + } + CONTRACTL_END; + + MethodTable * pMT = GetGCSafeMethodTable(); + _ASSERTE(pMT != NULL); + + if (pMT->IsArray()) + return ArrayBase::GetTypeHandle(pMT); + else + return TypeHandle(pMT); +} + +#endif // _OBJECT_INL_ |