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: genericdict.cpp |
6 | // |
7 | |
8 | // |
9 | // WARNING: Do NOT turn try to save dictionary slots except in the |
10 | // hardbind case. Saving further dictionary slots can lead |
11 | // to ComputeNeedsRestore returning TRUE for the dictionary and |
12 | // the associated method table (though of course only if some |
13 | // entries in the dictionary are prepopulated). However at |
14 | // earlier stages in the NGEN, code may have been compiled |
15 | // under the assumption that ComputeNeedsRestore was |
16 | // FALSE for the assocaited method table, and indeed this result |
17 | // may have been cached in the ComputeNeedsRestore |
18 | // for the MethodTable. Thus the combination of populating |
19 | // the dictionary and saving further dictionary slots could lead |
20 | // to inconsistencies and unsoundnesses in compilation. |
21 | // |
22 | |
23 | // |
24 | // ============================================================================ |
25 | |
26 | #include "common.h" |
27 | #include "genericdict.h" |
28 | #include "typestring.h" |
29 | #include "field.h" |
30 | #include "typectxt.h" |
31 | #include "virtualcallstub.h" |
32 | #include "sigbuilder.h" |
33 | #include "compile.h" |
34 | |
35 | #ifndef DACCESS_COMPILE |
36 | |
37 | //--------------------------------------------------------------------------------------- |
38 | // |
39 | //static |
40 | DictionaryLayout * |
41 | DictionaryLayout::Allocate( |
42 | WORD numSlots, |
43 | LoaderAllocator * pAllocator, |
44 | AllocMemTracker * pamTracker) |
45 | { |
46 | CONTRACT(DictionaryLayout*) |
47 | { |
48 | THROWS; |
49 | GC_NOTRIGGER; |
50 | INJECT_FAULT(COMPlusThrowOM();); |
51 | PRECONDITION(CheckPointer(pAllocator)); |
52 | PRECONDITION(numSlots > 0); |
53 | POSTCONDITION(CheckPointer(RETVAL)); |
54 | } |
55 | CONTRACT_END |
56 | |
57 | S_SIZE_T bytes = S_SIZE_T(sizeof(DictionaryLayout)) + S_SIZE_T(sizeof(DictionaryEntryLayout)) * S_SIZE_T(numSlots-1); |
58 | |
59 | TaggedMemAllocPtr ptr = pAllocator->GetLowFrequencyHeap()->AllocMem(bytes); |
60 | |
61 | if (pamTracker != NULL) |
62 | pamTracker->Track(ptr); |
63 | |
64 | DictionaryLayout * pD = (DictionaryLayout *)(void *)ptr; |
65 | |
66 | // When bucket spills we'll allocate another layout structure |
67 | pD->m_pNext = NULL; |
68 | |
69 | // This is the number of slots excluding the type parameters |
70 | pD->m_numSlots = numSlots; |
71 | |
72 | RETURN pD; |
73 | } // DictionaryLayout::Allocate |
74 | |
75 | #endif //!DACCESS_COMPILE |
76 | |
77 | //--------------------------------------------------------------------------------------- |
78 | // |
79 | // Count the number of bytes that are required by the first bucket in a dictionary with the specified layout |
80 | // |
81 | //static |
82 | DWORD |
83 | DictionaryLayout::GetFirstDictionaryBucketSize( |
84 | DWORD numGenericArgs, |
85 | PTR_DictionaryLayout pDictLayout) |
86 | { |
87 | LIMITED_METHOD_DAC_CONTRACT; |
88 | PRECONDITION(numGenericArgs > 0); |
89 | PRECONDITION(CheckPointer(pDictLayout, NULL_OK)); |
90 | |
91 | DWORD bytes = numGenericArgs * sizeof(TypeHandle); |
92 | if (pDictLayout != NULL) |
93 | bytes += pDictLayout->m_numSlots * sizeof(void*); |
94 | |
95 | return bytes; |
96 | } |
97 | |
98 | #ifndef DACCESS_COMPILE |
99 | //--------------------------------------------------------------------------------------- |
100 | // |
101 | // Find a token in the dictionary layout and return the offsets of indirections |
102 | // required to get to its slot in the actual dictionary |
103 | // |
104 | // NOTE: We will currently never return more than one indirection. We don't |
105 | // cascade dictionaries but we will record overflows in the dictionary layout |
106 | // (and cascade that accordingly) so we can prepopulate the overflow hash in |
107 | // reliability scenarios. |
108 | // |
109 | // Optimize the case of a token being !i (for class dictionaries) or !!i (for method dictionaries) |
110 | // |
111 | /* static */ |
112 | BOOL |
113 | DictionaryLayout::FindTokenWorker(LoaderAllocator * pAllocator, |
114 | DWORD numGenericArgs, |
115 | DictionaryLayout * pDictLayout, |
116 | CORINFO_RUNTIME_LOOKUP * pResult, |
117 | SigBuilder * pSigBuilder, |
118 | BYTE * pSig, |
119 | DWORD cbSig, |
120 | int nFirstOffset, |
121 | DictionaryEntrySignatureSource signatureSource, |
122 | WORD * pSlotOut) |
123 | { |
124 | CONTRACTL |
125 | { |
126 | STANDARD_VM_CHECK; |
127 | PRECONDITION(numGenericArgs > 0); |
128 | PRECONDITION(CheckPointer(pDictLayout)); |
129 | PRECONDITION(CheckPointer(pSlotOut)); |
130 | PRECONDITION(CheckPointer(pSig)); |
131 | PRECONDITION((pSigBuilder == NULL && cbSig == -1) || (CheckPointer(pSigBuilder) && cbSig > 0)); |
132 | } |
133 | CONTRACTL_END |
134 | |
135 | BOOL isFirstBucket = TRUE; |
136 | |
137 | // First bucket also contains type parameters |
138 | _ASSERTE(FitsIn<WORD>(numGenericArgs)); |
139 | WORD slot = static_cast<WORD>(numGenericArgs); |
140 | for (;;) |
141 | { |
142 | for (DWORD iSlot = 0; iSlot < pDictLayout->m_numSlots; iSlot++) |
143 | { |
144 | RetryMatch: |
145 | BYTE * pCandidate = (BYTE *)pDictLayout->m_slots[iSlot].m_signature; |
146 | if (pCandidate != NULL) |
147 | { |
148 | bool signaturesMatch = false; |
149 | |
150 | if (pSigBuilder != NULL) |
151 | { |
152 | // JIT case: compare signatures by comparing the bytes in them. We exclude |
153 | // any ReadyToRun signatures from the JIT case. |
154 | |
155 | if (pDictLayout->m_slots[iSlot].m_signatureSource != FromReadyToRunImage) |
156 | { |
157 | // Compare the signatures. We do not need to worry about the size of pCandidate. |
158 | // As long as we are comparing one byte at a time we are guaranteed to not overrun. |
159 | DWORD j; |
160 | for (j = 0; j < cbSig; j++) |
161 | { |
162 | if (pCandidate[j] != pSig[j]) |
163 | break; |
164 | } |
165 | signaturesMatch = (j == cbSig); |
166 | } |
167 | } |
168 | else |
169 | { |
170 | // ReadyToRun case: compare signatures by comparing their pointer values |
171 | signaturesMatch = (pCandidate == pSig); |
172 | } |
173 | |
174 | // We've found it |
175 | if (signaturesMatch) |
176 | { |
177 | pResult->signature = pDictLayout->m_slots[iSlot].m_signature; |
178 | |
179 | // We don't store entries outside the first bucket in the layout in the dictionary (they'll be cached in a hash |
180 | // instead). |
181 | if (!isFirstBucket) |
182 | { |
183 | return FALSE; |
184 | } |
185 | _ASSERTE(FitsIn<WORD>(nFirstOffset + 1)); |
186 | pResult->indirections = static_cast<WORD>(nFirstOffset + 1); |
187 | pResult->offsets[nFirstOffset] = slot * sizeof(DictionaryEntry); |
188 | *pSlotOut = slot; |
189 | return TRUE; |
190 | } |
191 | } |
192 | // If we hit an empty slot then there's no more so use it |
193 | else |
194 | { |
195 | { |
196 | BaseDomain::LockHolder lh(pAllocator->GetDomain()); |
197 | |
198 | if (pDictLayout->m_slots[iSlot].m_signature != NULL) |
199 | goto RetryMatch; |
200 | |
201 | PVOID pResultSignature = pSig; |
202 | |
203 | if (pSigBuilder != NULL) |
204 | { |
205 | pSigBuilder->AppendData(isFirstBucket ? slot : 0); |
206 | |
207 | DWORD cbNewSig; |
208 | PVOID pNewSig = pSigBuilder->GetSignature(&cbNewSig); |
209 | |
210 | pResultSignature = pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(cbNewSig)); |
211 | memcpy(pResultSignature, pNewSig, cbNewSig); |
212 | } |
213 | |
214 | *EnsureWritablePages(&(pDictLayout->m_slots[iSlot].m_signature)) = pResultSignature; |
215 | *EnsureWritablePages(&(pDictLayout->m_slots[iSlot].m_signatureSource)) = signatureSource; |
216 | } |
217 | |
218 | pResult->signature = pDictLayout->m_slots[iSlot].m_signature; |
219 | |
220 | // Again, we only store entries in the first layout bucket in the dictionary. |
221 | if (!isFirstBucket) |
222 | { |
223 | return FALSE; |
224 | } |
225 | _ASSERTE(FitsIn<WORD>(nFirstOffset + 1)); |
226 | pResult->indirections = static_cast<WORD>(nFirstOffset + 1); |
227 | pResult->offsets[nFirstOffset] = slot * sizeof(DictionaryEntry); |
228 | *pSlotOut = slot; |
229 | return TRUE; |
230 | } |
231 | slot++; |
232 | } |
233 | |
234 | // If we've reached the end of the chain we need to allocate another bucket. Make the pointer update carefully to avoid |
235 | // orphaning a bucket in a race. We leak the loser in such a race (since the allocation comes from the loader heap) but both |
236 | // the race and the overflow should be very rare. |
237 | if (pDictLayout->m_pNext == NULL) |
238 | FastInterlockCompareExchangePointer(EnsureWritablePages(&(pDictLayout->m_pNext)), Allocate(4, pAllocator, NULL), 0); |
239 | |
240 | pDictLayout = pDictLayout->m_pNext; |
241 | isFirstBucket = FALSE; |
242 | } |
243 | } // DictionaryLayout::FindToken |
244 | |
245 | /* static */ |
246 | BOOL |
247 | DictionaryLayout::FindToken(LoaderAllocator * pAllocator, |
248 | DWORD numGenericArgs, |
249 | DictionaryLayout * pDictLayout, |
250 | CORINFO_RUNTIME_LOOKUP * pResult, |
251 | SigBuilder * pSigBuilder, |
252 | int nFirstOffset, |
253 | DictionaryEntrySignatureSource signatureSource) |
254 | { |
255 | WRAPPER_NO_CONTRACT; |
256 | |
257 | DWORD cbSig; |
258 | BYTE * pSig = (BYTE *)pSigBuilder->GetSignature(&cbSig); |
259 | |
260 | WORD slotDummy; |
261 | return FindTokenWorker(pAllocator, numGenericArgs, pDictLayout, pResult, pSigBuilder, pSig, cbSig, nFirstOffset, signatureSource, &slotDummy); |
262 | } |
263 | |
264 | /* static */ |
265 | BOOL |
266 | DictionaryLayout::FindToken(LoaderAllocator * pAllocator, |
267 | DWORD numGenericArgs, |
268 | DictionaryLayout * pDictLayout, |
269 | CORINFO_RUNTIME_LOOKUP * pResult, |
270 | BYTE * signature, |
271 | int nFirstOffset, |
272 | DictionaryEntrySignatureSource signatureSource, |
273 | WORD * pSlotOut) |
274 | { |
275 | WRAPPER_NO_CONTRACT; |
276 | |
277 | return FindTokenWorker(pAllocator, numGenericArgs, pDictLayout, pResult, NULL, signature, -1, nFirstOffset, signatureSource, pSlotOut); |
278 | } |
279 | |
280 | #endif //!DACCESS_COMPILE |
281 | |
282 | //--------------------------------------------------------------------------------------- |
283 | // |
284 | DWORD |
285 | DictionaryLayout::GetMaxSlots() |
286 | { |
287 | LIMITED_METHOD_CONTRACT; |
288 | return m_numSlots; |
289 | } |
290 | |
291 | //--------------------------------------------------------------------------------------- |
292 | // |
293 | DWORD |
294 | DictionaryLayout::GetNumUsedSlots() |
295 | { |
296 | LIMITED_METHOD_CONTRACT; |
297 | |
298 | DWORD numUsedSlots = 0; |
299 | for (DWORD i = 0; i < m_numSlots; i++) |
300 | { |
301 | if (GetEntryLayout(i)->m_signature != NULL) |
302 | numUsedSlots++; |
303 | } |
304 | return numUsedSlots; |
305 | } |
306 | |
307 | |
308 | //--------------------------------------------------------------------------------------- |
309 | // |
310 | DictionaryEntryKind |
311 | DictionaryEntryLayout::GetKind() |
312 | { |
313 | STANDARD_VM_CONTRACT; |
314 | |
315 | if (m_signature == NULL) |
316 | return EmptySlot; |
317 | |
318 | SigPointer ptr((PCCOR_SIGNATURE)dac_cast<TADDR>(m_signature)); |
319 | |
320 | ULONG kind; // DictionaryEntryKind |
321 | IfFailThrow(ptr.GetData(&kind)); |
322 | |
323 | return (DictionaryEntryKind)kind; |
324 | } |
325 | |
326 | #ifndef DACCESS_COMPILE |
327 | #ifdef FEATURE_NATIVE_IMAGE_GENERATION |
328 | |
329 | //--------------------------------------------------------------------------------------- |
330 | // |
331 | DWORD |
332 | DictionaryLayout::GetObjectSize() |
333 | { |
334 | LIMITED_METHOD_CONTRACT; |
335 | return sizeof(DictionaryLayout) + sizeof(DictionaryEntryLayout) * (m_numSlots-1); |
336 | } |
337 | |
338 | //--------------------------------------------------------------------------------------- |
339 | // |
340 | // Save the dictionary layout for prejitting |
341 | // |
342 | void |
343 | DictionaryLayout::Save( |
344 | DataImage * image) |
345 | { |
346 | STANDARD_VM_CONTRACT; |
347 | |
348 | DictionaryLayout *pDictLayout = this; |
349 | |
350 | while (pDictLayout) |
351 | { |
352 | image->StoreStructure(pDictLayout, pDictLayout->GetObjectSize(), DataImage::ITEM_DICTIONARY_LAYOUT); |
353 | pDictLayout = pDictLayout->m_pNext; |
354 | } |
355 | |
356 | } |
357 | |
358 | //--------------------------------------------------------------------------------------- |
359 | // |
360 | // Save the dictionary layout for prejitting |
361 | // |
362 | void |
363 | DictionaryLayout::Trim() |
364 | { |
365 | CONTRACTL |
366 | { |
367 | THROWS; |
368 | GC_NOTRIGGER; |
369 | } |
370 | CONTRACTL_END; |
371 | |
372 | // Only the last bucket in the chain may have unused entries |
373 | DictionaryLayout *pDictLayout = this; |
374 | while (pDictLayout->m_pNext) |
375 | pDictLayout = pDictLayout->m_pNext; |
376 | |
377 | // Trim down the size to what's actually used |
378 | DWORD dwSlots = pDictLayout->GetNumUsedSlots(); |
379 | _ASSERTE(FitsIn<WORD>(dwSlots)); |
380 | *EnsureWritablePages(&pDictLayout->m_numSlots) = static_cast<WORD>(dwSlots); |
381 | |
382 | } |
383 | |
384 | //--------------------------------------------------------------------------------------- |
385 | // |
386 | // Fixup pointers in the dictionary layout for prejitting |
387 | // |
388 | void |
389 | DictionaryLayout::Fixup( |
390 | DataImage * image, |
391 | BOOL fMethod) |
392 | { |
393 | STANDARD_VM_CONTRACT; |
394 | |
395 | DictionaryLayout *pDictLayout = this; |
396 | |
397 | while (pDictLayout) |
398 | { |
399 | for (DWORD i = 0; i < pDictLayout->m_numSlots; i++) |
400 | { |
401 | PVOID signature = pDictLayout->m_slots[i].m_signature; |
402 | if (signature != NULL) |
403 | { |
404 | image->FixupFieldToNode(pDictLayout, (BYTE *)&pDictLayout->m_slots[i].m_signature - (BYTE *)pDictLayout, |
405 | image->GetGenericSignature(signature, fMethod)); |
406 | } |
407 | } |
408 | image->FixupPointerField(pDictLayout, offsetof(DictionaryLayout, m_pNext)); |
409 | pDictLayout = pDictLayout->m_pNext; |
410 | } |
411 | } |
412 | |
413 | //--------------------------------------------------------------------------------------- |
414 | // |
415 | // Fixup pointers in the actual dictionary, including the type arguments. Delete entries |
416 | // that are expensive or difficult to restore. |
417 | // |
418 | void |
419 | Dictionary::Fixup( |
420 | DataImage * image, |
421 | BOOL canSaveInstantiation, |
422 | BOOL canSaveSlots, |
423 | DWORD numGenericArgs, |
424 | Module * pModule, |
425 | DictionaryLayout * pDictLayout) |
426 | { |
427 | STANDARD_VM_CONTRACT; |
428 | |
429 | // First fixup the type handles in the instantiation itself |
430 | FixupPointer<TypeHandle> *pInst = GetInstantiation(); |
431 | for (DWORD j = 0; j < numGenericArgs; j++) |
432 | { |
433 | if (canSaveInstantiation) |
434 | { |
435 | image->FixupTypeHandlePointer(pInst, &pInst[j]); |
436 | } |
437 | else |
438 | { |
439 | image->ZeroPointerField(AsPtr(), j * sizeof(DictionaryEntry)); |
440 | } |
441 | } |
442 | |
443 | // Now traverse the remaining slots |
444 | if (pDictLayout != NULL) |
445 | { |
446 | for (DWORD i = 0; i < pDictLayout->m_numSlots; i++) |
447 | { |
448 | int slotOffset = (numGenericArgs + i) * sizeof(DictionaryEntry); |
449 | |
450 | // First check if we can simply hardbind to a prerestored object |
451 | DictionaryEntryLayout *pLayout = pDictLayout->GetEntryLayout(i); |
452 | switch (pLayout->GetKind()) |
453 | { |
454 | case TypeHandleSlot: |
455 | case DeclaringTypeHandleSlot: |
456 | if (canSaveSlots && |
457 | !IsSlotEmpty(numGenericArgs,i) && |
458 | image->CanPrerestoreEagerBindToTypeHandle(GetTypeHandleSlot(numGenericArgs, i), NULL) && |
459 | image->CanHardBindToZapModule(GetTypeHandleSlot(numGenericArgs, i).GetLoaderModule())) |
460 | { |
461 | image->HardBindTypeHandlePointer(AsPtr(), slotOffset); |
462 | } |
463 | else |
464 | { |
465 | // Otherwise just zero the slot |
466 | image->ZeroPointerField(AsPtr(), slotOffset); |
467 | } |
468 | break; |
469 | case MethodDescSlot: |
470 | if (canSaveSlots && |
471 | !IsSlotEmpty(numGenericArgs,i) && |
472 | image->CanPrerestoreEagerBindToMethodDesc(GetMethodDescSlot(numGenericArgs,i), NULL) && |
473 | image->CanHardBindToZapModule(GetMethodDescSlot(numGenericArgs,i)->GetLoaderModule())) |
474 | { |
475 | image->FixupPointerField(AsPtr(), slotOffset); |
476 | } |
477 | else |
478 | { |
479 | // Otherwise just zero the slot |
480 | image->ZeroPointerField(AsPtr(), slotOffset); |
481 | } |
482 | break; |
483 | case FieldDescSlot: |
484 | if (canSaveSlots && |
485 | !IsSlotEmpty(numGenericArgs,i) && |
486 | image->CanEagerBindToFieldDesc(GetFieldDescSlot(numGenericArgs,i)) && |
487 | image->CanHardBindToZapModule(GetFieldDescSlot(numGenericArgs,i)->GetLoaderModule())) |
488 | { |
489 | image->FixupPointerField(AsPtr(), slotOffset); |
490 | } |
491 | else |
492 | { |
493 | // Otherwise just zero the slot |
494 | image->ZeroPointerField(AsPtr(), slotOffset); |
495 | } |
496 | break; |
497 | default: |
498 | // <TODO> Method entry points are currently not saved </TODO> |
499 | // <TODO> Stub dispatch slots are currently not saved </TODO> |
500 | // Otherwise just zero the slot |
501 | image->ZeroPointerField(AsPtr(), slotOffset); |
502 | } |
503 | } |
504 | } |
505 | } // Dictionary::Fixup |
506 | |
507 | //--------------------------------------------------------------------------------------- |
508 | // |
509 | BOOL |
510 | Dictionary::IsWriteable( |
511 | DataImage * image, |
512 | BOOL canSaveSlots, |
513 | DWORD numGenericArgs, // Must be non-zero |
514 | Module * pModule, // module of the generic code |
515 | DictionaryLayout * pDictLayout) |
516 | { |
517 | STANDARD_VM_CONTRACT; |
518 | |
519 | // Traverse dictionary slots |
520 | if (pDictLayout != NULL) |
521 | { |
522 | for (DWORD i = 0; i < pDictLayout->m_numSlots; i++) |
523 | { |
524 | // First check if we can simply hardbind to a prerestored object |
525 | DictionaryEntryLayout *pLayout = pDictLayout->GetEntryLayout(i); |
526 | switch (pLayout->GetKind()) |
527 | { |
528 | case TypeHandleSlot: |
529 | case DeclaringTypeHandleSlot: |
530 | if (canSaveSlots && |
531 | !IsSlotEmpty(numGenericArgs,i) && |
532 | image->CanPrerestoreEagerBindToTypeHandle(GetTypeHandleSlot(numGenericArgs, i), NULL) && |
533 | image->CanHardBindToZapModule(GetTypeHandleSlot(numGenericArgs, i).GetLoaderModule())) |
534 | { |
535 | // do nothing |
536 | } |
537 | else |
538 | { |
539 | return TRUE; |
540 | } |
541 | break; |
542 | case MethodDescSlot: |
543 | if (canSaveSlots && |
544 | !IsSlotEmpty(numGenericArgs,i) && |
545 | image->CanPrerestoreEagerBindToMethodDesc(GetMethodDescSlot(numGenericArgs,i), NULL) && |
546 | image->CanHardBindToZapModule(GetMethodDescSlot(numGenericArgs,i)->GetLoaderModule())) |
547 | { |
548 | // do nothing |
549 | } |
550 | else |
551 | { |
552 | return TRUE; |
553 | } |
554 | break; |
555 | case FieldDescSlot: |
556 | if (canSaveSlots && |
557 | !IsSlotEmpty(numGenericArgs,i) && |
558 | image->CanEagerBindToFieldDesc(GetFieldDescSlot(numGenericArgs,i)) && |
559 | image->CanHardBindToZapModule(GetFieldDescSlot(numGenericArgs,i)->GetLoaderModule())) |
560 | { |
561 | // do nothing |
562 | } |
563 | else |
564 | { |
565 | return TRUE; |
566 | } |
567 | break; |
568 | default: |
569 | // <TODO> Method entry points are currently not saved </TODO> |
570 | // <TODO> Stub dispatch slots are currently not saved </TODO> |
571 | return TRUE; |
572 | } |
573 | } |
574 | } |
575 | |
576 | return FALSE; |
577 | } // Dictionary::IsWriteable |
578 | |
579 | //--------------------------------------------------------------------------------------- |
580 | // |
581 | BOOL |
582 | Dictionary::ComputeNeedsRestore( |
583 | DataImage * image, |
584 | TypeHandleList * pVisited, |
585 | DWORD numGenericArgs) |
586 | { |
587 | STANDARD_VM_CONTRACT; |
588 | |
589 | // First check the type handles in the instantiation itself |
590 | FixupPointer<TypeHandle> *inst = GetInstantiation(); |
591 | for (DWORD j = 0; j < numGenericArgs; j++) |
592 | { |
593 | if (!image->CanPrerestoreEagerBindToTypeHandle(inst[j].GetValue(), pVisited)) |
594 | return TRUE; |
595 | } |
596 | |
597 | // Unless prepopulating we don't need to check the entries |
598 | // of the dictionary because if we can't |
599 | // hardbind to them we just zero the dictionary entry and recover |
600 | // it on demand. |
601 | |
602 | return FALSE; |
603 | } |
604 | #endif //FEATURE_NATIVE_IMAGE_GENERATION |
605 | |
606 | #ifdef FEATURE_PREJIT |
607 | //--------------------------------------------------------------------------------------- |
608 | // |
609 | void |
610 | Dictionary::Restore( |
611 | DWORD numGenericArgs, |
612 | ClassLoadLevel level) |
613 | { |
614 | CONTRACTL |
615 | { |
616 | THROWS; |
617 | GC_TRIGGERS; |
618 | INSTANCE_CHECK; |
619 | } |
620 | CONTRACTL_END |
621 | |
622 | // First restore the type handles in the instantiation itself |
623 | FixupPointer<TypeHandle> *inst = GetInstantiation(); |
624 | for (DWORD j = 0; j < numGenericArgs; j++) |
625 | { |
626 | Module::RestoreTypeHandlePointer(&inst[j], NULL, level); |
627 | } |
628 | |
629 | // We don't restore the remainder of the dictionary - see |
630 | // long comment at the start of this file as to why |
631 | } |
632 | #endif // FEATURE_PREJIT |
633 | |
634 | //--------------------------------------------------------------------------------------- |
635 | // |
636 | DictionaryEntry |
637 | Dictionary::PopulateEntry( |
638 | MethodDesc * pMD, |
639 | MethodTable * pMT, |
640 | LPVOID signature, |
641 | BOOL nonExpansive, |
642 | DictionaryEntry ** ppSlot, |
643 | DWORD dictionaryIndexAndSlot, /* = -1 */ |
644 | Module * pModule /* = NULL */) |
645 | { |
646 | CONTRACTL { |
647 | THROWS; |
648 | GC_TRIGGERS; |
649 | } CONTRACTL_END; |
650 | |
651 | CORINFO_GENERIC_HANDLE result = NULL; |
652 | Dictionary * pDictionary = NULL; |
653 | *ppSlot = NULL; |
654 | |
655 | bool isReadyToRunModule = (pModule != NULL && pModule->IsReadyToRun()); |
656 | |
657 | ZapSig::Context zapSigContext(NULL, NULL, ZapSig::NormalTokens); |
658 | ZapSig::Context * pZapSigContext = NULL; |
659 | |
660 | ULONG kind = DictionaryEntryKind::EmptySlot; |
661 | |
662 | SigPointer ptr((PCCOR_SIGNATURE)signature); |
663 | |
664 | if (isReadyToRunModule) |
665 | { |
666 | PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)signature; |
667 | |
668 | BYTE fixupKind = *pBlob++; |
669 | |
670 | Module * pInfoModule = pModule; |
671 | if (fixupKind & ENCODE_MODULE_OVERRIDE) |
672 | { |
673 | DWORD moduleIndex = CorSigUncompressData(pBlob); |
674 | pInfoModule = pModule->GetModuleFromIndex(moduleIndex); |
675 | fixupKind &= ~ENCODE_MODULE_OVERRIDE; |
676 | } |
677 | |
678 | _ASSERTE(fixupKind == ENCODE_DICTIONARY_LOOKUP_THISOBJ || |
679 | fixupKind == ENCODE_DICTIONARY_LOOKUP_TYPE || |
680 | fixupKind == ENCODE_DICTIONARY_LOOKUP_METHOD); |
681 | |
682 | if (fixupKind == ENCODE_DICTIONARY_LOOKUP_THISOBJ) |
683 | { |
684 | SigPointer p(pBlob); |
685 | p.SkipExactlyOne(); |
686 | pBlob = p.GetPtr(); |
687 | } |
688 | |
689 | CORCOMPILE_FIXUP_BLOB_KIND signatureKind = (CORCOMPILE_FIXUP_BLOB_KIND)CorSigUncompressData(pBlob); |
690 | switch (signatureKind) |
691 | { |
692 | case ENCODE_DECLARINGTYPE_HANDLE: kind = DeclaringTypeHandleSlot; break; |
693 | case ENCODE_TYPE_HANDLE: kind = TypeHandleSlot; break; |
694 | case ENCODE_FIELD_HANDLE: kind = FieldDescSlot; break; |
695 | case ENCODE_METHOD_HANDLE: kind = MethodDescSlot; break; |
696 | case ENCODE_METHOD_ENTRY: kind = MethodEntrySlot; break; |
697 | case ENCODE_VIRTUAL_ENTRY: kind = DispatchStubAddrSlot; break; |
698 | |
699 | default: |
700 | _ASSERTE(!"Unexpected CORCOMPILE_FIXUP_BLOB_KIND" ); |
701 | ThrowHR(COR_E_BADIMAGEFORMAT); |
702 | } |
703 | |
704 | ptr = SigPointer(pBlob); |
705 | |
706 | zapSigContext = ZapSig::Context(pInfoModule, pModule, ZapSig::NormalTokens); |
707 | pZapSigContext = &zapSigContext; |
708 | } |
709 | else |
710 | { |
711 | ptr = SigPointer((PCCOR_SIGNATURE)signature); |
712 | IfFailThrow(ptr.GetData(&kind)); |
713 | |
714 | Module * pContainingZapModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(signature)); |
715 | |
716 | zapSigContext = ZapSig::Context(MscorlibBinder::GetModule(), (void *)pContainingZapModule, ZapSig::NormalTokens); |
717 | pZapSigContext = (pContainingZapModule != NULL) ? &zapSigContext : NULL; |
718 | } |
719 | |
720 | Module * pLookupModule = (isReadyToRunModule) ? pZapSigContext->pInfoModule : MscorlibBinder::GetModule(); |
721 | |
722 | if (pMT != NULL) |
723 | { |
724 | // We need to normalize the class passed in (if any) for reliability purposes. That's because preparation of a code region that |
725 | // contains these handle lookups depends on being able to predict exactly which lookups are required (so we can pre-cache the |
726 | // answers and remove any possibility of failure at runtime). This is hard to do if the lookup (in this case the lookup of the |
727 | // dictionary overflow cache) is keyed off the somewhat arbitrary type of the instance on which the call is made (we'd need to |
728 | // prepare for every possible derived type of the type containing the method). So instead we have to locate the exactly |
729 | // instantiated (non-shared) super-type of the class passed in. |
730 | |
731 | pDictionary = pMT->GetDictionary(); |
732 | |
733 | ULONG dictionaryIndex = 0; |
734 | |
735 | if (isReadyToRunModule) |
736 | { |
737 | dictionaryIndex = dictionaryIndexAndSlot >> 16; |
738 | } |
739 | else |
740 | { |
741 | IfFailThrow(ptr.GetData(&dictionaryIndex)); |
742 | } |
743 | |
744 | // MethodTable is expected to be normalized |
745 | _ASSERTE(pDictionary == pMT->GetPerInstInfo()[dictionaryIndex].GetValueMaybeNull()); |
746 | } |
747 | else |
748 | { |
749 | pDictionary = pMD->GetMethodDictionary(); |
750 | } |
751 | |
752 | { |
753 | SigTypeContext typeContext; |
754 | |
755 | if (pMT != NULL) |
756 | { |
757 | SigTypeContext::InitTypeContext(pMT, &typeContext); |
758 | } |
759 | else |
760 | { |
761 | SigTypeContext::InitTypeContext(pMD, &typeContext); |
762 | } |
763 | |
764 | TypeHandle constraintType; |
765 | TypeHandle declaringType; |
766 | |
767 | switch (kind) |
768 | { |
769 | case DeclaringTypeHandleSlot: |
770 | { |
771 | declaringType = ptr.GetTypeHandleThrowing( |
772 | pLookupModule, |
773 | &typeContext, |
774 | (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes), |
775 | CLASS_LOADED, |
776 | FALSE, |
777 | NULL, |
778 | pZapSigContext); |
779 | if (declaringType.IsNull()) |
780 | { |
781 | _ASSERTE(nonExpansive); |
782 | return NULL; |
783 | } |
784 | IfFailThrow(ptr.SkipExactlyOne()); |
785 | |
786 | // fall through |
787 | } |
788 | |
789 | case TypeHandleSlot: |
790 | { |
791 | TypeHandle th = ptr.GetTypeHandleThrowing( |
792 | pLookupModule, |
793 | &typeContext, |
794 | (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes), |
795 | CLASS_LOADED, |
796 | FALSE, |
797 | NULL, |
798 | pZapSigContext); |
799 | if (th.IsNull()) |
800 | { |
801 | _ASSERTE(nonExpansive); |
802 | return NULL; |
803 | } |
804 | IfFailThrow(ptr.SkipExactlyOne()); |
805 | |
806 | if (!declaringType.IsNull()) |
807 | { |
808 | th = th.GetMethodTable()->GetMethodTableMatchingParentClass(declaringType.AsMethodTable()); |
809 | } |
810 | |
811 | if (!IsCompilationProcess()) |
812 | { |
813 | th.GetMethodTable()->EnsureInstanceActive(); |
814 | } |
815 | |
816 | result = (CORINFO_GENERIC_HANDLE)th.AsPtr(); |
817 | break; |
818 | } |
819 | |
820 | case ConstrainedMethodEntrySlot: |
821 | { |
822 | constraintType = ptr.GetTypeHandleThrowing( |
823 | pLookupModule, |
824 | &typeContext, |
825 | (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes), |
826 | CLASS_LOADED, |
827 | FALSE, |
828 | NULL, |
829 | pZapSigContext); |
830 | if (constraintType.IsNull()) |
831 | { |
832 | _ASSERTE(nonExpansive); |
833 | return NULL; |
834 | } |
835 | IfFailThrow(ptr.SkipExactlyOne()); |
836 | |
837 | // fall through |
838 | } |
839 | |
840 | case MethodDescSlot: |
841 | case DispatchStubAddrSlot: |
842 | case MethodEntrySlot: |
843 | { |
844 | TypeHandle ownerType; |
845 | MethodTable * pOwnerMT = NULL; |
846 | MethodDesc * pMethod = NULL; |
847 | |
848 | DWORD methodFlags = 0; |
849 | BOOL isInstantiatingStub = 0; |
850 | BOOL isUnboxingStub = 0; |
851 | BOOL fMethodNeedsInstantiation = 0; |
852 | |
853 | DWORD methodSlot = -1; |
854 | BOOL fRequiresDispatchStub = 0; |
855 | |
856 | if (isReadyToRunModule) |
857 | { |
858 | IfFailThrow(ptr.GetData(&methodFlags)); |
859 | |
860 | if (methodFlags & ENCODE_METHOD_SIG_Constrained) |
861 | kind = ConstrainedMethodEntrySlot; |
862 | |
863 | isInstantiatingStub = ((methodFlags & ENCODE_METHOD_SIG_InstantiatingStub) != 0) || (kind == MethodEntrySlot); |
864 | isUnboxingStub = ((methodFlags & ENCODE_METHOD_SIG_UnboxingStub) != 0); |
865 | fMethodNeedsInstantiation = ((methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) != 0); |
866 | |
867 | if (methodFlags & ENCODE_METHOD_SIG_OwnerType) |
868 | { |
869 | ownerType = ptr.GetTypeHandleThrowing( |
870 | pZapSigContext->pInfoModule, |
871 | &typeContext, |
872 | ClassLoader::LoadTypes, |
873 | CLASS_LOADED, |
874 | FALSE, |
875 | NULL, |
876 | pZapSigContext); |
877 | |
878 | IfFailThrow(ptr.SkipExactlyOne()); |
879 | } |
880 | |
881 | if (methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) |
882 | { |
883 | // get the method desc using slot number |
884 | IfFailThrow(ptr.GetData(&methodSlot)); |
885 | |
886 | _ASSERTE(!ownerType.IsNull()); |
887 | pMethod = ownerType.GetMethodTable()->GetMethodDescForSlot(methodSlot); |
888 | } |
889 | else |
890 | { |
891 | // |
892 | // decode method token |
893 | // |
894 | RID rid; |
895 | IfFailThrow(ptr.GetData(&rid)); |
896 | |
897 | if (methodFlags & ENCODE_METHOD_SIG_MemberRefToken) |
898 | { |
899 | if (ownerType.IsNull()) |
900 | { |
901 | FieldDesc * pFDDummy = NULL; |
902 | |
903 | MemberLoader::GetDescFromMemberRef(pZapSigContext->pInfoModule, TokenFromRid(rid, mdtMemberRef), &pMethod, &pFDDummy, NULL, FALSE, &ownerType); |
904 | _ASSERTE(pMethod != NULL && pFDDummy == NULL); |
905 | } |
906 | else |
907 | { |
908 | pMethod = MemberLoader::GetMethodDescFromMemberRefAndType(pZapSigContext->pInfoModule, TokenFromRid(rid, mdtMemberRef), ownerType.GetMethodTable()); |
909 | } |
910 | } |
911 | else |
912 | { |
913 | pMethod = MemberLoader::GetMethodDescFromMethodDef(pZapSigContext->pInfoModule, TokenFromRid(rid, mdtMethodDef), FALSE); |
914 | } |
915 | } |
916 | |
917 | if (ownerType.IsNull()) |
918 | ownerType = pMethod->GetMethodTable(); |
919 | |
920 | _ASSERT(!ownerType.IsNull() && !nonExpansive); |
921 | pOwnerMT = ownerType.GetMethodTable(); |
922 | |
923 | if (kind == DispatchStubAddrSlot && pMethod->IsVtableMethod()) |
924 | { |
925 | fRequiresDispatchStub = TRUE; |
926 | methodSlot = pMethod->GetSlot(); |
927 | } |
928 | } |
929 | else |
930 | { |
931 | ownerType = ptr.GetTypeHandleThrowing( |
932 | pLookupModule, |
933 | &typeContext, |
934 | (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes), |
935 | CLASS_LOADED, |
936 | FALSE, |
937 | NULL, |
938 | pZapSigContext); |
939 | if (ownerType.IsNull()) |
940 | { |
941 | _ASSERTE(nonExpansive); |
942 | return NULL; |
943 | } |
944 | IfFailThrow(ptr.SkipExactlyOne()); |
945 | |
946 | // <NICE> wsperf: Create a path that doesn't load types or create new handles if nonExpansive is set </NICE> |
947 | if (nonExpansive) |
948 | return NULL; |
949 | |
950 | pOwnerMT = ownerType.GetMethodTable(); |
951 | _ASSERTE(pOwnerMT != NULL); |
952 | |
953 | IfFailThrow(ptr.GetData(&methodFlags)); |
954 | |
955 | isInstantiatingStub = ((methodFlags & ENCODE_METHOD_SIG_InstantiatingStub) != 0); |
956 | isUnboxingStub = ((methodFlags & ENCODE_METHOD_SIG_UnboxingStub) != 0); |
957 | fMethodNeedsInstantiation = ((methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) != 0); |
958 | |
959 | if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) != 0) |
960 | { |
961 | // get the method desc using slot number |
962 | IfFailThrow(ptr.GetData(&methodSlot)); |
963 | |
964 | if (kind == DispatchStubAddrSlot) |
965 | { |
966 | if (NingenEnabled()) |
967 | return NULL; |
968 | |
969 | #ifndef CROSSGEN_COMPILE |
970 | fRequiresDispatchStub = TRUE; |
971 | #endif |
972 | } |
973 | |
974 | if (!fRequiresDispatchStub) |
975 | pMethod = pOwnerMT->GetMethodDescForSlot(methodSlot); |
976 | } |
977 | else |
978 | { |
979 | // Decode type where the method token is defined |
980 | TypeHandle thMethodDefType = ptr.GetTypeHandleThrowing( |
981 | pLookupModule, |
982 | &typeContext, |
983 | (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes), |
984 | CLASS_LOADED, |
985 | FALSE, |
986 | NULL, |
987 | pZapSigContext); |
988 | if (thMethodDefType.IsNull()) |
989 | { |
990 | _ASSERTE(nonExpansive); |
991 | return NULL; |
992 | } |
993 | IfFailThrow(ptr.SkipExactlyOne()); |
994 | MethodTable * pMethodDefMT = thMethodDefType.GetMethodTable(); |
995 | _ASSERTE(pMethodDefMT != NULL); |
996 | |
997 | // decode method token |
998 | RID rid; |
999 | IfFailThrow(ptr.GetData(&rid)); |
1000 | mdMethodDef token = TokenFromRid(rid, mdtMethodDef); |
1001 | |
1002 | // The RID map should have been filled out if we fully loaded the class |
1003 | pMethod = pMethodDefMT->GetModule()->LookupMethodDef(token); |
1004 | _ASSERTE(pMethod != NULL); |
1005 | pMethod->CheckRestore(); |
1006 | } |
1007 | } |
1008 | |
1009 | if (fRequiresDispatchStub) |
1010 | { |
1011 | #ifndef CROSSGEN_COMPILE |
1012 | // Generate a dispatch stub and store it in the dictionary. |
1013 | // |
1014 | // We generate an indirection so we don't have to write to the dictionary |
1015 | // when we do updates, and to simplify stub indirect callsites. Stubs stored in |
1016 | // dictionaries use "RegisterIndirect" stub calling, e.g. "call [eax]", |
1017 | // i.e. here the register "eax" would contain the value fetched from the dictionary, |
1018 | // which in turn points to the stub indirection which holds the value the current stub |
1019 | // address itself. If we just used "call eax" then we wouldn't know which stub indirection |
1020 | // to update. If we really wanted to avoid the extra indirection we could return the _address_ of the |
1021 | // dictionary entry to the caller, still using "call [eax]", and then the |
1022 | // stub dispatch mechanism can update the dictitonary itself and we don't |
1023 | // need an indirection. |
1024 | LoaderAllocator * pDictLoaderAllocator = (pMT != NULL) ? pMT->GetLoaderAllocator() : pMD->GetLoaderAllocator(); |
1025 | |
1026 | VirtualCallStubManager * pMgr = pDictLoaderAllocator->GetVirtualCallStubManager(); |
1027 | |
1028 | // We indirect through a cell so that updates can take place atomically. |
1029 | // The call stub and the indirection cell have the same lifetime as the dictionary itself, i.e. |
1030 | // are allocated in the domain of the dicitonary. |
1031 | // |
1032 | // In the case of overflow (where there is no dictionary, just a global hash table) then |
1033 | // the entry will be placed in the overflow hash table (JitGenericHandleCache). This |
1034 | // is partitioned according to domain, i.e. is scraped each time an AppDomain gets unloaded. |
1035 | PCODE addr = pMgr->GetCallStub(ownerType, methodSlot); |
1036 | |
1037 | result = (CORINFO_GENERIC_HANDLE)pMgr->GenerateStubIndirection(addr); |
1038 | break; |
1039 | #endif // CROSSGEN_COMPILE |
1040 | } |
1041 | |
1042 | Instantiation inst; |
1043 | |
1044 | // Instantiate the method if needed, or create a stub to a static method in a generic class. |
1045 | if (fMethodNeedsInstantiation) |
1046 | { |
1047 | DWORD nargs; |
1048 | IfFailThrow(ptr.GetData(&nargs)); |
1049 | |
1050 | SIZE_T cbMem; |
1051 | |
1052 | if (!ClrSafeInt<SIZE_T>::multiply(nargs, sizeof(TypeHandle), cbMem/* passed by ref */)) |
1053 | ThrowHR(COR_E_OVERFLOW); |
1054 | |
1055 | TypeHandle * pInst = (TypeHandle*)_alloca(cbMem); |
1056 | for (DWORD i = 0; i < nargs; i++) |
1057 | { |
1058 | pInst[i] = ptr.GetTypeHandleThrowing( |
1059 | pLookupModule, |
1060 | &typeContext, |
1061 | ClassLoader::LoadTypes, |
1062 | CLASS_LOADED, |
1063 | FALSE, |
1064 | NULL, |
1065 | pZapSigContext); |
1066 | IfFailThrow(ptr.SkipExactlyOne()); |
1067 | } |
1068 | |
1069 | inst = Instantiation(pInst, nargs); |
1070 | } |
1071 | else |
1072 | { |
1073 | inst = pMethod->GetMethodInstantiation(); |
1074 | } |
1075 | |
1076 | // This must be called even if nargs == 0, in order to create an instantiating |
1077 | // stub for static methods in generic classees if needed, also for BoxedEntryPointStubs |
1078 | // in non-generic structs. |
1079 | pMethod = MethodDesc::FindOrCreateAssociatedMethodDesc( |
1080 | pMethod, |
1081 | pOwnerMT, |
1082 | isUnboxingStub, |
1083 | inst, |
1084 | (!isInstantiatingStub && !isUnboxingStub)); |
1085 | |
1086 | if (kind == ConstrainedMethodEntrySlot) |
1087 | { |
1088 | if (isReadyToRunModule) |
1089 | { |
1090 | _ASSERTE((methodFlags & ENCODE_METHOD_SIG_Constrained) == ENCODE_METHOD_SIG_Constrained); |
1091 | |
1092 | constraintType = ptr.GetTypeHandleThrowing( |
1093 | pZapSigContext->pInfoModule, |
1094 | &typeContext, |
1095 | ClassLoader::LoadTypes, |
1096 | CLASS_LOADED, |
1097 | FALSE, |
1098 | NULL, |
1099 | pZapSigContext); |
1100 | } |
1101 | _ASSERTE(!constraintType.IsNull()); |
1102 | |
1103 | MethodDesc *pResolvedMD = constraintType.GetMethodTable()->TryResolveConstraintMethodApprox(ownerType, pMethod); |
1104 | |
1105 | // All such calls should be resolvable. If not then for now just throw an error. |
1106 | _ASSERTE(pResolvedMD); |
1107 | INDEBUG(if (!pResolvedMD) constraintType.GetMethodTable()->TryResolveConstraintMethodApprox(ownerType, pMethod);) |
1108 | if (!pResolvedMD) |
1109 | COMPlusThrowHR(COR_E_BADIMAGEFORMAT); |
1110 | |
1111 | result = (CORINFO_GENERIC_HANDLE)pResolvedMD->GetMultiCallableAddrOfCode(); |
1112 | } |
1113 | else |
1114 | if (kind == MethodEntrySlot) |
1115 | { |
1116 | result = (CORINFO_GENERIC_HANDLE)pMethod->GetMultiCallableAddrOfCode(); |
1117 | } |
1118 | else |
1119 | if (kind == DispatchStubAddrSlot) |
1120 | { |
1121 | _ASSERTE((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0); |
1122 | PCODE *ppCode = (PCODE*)(void*)pMethod->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(PCODE))); |
1123 | *ppCode = pMethod->GetMultiCallableAddrOfCode(); |
1124 | result = (CORINFO_GENERIC_HANDLE)ppCode; |
1125 | } |
1126 | else |
1127 | { |
1128 | _ASSERTE(kind == MethodDescSlot); |
1129 | result = (CORINFO_GENERIC_HANDLE)pMethod; |
1130 | } |
1131 | break; |
1132 | } |
1133 | |
1134 | case FieldDescSlot: |
1135 | { |
1136 | TypeHandle ownerType; |
1137 | |
1138 | if (isReadyToRunModule) |
1139 | { |
1140 | FieldDesc* pField = ZapSig::DecodeField((Module*)pZapSigContext->pModuleContext, pZapSigContext->pInfoModule, ptr.GetPtr(), &typeContext, &ownerType); |
1141 | _ASSERTE(!ownerType.IsNull()); |
1142 | |
1143 | if (!IsCompilationProcess()) |
1144 | ownerType.AsMethodTable()->EnsureInstanceActive(); |
1145 | |
1146 | result = (CORINFO_GENERIC_HANDLE)pField; |
1147 | } |
1148 | else |
1149 | { |
1150 | ownerType = ptr.GetTypeHandleThrowing( |
1151 | pLookupModule, |
1152 | &typeContext, |
1153 | (nonExpansive ? ClassLoader::DontLoadTypes : ClassLoader::LoadTypes), |
1154 | CLASS_LOADED, |
1155 | FALSE, |
1156 | NULL, |
1157 | pZapSigContext); |
1158 | if (ownerType.IsNull()) |
1159 | { |
1160 | _ASSERTE(nonExpansive); |
1161 | return NULL; |
1162 | } |
1163 | IfFailThrow(ptr.SkipExactlyOne()); |
1164 | |
1165 | DWORD fieldIndex; |
1166 | IfFailThrow(ptr.GetData(&fieldIndex)); |
1167 | |
1168 | if (!IsCompilationProcess()) |
1169 | ownerType.AsMethodTable()->EnsureInstanceActive(); |
1170 | |
1171 | result = (CORINFO_GENERIC_HANDLE)ownerType.AsMethodTable()->GetFieldDescByIndex(fieldIndex); |
1172 | } |
1173 | break; |
1174 | } |
1175 | |
1176 | default: |
1177 | _ASSERTE(!"Invalid DictionaryEntryKind" ); |
1178 | break; |
1179 | } |
1180 | |
1181 | ULONG slotIndex; |
1182 | if (isReadyToRunModule) |
1183 | { |
1184 | _ASSERT(dictionaryIndexAndSlot != -1); |
1185 | slotIndex = (ULONG)(dictionaryIndexAndSlot & 0xFFFF); |
1186 | } |
1187 | else |
1188 | { |
1189 | IfFailThrow(ptr.GetData(&slotIndex)); |
1190 | } |
1191 | |
1192 | MemoryBarrier(); |
1193 | |
1194 | if ((slotIndex != 0) && !IsCompilationProcess()) |
1195 | { |
1196 | *EnsureWritablePages(pDictionary->GetSlotAddr(0, slotIndex)) = result; |
1197 | *ppSlot = pDictionary->GetSlotAddr(0, slotIndex); |
1198 | } |
1199 | } |
1200 | |
1201 | return result; |
1202 | } // Dictionary::PopulateEntry |
1203 | |
1204 | //--------------------------------------------------------------------------------------- |
1205 | // |
1206 | void |
1207 | Dictionary::PrepopulateDictionary( |
1208 | MethodDesc * pMD, |
1209 | MethodTable * pMT, |
1210 | BOOL nonExpansive) |
1211 | { |
1212 | STANDARD_VM_CONTRACT; |
1213 | |
1214 | DictionaryLayout * pDictLayout = (pMT != NULL) ? pMT->GetClass()->GetDictionaryLayout() : pMD->GetDictionaryLayout(); |
1215 | DWORD numGenericArgs = (pMT != NULL) ? pMT->GetNumGenericArgs() : pMD->GetNumGenericMethodArgs(); |
1216 | |
1217 | if (pDictLayout != NULL) |
1218 | { |
1219 | for (DWORD i = 0; i < pDictLayout->GetNumUsedSlots(); i++) |
1220 | { |
1221 | if (IsSlotEmpty(numGenericArgs,i)) |
1222 | { |
1223 | DictionaryEntry * pSlot; |
1224 | DictionaryEntry entry; |
1225 | entry = PopulateEntry( |
1226 | pMD, |
1227 | pMT, |
1228 | pDictLayout->GetEntryLayout(i)->m_signature, |
1229 | nonExpansive, |
1230 | &pSlot); |
1231 | |
1232 | _ASSERT((entry == NULL) || (entry == GetSlot(numGenericArgs,i)) || IsCompilationProcess()); |
1233 | _ASSERT((pSlot == NULL) || (pSlot == GetSlotAddr(numGenericArgs,i))); |
1234 | } |
1235 | } |
1236 | } |
1237 | } // Dictionary::PrepopulateDictionary |
1238 | |
1239 | #endif //!DACCESS_COMPILE |
1240 | |