diff options
Diffstat (limited to 'src/vm/field.cpp')
-rw-r--r-- | src/vm/field.cpp | 1024 |
1 files changed, 1024 insertions, 0 deletions
diff --git a/src/vm/field.cpp b/src/vm/field.cpp new file mode 100644 index 0000000000..da424db038 --- /dev/null +++ b/src/vm/field.cpp @@ -0,0 +1,1024 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// =========================================================================== +// File: Field.cpp +// + +// =========================================================================== +// This file contains the implementation for FieldDesc methods. +// =========================================================================== +// + + +#include "common.h" + +#include "encee.h" +#include "field.h" +#ifdef FEATURE_REMOTING +#include "remoting.h" +#endif +#include "generics.h" + +#include "peimagelayout.inl" + +// called from code:MethodTableBuilder::InitializeFieldDescs#InitCall +VOID FieldDesc::Init(mdFieldDef mb, CorElementType FieldType, DWORD dwMemberAttrs, BOOL fIsStatic, BOOL fIsRVA, BOOL fIsThreadLocal, BOOL fIsContextLocal, LPCSTR pszFieldName) +{ + LIMITED_METHOD_CONTRACT; + + // We allow only a subset of field types here - all objects must be set to TYPE_CLASS + // By-value classes are ELEMENT_TYPE_VALUETYPE + _ASSERTE( + FieldType == ELEMENT_TYPE_I1 || + FieldType == ELEMENT_TYPE_BOOLEAN || + FieldType == ELEMENT_TYPE_U1 || + FieldType == ELEMENT_TYPE_I2 || + FieldType == ELEMENT_TYPE_U2 || + FieldType == ELEMENT_TYPE_CHAR || + FieldType == ELEMENT_TYPE_I4 || + FieldType == ELEMENT_TYPE_U4 || + FieldType == ELEMENT_TYPE_I8 || + FieldType == ELEMENT_TYPE_I || + FieldType == ELEMENT_TYPE_U || + FieldType == ELEMENT_TYPE_U8 || + FieldType == ELEMENT_TYPE_R4 || + FieldType == ELEMENT_TYPE_R8 || + FieldType == ELEMENT_TYPE_CLASS || + FieldType == ELEMENT_TYPE_VALUETYPE || + FieldType == ELEMENT_TYPE_PTR || + FieldType == ELEMENT_TYPE_FNPTR + ); + _ASSERTE(fIsStatic || (!fIsRVA && !fIsThreadLocal && !fIsContextLocal)); + _ASSERTE(fIsRVA + fIsThreadLocal + fIsContextLocal <= 1); + + m_requiresFullMbValue = 0; + SetMemberDef(mb); + + m_type = FieldType; + m_prot = fdFieldAccessMask & dwMemberAttrs; + m_isStatic = fIsStatic != 0; + m_isRVA = fIsRVA != 0; + m_isThreadLocal = fIsThreadLocal != 0; +#ifdef FEATURE_REMOTING + m_isContextLocal = fIsContextLocal != 0; +#endif + +#ifdef _DEBUG + m_debugName = (LPUTF8)pszFieldName; +#endif + +#if CHECK_APP_DOMAIN_LEAKS + m_isDangerousAppDomainAgileField = 0; +#endif + + _ASSERTE(GetMemberDef() == mb); // no truncation + _ASSERTE(GetFieldType() == FieldType); + _ASSERTE(GetFieldProtection() == (fdFieldAccessMask & dwMemberAttrs)); + _ASSERTE((BOOL) IsStatic() == (fIsStatic != 0)); +} + +// Return whether the field is a GC ref type +BOOL FieldDesc::IsObjRef() +{ + WRAPPER_NO_CONTRACT; + SUPPORTS_DAC; + return CorTypeInfo::IsObjRef_NoThrow(GetFieldType()); +} + +#ifndef DACCESS_COMPILE +void FieldDesc::PrecomputeNameHash() +{ + CONTRACTL + { + STANDARD_VM_CHECK; + PRECONDITION(IsCompilationProcess()); + } + CONTRACTL_END; + + // We only have space for the name hash when we can use the packed mb layout + if (m_requiresFullMbValue) + { + return; + } + + // Store a case-insensitive hash so that we can use this value for + // both case-sensitive and case-insensitive name lookups + SString name(SString::Utf8Literal, GetName()); + ULONG nameHashValue = name.HashCaseInsensitive() & enum_packedMbLayout_NameHashMask; + + // We should never overwrite any other bits + _ASSERTE((m_mb & enum_packedMbLayout_NameHashMask) == 0 || + (m_mb & enum_packedMbLayout_NameHashMask) == nameHashValue); + + m_mb |= nameHashValue; +} +#endif + +BOOL FieldDesc::MightHaveName(ULONG nameHashValue) +{ + LIMITED_METHOD_CONTRACT; + + g_IBCLogger.LogFieldDescsAccess(this); + + // We only have space for a name hash when we are using the packed mb layout + if (m_requiresFullMbValue) + { + return TRUE; + } + + ULONG thisHashValue = m_mb & enum_packedMbLayout_NameHashMask; + + // A zero value might mean no hash has ever been set + // (checking this way is better than dedicating a bit to tell us) + if (thisHashValue == 0) + { + return TRUE; + } + + ULONG testHashValue = nameHashValue & enum_packedMbLayout_NameHashMask; + + return (thisHashValue == testHashValue); +} + +#ifndef DACCESS_COMPILE //we don't require DAC to special case simple types +// Return the type of the field, as a class, but only if it's loaded. +TypeHandle FieldDesc::LookupFieldTypeHandle(ClassLoadLevel level, BOOL dropGenericArgumentLevel) +{ + + CONTRACTL + { + INSTANCE_CHECK; + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + FORBID_FAULT; + SO_TOLERANT; + } + CONTRACTL_END + + // This function is called during GC promotion. + ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); + + // Caller should have handled all the non-class cases, already. + _ASSERTE(GetFieldType() == ELEMENT_TYPE_CLASS || + GetFieldType() == ELEMENT_TYPE_VALUETYPE); + + MetaSig sig(this); + CorElementType type; + + type = sig.NextArg(); + + // This may be the real type which includes other things + // beside class and value class such as arrays + _ASSERTE(type == ELEMENT_TYPE_CLASS || + type == ELEMENT_TYPE_VALUETYPE || + type == ELEMENT_TYPE_STRING || + type == ELEMENT_TYPE_SZARRAY || + type == ELEMENT_TYPE_VAR + ); + + // == FailIfNotLoaded, can also assert that the thing is restored + TypeHandle th = NULL; + + BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), return NULL); + { + th = sig.GetLastTypeHandleThrowing(ClassLoader::DontLoadTypes, level, dropGenericArgumentLevel); + } + END_SO_INTOLERANT_CODE; + + return th; +} +#else //simplified version +TypeHandle FieldDesc::LookupFieldTypeHandle(ClassLoadLevel level, BOOL dropGenericArgumentLevel) +{ + WRAPPER_NO_CONTRACT; + MetaSig sig(this); + CorElementType type; + type = sig.NextArg(); + return sig.GetLastTypeHandleThrowing(ClassLoader::DontLoadTypes, level, dropGenericArgumentLevel); +} +#endif //DACCESS_COMPILE + +TypeHandle FieldDesc::GetFieldTypeHandleThrowing(ClassLoadLevel level/*=CLASS_LOADED*/, + BOOL dropGenericArgumentLevel /*=FALSE*/) +{ + WRAPPER_NO_CONTRACT; + + MetaSig sig(this); + sig.NextArg(); + + return sig.GetLastTypeHandleThrowing(ClassLoader::LoadTypes, level, dropGenericArgumentLevel); +} + +#ifndef DACCESS_COMPILE + +void* FieldDesc::GetStaticAddress(void *base) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SO_TOLERANT; + MODE_ANY; // Needed by profiler and server GC + } + CONTRACTL_END; + + void* ret = GetStaticAddressHandle(base); // Get the handle + + // For value classes, the handle points at an OBJECTREF + // which holds the boxed value class, so derefernce and unbox. + if (GetFieldType() == ELEMENT_TYPE_VALUETYPE && !IsRVA()) + { + OBJECTREF obj = ObjectToOBJECTREF(*(Object**) ret); + ret = obj->GetData(); + } + return ret; +} + +MethodTable * FieldDesc::GetExactDeclaringType(MethodTable * ownerOrSubType) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SO_TOLERANT; + MODE_ANY; + } + CONTRACTL_END; + + MethodTable * pMT = GetApproxEnclosingMethodTable(); + + // Fast path for typical case. + if (ownerOrSubType == pMT) + return pMT; + + return ownerOrSubType->GetMethodTableMatchingParentClass(pMT); +} + +#endif // #ifndef DACCESS_COMPILE + + // static value classes are actually stored in their boxed form. + // this means that their address moves. +PTR_VOID FieldDesc::GetStaticAddressHandle(PTR_VOID base) +{ + + CONTRACTL + { + INSTANCE_CHECK; + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + FORBID_FAULT; + SO_TOLERANT; + PRECONDITION(IsStatic()); + PRECONDITION(GetEnclosingMethodTable()->IsRestored_NoLogging()); + } + CONTRACTL_END + + g_IBCLogger.LogFieldDescsAccess(this); + + _ASSERTE(IsStatic()); +#ifdef EnC_SUPPORTED + if (IsEnCNew()) + { + EnCFieldDesc * pFD = dac_cast<PTR_EnCFieldDesc>(this); + _ASSERTE_IMPL(pFD->GetApproxEnclosingMethodTable()->SanityCheck()); + _ASSERTE(pFD->GetModule()->IsEditAndContinueEnabled()); + + EditAndContinueModule *pModule = (EditAndContinueModule*)pFD->GetModule(); + _ASSERTE(pModule->IsEditAndContinueEnabled()); + + PTR_VOID retVal = NULL; + + // BEGIN_SO_INTOLERANT_CODE will throw if we don't have enough stack + // and GetStaticAddressHandle has no failure semantics, so we need + // to just do the SO policy (e.g. rip the appdomain or process). + CONTRACT_VIOLATION(ThrowsViolation) + +#ifdef DACCESS_COMPILE + DacNotImpl(); +#else + BEGIN_SO_INTOLERANT_CODE(GetThread()); + { + GCX_COOP(); + // This routine doesn't have a failure semantic - but Resolve*Field(...) does. + // Something needs to be rethought here and I think it's E&C. + CONTRACT_VIOLATION(ThrowsViolation|FaultViolation|GCViolation); //B#25680 (Fix Enc violations) + retVal = (void *)(pModule->ResolveOrAllocateField(NULL, pFD)); + } + END_SO_INTOLERANT_CODE; +#endif // !DACCESS_COMPILE + return retVal; + } +#endif // EnC_SUPPORTED + + + if (IsRVA()) + { + Module* pModule = GetModule(); + PTR_VOID ret = pModule->GetRvaField(GetOffset(), IsZapped()); + + _ASSERTE(!pModule->IsPEFile() || !pModule->IsRvaFieldTls(GetOffset())); + + return(ret); + } + + CONSISTENCY_CHECK(CheckPointer(base)); + + PTR_VOID ret = PTR_VOID(dac_cast<PTR_BYTE>(base) + GetOffset()); + + + return ret; +} + + +#ifndef CROSSGEN_COMPILE + +// These routines encapsulate the operation of getting and setting +// fields. +void FieldDesc::GetInstanceField(OBJECTREF o, VOID * pOutVal) +{ + CONTRACTL + { + INSTANCE_CHECK; + if (FORBIDGC_LOADER_USE_ENABLED() ) NOTHROW; else THROWS; + if (FORBIDGC_LOADER_USE_ENABLED() ) GC_NOTRIGGER; else GC_TRIGGERS; + MODE_ANY; + if (FORBIDGC_LOADER_USE_ENABLED() ) FORBID_FAULT; else INJECT_FAULT(COMPlusThrowOM();); + } + CONTRACTL_END + + // We know that it isn't going to be null here. Tell PREFIX that we know it. + PREFIX_ASSUME(o != NULL); + + // Check whether we are getting a field value on a proxy. If so, then ask + // remoting services to extract the value from the instance. +#ifdef FEATURE_REMOTING + if (o->IsTransparentProxy()) + { +#ifndef DACCESS_COMPILE + o = CRemotingServices::GetObjectFromProxy(o); + + if (o->IsTransparentProxy()) + { +#ifdef PROFILING_SUPPORTED + + GCPROTECT_BEGIN(o); // protect from RemotingClientInvocationStarted + + // If profiling is active, notify it that remoting stuff is kicking in, + // if AlwaysUnwrap returned an identical object pointer which means that + // we are definitely going through remoting for this access. + { + BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); + { + GCX_PREEMP(); + g_profControlBlock.pProfInterface->RemotingClientInvocationStarted(); + } + END_PIN_PROFILER(); + } +#endif // PROFILING_SUPPORTED + + CRemotingServices::FieldAccessor(this, o, pOutVal, TRUE); + +#ifdef PROFILING_SUPPORTED + { + BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); + { + GCX_PREEMP(); + g_profControlBlock.pProfInterface->RemotingClientInvocationFinished(); + } + END_PIN_PROFILER(); + } + + GCPROTECT_END(); // protect from RemotingClientInvocationStarted + +#endif // PROFILING_SUPPORTED + + return; + } +#else + DacNotImpl(); +#endif // #ifndef DACCESS_COMPILE + } +#endif // FEATURE_REMOTING + + // Unbox the value class + TADDR pFieldAddress = (TADDR)GetInstanceAddress(o); + UINT cbSize = GetSize(); + + switch (cbSize) + { + case 1: + *(INT8*)pOutVal = VolatileLoad<INT8>(PTR_INT8(pFieldAddress)); + break; + + case 2: + *(INT16*)pOutVal = VolatileLoad<INT16>(PTR_INT16(pFieldAddress)); + break; + + case 4: + *(INT32*)pOutVal = VolatileLoad<INT32>(PTR_INT32(pFieldAddress)); + break; + + case 8: + *(INT64*)pOutVal = VolatileLoad<INT64>(PTR_INT64(pFieldAddress)); + break; + + default: + UNREACHABLE(); + break; + } +} + +#ifndef DACCESS_COMPILE +void FieldDesc::SetInstanceField(OBJECTREF o, const VOID * pInVal) +{ + CONTRACTL + { + INSTANCE_CHECK; + THROWS; + GC_TRIGGERS; + MODE_ANY; + INJECT_FAULT(COMPlusThrowOM();); + } + CONTRACTL_END + + + // Check whether we are setting a field value on a proxy or a marshalbyref + // class. If so, then ask remoting services to set the value on the + // instance + +#ifdef FEATURE_REMOTING + if(o->IsTransparentProxy()) + { + o = CRemotingServices::GetObjectFromProxy(o); + + if (o->IsTransparentProxy()) + { +#ifdef PROFILING_SUPPORTED + + GCPROTECT_BEGIN(o); + + // If profiling is active, notify it that remoting stuff is kicking in, + // if AlwaysUnwrap returned an identical object pointer which means that + // we are definitely going through remoting for this access. + + { + BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); + { + GCX_PREEMP(); + g_profControlBlock.pProfInterface->RemotingClientInvocationStarted(); + } + END_PIN_PROFILER(); + } +#endif // PROFILING_SUPPORTED + + CRemotingServices::FieldAccessor(this, o, (void *)pInVal, FALSE); + +#ifdef PROFILING_SUPPORTED + { + BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); + { + GCX_PREEMP(); + g_profControlBlock.pProfInterface->RemotingClientInvocationFinished(); + } + END_PIN_PROFILER(); + } + GCPROTECT_END(); + +#endif // PROFILING_SUPPORTED + + return; + } + } +#endif // FEATURE_REMOTING + +#ifdef _DEBUG + // + // assert that o is derived from MT of enclosing class + // + // walk up o's inheritence chain to make sure m_pMTOfEnclosingClass is along it + // + MethodTable* pCursor = o->GetMethodTable(); + + //<TODO>@todo : work out exactly why instantiations aren't matching; probably + // because of approx loads on field types in the loader</TODO> + while (pCursor && (GetApproxEnclosingMethodTable()->HasSameTypeDefAs(pCursor))) + { + pCursor = pCursor->GetParentMethodTable(); + } + _ASSERTE(pCursor != NULL); +#endif // _DEBUG + + // Unbox the value class + LPVOID pFieldAddress = GetInstanceAddress(o); + + CorElementType fieldType = GetFieldType(); + + if (fieldType == ELEMENT_TYPE_CLASS) + { + OBJECTREF ref = ObjectToOBJECTREF(*(Object**)pInVal); + + SetObjectReference((OBJECTREF*)pFieldAddress, ref, + o->GetAppDomain()); + } + else if (fieldType == ELEMENT_TYPE_VALUETYPE) + { + CONSISTENCY_CHECK(!LookupFieldTypeHandle().IsNull()); + // The Approximate MT is enough to do the copy + CopyValueClass(pFieldAddress, + (void*)pInVal, + LookupFieldTypeHandle().GetMethodTable(), + o->GetAppDomain()); + } + else + { + UINT cbSize = LoadSize(); + + switch (cbSize) + { + case 1: + VolatileStore<INT8>((INT8*)pFieldAddress, *(INT8*)pInVal); + break; + + case 2: + VolatileStore<INT16>((INT16*)pFieldAddress, *(INT16*)pInVal); + break; + + case 4: + VolatileStore<INT32>((INT32*)pFieldAddress, *(INT32*)pInVal); + break; + + case 8: + VolatileStore<INT64>((INT64*)pFieldAddress, *(INT64*)pInVal); + break; + + default: + UNREACHABLE(); + break; + } + } +} +#endif // #ifndef DACCESS_COMPILE + + +// This function is used for BYREF support of fields. Since it generates +// interior pointers, you really have to watch the lifetime of the pointer +// so that GCs don't happen while you have the reference active +PTR_VOID FieldDesc::GetAddressNoThrowNoGC(PTR_VOID o) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_COOPERATIVE; + SO_TOLERANT; + PRECONDITION(!IsEnCNew()); + SO_TOLERANT; + SUPPORTS_DAC; + } + CONTRACTL_END; + + DWORD dwOffset = GetOffset(); + if (!IsFieldOfValueType()) + { + dwOffset += sizeof(Object); + } + return dac_cast<PTR_BYTE>(o) + dwOffset; +} + +PTR_VOID FieldDesc::GetAddress(PTR_VOID o) +{ + CONTRACTL + { + if(IsEnCNew()) {THROWS;} else {DISABLED(THROWS);}; + if(IsEnCNew()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}; + SUPPORTS_DAC; + } + CONTRACTL_END; + +#ifdef DACCESS_COMPILE + _ASSERTE(!IsEnCNew()); // when we call this while finding an EnC field via the DAC, + // the field desc is for the EnCHelper, not the new EnC field +#endif + g_IBCLogger.LogFieldDescsAccess(this); + +#if defined(EnC_SUPPORTED) && !defined(DACCESS_COMPILE) + // EnC added fields aren't at a simple offset like normal fields. + if (IsEnCNew()) + { + // We'll have to go through some effort to compute the address of this field. + return ((EnCFieldDesc *)this)->GetAddress(o); + } +#endif // defined(EnC_SUPPORTED) && !defined(DACCESS_COMPILE) + return GetAddressNoThrowNoGC(o); +} + +void *FieldDesc::GetInstanceAddress(OBJECTREF o) +{ + CONTRACTL + { + if(IsEnCNew()) {THROWS;} else {DISABLED(THROWS);}; + if(IsEnCNew()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}; + } + CONTRACTL_END; + + g_IBCLogger.LogFieldDescsAccess(this); + + DWORD dwOffset = m_dwOffset; // GetOffset() + +#ifdef EnC_SUPPORTED + // EnC added fields aren't at a simple offset like normal fields. + if (dwOffset == FIELD_OFFSET_NEW_ENC) // IsEnCNew() + { + // We'll have to go through some effort to compute the address of this field. + return ((EnCFieldDesc *)this)->GetAddress(OBJECTREFToObject(o)); + } +#endif + + return (void *) (dac_cast<TADDR>(o->GetData()) + dwOffset); +} + +// And here's the equivalent, when you are guaranteed that the enclosing instance of +// the field is in the GC Heap. So if the enclosing instance is a value type, it had +// better be boxed. We ASSERT this. +void *FieldDesc::GetAddressGuaranteedInHeap(void *o) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_COOPERATIVE; + SO_TOLERANT; + } + CONTRACTL_END; + + _ASSERTE(!IsEnCNew()); + + return ((BYTE*)(o)) + sizeof(Object) + m_dwOffset; +} + + +DWORD FieldDesc::GetValue32(OBJECTREF o) +{ + WRAPPER_NO_CONTRACT; + + DWORD val; + GetInstanceField(o, (LPVOID)&val); + return val; +} + +#ifndef DACCESS_COMPILE +VOID FieldDesc::SetValue32(OBJECTREF o, DWORD dwValue) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + } + CONTRACTL_END; + + SetInstanceField(o, (LPVOID)&dwValue); +} +#endif // #ifndef DACCESS_COMPILE + +void* FieldDesc::GetValuePtr(OBJECTREF o) +{ + WRAPPER_NO_CONTRACT; + + void* val; + GetInstanceField(o, (LPVOID)&val); + return val; +} + +#ifndef DACCESS_COMPILE +VOID FieldDesc::SetValuePtr(OBJECTREF o, void* pValue) +{ + WRAPPER_NO_CONTRACT; + + SetInstanceField(o, (LPVOID)&pValue); +} +#endif // #ifndef DACCESS_COMPILE + +OBJECTREF FieldDesc::GetRefValue(OBJECTREF o) +{ + WRAPPER_NO_CONTRACT; + + OBJECTREF val = NULL; + +#ifdef PROFILING_SUPPORTED + GCPROTECT_BEGIN(val); +#endif + + GetInstanceField(o, (LPVOID)&val); + +#ifdef PROFILING_SUPPORTED + GCPROTECT_END(); +#endif + + return val; +} + +#ifndef DACCESS_COMPILE +VOID FieldDesc::SetRefValue(OBJECTREF o, OBJECTREF orValue) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + } + CONTRACTL_END; + VALIDATEOBJECTREF(o); + VALIDATEOBJECTREF(orValue); + + SetInstanceField(o, (LPVOID)&orValue); +} +#endif // #ifndef DACCESS_COMPILE + +USHORT FieldDesc::GetValue16(OBJECTREF o) +{ + WRAPPER_NO_CONTRACT; + + USHORT val; + GetInstanceField(o, (LPVOID)&val); + return val; +} + +#ifndef DACCESS_COMPILE +VOID FieldDesc::SetValue16(OBJECTREF o, DWORD dwValue) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + } + CONTRACTL_END; + + USHORT val = (USHORT)dwValue; + SetInstanceField(o, (LPVOID)&val); +} +#endif // #ifndef DACCESS_COMPILE + +BYTE FieldDesc::GetValue8(OBJECTREF o) +{ + WRAPPER_NO_CONTRACT; + + BYTE val; + GetInstanceField(o, (LPVOID)&val); + return val; + +} + +#ifndef DACCESS_COMPILE +VOID FieldDesc::SetValue8(OBJECTREF o, DWORD dwValue) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + } + CONTRACTL_END; + + BYTE val = (BYTE)dwValue; + SetInstanceField(o, (LPVOID)&val); +} +#endif // #ifndef DACCESS_COMPILE + +__int64 FieldDesc::GetValue64(OBJECTREF o) +{ + WRAPPER_NO_CONTRACT; + __int64 val; + GetInstanceField(o, (LPVOID)&val); + return val; + +} + +#ifndef DACCESS_COMPILE +VOID FieldDesc::SetValue64(OBJECTREF o, __int64 value) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + } + CONTRACTL_END; + SetInstanceField(o, (LPVOID)&value); +} +#endif // #ifndef DACCESS_COMPILE + +#endif // !CROSSGEN_COMPILE + + +#ifndef DACCESS_COMPILE + +#ifdef FEATURE_NATIVE_IMAGE_GENERATION +void FieldDesc::SaveContents(DataImage *image) +{ + STANDARD_VM_CONTRACT; + +#ifdef _DEBUG + if (m_debugName && !image->IsStored((void*) m_debugName)) + image->StoreStructure((void *) m_debugName, + (ULONG)(strlen(m_debugName) + 1), + DataImage::ITEM_DEBUG, + 1); +#endif + + // + // If we are compiling an IL only image, and our RVA fits + // in the designated range, copy the RVA data over to the prejit + // image. + // + + if (IsILOnlyRVAField()) + { + // + // Move the RVA data into the prejit image. + // + + UINT size = LoadSize(); + + // + // Compute an alignment for the data based on the alignment + // of the RVA. We'll align up to 8 bytes. + // + + UINT align = 1; + DWORD rva = GetOffset(); + DWORD rvaTemp = rva; + + while ((rvaTemp&1) == 0 && align < 8 && align < size) + { + align <<= 1; + rvaTemp >>= 1; + } + + image->StoreRvaInfo(this, + rva, + size, + align); + } +} + +void FieldDesc::Fixup(DataImage *image) +{ + STANDARD_VM_CONTRACT; + + LOG((LF_ZAP, LL_INFO10000, "FieldDesc::Fixup %s::%s\n", GetApproxEnclosingMethodTable()->GetDebugClassName(), m_debugName)); + image->FixupRelativePointerField(this, offsetof(FieldDesc, m_pMTOfEnclosingClass)); + +#ifdef _DEBUG + image->FixupPointerField(this, offsetof(FieldDesc, m_debugName)); +#endif + + // if (IsRVAFieldWithLessThanBigOffset()) + // { + // offset of RVA fields is fixed up in DataImage::FixupRvaStructure + // } +} +#endif // FEATURE_NATIVE_IMAGE_GENERATION + +#endif // #ifndef DACCESS_COMPILE + +UINT FieldDesc::LoadSize() +{ + CONTRACTL + { + INSTANCE_CHECK; + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END + + CorElementType type = GetFieldType(); + UINT size = GetSizeForCorElementType(type); + if (size == (UINT) -1) + { + // LOG((LF_CLASSLOADER, LL_INFO10000, "FieldDesc::LoadSize %s::%s\n", GetApproxEnclosingMethodTable()->GetDebugClassName(), m_debugName)); + CONSISTENCY_CHECK(GetFieldType() == ELEMENT_TYPE_VALUETYPE); + size = GetApproxFieldTypeHandleThrowing().GetMethodTable()->GetNumInstanceFieldBytes(); + } + + return size; +} + +UINT FieldDesc::GetSize() +{ + CONTRACTL + { + INSTANCE_CHECK; + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + FORBID_FAULT; + } + CONTRACTL_END + + CorElementType type = GetFieldType(); + UINT size = GetSizeForCorElementType(type); + if (size == (UINT) -1) + { + LOG((LF_CLASSLOADER, LL_INFO10000, "FieldDesc::GetSize %s::%s\n", GetApproxEnclosingMethodTable()->GetDebugClassName(), m_debugName)); + CONSISTENCY_CHECK(GetFieldType() == ELEMENT_TYPE_VALUETYPE); + TypeHandle t = LookupApproxFieldTypeHandle(); + if (!t.IsNull()) + { + size = t.GetMethodTable()->GetNumInstanceFieldBytes(); + } + } + + return size; +} + +// See field.h for details +Instantiation FieldDesc::GetExactClassInstantiation(TypeHandle possibleObjType) +{ + WRAPPER_NO_CONTRACT; + + // We know that it isn't going to be null here. Tell PREFIX that we know it. + PREFIX_ASSUME(GetApproxEnclosingMethodTable()!=NULL); + if (possibleObjType.IsNull()) + { + return GetApproxEnclosingMethodTable()->GetInstantiation(); + } + else + { + PREFIX_ASSUME(GetApproxEnclosingMethodTable()!=NULL); + return possibleObjType.GetInstantiationOfParentClass(GetApproxEnclosingMethodTable()); + } +} + +// Given, { List<String>, List<__Canon>._items } where _items is of type T[], +// it returns String[]. + +TypeHandle FieldDesc::GetExactFieldType(TypeHandle owner) +{ + CONTRACT(TypeHandle) + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + PRECONDITION(CheckPointer(owner, NULL_OK)); + POSTCONDITION(CheckPointer(RETVAL)); + } + CONTRACT_END + + if (GetApproxEnclosingMethodTable() == owner.AsMethodTable()) + { + //Yes, this is exactly the type I was looking for. + RETURN(GetFieldTypeHandleThrowing()); + } + else + { + //This FieldDesc doesn't exactly represent the owner type. Go look up the exact type. + + // We need to figure out the precise type of the field. + // First, get the signature of the field + PCCOR_SIGNATURE pSig; + DWORD cSig; + GetSig(&pSig, &cSig); + SigPointer sig(pSig, cSig); + + // Get the generics information + SigTypeContext sigTypeContext(GetExactClassInstantiation(owner), Instantiation()); + + TypeHandle thApproxFieldType = GetApproxFieldTypeHandleThrowing(); + // Load the exact type + RETURN (sig.GetTypeHandleThrowing(thApproxFieldType.GetModule(), &sigTypeContext)); + } +} + +#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) +REFLECTFIELDREF FieldDesc::GetStubFieldInfo() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + MODE_COOPERATIVE; + } + CONTRACTL_END; + + REFLECTFIELDREF retVal; + REFLECTFIELDREF fieldRef = (REFLECTFIELDREF)AllocateObject(MscorlibBinder::GetClass(CLASS__STUBFIELDINFO)); + GCPROTECT_BEGIN(fieldRef); + + fieldRef->SetField(this); + LoaderAllocator *pLoaderAllocatorOfMethod = this->GetApproxEnclosingMethodTable()->GetLoaderAllocator(); + if (pLoaderAllocatorOfMethod->IsCollectible()) + fieldRef->SetKeepAlive(pLoaderAllocatorOfMethod->GetExposedObject()); + + retVal = fieldRef; + GCPROTECT_END(); + + return retVal; +} +#endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE |