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: typehash.cpp
6//
7
8//
9
10#include "common.h"
11#include "excep.h"
12#include "typehash.h"
13#include "eeconfig.h"
14#include "generics.h"
15#include "typestring.h"
16#include "typedesc.h"
17#include "typekey.h"
18#ifdef FEATURE_PREJIT
19#include "zapsig.h"
20#include "compile.h"
21#endif
22#include "ngenhash.inl"
23
24#ifdef _MSC_VER
25#pragma warning(push)
26#pragma warning(disable:4244)
27#endif // _MSC_VER
28
29#ifndef DACCESS_COMPILE
30
31// ============================================================================
32// Class hash table methods
33// ============================================================================
34/* static */
35EETypeHashTable *EETypeHashTable::Create(LoaderAllocator* pAllocator, Module *pModule, DWORD dwNumBuckets, AllocMemTracker *pamTracker)
36{
37 CONTRACTL
38 {
39 THROWS;
40 GC_NOTRIGGER;
41 MODE_ANY;
42 INJECT_FAULT(COMPlusThrowOM(););
43 }
44 CONTRACTL_END
45
46 LoaderHeap *pHeap = pAllocator->GetLowFrequencyHeap();
47 EETypeHashTable *pThis = (EETypeHashTable*)pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(EETypeHashTable)));
48
49 new (pThis) EETypeHashTable(pModule, pHeap, dwNumBuckets);
50
51#ifdef _DEBUG
52 pThis->InitUnseal();
53#endif
54
55 pThis->m_pAllocator = pAllocator;
56
57 return pThis;
58}
59
60LoaderAllocator *EETypeHashTable::GetLoaderAllocator()
61{
62 WRAPPER_NO_CONTRACT;
63
64 if (m_pAllocator)
65 {
66 return m_pAllocator;
67 }
68 else
69 {
70 _ASSERTE(!m_pModule.IsNull());
71 return GetModule()->GetLoaderAllocator();
72 }
73}
74
75#endif // #ifdef DACCESS_COMPILE
76
77void EETypeHashTable::Iterator::Reset()
78{
79 WRAPPER_NO_CONTRACT;
80
81 if (m_pTable)
82 {
83#ifdef _DEBUG
84 m_pTable->Unseal();
85#endif
86 m_pTable = NULL;
87 }
88
89 Init();
90}
91
92void EETypeHashTable::Iterator::Init()
93{
94 WRAPPER_NO_CONTRACT;
95
96#ifdef _DEBUG
97 if (m_pTable)
98 m_pTable->Seal(); // The table cannot be changing while it is being iterated
99#endif
100
101 m_fIterating = false;
102}
103
104EETypeHashTable::Iterator::Iterator()
105{
106 WRAPPER_NO_CONTRACT;
107 m_pTable = NULL;
108 Init();
109}
110
111EETypeHashTable::Iterator::Iterator(EETypeHashTable * pTable)
112{
113 WRAPPER_NO_CONTRACT;
114 m_pTable = pTable;
115 Init();
116}
117
118EETypeHashTable::Iterator::~Iterator()
119{
120 WRAPPER_NO_CONTRACT;
121
122#ifdef _DEBUG
123 if (m_pTable)
124 m_pTable->Unseal(); // Done with the iterator so we unseal
125#endif
126}
127
128BOOL EETypeHashTable::FindNext(Iterator *it, EETypeHashEntry **ppEntry)
129{
130 LIMITED_METHOD_CONTRACT;
131
132 if (!it->m_fIterating)
133 {
134 BaseInitIterator(&it->m_sIterator);
135 it->m_fIterating = true;
136 }
137
138 *ppEntry = it->m_sIterator.Next();
139 return *ppEntry ? TRUE : FALSE;
140}
141
142DWORD EETypeHashTable::GetCount()
143{
144 LIMITED_METHOD_CONTRACT;
145
146 return BaseGetElementCount();
147}
148
149static DWORD HashTypeHandle(DWORD level, TypeHandle t);
150
151// Calculate hash value for a type def or instantiated type def
152static DWORD HashPossiblyInstantiatedType(DWORD level, mdTypeDef token, Instantiation inst)
153{
154 CONTRACTL
155 {
156 NOTHROW;
157 GC_NOTRIGGER;
158 MODE_ANY;
159 PRECONDITION(TypeFromToken(token) == mdtTypeDef);
160 SUPPORTS_DAC;
161 }
162 CONTRACTL_END
163
164 INT_PTR dwHash = 5381;
165
166 dwHash = ((dwHash << 5) + dwHash) ^ token;
167 if (!inst.IsEmpty())
168 {
169 dwHash = ((dwHash << 5) + dwHash) ^ inst.GetNumArgs();
170
171 // Hash two levels of the hiearchy. A simple nesting of generics instantiations is
172 // pretty common in generic collections, e.g.: ICollection<KeyValuePair<TKey, TValue>>
173 if (level < 2)
174 {
175 // Hash n type parameters
176 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
177 {
178 dwHash = ((dwHash << 5) + dwHash) ^ HashTypeHandle(level+1, inst[i]);
179 }
180 }
181 }
182
183 return dwHash;
184}
185
186// Calculate hash value for a function pointer type
187static DWORD HashFnPtrType(DWORD level, BYTE callConv, DWORD numArgs, TypeHandle *retAndArgTypes)
188{
189 WRAPPER_NO_CONTRACT;
190 SUPPORTS_DAC;
191 INT_PTR dwHash = 5381;
192
193 dwHash = ((dwHash << 5) + dwHash) ^ ELEMENT_TYPE_FNPTR;
194 dwHash = ((dwHash << 5) + dwHash) ^ callConv;
195 dwHash = ((dwHash << 5) + dwHash) ^ numArgs;
196 if (level < 1)
197 {
198 for (DWORD i = 0; i <= numArgs; i++)
199 {
200 dwHash = ((dwHash << 5) + dwHash) ^ HashTypeHandle(level+1, retAndArgTypes[i]);
201 }
202 }
203
204 return dwHash;
205}
206
207// Calculate hash value for an array/pointer/byref type
208static DWORD HashParamType(DWORD level, CorElementType kind, TypeHandle typeParam)
209{
210 WRAPPER_NO_CONTRACT;
211 INT_PTR dwHash = 5381;
212
213 dwHash = ((dwHash << 5) + dwHash) ^ kind;
214 dwHash = ((dwHash << 5) + dwHash) ^ HashTypeHandle(level, typeParam);
215
216 return dwHash;
217}
218
219// Calculate hash value from type handle
220static DWORD HashTypeHandle(DWORD level, TypeHandle t)
221{
222 CONTRACTL
223 {
224 NOTHROW;
225 GC_NOTRIGGER;
226 MODE_ANY;
227 SO_TOLERANT;
228 PRECONDITION(CheckPointer(t));
229 PRECONDITION(!t.IsEncodedFixup());
230 SUPPORTS_DAC;
231 }
232 CONTRACTL_END;
233
234 DWORD retVal = 0;
235
236 INTERIOR_STACK_PROBE_NOTHROW_CHECK_THREAD(goto Exit;);
237
238 if (t.HasTypeParam())
239 {
240 retVal = HashParamType(level, t.GetInternalCorElementType(), t.GetTypeParam());
241 }
242 else if (t.IsGenericVariable())
243 {
244 retVal = (dac_cast<PTR_TypeVarTypeDesc>(t.AsTypeDesc())->GetToken());
245 }
246 else if (t.HasInstantiation())
247 {
248 retVal = HashPossiblyInstantiatedType(level, t.GetCl(), t.GetInstantiation());
249 }
250 else if (t.IsFnPtrType())
251 {
252 FnPtrTypeDesc* pTD = t.AsFnPtrType();
253 retVal = HashFnPtrType(level, pTD->GetCallConv(), pTD->GetNumArgs(), pTD->GetRetAndArgTypesPointer());
254 }
255 else
256 retVal = HashPossiblyInstantiatedType(level, t.GetCl(), Instantiation());
257
258#if defined(FEATURE_STACK_PROBE) && !defined(DACCESS_COMPILE)
259Exit:
260 ;
261#endif
262 END_INTERIOR_STACK_PROBE;
263
264 return retVal;
265}
266
267// Calculate hash value from key
268static DWORD HashTypeKey(TypeKey* pKey)
269{
270 CONTRACTL
271 {
272 NOTHROW;
273 GC_NOTRIGGER;
274 MODE_ANY;
275 PRECONDITION(CheckPointer(pKey));
276 SUPPORTS_DAC;
277 }
278 CONTRACTL_END;
279
280 if (pKey->GetKind() == ELEMENT_TYPE_CLASS)
281 {
282 return HashPossiblyInstantiatedType(0, pKey->GetTypeToken(), pKey->GetInstantiation());
283 }
284 else if (pKey->GetKind() == ELEMENT_TYPE_FNPTR)
285 {
286 return HashFnPtrType(0, pKey->GetCallConv(), pKey->GetNumArgs(), pKey->GetRetAndArgTypes());
287 }
288 else
289 {
290 return HashParamType(0, pKey->GetKind(), pKey->GetElementType());
291 }
292}
293
294// Look up a value in the hash table
295//
296// The logic is subtle: type handles in the hash table may not be
297// restored, but we need to compare components of the types (rank and
298// element type for arrays, generic type and instantiation for
299// instantiated types) against pKey
300//
301// We avoid restoring types during search by cracking the signature
302// encoding used by the zapper for out-of-module types e.g. in the
303// instantiation of an instantiated type.
304EETypeHashEntry_t *EETypeHashTable::FindItem(TypeKey* pKey)
305{
306 CONTRACTL
307 {
308 INSTANCE_CHECK;
309 NOTHROW;
310 GC_NOTRIGGER;
311 MODE_ANY;
312 PRECONDITION(CheckPointer(pKey));
313 SUPPORTS_DAC;
314 }
315 CONTRACTL_END;
316
317 EETypeHashEntry_t * result = NULL;
318
319 DWORD dwHash = HashTypeKey(pKey);
320 EETypeHashEntry_t * pSearch;
321 CorElementType kind = pKey->GetKind();
322 LookupContext sContext;
323
324 if (kind == ELEMENT_TYPE_CLASS)
325 {
326 pSearch = BaseFindFirstEntryByHash(dwHash, &sContext);
327 while (pSearch)
328 {
329 if (CompareInstantiatedType(pSearch->GetTypeHandle(), pKey->GetModule(), pKey->GetTypeToken(), pKey->GetInstantiation()))
330 {
331 result = pSearch;
332 break;
333 }
334
335 pSearch = BaseFindNextEntryByHash(&sContext);
336 }
337 }
338 else if (kind == ELEMENT_TYPE_FNPTR)
339 {
340 BYTE callConv = pKey->GetCallConv();
341 DWORD numArgs = pKey->GetNumArgs();
342 TypeHandle *retAndArgTypes = pKey->GetRetAndArgTypes();
343
344 pSearch = BaseFindFirstEntryByHash(dwHash, &sContext);
345 while (pSearch)
346 {
347 if (CompareFnPtrType(pSearch->GetTypeHandle(), callConv, numArgs, retAndArgTypes))
348 {
349 result = pSearch;
350 break;
351 }
352
353 pSearch = BaseFindNextEntryByHash(&sContext);
354 }
355 }
356 else
357 {
358 // Type parameters for array and pointer types are necessarily in the same loader module
359 // as the constructed type itself, so we can just do handle comparisons
360 // Unfortunately the rank of the array might live elsewhere
361
362 for (pSearch = BaseFindFirstEntryByHash(dwHash, &sContext);
363 pSearch != NULL;
364 pSearch = BaseFindNextEntryByHash(&sContext))
365 {
366 if (!pSearch->GetTypeHandle().IsRestored())
367 {
368 // workaround: If we encounter an unrestored MethodTable, then it
369 // isn't the type for which we are looking (plus, it will crash
370 // in GetSignatureCorElementType). However TypeDescs can be
371 // accessed when unrestored. Also they are accessed in that
372 // manner at startup when we're loading the global types
373 // (i.e. System.Object).
374
375 if (!pSearch->GetTypeHandle().IsTypeDesc())
376 {
377 // Not a match
378 continue;
379 }
380 else
381 {
382 // We have an unrestored TypeDesc
383 }
384 }
385
386 if (pSearch->GetTypeHandle().GetSignatureCorElementType() != kind)
387 continue;
388
389 if (pSearch->GetTypeHandle().GetTypeParam() != pKey->GetElementType())
390 continue;
391
392 if (pSearch->GetTypeHandle().IsTypeDesc() == pKey->IsTemplateMethodTable())
393 continue;
394
395 if (kind == ELEMENT_TYPE_ARRAY)
396 {
397 if (pKey->IsTemplateMethodTable())
398 {
399 if (pSearch->GetTypeHandle().AsMethodTable()->GetRank() != pKey->GetRank())
400 continue;
401 }
402 else
403 {
404 ArrayTypeDesc *pATD = pSearch->GetTypeHandle().AsArray();
405#ifdef FEATURE_PREJIT
406 // This ensures that GetAssemblyIfLoaded operations that may be triggered by signature walks will succeed if at all possible.
407 ClrFlsThreadTypeSwitch genericInstantionCompareHolder(ThreadType_GenericInstantiationCompare);
408
409 TADDR fixup = pATD->GetTemplateMethodTableMaybeTagged();
410 if (!CORCOMPILE_IS_POINTER_TAGGED(fixup))
411 {
412 TADDR canonFixup = pATD->GetTemplateMethodTable()->GetCanonicalMethodTableFixup();
413 if (CORCOMPILE_IS_POINTER_TAGGED(canonFixup))
414 fixup = canonFixup;
415 }
416
417 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
418 {
419 Module *pDefiningModule;
420 PCCOR_SIGNATURE pSig = GetModule()->GetEncodedSigIfLoaded(CORCOMPILE_UNTAG_TOKEN(fixup), &pDefiningModule);
421 if (pDefiningModule == NULL)
422 break;
423
424 _ASSERTE(*pSig == ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
425 pSig++;
426 _ASSERTE(*pSig == ELEMENT_TYPE_ARRAY);
427 pSig++;
428 SigPointer sp(pSig);
429 if (FAILED(sp.SkipExactlyOne()))
430 break; // return NULL;
431
432 ULONG data;
433 if (FAILED(sp.GetData(&data)))
434 break; // return NULL;
435
436 if (data != pKey->GetRank())
437 continue;
438 }
439 else
440#endif //FEATURE_PREJIT
441 {
442 if (pATD->GetRank() != pKey->GetRank())
443 continue;
444 }
445 }
446 }
447
448 result = pSearch;
449 break;
450 }
451 }
452
453 return result;
454}
455
456BOOL EETypeHashTable::CompareInstantiatedType(TypeHandle t, Module *pModule, mdTypeDef token, Instantiation inst)
457{
458 CONTRACTL
459 {
460 INSTANCE_CHECK;
461 NOTHROW;
462 GC_NOTRIGGER;
463 MODE_ANY;
464 PRECONDITION(CheckPointer(t));
465 PRECONDITION(CheckPointer(pModule));
466 PRECONDITION(!inst.IsEmpty());
467 SUPPORTS_DAC;
468 }
469 CONTRACTL_END
470
471 if (t.IsTypeDesc())
472 return FALSE;
473
474 // Even the EEClass pointer might be encoded
475 MethodTable * pMT = t.AsMethodTable();
476
477 if (pMT->GetNumGenericArgs() != inst.GetNumArgs())
478 return FALSE;
479
480#ifdef FEATURE_PREJIT
481 // This ensures that GetAssemblyIfLoaded operations that may be triggered by signature walks will succeed if at all possible.
482 ClrFlsThreadTypeSwitch genericInstantionCompareHolder(ThreadType_GenericInstantiationCompare);
483
484 TADDR fixup = pMT->GetCanonicalMethodTableFixup();
485
486 // The EEClass pointer is actually an encoding.
487 if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
488 {
489 Module *pDefiningModule;
490
491 PCCOR_SIGNATURE pSig = GetModule()->GetEncodedSigIfLoaded(CORCOMPILE_UNTAG_TOKEN(fixup), &pDefiningModule);
492
493 // First check that the modules for the generic type defs match
494 if (dac_cast<TADDR>(pDefiningModule) !=
495 dac_cast<TADDR>(pModule))
496 return FALSE;
497
498 // Now crack the signature encoding, expected to be an instantiated type
499 _ASSERTE(*pSig == ELEMENT_TYPE_GENERICINST);
500 pSig++;
501 _ASSERTE(*pSig == ELEMENT_TYPE_CLASS || *pSig == ELEMENT_TYPE_VALUETYPE);
502 pSig++;
503
504 // Check that the tokens of the generic type def match
505 if (CorSigUncompressToken(pSig) != token)
506 return FALSE;
507 }
508
509 // The EEClass pointer is a real pointer
510 else
511#endif //FEATURE_PREJIT
512 {
513 // First check that the typedef tokens match
514 if (pMT->GetCl() != token)
515 return FALSE;
516
517 // The class might not be restored, and its metadata module pointer might be encoded.
518 // This will return NULL if the module for the corresponding generic class
519 // is not loaded.
520 Module *pGenericModuleIfLoaded = pMT->GetModuleIfLoaded();
521
522 // Now check that the modules match
523 if (!pGenericModuleIfLoaded ||
524 dac_cast<TADDR>(pGenericModuleIfLoaded) !=
525 dac_cast<TADDR>(pModule))
526 return FALSE;
527
528 }
529
530 Instantiation candidateInst = t.GetInstantiation();
531
532 // Now check the instantiations. Some type arguments might be encoded.
533 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
534 {
535 // Fetch the type handle as TADDR. It may be may be encoded fixup - TypeHandle debug-only validation
536 // asserts on encoded fixups.
537 DACCOP_IGNORE(CastOfMarshalledType, "Dual mode DAC problem, but since the size is the same, the cast is safe");
538 TADDR candidateArg = ((FixupPointer<TADDR> *)candidateInst.GetRawArgs())[i].GetValue();
539
540 if (!ZapSig::CompareTaggedPointerToTypeHandle(GetModule(), candidateArg, inst[i]))
541 {
542 return FALSE;
543 }
544 }
545
546 return TRUE;
547}
548
549BOOL EETypeHashTable::CompareFnPtrType(TypeHandle t, BYTE callConv, DWORD numArgs, TypeHandle *retAndArgTypes)
550{
551 CONTRACTL
552 {
553 INSTANCE_CHECK;
554 NOTHROW;
555 GC_NOTRIGGER;
556 MODE_ANY;
557 PRECONDITION(CheckPointer(t));
558 PRECONDITION(CheckPointer(retAndArgTypes));
559 SUPPORTS_DAC;
560 }
561 CONTRACTL_END
562
563 if (!t.IsFnPtrType())
564 return FALSE;
565
566#ifndef DACCESS_COMPILE
567#ifdef FEATURE_PREJIT
568 // This ensures that GetAssemblyIfLoaded operations that may be triggered by signature walks will succeed if at all possible.
569 ClrFlsThreadTypeSwitch genericInstantionCompareHolder(ThreadType_GenericInstantiationCompare);
570#endif
571
572 FnPtrTypeDesc* pTD = t.AsFnPtrType();
573
574 if (pTD->GetNumArgs() != numArgs || pTD->GetCallConv() != callConv)
575 return FALSE;
576
577 // Now check the return and argument types. Some type arguments might be encoded.
578 TypeHandle *retAndArgTypes2 = pTD->GetRetAndArgTypesPointer();
579 for (DWORD i = 0; i <= numArgs; i++)
580 {
581 TADDR candidateArg = retAndArgTypes2[i].AsTAddr();
582 if (!ZapSig::CompareTaggedPointerToTypeHandle(GetModule(), candidateArg, retAndArgTypes[i]))
583 {
584 return FALSE;
585 }
586 }
587
588 return TRUE;
589
590#else
591 DacNotImpl();
592 return FALSE;
593#endif // #ifndef DACCESS_COMPILE
594}
595
596TypeHandle EETypeHashTable::GetValue(TypeKey *pKey)
597{
598 CONTRACTL
599 {
600 NOTHROW;
601 GC_NOTRIGGER;
602 MODE_ANY;
603 SUPPORTS_DAC;
604 }
605 CONTRACTL_END;
606
607 EETypeHashEntry_t *pItem = FindItem(pKey);
608
609 if (pItem)
610 {
611 TypeHandle th = pItem->GetTypeHandle();
612 g_IBCLogger.LogTypeHashTableAccess(&th);
613 return pItem->GetTypeHandle();
614 }
615 else
616 return TypeHandle();
617}
618
619#ifndef DACCESS_COMPILE
620
621BOOL EETypeHashTable::ContainsValue(TypeHandle th)
622{
623 CONTRACTL
624 {
625 NOTHROW;
626 GC_NOTRIGGER;
627 SO_INTOLERANT;
628 MODE_ANY;
629 }
630 CONTRACTL_END;
631
632 TypeKey typeKey = th.GetTypeKey();
633 return !GetValue(&typeKey).IsNull();
634}
635
636// Insert a value not already in the hash table
637VOID EETypeHashTable::InsertValue(TypeHandle data)
638{
639 CONTRACTL
640 {
641 INSTANCE_CHECK;
642 THROWS;
643 GC_NOTRIGGER;
644 MODE_ANY;
645 INJECT_FAULT(COMPlusThrowOM(););
646 PRECONDITION(IsUnsealed()); // If we are sealed then we should not be adding to this hashtable
647 PRECONDITION(CheckPointer(data));
648 PRECONDITION(!data.IsEncodedFixup());
649 PRECONDITION(!data.IsGenericTypeDefinition()); // Generic type defs live in typedef table (availableClasses)
650 PRECONDITION(data.HasInstantiation() || data.HasTypeParam() || data.IsFnPtrType()); // It's an instantiated type or an array/ptr/byref type
651 PRECONDITION(m_pModule.IsNull() || GetModule()->IsTenured()); // Destruct won't destruct m_pAvailableParamTypes for non-tenured modules - so make sure no one tries to insert one before the Module has been tenured
652 }
653 CONTRACTL_END
654
655 EETypeHashEntry_t * pNewEntry = (EETypeHashEntry_t*)BaseAllocateEntry(NULL);
656
657 pNewEntry->SetTypeHandle(data);
658
659 BaseInsertEntry(HashTypeHandle(0, data), pNewEntry);
660}
661
662#ifdef FEATURE_NATIVE_IMAGE_GENERATION
663
664#ifdef _DEBUG
665void EETypeHashTableSeal(EETypeHashTable * pTable) { WRAPPER_NO_CONTRACT; pTable->Seal(); }
666void EETypeHashTableUnseal(EETypeHashTable * pTable) { WRAPPER_NO_CONTRACT; pTable->Unseal(); }
667typedef Wrapper<EETypeHashTable *, EETypeHashTableSeal, EETypeHashTableUnseal> EETypeHashTableSealHolder;
668#endif
669
670// Save the hash table and any type descriptors referenced by it
671// Method tables must be saved separately
672void EETypeHashTable::Save(DataImage *image, Module *module, CorProfileData *profileData)
673{
674 CONTRACTL
675 {
676 STANDARD_VM_CHECK;
677 PRECONDITION(image->GetModule() == GetModule());
678 }
679 CONTRACTL_END;
680
681#ifdef _DEBUG
682 // The table should not change while we are walking the buckets
683 EETypeHashTableSealHolder h(this);
684#endif
685
686 // The base class will call us back for every entry to see if it's considered hot. To determine this we
687 // have to walk through the profiling data. It's very inefficient for us to do this every time. Instead
688 // we'll walk the data once just now and mark each hot entry as we find it.
689 CORBBTPROF_TOKEN_INFO * pTypeProfilingData = profileData->GetTokenFlagsData(TypeProfilingData);
690 DWORD cTypeProfilingData = profileData->GetTokenFlagsCount(TypeProfilingData);
691
692 for (unsigned int i = 0; i < cTypeProfilingData; i++)
693 {
694 CORBBTPROF_TOKEN_INFO *entry = &pTypeProfilingData[i];
695 mdToken token = entry->token;
696 DWORD flags = entry->flags;
697
698 if (TypeFromToken(token) != ibcTypeSpec)
699 continue;
700
701 if ((flags & (1 << ReadTypeHashTable)) == 0)
702 continue;
703
704 CORBBTPROF_BLOB_ENTRY *pBlobEntry = profileData->GetBlobStream();
705 if (pBlobEntry)
706 {
707 while (pBlobEntry->TypeIsValid())
708 {
709 if (TypeFromToken(pBlobEntry->token) == ibcTypeSpec)
710 {
711 _ASSERTE(pBlobEntry->type == ParamTypeSpec);
712
713 CORBBTPROF_BLOB_PARAM_SIG_ENTRY *pBlobSigEntry = (CORBBTPROF_BLOB_PARAM_SIG_ENTRY *) pBlobEntry;
714
715 if (pBlobEntry->token == token)
716 {
717 if (flags & (1<<ReadTypeHashTable))
718 {
719 TypeHandle th = GetModule()->LoadIBCTypeHelper(image, pBlobSigEntry);
720#if defined(_DEBUG) && !defined(DACCESS_COMPILE)
721 g_pConfig->DebugCheckAndForceIBCFailure(EEConfig::CallSite_8);
722#endif
723 if (!th.IsNull())
724 {
725 // Found a hot type. See if we have it in our table.
726 DWORD dwHash = HashTypeHandle(0, th);
727 LookupContext sContext;
728 EETypeHashEntry_t *pSearch = BaseFindFirstEntryByHash(dwHash, &sContext);
729 while (pSearch)
730 {
731 if (pSearch->GetTypeHandle() == th)
732 {
733 // Found the corresponding entry in the table. Mark it as hot.
734 pSearch->MarkAsHot();
735 break;
736 }
737
738 pSearch = BaseFindNextEntryByHash(&sContext);
739 }
740 }
741 }
742 }
743 }
744 pBlobEntry = pBlobEntry->GetNextEntry();
745 }
746 }
747 }
748
749 BaseSave(image, profileData);
750}
751
752bool EETypeHashTable::ShouldSave(DataImage *pImage, EETypeHashEntry_t *pEntry)
753{
754 STANDARD_VM_CONTRACT;
755
756 return !!pImage->GetPreloader()->IsTypeInTransitiveClosureOfInstantiations(CORINFO_CLASS_HANDLE(pEntry->GetTypeHandle().AsPtr()));
757}
758
759bool EETypeHashTable::IsHotEntry(EETypeHashEntry_t *pEntry, CorProfileData *pProfileData)
760{
761 STANDARD_VM_CONTRACT;
762
763 // EETypeHashTable::Save() will have marked the entry as hot if the profile data indicated this.
764 return pEntry->IsHot();
765}
766
767bool EETypeHashTable::SaveEntry(DataImage *pImage, CorProfileData *pProfileData, EETypeHashEntry_t *pOldEntry, EETypeHashEntry_t *pNewEntry, EntryMappingTable *pMap)
768{
769 LIMITED_METHOD_CONTRACT;
770
771 return false;
772}
773
774void EETypeHashTable::Fixup(DataImage *image)
775{
776 STANDARD_VM_CONTRACT;
777
778 BaseFixup(image);
779
780 image->ZeroPointerField(this, offsetof(EETypeHashTable, m_pAllocator));
781
782#ifdef _DEBUG
783 // The persisted table should be unsealed.
784 EETypeHashTable *pNewTable = (EETypeHashTable*) image->GetImagePointer(this);
785 pNewTable->InitUnseal();
786#endif
787}
788
789void EETypeHashTable::FixupEntry(DataImage *pImage, EETypeHashEntry_t *pEntry, void *pFixupBase, DWORD cbFixupOffset)
790{
791 STANDARD_VM_CONTRACT;
792
793 TypeHandle pType = pEntry->GetTypeHandle();
794 _ASSERTE(!pType.IsNull());
795
796 // Clear any hot entry marking in the data, it's not needed after the Save phase.
797 pEntry->SetTypeHandle(pType);
798
799 if (pType.IsTypeDesc())
800 {
801 pImage->FixupField(pFixupBase, cbFixupOffset + offsetof(EETypeHashEntry_t, m_data),
802 pType.AsTypeDesc(), 2, IMAGE_REL_BASED_RelativePointer);
803
804 pType.AsTypeDesc()->Fixup(pImage);
805 }
806 else
807 {
808 pImage->FixupField(pFixupBase, cbFixupOffset + offsetof(EETypeHashEntry_t, m_data),
809 pType.AsMethodTable(), 0, IMAGE_REL_BASED_RelativePointer);
810
811 pType.AsMethodTable()->Fixup(pImage);
812 }
813}
814#endif // FEATURE_NATIVE_IMAGE_GENERATION
815
816#endif // #ifndef DACCESS_COMPILE
817
818#ifdef DACCESS_COMPILE
819
820void
821EETypeHashTable::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
822{
823 SUPPORTS_DAC;
824
825 BaseEnumMemoryRegions(flags);
826}
827
828void EETypeHashTable::EnumMemoryRegionsForEntry(EETypeHashEntry_t *pEntry, CLRDataEnumMemoryFlags flags)
829{
830 SUPPORTS_DAC;
831
832 pEntry->GetTypeHandle().EnumMemoryRegions(flags);
833}
834
835#endif // #ifdef DACCESS_COMPILE
836
837TypeHandle EETypeHashEntry::GetTypeHandle()
838{
839 LIMITED_METHOD_DAC_CONTRACT;
840
841 // Remove any hot entry indicator bit that may have been set as the result of Ngen saving.
842 TADDR data = dac_cast<TADDR>(GetData());
843 return TypeHandle::FromTAddr(data & ~0x1);
844}
845
846#ifndef DACCESS_COMPILE
847void EETypeHashEntry::SetTypeHandle(TypeHandle handle)
848{
849 LIMITED_METHOD_DAC_CONTRACT;
850
851 // We plan to steal the low-order bit of the handle for ngen purposes.
852 _ASSERTE((handle.AsTAddr() & 0x1) == 0);
853 m_data.SetValueMaybeNull(handle.AsPtr());
854}
855#endif // !DACCESS_COMPILE
856
857#ifdef FEATURE_PREJIT
858bool EETypeHashEntry::IsHot()
859{
860 LIMITED_METHOD_CONTRACT;
861
862 // Low order bit of data field indicates a hot entry.
863 TADDR data = dac_cast<TADDR>(GetData());
864 return (data & 1) != 0;
865}
866
867#ifndef DACCESS_COMPILE
868void EETypeHashEntry::MarkAsHot()
869{
870 LIMITED_METHOD_CONTRACT;
871
872 // Low order bit of data field indicates a hot entry.
873 TADDR data = dac_cast<TADDR>(GetData());
874 data |= 0x1;
875 m_data.SetValueMaybeNull(dac_cast<PTR_VOID>(data));
876}
877#endif // !DACCESS_COMPILE
878#endif // FEATURE_PREJIT
879
880#ifdef _MSC_VER
881#pragma warning(pop)
882#endif // _MSC_VER: warning C4244
883