//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
//
// File: methodimpl.cpp
//
//
//
// ============================================================================
#include "common.h"
#include "methodimpl.h"
DWORD MethodImpl::FindSlotIndex(DWORD slot)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
PRECONDITION(CheckPointer(GetSlots()));
} CONTRACTL_END;
DWORD dwSize = GetSize();
if(dwSize == 0) {
return INVALID_INDEX;
}
// Simple binary search
PTR_DWORD rgSlots = GetSlots();
INT32 l = 0;
INT32 r = dwSize - 1;
INT32 pivot;
while(1) {
pivot = (l + r) / 2;
if(rgSlots[pivot] == slot) {
break; // found it
}
else if(rgSlots[pivot] < slot) {
l = pivot + 1;
}
else {
r = pivot - 1;
}
if(l > r) {
return INVALID_INDEX; // Not here
}
}
CONSISTENCY_CHECK(pivot >= 0);
return (DWORD)pivot;
}
PTR_MethodDesc MethodImpl::FindMethodDesc(DWORD slot, PTR_MethodDesc defaultReturn)
{
CONTRACTL
{
if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
MODE_ANY;
}
CONTRACTL_END
DWORD slotIndex = FindSlotIndex(slot);
if (slotIndex == INVALID_INDEX) {
return defaultReturn;
}
PTR_MethodDesc result = pImplementedMD[slotIndex]; // The method descs are not offset by one
// Prejitted images may leave NULL in this table if
// the methoddesc is declared in another module.
// In this case we need to manually compute & restore it
// from the slot number.
if (result == NULL)
#ifndef DACCESS_COMPILE
result = RestoreSlot(slotIndex, defaultReturn->GetMethodTable());
#else // DACCESS_COMPILE
DacNotImpl();
#endif // DACCESS_COMPILE
return result;
}
#ifndef DACCESS_COMPILE
MethodDesc *MethodImpl::RestoreSlot(DWORD index, MethodTable *pMT)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
FORBID_FAULT;
PRECONDITION(CheckPointer(pdwSlots));
}
CONTRACTL_END
MethodDesc *result;
PREFIX_ASSUME(pdwSlots != NULL);
DWORD slot = GetSlots()[index];
// Since the overridden method is in a different module, we
// are guaranteed that it is from a different class. It is
// either an override of a parent virtual method or parent-implemented
// interface, or of an interface that this class has introduced.
// In the former 2 cases, the slot number will be in the parent's
// vtable section, and we can retrieve the implemented MethodDesc from
// there. In the latter case, we can search through our interface
// map to determine which interface it is from.
MethodTable *pParentMT = pMT->GetParentMethodTable();
CONSISTENCY_CHECK(pParentMT != NULL && slot < pParentMT->GetNumVirtuals());
{
result = pParentMT->GetMethodDescForSlot(slot);
}
_ASSERTE(result != NULL);
// Don't worry about races since we would all be setting the same result
if (EnsureWritableExecutablePagesNoThrow(&pImplementedMD[index], sizeof(pImplementedMD[index])))
pImplementedMD[index] = result;
return result;
}
///////////////////////////////////////////////////////////////////////////////////////
void MethodImpl::SetSize(LoaderHeap *pHeap, AllocMemTracker *pamTracker, DWORD size)
{
CONTRACTL {
THROWS;
GC_NOTRIGGER;
PRECONDITION(CheckPointer(this));
PRECONDITION(pdwSlots==NULL && pImplementedMD==NULL);
INJECT_FAULT(ThrowOutOfMemory());
} CONTRACTL_END;
if(size > 0) {
// An array of DWORDs, the first entry representing count, and the rest representing slot numbers
S_SIZE_T cbCountAndSlots = S_SIZE_T(sizeof(DWORD)) + // DWORD for the total count of slots
S_SIZE_T(size) * S_SIZE_T(sizeof(DWORD)); // DWORD each for the slot numbers
// MethodDesc* for each of the implemented methods
S_SIZE_T cbMethodDescs = S_SIZE_T(size) * S_SIZE_T(sizeof(MethodDesc *));
// Need to align-up the slot entries so that the MethodDesc* array starts on a pointer boundary.
cbCountAndSlots.AlignUp(sizeof(MethodDesc*));
S_SIZE_T cbTotal = cbCountAndSlots + cbMethodDescs;
if(cbCountAndSlots.IsOverflow())
ThrowOutOfMemory();
// Allocate the memory.
LPBYTE pAllocData = (BYTE*)pamTracker->Track(pHeap->AllocMem(cbTotal));
// Set the count and slot array
pdwSlots = (DWORD*)pAllocData;
// Set the MethodDesc* array. Make sure to adjust for alignment.
pImplementedMD = (MethodDesc**)ALIGN_UP(pAllocData + cbCountAndSlots.Value(), sizeof(MethodDesc*));
// Store the count in the first entry
*pdwSlots = size;
}
}
///////////////////////////////////////////////////////////////////////////////////////
void MethodImpl::SetData(DWORD* slots, MethodDesc** md)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
PRECONDITION(CheckPointer(this));
PRECONDITION(CheckPointer(pdwSlots));
} CONTRACTL_END;
DWORD dwSize = *pdwSlots;
memcpy(&(pdwSlots[1]), slots, dwSize*sizeof(DWORD));
memcpy(pImplementedMD, md, dwSize*sizeof(MethodDesc*));
}
#ifdef FEATURE_NATIVE_IMAGE_GENERATION
void MethodImpl::Save(DataImage *image)
{
STANDARD_VM_CONTRACT;
DWORD size = GetSize();
_ASSERTE(size > 0);
image->StoreStructure(pdwSlots, (size+1)*sizeof(DWORD),
DataImage::ITEM_METHOD_DESC_COLD,
sizeof(DWORD));
image->StoreStructure(pImplementedMD, size*sizeof(MethodDesc*),
DataImage::ITEM_METHOD_DESC_COLD,
sizeof(MethodDesc*));
}
void MethodImpl::Fixup(DataImage *image, PVOID p, SSIZE_T offset)
{
STANDARD_VM_CONTRACT;
DWORD size = GetSize();
_ASSERTE(size > 0);
for (DWORD iMD = 0; iMD < size; iMD++)
{
// Why not use FixupMethodDescPointer?
// Does it matter if the MethodDesc needs a restore?
MethodDesc * pMD = pImplementedMD[iMD];
if (image->CanEagerBindToMethodDesc(pMD) &&
image->CanHardBindToZapModule(pMD->GetLoaderModule()))
{
image->FixupPointerField(pImplementedMD, iMD * sizeof(MethodDesc *));
}
else
{
image->ZeroPointerField(pImplementedMD, iMD * sizeof(MethodDesc *));
}
}
image->FixupPointerField(p, offset + offsetof(MethodImpl, pdwSlots));
image->FixupPointerField(p, offset + offsetof(MethodImpl, pImplementedMD));
}
#endif // FEATURE_NATIVE_IMAGE_GENERATION
#endif //!DACCESS_COMPILE
#ifdef DACCESS_COMPILE
void
MethodImpl::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
{
SUPPORTS_DAC;
#ifndef STUB_DISPATCH_ALL
CONSISTENCY_CHECK_MSG(FALSE, "Stub Dispatch forbidden code");
#else // STUB_DISPATCH_ALL
// 'this' memory should already be enumerated as
// part of the base MethodDesc.
if (pdwSlots.IsValid() && GetSize())
{
ULONG32 numSlots = GetSize();
DacEnumMemoryRegion(dac_cast(pdwSlots),
(numSlots + 1) * sizeof(DWORD));
if (pImplementedMD.IsValid())
{
DacEnumMemoryRegion(dac_cast(pImplementedMD),
numSlots * sizeof(PTR_MethodDesc));
for (DWORD i = 0; i < numSlots; i++)
{
PTR_MethodDesc methodDesc = pImplementedMD[i];
if (methodDesc.IsValid())
{
methodDesc->EnumMemoryRegions(flags);
}
}
}
}
#endif // STUB_DISPATCH_ALL
}
#endif //DACCESS_COMPILE
#ifndef DACCESS_COMPILE
MethodImpl::Iterator::Iterator(MethodDesc *pMD) : m_pMD(pMD), m_pImpl(NULL), m_iCur(0)
{
LIMITED_METHOD_CONTRACT;
if (pMD->IsMethodImpl())
{
m_pImpl = pMD->GetMethodImpl();
}
}
#endif //!DACCESS_COMPILE