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 | |
17 | DWORD 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 | |
59 | PTR_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 | |
78 | PTR_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 | |
111 | MethodDesc *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 | /////////////////////////////////////////////////////////////////////////////////////// |
154 | void 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 | /////////////////////////////////////////////////////////////////////////////////////// |
194 | void 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 |
219 | void 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 | |
234 | void 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 | |
270 | void |
271 | MethodImpl::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 |
307 | MethodImpl::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 | |