value.stubLookup.runtimeLookup.indirections = (DWORD)pResult->stubLookup.runtimeLookup.indirections;
value.stubLookup.runtimeLookup.testForNull = (DWORD)pResult->stubLookup.runtimeLookup.testForNull;
value.stubLookup.runtimeLookup.testForFixup = (DWORD)pResult->stubLookup.runtimeLookup.testForFixup;
+ value.stubLookup.runtimeLookup.indirectFirstOffset = (DWORD)pResult->stubLookup.runtimeLookup.indirectFirstOffset;
for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
value.stubLookup.runtimeLookup.offsets[i] = (DWORDLONG)pResult->stubLookup.runtimeLookup.offsets[i];
}
value.stubLookup.runtimeLookup.indirections = (DWORD)0;
value.stubLookup.runtimeLookup.testForNull = (DWORD)0;
value.stubLookup.runtimeLookup.testForFixup = (DWORD)0;
+ value.stubLookup.runtimeLookup.indirectFirstOffset = (DWORD)0;
for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
value.stubLookup.runtimeLookup.offsets[i] = (DWORDLONG)0;
pResult->stubLookup.runtimeLookup.indirections = (WORD)value.stubLookup.runtimeLookup.indirections;
pResult->stubLookup.runtimeLookup.testForNull = value.stubLookup.runtimeLookup.testForNull != 0;
pResult->stubLookup.runtimeLookup.testForFixup = value.stubLookup.runtimeLookup.testForFixup != 0;
+ pResult->stubLookup.runtimeLookup.indirectFirstOffset = value.stubLookup.runtimeLookup.indirectFirstOffset != 0;
for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
pResult->stubLookup.runtimeLookup.offsets[i] = (SIZE_T)value.stubLookup.runtimeLookup.offsets[i];
}
value.lookup.runtimeLookup.indirections = (DWORD)pResult->lookup.runtimeLookup.indirections;
value.lookup.runtimeLookup.testForNull = (DWORD)pResult->lookup.runtimeLookup.testForNull;
value.lookup.runtimeLookup.testForFixup = (DWORD)pResult->lookup.runtimeLookup.testForFixup;
+ value.lookup.runtimeLookup.indirectFirstOffset = (DWORD)pResult->lookup.runtimeLookup.indirectFirstOffset;
for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
value.lookup.runtimeLookup.offsets[i] = (DWORDLONG)pResult->lookup.runtimeLookup.offsets[i];
}
value.lookup.runtimeLookup.indirections = (DWORD)0;
value.lookup.runtimeLookup.testForNull = (DWORD)0;
value.lookup.runtimeLookup.testForFixup = (DWORD)0;
+ value.lookup.runtimeLookup.indirectFirstOffset = (DWORD)0;
for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
value.lookup.runtimeLookup.offsets[i] = (DWORDLONG)0;
// copy the constLookup view of the union
pResult->lookup.runtimeLookup.indirections = (WORD)value.lookup.runtimeLookup.indirections;
pResult->lookup.runtimeLookup.testForNull = value.lookup.runtimeLookup.testForNull != 0;
pResult->lookup.runtimeLookup.testForFixup = value.lookup.runtimeLookup.testForFixup != 0;
+ pResult->lookup.runtimeLookup.indirectFirstOffset = value.lookup.runtimeLookup.indirectFirstOffset != 0;
for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
pResult->lookup.runtimeLookup.offsets[i] = (size_t)value.lookup.runtimeLookup.offsets[i];
}
DWORD testForNull;
DWORD testForFixup;
DWORDLONG offsets[CORINFO_MAXINDIRECTIONS];
+ DWORD indirectFirstOffset;
};
struct Agnostic_CORINFO_CONST_LOOKUP
{
if( !CHECK_OPT(METHODDESCS) )
CoverageReadString( dac_cast<TADDR>(ndmd->GetLibNameRaw()) );
- PTR_NDirectWriteableData wnd( nd->m_pWriteableData );
+ PTR_NDirectWriteableData wnd( ndmd->GetWriteableData() );
DisplayStartStructureWithOffset( m_pWriteableData,
DPtrToPreferredAddr(wnd),
sizeof(*wnd),
}
//now handle the contents of the m_pMethInst/m_pPerInstInfo union.
unsigned numSlots = imd->m_wNumGenericArgs;
- PTR_Dictionary inst(imd->m_pPerInstInfo);
+ PTR_Dictionary inst(imd->IMD_GetMethodDictionary());
unsigned dictSize;
if( kind == InstantiatedMethodDesc::SharedMethodInstantiation )
{
bool testForFixup;
SIZE_T offsets[CORINFO_MAXINDIRECTIONS];
+
+ // If set, first offset is indirect.
+ // 0 means that value stored at first offset (offsets[0]) from pointer is next pointer, to which the next offset
+ // (offsets[1]) is added and so on.
+ // 1 means that value stored at first offset (offsets[0]) from pointer is offset1, and the next pointer is
+ // stored at pointer+offsets[0]+offset1.
+ bool indirectFirstOffset;
} ;
// Result of calling embedGenericHandle
class RelativePointer
{
public:
+
+ static constexpr bool isRelative = true;
+ typedef PTR_TYPE type;
+
#ifndef DACCESS_COMPILE
RelativePointer()
{
class FixupPointer
{
public:
+
+ static constexpr bool isRelative = false;
+ typedef PTR_TYPE type;
+
// Returns whether the encoded pointer is NULL.
BOOL IsNull() const
{
class RelativeFixupPointer
{
public:
+
+ static constexpr bool isRelative = true;
+ typedef PTR_TYPE type;
+
// Implicit copy/move is not allowed
RelativeFixupPointer<PTR_TYPE>(const RelativeFixupPointer<PTR_TYPE> &) =delete;
RelativeFixupPointer<PTR_TYPE>(RelativeFixupPointer<PTR_TYPE> &&) =delete;
// Fixup used for RelativePointer
#define IMAGE_REL_BASED_RelativePointer IMAGE_REL_BASED_RELPTR
-#else // FEATURE_PREJIT
+#endif // FEATURE_PREJIT
//----------------------------------------------------------------------------
// PlainPointer is simple pointer wrapper to support compilation without indirections
class PlainPointer
{
public:
+
+ static constexpr bool isRelative = false;
+ typedef PTR_TYPE type;
+
// Returns whether the encoded pointer is NULL.
BOOL IsNull() const
{
TADDR m_ptr;
};
+#ifndef FEATURE_PREJIT
+
#define FixupPointer PlainPointer
#define RelativePointer PlainPointer
#define RelativeFixupPointer PlainPointer
-#endif // FEATURE_PREJIT
+#endif // !FEATURE_PREJIT
//----------------------------------------------------------------------------
// RelativePointer32 is pointer encoded as relative 32-bit offset. It is used
class RelativePointer32
{
public:
+
+ static constexpr bool isRelative = true;
+ typedef PTR_TYPE type;
+
// Returns whether the encoded pointer is NULL.
BOOL IsNull() const
{
INT32 m_delta;
};
+template<bool isMaybeNull, typename T, typename PT>
+typename PT::type
+ReadPointer(const T *base, const PT T::* pPointerFieldMember)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ uintptr_t offset = (uintptr_t) &(base->*pPointerFieldMember) - (uintptr_t) base;
+
+ if (isMaybeNull)
+ {
+ return PT::GetValueMaybeNullAtPtr(dac_cast<TADDR>(base) + offset);
+ }
+ else
+ {
+ return PT::GetValueAtPtr(dac_cast<TADDR>(base) + offset);
+ }
+}
+
+template<typename T, typename PT>
+typename PT::type
+ReadPointerMaybeNull(const T *base, const PT T::* pPointerFieldMember)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return ReadPointer<true>(base, pPointerFieldMember);
+}
+
+template<typename T, typename PT>
+typename PT::type
+ReadPointer(const T *base, const PT T::* pPointerFieldMember)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return ReadPointer<false>(base, pPointerFieldMember);
+}
+
+template<bool isMaybeNull, typename T, typename C, typename PT>
+typename PT::type
+ReadPointer(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ const PT *ptr = &(base->*pFirstPointerFieldMember.*pSecondPointerFieldMember);
+ uintptr_t offset = (uintptr_t) ptr - (uintptr_t) base;
+
+ if (isMaybeNull)
+ {
+ return PT::GetValueMaybeNullAtPtr(dac_cast<TADDR>(base) + offset);
+ }
+ else
+ {
+ return PT::GetValueAtPtr(dac_cast<TADDR>(base) + offset);
+ }
+}
+
+template<typename T, typename C, typename PT>
+typename PT::type
+ReadPointerMaybeNull(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return ReadPointer<true>(base, pFirstPointerFieldMember, pSecondPointerFieldMember);
+}
+
+template<typename T, typename C, typename PT>
+typename PT::type
+ReadPointer(const T *base, const C T::* pFirstPointerFieldMember, const PT C::* pSecondPointerFieldMember)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return ReadPointer<false>(base, pFirstPointerFieldMember, pSecondPointerFieldMember);
+}
+
#endif //_FIXUPPOINTER_H
nullptr DEBUGARG("impRuntimeLookup slot"));
}
+ GenTreePtr indOffTree = nullptr;
+
// Applied repeated indirections
for (WORD i = 0; i < pRuntimeLookup->indirections; i++)
{
+ if (i == 1 && pRuntimeLookup->indirectFirstOffset)
+ {
+ indOffTree = impCloneExpr(slotPtrTree, &slotPtrTree, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL,
+ nullptr DEBUGARG("impRuntimeLookup indirectFirstOffset"));
+ }
+
if (i != 0)
{
slotPtrTree = gtNewOperNode(GT_IND, TYP_I_IMPL, slotPtrTree);
slotPtrTree->gtFlags |= GTF_IND_NONFAULTING;
slotPtrTree->gtFlags |= GTF_IND_INVARIANT;
}
+
+ if (i == 1 && pRuntimeLookup->indirectFirstOffset)
+ {
+ slotPtrTree = gtNewOperNode(GT_ADD, TYP_I_IMPL, indOffTree, slotPtrTree);
+ }
+
if (pRuntimeLookup->offsets[i] != 0)
{
slotPtrTree =
//pcsEmit->EmitCALL(METHOD__STUBHELPERS__GET_NDIRECT_TARGET, 1, 1);
pcsEmit->EmitLDC(offsetof(NDirectMethodDesc, ndirect.m_pWriteableData));
pcsEmit->EmitADD();
+
+ if (decltype(NDirectMethodDesc::ndirect.m_pWriteableData)::isRelative)
+ {
+ pcsEmit->EmitDUP();
+ }
+
pcsEmit->EmitLDIND_I();
+
+ if (decltype(NDirectMethodDesc::ndirect.m_pWriteableData)::isRelative)
+ {
+ pcsEmit->EmitADD();
+ }
+
pcsEmit->EmitLDIND_I();
}
}
S_SIZE_T dwAllocSize = S_SIZE_T(numTyPars) * S_SIZE_T(sizeof(TypeHandle));
// the memory allocated for m_pMethInst will be freed if the declaring type fails to load
- m_pPerInstInfo = (Dictionary *) pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(dwAllocSize));
+ m_pPerInstInfo.SetValue((Dictionary *) pamTracker->Track(pAllocator->GetLowFrequencyHeap()->AllocMem(dwAllocSize)));
- TypeHandle * pInstDest = (TypeHandle *)m_pPerInstInfo;
+ TypeHandle * pInstDest = (TypeHandle *) IMD_GetMethodDictionaryNonNull();
for(unsigned int i = 0; i < numTyPars; i++)
{
hEnumTyPars.EnumNext(&tkTyPar);
m_pWrappedMethodDesc.SetValue(wrappedMD);
m_wFlags2 = WrapperStubWithInstantiations | (m_wFlags2 & ~KindMask);
- m_pPerInstInfo = (Dictionary*)pInst;
+ m_pPerInstInfo.SetValueMaybeNull((Dictionary*)pInst);
_ASSERTE(FitsIn<WORD>(numGenericArgs));
m_wNumGenericArgs = static_cast<WORD>(numGenericArgs);
_ASSERTE(numGenericArgs != 0);
// Initially the dictionary layout is empty
m_wFlags2 = SharedMethodInstantiation | (m_wFlags2 & ~KindMask);
- m_pPerInstInfo = (Dictionary *)pPerInstInfo;
+ m_pPerInstInfo.SetValueMaybeNull((Dictionary *)pPerInstInfo);
_ASSERTE(FitsIn<WORD>(numGenericArgs));
m_wNumGenericArgs = static_cast<WORD>(numGenericArgs);
// The first field is never used
m_wFlags2 = UnsharedMethodInstantiation | (m_wFlags2 & ~KindMask);
- m_pPerInstInfo = (Dictionary *)pInst;
+ m_pPerInstInfo.SetValueMaybeNull((Dictionary *)pInst);
_ASSERTE(FitsIn<WORD>(numGenericArgs));
m_wNumGenericArgs = static_cast<WORD>(numGenericArgs);
CORINFO_RUNTIME_LOOKUP *pResult = &pResultLookup->runtimeLookup;
pResult->signature = NULL;
+ pResult->indirectFirstOffset = 0;
+
// Unless we decide otherwise, just do the lookup via a helper function
pResult->indirections = CORINFO_USEHELPER;
#endif
pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
+ if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
+ {
+ pResult->indirectFirstOffset = 1;
+ }
+
ULONG data;
IfFailThrow(sigptr.GetData(&data));
pResult->offsets[1] = sizeof(TypeHandle) * data;
// Indirect through dictionary table pointer in InstantiatedMethodDesc
pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
+
+ if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
+ {
+ pResult->indirectFirstOffset = 1;
+ }
}
}
}
}
- image->FixupPointerField(this, offsetof(InstantiatedMethodDesc, m_pPerInstInfo));
+ if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
+ {
+ image->FixupRelativePointerField(this, offsetof(InstantiatedMethodDesc, m_pPerInstInfo));
+ }
+ else
+ {
+ image->FixupPointerField(this, offsetof(InstantiatedMethodDesc, m_pPerInstInfo));
+ }
// Generic methods are dealt with specially to avoid encoding the formal method type parameters
if (IsTypicalMethodDefinition())
NDirectMethodDesc *pNMD = (NDirectMethodDesc *)this;
- image->FixupPointerField(this, offsetof(NDirectMethodDesc, ndirect.m_pWriteableData));
+ if (decltype(NDirectMethodDesc::ndirect.m_pWriteableData)::isRelative)
+ {
+ image->FixupRelativePointerField(this, offsetof(NDirectMethodDesc, ndirect.m_pWriteableData));
+ }
+ else
+ {
+ image->FixupPointerField(this, offsetof(NDirectMethodDesc, ndirect.m_pWriteableData));
+ }
NDirectWriteableData *pWriteableData = pNMD->GetWriteableData();
NDirectImportThunkGlue *pImportThunkGlue = pNMD->GetNDirectImportThunkGlue();
};
// The writeable part of the methoddesc.
- PTR_NDirectWriteableData m_pWriteableData;
+#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
+ RelativePointer<PTR_NDirectWriteableData> m_pWriteableData;
+#else
+ PlainPointer<PTR_NDirectWriteableData> m_pWriteableData;
+#endif
#ifdef HAS_NDIRECT_IMPORT_PRECODE
RelativePointer<PTR_NDirectImportThunkGlue> m_pImportThunkGlue;
return (ndirect.m_wFlags & kStdCallWithRetBuf) != 0;
}
- NDirectWriteableData* GetWriteableData() const
+ PTR_NDirectWriteableData GetWriteableData() const
{
- LIMITED_METHOD_CONTRACT;
+ LIMITED_METHOD_DAC_CONTRACT;
- return ndirect.m_pWriteableData;
+ return ReadPointer(this, &NDirectMethodDesc::ndirect, &decltype(NDirectMethodDesc::ndirect)::m_pWriteableData);
}
PTR_NDirectImportThunkGlue GetNDirectImportThunkGlue()
if (IMD_IsGenericMethodDefinition())
return TRUE;
else
- return m_pPerInstInfo != NULL;
+ return !m_pPerInstInfo.IsNull();
}
// All varieties of InstantiatedMethodDesc's support this method.
{
LIMITED_METHOD_DAC_CONTRACT;
- return Instantiation(m_pPerInstInfo->GetInstantiation(), m_wNumGenericArgs);
+ return Instantiation(IMD_GetMethodDictionary()->GetInstantiation(), m_wNumGenericArgs);
}
PTR_Dictionary IMD_GetMethodDictionary()
{
LIMITED_METHOD_DAC_CONTRACT;
- return m_pPerInstInfo;
+
+ return ReadPointerMaybeNull(this, &InstantiatedMethodDesc::m_pPerInstInfo);
+ }
+
+ PTR_Dictionary IMD_GetMethodDictionaryNonNull()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return ReadPointer(this, &InstantiatedMethodDesc::m_pPerInstInfo);
}
BOOL IMD_IsGenericMethodDefinition()
//
// For generic method definitions that are not the typical method definition (e.g. C<int>.m<U>)
// this field is null; to obtain the instantiation use LoadMethodInstantiation
- PTR_Dictionary m_pPerInstInfo; //SHARED
+#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
+ RelativePointer<PTR_Dictionary> m_pPerInstInfo; //SHARED
+#else
+ PlainPointer<PTR_Dictionary> m_pPerInstInfo; //SHARED
+#endif
private:
WORD m_wFlags2;
NDirectMethodDesc *pNewNMD = (NDirectMethodDesc*)pNewMD;
// Allocate writeable data
- pNewNMD->ndirect.m_pWriteableData = (NDirectWriteableData*)
- AllocateFromHighFrequencyHeap(S_SIZE_T(sizeof(NDirectWriteableData)));
+ pNewNMD->ndirect.m_pWriteableData.SetValue((NDirectWriteableData*)
+ AllocateFromHighFrequencyHeap(S_SIZE_T(sizeof(NDirectWriteableData))));
#ifdef HAS_NDIRECT_IMPORT_PRECODE
pNewNMD->ndirect.m_pImportThunkGlue.SetValue(Precode::Allocate(PRECODE_NDIRECT_IMPORT, pNewMD,
pResult->testForFixup = pResult->testForNull = false;
pResult->signature = NULL;
+
+ pResult->indirectFirstOffset = 0;
+
pResult->indirections = CORINFO_USEHELPER;
DWORD numGenericArgs = 0;
pResult->indirections = 2;
pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
+ if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
+ {
+ pResult->indirectFirstOffset = 1;
+ }
+
ULONG data;
IfFailThrow(sigptr.GetData(&data));
pResult->offsets[1] = sizeof(TypeHandle) * data;
// Indirect through dictionary table pointer in InstantiatedMethodDesc
pResult->offsets[0] = offsetof(InstantiatedMethodDesc, m_pPerInstInfo);
+ if (decltype(InstantiatedMethodDesc::m_pPerInstInfo)::isRelative)
+ {
+ pResult->indirectFirstOffset = 1;
+ }
+
*pDictionaryIndexAndSlot |= dictionarySlot;
}
}