summaryrefslogtreecommitdiff
path: root/src/vm/methodimpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/methodimpl.cpp')
-rw-r--r--src/vm/methodimpl.cpp285
1 files changed, 285 insertions, 0 deletions
diff --git a/src/vm/methodimpl.cpp b/src/vm/methodimpl.cpp
new file mode 100644
index 0000000000..1779c2de89
--- /dev/null
+++ b/src/vm/methodimpl.cpp
@@ -0,0 +1,285 @@
+// 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: 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++)
+ {
+ // <TODO> Why not use FixupMethodDescPointer? </TODO>
+ // <TODO> Does it matter if the MethodDesc needs a restore? </TODO>
+
+ 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<TADDR>(pdwSlots),
+ (numSlots + 1) * sizeof(DWORD));
+
+ if (pImplementedMD.IsValid())
+ {
+ DacEnumMemoryRegion(dac_cast<TADDR>(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
+