[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / readytoruninfo.cpp
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: ReadyToRunInfo.cpp
6 // 
7
8 //
9 // Runtime support for Ready to Run
10 // ===========================================================================
11
12 #include "common.h"
13
14 #include "dbginterface.h"
15 #include "compile.h"
16 #include "versionresilienthashcode.h"
17 #include "typehashingalgorithms.h"
18 #include "method.hpp"
19 #include "wellknownattributes.h"
20
21 using namespace NativeFormat;
22
23 IMAGE_DATA_DIRECTORY * ReadyToRunInfo::FindSection(DWORD type)
24 {
25     CONTRACTL
26     {
27         GC_NOTRIGGER;
28         NOTHROW;
29         SUPPORTS_DAC;
30     }
31     CONTRACTL_END;
32
33     PTR_READYTORUN_SECTION pSections = dac_cast<PTR_READYTORUN_SECTION>(dac_cast<TADDR>(m_pHeader) + sizeof(READYTORUN_HEADER));
34     for (DWORD i = 0; i < m_pHeader->NumberOfSections; i++)
35     {
36         // Verify that section types are sorted
37         _ASSERTE(i == 0 || (pSections[i-1].Type < pSections[i].Type));
38
39         READYTORUN_SECTION * pSection = pSections + i;
40         if (pSection->Type == type)
41             return &pSection->Section;
42     }
43     return NULL;
44 }
45
46 MethodDesc * ReadyToRunInfo::GetMethodDescForEntryPoint(PCODE entryPoint)
47 {
48     CONTRACTL
49     {
50         GC_NOTRIGGER;
51         NOTHROW;
52         SUPPORTS_DAC;
53     }
54     CONTRACTL_END;
55
56 #if defined(_TARGET_AMD64_) || (defined(_TARGET_X86_) && defined(FEATURE_PAL))
57     // A normal method entry point is always 8 byte aligned, but a funclet can start at an odd address.
58     // Since PtrHashMap can't handle odd pointers, check for this case and return NULL.
59     if ((entryPoint & 0x1) != 0)
60         return NULL;
61 #endif
62
63     TADDR val = (TADDR)m_entryPointToMethodDescMap.LookupValue(PCODEToPINSTR(entryPoint), (LPVOID)PCODEToPINSTR(entryPoint));
64     if (val == (TADDR)INVALIDENTRY)
65         return NULL;
66     return dac_cast<PTR_MethodDesc>(val);
67 }
68
69 BOOL ReadyToRunInfo::HasHashtableOfTypes()
70 {
71     CONTRACTL
72     {
73         GC_NOTRIGGER;
74         NOTHROW;
75         SUPPORTS_DAC;
76     }
77     CONTRACTL_END;
78
79     return !m_availableTypesHashtable.IsNull();
80 }
81
82 BOOL ReadyToRunInfo::TryLookupTypeTokenFromName(const NameHandle *pName, mdToken * pFoundTypeToken)
83 {
84     CONTRACTL
85     {
86         GC_NOTRIGGER;
87         NOTHROW;
88         SUPPORTS_DAC;
89         PRECONDITION(!m_availableTypesHashtable.IsNull());
90     }
91     CONTRACTL_END;
92
93     if (m_availableTypesHashtable.IsNull())
94         return FALSE;
95
96     LPCUTF8 pszName = NULL;
97     LPCUTF8 pszNameSpace = NULL;
98
99     //
100     // Compute the hashcode of the type (hashcode based on type name and namespace name)
101     //
102     int dwHashCode = 0;
103
104     if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
105     {
106         // Name-based lookups (ex: Type.GetType()). 
107
108         pszName = pName->GetName();
109         pszNameSpace = "";
110
111         if (pName->GetNameSpace() != NULL)
112         {
113             pszNameSpace = pName->GetNameSpace();
114         }
115         else
116         {
117             LPCUTF8 p;
118             CQuickBytes szNamespace;
119
120             if ((p = ns::FindSep(pszName)) != NULL)
121             {
122                 SIZE_T d = p - pszName;
123
124                 FAULT_NOT_FATAL();
125                 pszNameSpace = szNamespace.SetStringNoThrow(pszName, d);
126
127                 if (pszNameSpace == NULL)
128                     return FALSE;
129
130                 pszName = (p + 1);
131             }
132         }
133
134         _ASSERT(pszNameSpace != NULL);
135         dwHashCode ^= ComputeNameHashCode(pszNameSpace, pszName);
136
137         // Bucket is not 'null' for a nested type, and it will have information about the nested type's encloser
138         if (!pName->GetBucket().IsNull())
139         {
140             // Must be a token based bucket that we found earlier in the R2R types hashtable
141             _ASSERT(pName->GetBucket().GetEntryType() == HashedTypeEntry::IsHashedTokenEntry);
142
143             const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
144
145             // Token must be a typedef token that we previously resolved (we shouldn't get here with an exported type token)
146             _ASSERT(TypeFromToken(tokenBasedEncloser.m_TypeToken) == mdtTypeDef);
147
148             int dwCurrentHashCode;
149             mdToken mdCurrentTypeToken = tokenBasedEncloser.m_TypeToken;
150             if (!GetVersionResilientTypeHashCode(tokenBasedEncloser.m_pModule->GetMDImport(), mdCurrentTypeToken, &dwCurrentHashCode))
151                 return FALSE;
152             dwHashCode ^= dwCurrentHashCode;
153         }
154     }
155     else
156     {
157         // Token based lookups (ex: tokens from IL code)
158
159         if (!GetVersionResilientTypeHashCode(pName->GetTypeModule()->GetMDImport(), pName->GetTypeToken(), &dwHashCode))
160             return FALSE;
161     }
162
163
164     //
165     // Lookup the type in the native hashtable using the computed token
166     //
167     {
168         NativeHashtable::Enumerator lookup = m_availableTypesHashtable.Lookup((int)dwHashCode);
169         NativeParser entryParser;
170         while (lookup.GetNext(entryParser))
171         {
172             DWORD ridAndFlag = entryParser.GetUnsigned();
173             mdToken cl = ((ridAndFlag & 1) ? ((ridAndFlag >> 1) | mdtExportedType) : ((ridAndFlag >> 1) | mdtTypeDef));
174             _ASSERT(RidFromToken(cl) != 0);
175
176             if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
177             {
178                 // Compare type name and namespace name
179                 LPCUTF8 pszFoundName;
180                 LPCUTF8 pszFoundNameSpace;
181                 if (!GetTypeNameFromToken(m_pModule->GetMDImport(), cl, &pszFoundName, &pszFoundNameSpace))
182                     continue;
183                 if (strcmp(pszName, pszFoundName) != 0 || strcmp(pszNameSpace, pszFoundNameSpace) != 0)
184                     continue;
185
186                 mdToken mdFoundTypeEncloser;
187                 BOOL inputTypeHasEncloser = !pName->GetBucket().IsNull();
188                 BOOL foundTypeHasEncloser = GetEnclosingToken(m_pModule->GetMDImport(), cl, &mdFoundTypeEncloser);
189                 if (inputTypeHasEncloser != foundTypeHasEncloser)
190                     continue;
191
192                 // Compare the enclosing types chain for a match
193                 if (inputTypeHasEncloser)
194                 {
195                     const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
196
197                     if (!CompareTypeNameOfTokens(tokenBasedEncloser.m_TypeToken, tokenBasedEncloser.m_pModule->GetMDImport(), mdFoundTypeEncloser, m_pModule->GetMDImport()))
198                         continue;
199                 }
200             }
201             else
202             {
203                 // Compare type name, namespace name, and enclosing types chain for a match
204                 if (!CompareTypeNameOfTokens(pName->GetTypeToken(), pName->GetTypeModule()->GetMDImport(), cl, m_pModule->GetMDImport()))
205                     continue;
206             }
207
208             // Found a match!
209             *pFoundTypeToken = cl;
210             return TRUE;
211         }
212     }
213
214     return FALSE;   // No matching type found
215 }
216
217 BOOL ReadyToRunInfo::GetTypeNameFromToken(IMDInternalImport * pImport, mdToken mdType, LPCUTF8 * ppszName, LPCUTF8 * ppszNameSpace)
218 {
219     CONTRACTL
220     {
221         GC_NOTRIGGER;
222         NOTHROW;
223         SUPPORTS_DAC;
224         PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
225     }
226     CONTRACTL_END;
227
228     switch (TypeFromToken(mdType))
229     {
230     case mdtTypeDef: 
231         return SUCCEEDED(pImport->GetNameOfTypeDef(mdType, ppszName, ppszNameSpace));
232     case mdtTypeRef: 
233         return SUCCEEDED(pImport->GetNameOfTypeRef(mdType, ppszNameSpace, ppszName));
234     case mdtExportedType:
235         return SUCCEEDED(pImport->GetExportedTypeProps(mdType, ppszNameSpace, ppszName, NULL, NULL, NULL));
236     }
237
238     return FALSE;
239 }
240
241 BOOL ReadyToRunInfo::GetEnclosingToken(IMDInternalImport * pImport, mdToken mdType, mdToken * pEnclosingToken)
242 {
243     CONTRACTL
244     {
245         GC_NOTRIGGER;
246         NOTHROW;
247         SUPPORTS_DAC;
248         PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
249     }
250     CONTRACTL_END;
251
252     switch (TypeFromToken(mdType))
253     {
254     case mdtTypeDef:
255         return SUCCEEDED(pImport->GetNestedClassProps(mdType, pEnclosingToken));
256
257     case mdtTypeRef:
258         if (SUCCEEDED(pImport->GetResolutionScopeOfTypeRef(mdType, pEnclosingToken)))
259             return ((TypeFromToken(*pEnclosingToken) == mdtTypeRef) && (*pEnclosingToken != mdTypeRefNil));
260
261     case mdtExportedType:
262         if (SUCCEEDED(pImport->GetExportedTypeProps(mdType, NULL, NULL, pEnclosingToken, NULL, NULL)))
263             return ((TypeFromToken(*pEnclosingToken) == mdtExportedType) && (*pEnclosingToken != mdExportedTypeNil));
264     }
265
266     return FALSE;
267 }
268
269 BOOL ReadyToRunInfo::CompareTypeNameOfTokens(mdToken mdToken1, IMDInternalImport * pImport1, mdToken mdToken2, IMDInternalImport * pImport2)
270 {
271     CONTRACTL
272     {
273         GC_NOTRIGGER;
274         NOTHROW;
275         SUPPORTS_DAC;
276         PRECONDITION(TypeFromToken(mdToken1) == mdtTypeDef || TypeFromToken(mdToken1) == mdtTypeRef || TypeFromToken(mdToken1) == mdtExportedType);
277         PRECONDITION(TypeFromToken(mdToken2) == mdtTypeDef || TypeFromToken(mdToken2) == mdtExportedType);
278     }
279     CONTRACTL_END;
280
281     BOOL hasEncloser;
282     do
283     {
284         LPCUTF8 pszName1;
285         LPCUTF8 pszNameSpace1;
286         if (!GetTypeNameFromToken(pImport1, mdToken1, &pszName1, &pszNameSpace1))
287             return FALSE;
288
289         LPCUTF8 pszName2;
290         LPCUTF8 pszNameSpace2;
291         if (!GetTypeNameFromToken(pImport2, mdToken2, &pszName2, &pszNameSpace2))
292             return FALSE;
293
294         if (strcmp(pszName1, pszName2) != 0 || strcmp(pszNameSpace1, pszNameSpace2) != 0)
295             return FALSE;
296
297         if ((hasEncloser = GetEnclosingToken(pImport1, mdToken1, &mdToken1)) != GetEnclosingToken(pImport2, mdToken2, &mdToken2))
298             return FALSE;
299
300     } while (hasEncloser);
301
302     return TRUE;
303 }
304
305 PTR_BYTE ReadyToRunInfo::GetDebugInfo(PTR_RUNTIME_FUNCTION pRuntimeFunction)
306 {
307     CONTRACTL
308     {
309         GC_NOTRIGGER;
310         THROWS;
311         MODE_ANY;
312         SUPPORTS_DAC;
313     }
314     CONTRACTL_END;
315
316     IMAGE_DATA_DIRECTORY * pDebugInfoDir = FindSection(READYTORUN_SECTION_DEBUG_INFO);
317     if (pDebugInfoDir == NULL)
318         return NULL;
319
320     SIZE_T methodIndex = pRuntimeFunction - m_pRuntimeFunctions;
321     _ASSERTE(methodIndex < m_nRuntimeFunctions);
322
323     NativeArray debugInfoIndex(dac_cast<PTR_NativeReader>(PTR_HOST_INT_TO_TADDR(&m_nativeReader)), pDebugInfoDir->VirtualAddress);
324
325     uint offset;
326     if (!debugInfoIndex.TryGetAt((DWORD)methodIndex, &offset))
327         return NULL;
328
329     uint lookBack;
330     uint debugInfoOffset = m_nativeReader.DecodeUnsigned(offset, &lookBack);
331
332     if (lookBack != 0)
333         debugInfoOffset = offset - lookBack;
334
335     return dac_cast<PTR_BYTE>(m_pLayout->GetBase()) + debugInfoOffset;
336 }
337
338 #ifndef DACCESS_COMPILE
339
340 BOOL ReadyToRunInfo::IsReadyToRunEnabled()
341 {
342     WRAPPER_NO_CONTRACT;
343
344     static ConfigDWORD configReadyToRun;
345     return configReadyToRun.val(CLRConfig::EXTERNAL_ReadyToRun);
346 }
347
348 // A log file to record success/failure of R2R loads. s_r2rLogFile can have the following values:
349 // -1: Logging not yet initialized.
350 // NULL: Logging disabled.
351 // Any other value: Handle of the log file.
352 static  FILE * volatile s_r2rLogFile = (FILE *)(-1);
353
354 static void LogR2r(const char *msg, PEFile *pFile)
355 {
356     STANDARD_VM_CONTRACT;
357
358     // Make a local copy of s_r2rLogFile, so we're not affected by other threads.
359     FILE *r2rLogFile = s_r2rLogFile;
360     if (r2rLogFile == (FILE *)(-1))
361     {
362         // Initialize Ready to Run logging. Any errors cause logging to be disabled.
363         NewArrayHolder<WCHAR> wszReadyToRunLogFile;
364         if (SUCCEEDED(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ReadyToRunLogFile, &wszReadyToRunLogFile)) && wszReadyToRunLogFile)
365         {
366             // Append process ID to the log file name, so multiple processes can log at the same time.
367             StackSString fullname;
368             fullname.Printf(W("%s.%u"), wszReadyToRunLogFile.GetValue(), GetCurrentProcessId());
369             r2rLogFile = _wfopen(fullname.GetUnicode(), W("w"));
370         }
371         else
372             r2rLogFile = NULL;
373
374         if (r2rLogFile != NULL && !ReadyToRunInfo::IsReadyToRunEnabled())
375         {
376             fputs("Ready to Run not enabled.\n", r2rLogFile);
377             fclose(r2rLogFile);
378             r2rLogFile = NULL;
379         }
380
381         if (InterlockedCompareExchangeT(&s_r2rLogFile, r2rLogFile, (FILE *)(-1)) != (FILE *)(-1))
382         {
383             if (r2rLogFile != NULL)
384                 fclose(r2rLogFile);
385             r2rLogFile = s_r2rLogFile;
386         }
387     }
388
389     if (r2rLogFile == NULL)
390         return;
391
392     fprintf(r2rLogFile, "%s: \"%S\".\n", msg, pFile->GetPath().GetUnicode());
393     fflush(r2rLogFile);
394 }
395
396 #define DoLog(msg) if (s_r2rLogFile != NULL) LogR2r(msg, pFile)
397
398 // Try to acquire an R2R image for exclusive use by a particular module.
399 // Returns true if successful. Returns false if the image is already been used
400 // by another module. Each R2R image has a space to store a pointer to the
401 // module that owns it. We set this pointer unless it has already be
402 // initialized to point to another Module.
403 static bool AcquireImage(Module * pModule, PEImageLayout * pLayout, READYTORUN_HEADER * pHeader)
404 {
405     STANDARD_VM_CONTRACT;
406
407     // First find the import sections of the image.
408     READYTORUN_IMPORT_SECTION * pImportSections = NULL;
409     READYTORUN_IMPORT_SECTION * pImportSectionsEnd = NULL;
410     READYTORUN_SECTION * pSections = (READYTORUN_SECTION*)(pHeader + 1);
411     for (DWORD i = 0; i < pHeader->NumberOfSections; i++)
412     {
413         if (pSections[i].Type == READYTORUN_SECTION_IMPORT_SECTIONS)
414         {
415             pImportSections = (READYTORUN_IMPORT_SECTION*)((PBYTE)pLayout->GetBase() + pSections[i].Section.VirtualAddress);
416             pImportSectionsEnd = (READYTORUN_IMPORT_SECTION*)((PBYTE)pImportSections + pSections[i].Section.Size);
417             break;
418         }
419     }
420
421     // Go through the import sections to find the import for the module pointer.
422     for (READYTORUN_IMPORT_SECTION * pCurSection = pImportSections; pCurSection < pImportSectionsEnd; pCurSection++)
423     {
424         // The import for the module pointer is always in an eager fixup section, so skip delayed fixup sections.
425         if ((pCurSection->Flags & READYTORUN_IMPORT_SECTION_FLAGS_EAGER) == 0)
426             continue;
427
428         // Found an eager fixup section. Check the signature of each fixup in this section.
429         PVOID *pFixups = (PVOID *)((PBYTE)pLayout->GetBase() + pCurSection->Section.VirtualAddress);
430         DWORD nFixups = pCurSection->Section.Size / TARGET_POINTER_SIZE;
431         DWORD *pSignatures = (DWORD *)((PBYTE)pLayout->GetBase() + pCurSection->Signatures);
432         for (DWORD i = 0; i < nFixups; i++)
433         {
434             // See if we found the fixup for the Module pointer.
435             PBYTE pSig = (PBYTE)pLayout->GetBase() + pSignatures[i];
436             if (pSig[0] == READYTORUN_FIXUP_Helper && pSig[1] == READYTORUN_HELPER_Module)
437             {
438                 Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)(pFixups + i)), pModule, NULL);
439                 return pPrevious == NULL || pPrevious == pModule;
440             }
441         }
442     }
443
444     return false;
445 }
446
447 PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker *pamTracker)
448 {
449     STANDARD_VM_CONTRACT;
450
451     PEFile * pFile = pModule->GetFile();
452
453     if (!IsReadyToRunEnabled())
454     {
455         // Log message is ignored in this case.
456         DoLog(NULL);
457         return NULL;
458     }
459
460     if (pModule->IsCollectible())
461     {
462         DoLog("Ready to Run disabled - collectible module");
463         return NULL;
464     }
465
466     if (!pFile->HasLoadedIL())
467     {
468         DoLog("Ready to Run disabled - no loaded IL image");
469         return NULL;
470     }
471
472     PEImageLayout * pLayout = pFile->GetLoadedIL();
473     if (!pLayout->HasReadyToRunHeader())
474     {
475         DoLog("Ready to Run header not found");
476         return NULL;
477     }
478
479     if (CORProfilerDisableAllNGenImages() || CORProfilerUseProfileImages())
480     {
481         DoLog("Ready to Run disabled - profiler disabled native images");
482         return NULL;
483     }
484
485     if (g_pConfig->ExcludeReadyToRun(pModule->GetSimpleName()))
486     {
487         DoLog("Ready to Run disabled - module on exclusion list");
488         return NULL;
489     }
490
491 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
492     // Ignore ReadyToRun during NGen
493     if (IsCompilationProcess() && !IsNgenPDBCompilationProcess())
494     {
495         DoLog("Ready to Run disabled - compilation process");
496         return NULL;
497     }
498 #endif
499
500     if (!pLayout->IsNativeMachineFormat())
501     {
502         // For CoreCLR, be strict about disallowing machine mismatches.
503         COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
504     }
505
506 #ifndef CROSSGEN_COMPILE
507     // The file must have been loaded using LoadLibrary
508     if (!pLayout->IsRelocated())
509     {
510         DoLog("Ready to Run disabled - module not loaded for execution");
511         return NULL;
512     }
513 #endif
514
515     READYTORUN_HEADER * pHeader = pLayout->GetReadyToRunHeader();
516
517     // Ignore the content if the image major version is higher or lower than the major version currently supported by the runtime
518     if (pHeader->MajorVersion < MINIMUM_READYTORUN_MAJOR_VERSION || pHeader->MajorVersion > READYTORUN_MAJOR_VERSION)
519     {
520         DoLog("Ready to Run disabled - unsupported header version");
521         return NULL;
522     }
523
524     if (!AcquireImage(pModule, pLayout, pHeader))
525     {
526         DoLog("Ready to Run disabled - module already loaded in another AppDomain");
527         return NULL;
528     }
529
530     LoaderHeap *pHeap = pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
531     void * pMemory = pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(ReadyToRunInfo)));
532
533     DoLog("Ready to Run initialized successfully");
534
535     return new (pMemory) ReadyToRunInfo(pModule, pLayout, pHeader, pamTracker);
536 }
537
538 ReadyToRunInfo::ReadyToRunInfo(Module * pModule, PEImageLayout * pLayout, READYTORUN_HEADER * pHeader, AllocMemTracker *pamTracker)
539     : m_pModule(pModule), m_pLayout(pLayout), m_pHeader(pHeader), m_Crst(CrstReadyToRunEntryPointToMethodDescMap),
540     m_pPersistentInlineTrackingMap(NULL)
541 {
542     STANDARD_VM_CONTRACT;
543
544     IMAGE_DATA_DIRECTORY * pRuntimeFunctionsDir = FindSection(READYTORUN_SECTION_RUNTIME_FUNCTIONS);
545     if (pRuntimeFunctionsDir != NULL)
546     {
547         m_pRuntimeFunctions = (T_RUNTIME_FUNCTION *)pLayout->GetDirectoryData(pRuntimeFunctionsDir);
548         m_nRuntimeFunctions = pRuntimeFunctionsDir->Size / sizeof(T_RUNTIME_FUNCTION);
549     }
550     else
551     {
552         m_nRuntimeFunctions = 0;
553     }
554
555     IMAGE_DATA_DIRECTORY * pImportSectionsDir = FindSection(READYTORUN_SECTION_IMPORT_SECTIONS);
556     if (pImportSectionsDir != NULL)
557     {
558         m_pImportSections = (CORCOMPILE_IMPORT_SECTION*)pLayout->GetDirectoryData(pImportSectionsDir);
559         m_nImportSections = pImportSectionsDir->Size / sizeof(CORCOMPILE_IMPORT_SECTION);
560     }
561     else
562     {
563         m_nImportSections = 0;
564     }
565
566     m_nativeReader = NativeReader((byte *)pLayout->GetBase(), pLayout->GetVirtualSize());
567
568     IMAGE_DATA_DIRECTORY * pEntryPointsDir = FindSection(READYTORUN_SECTION_METHODDEF_ENTRYPOINTS);
569     if (pEntryPointsDir != NULL)
570     {
571         m_methodDefEntryPoints = NativeArray(&m_nativeReader, pEntryPointsDir->VirtualAddress);
572     }
573
574     IMAGE_DATA_DIRECTORY * pinstMethodsDir = FindSection(READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS);
575     if (pinstMethodsDir != NULL)
576     {
577         NativeParser parser = NativeParser(&m_nativeReader, pinstMethodsDir->VirtualAddress);
578         m_instMethodEntryPoints = NativeHashtable(parser);
579     }
580
581     IMAGE_DATA_DIRECTORY * pAvailableTypesDir = FindSection(READYTORUN_SECTION_AVAILABLE_TYPES);
582     if (pAvailableTypesDir != NULL)
583     {
584         NativeParser parser = NativeParser(&m_nativeReader, pAvailableTypesDir->VirtualAddress);
585         m_availableTypesHashtable = NativeHashtable(parser);
586     }
587
588     {
589         LockOwner lock = {&m_Crst, IsOwnerOfCrst};
590         m_entryPointToMethodDescMap.Init(TRUE, &lock);
591     }
592
593     // For format version 2.1 and later, there is an optional inlining table 
594     if (IsImageVersionAtLeast(2, 1))
595     {
596         IMAGE_DATA_DIRECTORY * pInlineTrackingInfoDir = FindSection(READYTORUN_SECTION_INLINING_INFO);
597         if (pInlineTrackingInfoDir != NULL)
598         {
599             const BYTE* pInlineTrackingMapData = (const BYTE*)GetImage()->GetDirectoryData(pInlineTrackingInfoDir);
600             PersistentInlineTrackingMapR2R::TryLoad(pModule, pInlineTrackingMapData, pInlineTrackingInfoDir->Size,
601                                                     pamTracker, &m_pPersistentInlineTrackingMap);
602         }
603     }
604
605     // For format version 2.2 and later, there is an optional profile-data section
606     if (IsImageVersionAtLeast(2, 2))
607     {
608         IMAGE_DATA_DIRECTORY * pProfileDataInfoDir = FindSection(READYTORUN_SECTION_PROFILEDATA_INFO);
609         if (pProfileDataInfoDir != NULL)
610         {
611             CORCOMPILE_METHOD_PROFILE_LIST * pMethodProfileList;
612             pMethodProfileList = (CORCOMPILE_METHOD_PROFILE_LIST *)GetImage()->GetDirectoryData(pProfileDataInfoDir);
613
614             pModule->SetMethodProfileList(pMethodProfileList);  
615         }
616     }
617
618     // For format version 3.1 and later, there is an optional attributes section
619     IMAGE_DATA_DIRECTORY *attributesPresenceDataInfoDir = FindSection(READYTORUN_SECTION_ATTRIBUTEPRESENCE);
620     if (attributesPresenceDataInfoDir != NULL)
621     {
622         NativeCuckooFilter newFilter(
623             (byte *)pLayout->GetBase(),
624             pLayout->GetVirtualSize(),
625             attributesPresenceDataInfoDir->VirtualAddress,
626             attributesPresenceDataInfoDir->Size);
627
628         m_attributesPresence = newFilter;
629     }
630 }
631
632 static bool SigMatchesMethodDesc(MethodDesc* pMD, SigPointer &sig, Module * pModule)
633 {
634     STANDARD_VM_CONTRACT;
635
636     ZapSig::Context    zapSigContext(pModule, (void *)pModule, ZapSig::NormalTokens);
637     ZapSig::Context *  pZapSigContext = &zapSigContext;
638
639     DWORD methodFlags;
640     IfFailThrow(sig.GetData(&methodFlags));
641
642     if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
643     {
644         PCCOR_SIGNATURE pSigType;
645         DWORD cbSigType;
646         sig.GetSignature(&pSigType, &cbSigType);
647         if (!ZapSig::CompareSignatureToTypeHandle(pSigType, pModule, TypeHandle(pMD->GetMethodTable()), pZapSigContext))
648             return false;
649
650         IfFailThrow(sig.SkipExactlyOne());
651     }
652
653     _ASSERTE((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0);
654     _ASSERTE((methodFlags & ENCODE_METHOD_SIG_MemberRefToken) == 0);
655
656     RID rid;
657     IfFailThrow(sig.GetData(&rid));
658     if (RidFromToken(pMD->GetMemberDef()) != rid)
659         return false;
660
661     if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
662     {
663         DWORD numGenericArgs;
664         IfFailThrow(sig.GetData(&numGenericArgs));
665         Instantiation inst = pMD->GetMethodInstantiation();
666         if (numGenericArgs != inst.GetNumArgs())
667             return false;
668
669         for (DWORD i = 0; i < numGenericArgs; i++)
670         {
671             PCCOR_SIGNATURE pSigArg;
672             DWORD cbSigArg;
673             sig.GetSignature(&pSigArg, &cbSigArg);
674             if (!ZapSig::CompareSignatureToTypeHandle(pSigArg, pModule, inst[i], pZapSigContext))
675                 return false;
676
677             IfFailThrow(sig.SkipExactlyOne());
678         }
679     }
680
681     return true;
682 }
683
684 PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, PrepareCodeConfig* pConfig, BOOL fFixups)
685 {
686     STANDARD_VM_CONTRACT;
687
688     PCODE pEntryPoint = NULL;
689 #ifndef CROSSGEN_COMPILE
690 #ifdef PROFILING_SUPPORTED
691     BOOL fShouldSearchCache = TRUE;
692 #endif // PROFILING_SUPPORTED
693 #endif // CROSSGEN_COMPILE
694     mdToken token = pMD->GetMemberDef();
695     int rid = RidFromToken(token);
696     if (rid == 0)
697         goto done;
698
699     uint offset;
700     if (pMD->HasClassOrMethodInstantiation())
701     {
702         if (m_instMethodEntryPoints.IsNull())
703             goto done;
704
705         NativeHashtable::Enumerator lookup = m_instMethodEntryPoints.Lookup(GetVersionResilientMethodHashCode(pMD));
706         NativeParser entryParser;
707         offset = (uint)-1;
708         while (lookup.GetNext(entryParser))
709         {
710             PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)entryParser.GetBlob();
711             SigPointer sig(pBlob);
712             if (SigMatchesMethodDesc(pMD, sig, m_pModule))
713             {
714                 // Get the updated SigPointer location, so we can calculate the size of the blob,
715                 // in order to skip the blob and find the entry point data.
716                 PCCOR_SIGNATURE pSigNew;
717                 DWORD cbSigNew;
718                 sig.GetSignature(&pSigNew, &cbSigNew);
719                 offset = entryParser.GetOffset() + (uint)(pSigNew - pBlob);
720                 break;
721             }
722         }
723
724         if (offset == (uint)-1)
725             goto done;
726     }
727     else
728     {
729         if (!m_methodDefEntryPoints.TryGetAt(rid - 1, &offset))
730             goto done;
731     }
732
733 #ifndef CROSSGEN_COMPILE
734 #ifdef PROFILING_SUPPORTED
735         {
736             BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
737             g_profControlBlock.pProfInterface->
738                 JITCachedFunctionSearchStarted((FunctionID)pMD, &fShouldSearchCache);
739             END_PIN_PROFILER();
740         }
741         if (!fShouldSearchCache)
742         {
743             pConfig->SetProfilerRejectedPrecompiledCode();
744             goto done;
745         }
746 #endif // PROFILING_SUPPORTED
747 #endif // CROSSGEN_COMPILE
748
749     uint id;
750     offset = m_nativeReader.DecodeUnsigned(offset, &id);
751
752     if (id & 1)
753     {
754         if (id & 2)
755         {
756             uint val;
757             m_nativeReader.DecodeUnsigned(offset, &val);
758             offset -= val;
759         }
760
761         if (fFixups)
762         {
763             if (!m_pModule->FixupDelayList(dac_cast<TADDR>(m_pLayout->GetBase()) + offset))
764             {
765 #ifndef CROSSGEN_COMPILE
766                 pConfig->SetReadyToRunRejectedPrecompiledCode();
767 #endif // CROSSGEN_COMPILE
768                 goto done;
769             }
770         }
771
772         id >>= 2;
773     }
774     else
775     {
776         id >>= 1;
777     }
778
779     _ASSERTE(id < m_nRuntimeFunctions);
780     pEntryPoint = dac_cast<TADDR>(m_pLayout->GetBase()) + m_pRuntimeFunctions[id].BeginAddress;
781
782     {
783         CrstHolder ch(&m_Crst);
784
785         if (m_entryPointToMethodDescMap.LookupValue(PCODEToPINSTR(pEntryPoint), (LPVOID)PCODEToPINSTR(pEntryPoint)) == (LPVOID)INVALIDENTRY)
786             m_entryPointToMethodDescMap.InsertValue(PCODEToPINSTR(pEntryPoint), pMD);
787     }
788
789 #ifndef CROSSGEN_COMPILE
790 #ifdef PROFILING_SUPPORTED
791         {
792             BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
793             g_profControlBlock.pProfInterface->
794                 JITCachedFunctionSearchFinished((FunctionID)pMD, COR_PRF_CACHED_FUNCTION_FOUND);
795             END_PIN_PROFILER();
796         }
797 #endif // PROFILING_SUPPORTED
798 #endif // CROSSGEN_COMPILE
799
800     if (g_pDebugInterface != NULL)
801     {
802 #if defined(CROSSGEN_COMPILE)
803         g_pDebugInterface->JITComplete(NativeCodeVersion(pMD), pEntryPoint);
804 #else
805         g_pDebugInterface->JITComplete(pConfig->GetCodeVersion(), pEntryPoint);
806 #endif
807     }
808
809 done:
810     if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, R2RGetEntryPoint))
811     {
812         ETW::MethodLog::GetR2RGetEntryPoint(pMD, pEntryPoint);
813     }
814     return pEntryPoint;
815 }
816
817
818 void ReadyToRunInfo::MethodIterator::ParseGenericMethodSignatureAndRid(uint *pOffset, RID *pRid)
819 {
820     _ASSERTE(!m_genericParser.IsNull());
821
822     HRESULT hr = S_OK;
823     *pOffset = -1;
824     *pRid = -1;
825
826     PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)m_genericParser.GetBlob();
827     SigPointer sig(pBlob);
828
829     DWORD methodFlags = 0;
830     // Skip the signature so we can get to the offset
831     hr = sig.GetData(&methodFlags);
832     if (FAILED(hr))
833     {
834         return;
835     }
836
837     if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
838     {
839         hr = sig.SkipExactlyOne();
840         if (FAILED(hr))
841         {
842             return;
843         }
844     }
845
846     _ASSERTE((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0);
847     _ASSERTE((methodFlags & ENCODE_METHOD_SIG_MemberRefToken) == 0);
848
849     hr = sig.GetData(pRid);
850     if (FAILED(hr))
851     {
852         return;
853     }
854     
855     if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
856     {
857         DWORD numGenericArgs;
858         hr = sig.GetData(&numGenericArgs);
859         if (FAILED(hr))
860         {
861             return;
862         }
863     
864         for (DWORD i = 0; i < numGenericArgs; i++)
865         {
866             hr = sig.SkipExactlyOne();
867             if (FAILED(hr))
868             {
869                 return;
870             }
871         }
872     }
873
874     // Now that we have the size of the signature we can grab the offset and decode it
875     PCCOR_SIGNATURE pSigNew;
876     DWORD cbSigNew;
877     sig.GetSignature(&pSigNew, &cbSigNew);
878
879     m_genericCurrentSig = pBlob;
880     *pOffset = m_genericParser.GetOffset() + (uint)(pSigNew - pBlob);
881 }
882
883 BOOL ReadyToRunInfo::MethodIterator::Next()
884 {
885     CONTRACTL
886     {
887         GC_TRIGGERS;
888         THROWS;
889         MODE_ANY;
890     }
891     CONTRACTL_END;
892
893     // Enumerate non-generic methods
894     while (++m_methodDefIndex < (int)m_pInfo->m_methodDefEntryPoints.GetCount())
895     {
896         uint offset;
897         if (m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
898         {
899             return TRUE;
900         }
901     }
902
903     // Enumerate generic instantiations
904     m_genericParser = m_genericEnum.GetNext();
905     if (!m_genericParser.IsNull())
906     {
907         ParseGenericMethodSignatureAndRid(&m_genericCurrentOffset, &m_genericCurrentRid);
908         return TRUE;
909     }
910
911     return FALSE;
912 }
913
914 MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc()
915 {
916     STANDARD_VM_CONTRACT;
917
918     mdMethodDef methodToken = mdTokenNil;
919     if (m_methodDefIndex < (int)m_pInfo->m_methodDefEntryPoints.GetCount())
920     {
921         methodToken = mdtMethodDef | (m_methodDefIndex + 1);
922         return MemberLoader::GetMethodDescFromMethodDef(m_pInfo->m_pModule, methodToken, FALSE);
923     }
924     else
925     {
926         _ASSERTE(m_genericCurrentOffset > 0 && m_genericCurrentSig != NULL);
927         return ZapSig::DecodeMethod(m_pInfo->m_pModule, m_pInfo->m_pModule, m_genericCurrentSig);
928     }
929     
930 }
931
932 MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc_NoRestore()
933 {
934     CONTRACTL
935     {
936         GC_TRIGGERS;
937         THROWS;
938         MODE_ANY;
939     }
940     CONTRACTL_END;
941
942     uint offset;
943     if (m_methodDefIndex < (int)m_pInfo->m_methodDefEntryPoints.GetCount())
944     {
945         if (!m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
946         {
947             return NULL;
948         }
949     }
950     else
951     {
952         if (m_genericCurrentOffset <= 0)
953         {
954             // Failed to parse generic info.
955             return NULL;
956         }
957
958         offset = m_genericCurrentOffset;
959     }
960
961     uint id;
962     offset = m_pInfo->m_nativeReader.DecodeUnsigned(offset, &id);
963
964     if (id & 1)
965     {
966         if (id & 2)
967         {
968             uint val;
969             m_pInfo->m_nativeReader.DecodeUnsigned(offset, &val);
970             offset -= val;
971         }
972
973         id >>= 2;
974     }
975     else
976     {
977         id >>= 1;
978     }
979
980     _ASSERTE(id < m_pInfo->m_nRuntimeFunctions);
981     PCODE pEntryPoint = dac_cast<TADDR>(m_pInfo->m_pLayout->GetBase()) + m_pInfo->m_pRuntimeFunctions[id].BeginAddress;
982
983     return m_pInfo->GetMethodDescForEntryPoint(pEntryPoint);
984 }
985
986 PCODE ReadyToRunInfo::MethodIterator::GetMethodStartAddress()
987 {
988     STANDARD_VM_CONTRACT;
989
990     PCODE ret = m_pInfo->GetEntryPoint(GetMethodDesc(), NULL, FALSE);
991     _ASSERTE(ret != NULL);
992     return ret;
993 }
994
995 DWORD ReadyToRunInfo::GetFieldBaseOffset(MethodTable * pMT)
996 {
997     STANDARD_VM_CONTRACT;
998
999     DWORD dwAlignment = DATA_ALIGNMENT;
1000     DWORD dwOffsetBias = 0;
1001 #ifdef FEATURE_64BIT_ALIGNMENT
1002     dwOffsetBias = 4;
1003     if (pMT->RequiresAlign8())
1004         dwAlignment = 8;
1005 #endif
1006
1007     MethodTable * pParentMT = pMT->GetParentMethodTable();
1008     DWORD dwCumulativeInstanceFieldPos = (pParentMT != NULL) ? pParentMT->GetNumInstanceFieldBytes() : 0;
1009
1010     dwCumulativeInstanceFieldPos += dwOffsetBias;
1011
1012     dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwAlignment);
1013
1014     return OBJECT_SIZE + dwCumulativeInstanceFieldPos - dwOffsetBias;
1015 }
1016
1017 BOOL ReadyToRunInfo::IsImageVersionAtLeast(int majorVersion, int minorVersion)
1018 {
1019         LIMITED_METHOD_CONTRACT;
1020         return (m_pHeader->MajorVersion == majorVersion && m_pHeader->MinorVersion >= minorVersion) ||
1021                    (m_pHeader->MajorVersion > majorVersion);
1022
1023 }
1024
1025 static DWORD s_wellKnownAttributeHashes[(DWORD)WellKnownAttribute::CountOfWellKnownAttributes];
1026
1027 bool ReadyToRunInfo::MayHaveCustomAttribute(WellKnownAttribute attribute, mdToken token)
1028 {
1029     UINT32 hash = 0;
1030     UINT16 fingerprint = 0;
1031     if (!m_attributesPresence.HashComputationImmaterial())
1032     {
1033         DWORD wellKnownHash = s_wellKnownAttributeHashes[(DWORD)attribute];
1034         if (wellKnownHash == 0)
1035         {
1036             // TODO, investigate using constexpr to compute string hashes at compile time initially
1037             s_wellKnownAttributeHashes[(DWORD)attribute] = wellKnownHash = ComputeNameHashCode(GetWellKnownAttributeName(attribute));
1038         }
1039
1040         hash = CombineTwoValuesIntoHash(wellKnownHash, token);
1041         fingerprint = hash >> 16;
1042     }
1043     
1044     return m_attributesPresence.MayExist(hash, fingerprint);
1045 }
1046
1047 void ReadyToRunInfo::DisableCustomAttributeFilter()
1048 {
1049     m_attributesPresence.DisableFilter();
1050 }
1051
1052 #endif // DACCESS_COMPILE