1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5// File: methodimpl.cpp
6//
7
8
9//
10
11//
12// ============================================================================
13
14#include "common.h"
15#include "methodimpl.h"
16
17DWORD MethodImpl::FindSlotIndex(DWORD slot)
18{
19 CONTRACTL {
20 NOTHROW;
21 GC_NOTRIGGER;
22 MODE_ANY;
23 PRECONDITION(CheckPointer(GetSlots()));
24 } CONTRACTL_END;
25
26 DWORD dwSize = GetSize();
27 if(dwSize == 0) {
28 return INVALID_INDEX;
29 }
30
31 // Simple binary search
32 PTR_DWORD rgSlots = GetSlots();
33 INT32 l = 0;
34 INT32 r = dwSize - 1;
35 INT32 pivot;
36
37 while(1) {
38 pivot = (l + r) / 2;
39
40 if(rgSlots[pivot] == slot) {
41 break; // found it
42 }
43 else if(rgSlots[pivot] < slot) {
44 l = pivot + 1;
45 }
46 else {
47 r = pivot - 1;
48 }
49
50 if(l > r) {
51 return INVALID_INDEX; // Not here
52 }
53 }
54
55 CONSISTENCY_CHECK(pivot >= 0);
56 return (DWORD)pivot;
57}
58
59PTR_MethodDesc MethodImpl::FindMethodDesc(DWORD slot, PTR_MethodDesc defaultReturn)
60{
61 CONTRACTL
62 {
63 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
64 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
65 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
66 MODE_ANY;
67 }
68 CONTRACTL_END
69
70 DWORD slotIndex = FindSlotIndex(slot);
71 if (slotIndex == INVALID_INDEX) {
72 return defaultReturn;
73 }
74
75 return GetMethodDesc(slotIndex, defaultReturn);
76}
77
78PTR_MethodDesc MethodImpl::GetMethodDesc(DWORD slotIndex, PTR_MethodDesc defaultReturn)
79{
80 CONTRACTL
81 {
82 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
83 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
84 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
85 MODE_ANY;
86 }
87 CONTRACTL_END
88
89 DPTR(RelativePointer<PTR_MethodDesc>) pRelPtrForSlot = GetImpMDsNonNull();
90 // The method descs are not offset by one
91 TADDR base = dac_cast<TADDR>(pRelPtrForSlot) + slotIndex * sizeof(RelativePointer<MethodDesc *>);
92 PTR_MethodDesc result = RelativePointer<PTR_MethodDesc>::GetValueMaybeNullAtPtr(base);
93
94 // Prejitted images may leave NULL in this table if
95 // the methoddesc is declared in another module.
96 // In this case we need to manually compute & restore it
97 // from the slot number.
98
99 if (result == NULL)
100#ifndef DACCESS_COMPILE
101 result = RestoreSlot(slotIndex, defaultReturn->GetMethodTable());
102#else // DACCESS_COMPILE
103 DacNotImpl();
104#endif // DACCESS_COMPILE
105
106 return result;
107}
108
109#ifndef DACCESS_COMPILE
110
111MethodDesc *MethodImpl::RestoreSlot(DWORD index, MethodTable *pMT)
112{
113 CONTRACTL
114 {
115 NOTHROW;
116 GC_NOTRIGGER;
117 FORBID_FAULT;
118 PRECONDITION(!pdwSlots.IsNull());
119 }
120 CONTRACTL_END
121
122 MethodDesc *result;
123
124 PREFIX_ASSUME(!pdwSlots.IsNull());
125 DWORD slot = GetSlots()[index];
126
127 // Since the overridden method is in a different module, we
128 // are guaranteed that it is from a different class. It is
129 // either an override of a parent virtual method or parent-implemented
130 // interface, or of an interface that this class has introduced.
131
132 // In the former 2 cases, the slot number will be in the parent's
133 // vtable section, and we can retrieve the implemented MethodDesc from
134 // there. In the latter case, we can search through our interface
135 // map to determine which interface it is from.
136
137 MethodTable *pParentMT = pMT->GetParentMethodTable();
138 CONSISTENCY_CHECK(pParentMT != NULL && slot < pParentMT->GetNumVirtuals());
139 {
140 result = pParentMT->GetMethodDescForSlot(slot);
141 }
142
143 _ASSERTE(result != NULL);
144
145 // Don't worry about races since we would all be setting the same result
146 if (EnsureWritableExecutablePagesNoThrow(&pImplementedMD.GetValue()[index],
147 sizeof(pImplementedMD.GetValue()[index])))
148 pImplementedMD.GetValue()[index].SetValue(result);
149
150 return result;
151}
152
153///////////////////////////////////////////////////////////////////////////////////////
154void MethodImpl::SetSize(LoaderHeap *pHeap, AllocMemTracker *pamTracker, DWORD size)
155{
156 CONTRACTL {
157 THROWS;
158 GC_NOTRIGGER;
159 PRECONDITION(CheckPointer(this));
160 PRECONDITION(pdwSlots.GetValueMaybeNull()==NULL && pImplementedMD.GetValueMaybeNull()==NULL);
161 INJECT_FAULT(ThrowOutOfMemory());
162 } CONTRACTL_END;
163
164 if(size > 0) {
165 // An array of DWORDs, the first entry representing count, and the rest representing slot numbers
166 S_SIZE_T cbCountAndSlots = S_SIZE_T(sizeof(DWORD)) + // DWORD for the total count of slots
167 S_SIZE_T(size) * S_SIZE_T(sizeof(DWORD)) + // DWORD each for the slot numbers
168 S_SIZE_T(size) * S_SIZE_T(sizeof(mdToken)); // Token each for the method tokens
169
170 // MethodDesc* for each of the implemented methods
171 S_SIZE_T cbMethodDescs = S_SIZE_T(size) * S_SIZE_T(sizeof(RelativePointer<MethodDesc *>));
172
173 // Need to align-up the slot entries so that the MethodDesc* array starts on a pointer boundary.
174 cbCountAndSlots.AlignUp(sizeof(MethodDesc*));
175 S_SIZE_T cbTotal = cbCountAndSlots + cbMethodDescs;
176 if(cbCountAndSlots.IsOverflow())
177 ThrowOutOfMemory();
178
179 // Allocate the memory.
180 LPBYTE pAllocData = (BYTE*)pamTracker->Track(pHeap->AllocMem(cbTotal));
181
182 // Set the count and slot array
183 pdwSlots.SetValue((DWORD*)pAllocData);
184
185 // Set the MethodDesc* array. Make sure to adjust for alignment.
186 pImplementedMD.SetValue((RelativePointer<MethodDesc*> *)ALIGN_UP(pAllocData + cbCountAndSlots.Value(), sizeof(RelativePointer <MethodDesc*>)));
187
188 // Store the count in the first entry
189 *pdwSlots.GetValue() = size;
190 }
191}
192
193///////////////////////////////////////////////////////////////////////////////////////
194void MethodImpl::SetData(DWORD* slots, mdToken* tokens, RelativePointer<MethodDesc*>* md)
195{
196 CONTRACTL {
197 NOTHROW;
198 GC_NOTRIGGER;
199 PRECONDITION(CheckPointer(this));
200 PRECONDITION(!pdwSlots.IsNull());
201 } CONTRACTL_END;
202
203 DWORD *pdwSize = pdwSlots.GetValue();
204 DWORD dwSize = *pdwSize;
205 memcpy(&(pdwSize[1]), slots, dwSize*sizeof(DWORD));
206
207 // Copy tokens that correspond to the slots above
208 memcpy(&(pdwSize[1 + dwSize]), tokens, dwSize*sizeof(mdToken));
209
210 RelativePointer<MethodDesc *> *pImplMD = pImplementedMD.GetValue();
211
212 for (uint32_t i = 0; i < dwSize; ++i)
213 {
214 pImplMD[i].SetValue(md[i].GetValue());
215 }
216}
217
218#ifdef FEATURE_NATIVE_IMAGE_GENERATION
219void MethodImpl::Save(DataImage *image)
220{
221 STANDARD_VM_CONTRACT;
222
223 DWORD size = GetSize();
224 _ASSERTE(size > 0);
225
226 image->StoreStructure(pdwSlots.GetValue(), (size+1)*sizeof(DWORD)+size*sizeof(mdToken),
227 DataImage::ITEM_METHOD_DESC_COLD,
228 sizeof(DWORD));
229 image->StoreStructure(pImplementedMD.GetValue(), size*sizeof(RelativePointer<MethodDesc*>),
230 DataImage::ITEM_METHOD_DESC_COLD,
231 sizeof(MethodDesc*));
232}
233
234void MethodImpl::Fixup(DataImage *image, PVOID p, SSIZE_T offset)
235{
236 STANDARD_VM_CONTRACT;
237
238 DWORD size = GetSize();
239 _ASSERTE(size > 0);
240
241 for (DWORD iMD = 0; iMD < size; iMD++)
242 {
243 // <TODO> Why not use FixupMethodDescPointer? </TODO>
244 // <TODO> Does it matter if the MethodDesc needs a restore? </TODO>
245
246 RelativePointer<MethodDesc *> *pRelPtr = pImplementedMD.GetValue();
247 MethodDesc * pMD = pRelPtr[iMD].GetValueMaybeNull();
248
249 if (image->CanEagerBindToMethodDesc(pMD) &&
250 image->CanHardBindToZapModule(pMD->GetLoaderModule()))
251 {
252 image->FixupRelativePointerField(pImplementedMD.GetValue(), iMD * sizeof(RelativePointer<MethodDesc *>));
253 }
254 else
255 {
256 image->ZeroPointerField(pImplementedMD.GetValue(), iMD * sizeof(RelativePointer<MethodDesc *>));
257 }
258 }
259
260 image->FixupRelativePointerField(p, offset + offsetof(MethodImpl, pdwSlots));
261 image->FixupRelativePointerField(p, offset + offsetof(MethodImpl, pImplementedMD));
262}
263
264#endif // FEATURE_NATIVE_IMAGE_GENERATION
265
266#endif //!DACCESS_COMPILE
267
268#ifdef DACCESS_COMPILE
269
270void
271MethodImpl::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
272{
273 SUPPORTS_DAC;
274#ifndef STUB_DISPATCH_ALL
275 CONSISTENCY_CHECK_MSG(FALSE, "Stub Dispatch forbidden code");
276#else // STUB_DISPATCH_ALL
277 // 'this' memory should already be enumerated as
278 // part of the base MethodDesc.
279
280 if (GetSlotsRaw().IsValid() && GetSize())
281 {
282 ULONG32 numSlots = GetSize();
283 DacEnumMemoryRegion(dac_cast<TADDR>(GetSlotsRawNonNull()),
284 (numSlots + 1) * sizeof(DWORD) + numSlots * sizeof(mdToken));
285
286 if (GetImpMDs().IsValid())
287 {
288 DacEnumMemoryRegion(dac_cast<TADDR>(GetImpMDsNonNull()),
289 numSlots * sizeof(RelativePointer<MethodDesc *>));
290 for (DWORD i = 0; i < numSlots; i++)
291 {
292 DPTR(RelativePointer<PTR_MethodDesc>) pRelPtr = GetImpMDsNonNull();
293 PTR_MethodDesc methodDesc = pRelPtr[i].GetValueMaybeNull();
294 if (methodDesc.IsValid())
295 {
296 methodDesc->EnumMemoryRegions(flags);
297 }
298 }
299 }
300 }
301#endif // STUB_DISPATCH_ALL
302}
303
304#endif //DACCESS_COMPILE
305
306#ifndef DACCESS_COMPILE
307MethodImpl::Iterator::Iterator(MethodDesc *pMD) : m_pMD(pMD), m_pImpl(NULL), m_iCur(0)
308{
309 LIMITED_METHOD_CONTRACT;
310 if (pMD->IsMethodImpl())
311 {
312 m_pImpl = pMD->GetMethodImpl();
313 }
314}
315#endif //!DACCESS_COMPILE
316
317