Remove always defined FEATURE_CORECLR
[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
19 using namespace NativeFormat;
20
21 IMAGE_DATA_DIRECTORY * ReadyToRunInfo::FindSection(DWORD type)
22 {
23     CONTRACTL
24     {
25         GC_NOTRIGGER;
26         NOTHROW;
27         SO_TOLERANT;
28         SUPPORTS_DAC;
29     }
30     CONTRACTL_END;
31
32     PTR_READYTORUN_SECTION pSections = dac_cast<PTR_READYTORUN_SECTION>(dac_cast<TADDR>(m_pHeader) + sizeof(READYTORUN_HEADER));
33     for (DWORD i = 0; i < m_pHeader->NumberOfSections; i++)
34     {
35         // Verify that section types are sorted
36         _ASSERTE(i == 0 || (pSections[i-1].Type < pSections[i].Type));
37
38         READYTORUN_SECTION * pSection = pSections + i;
39         if (pSection->Type == type)
40             return &pSection->Section;
41     }
42     return NULL;
43 }
44
45 MethodDesc * ReadyToRunInfo::GetMethodDescForEntryPoint(PCODE entryPoint)
46 {
47     CONTRACTL
48     {
49         GC_NOTRIGGER;
50         NOTHROW;
51         SO_TOLERANT;
52         SUPPORTS_DAC;
53     }
54     CONTRACTL_END;
55
56 #ifdef _TARGET_AMD64_
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         SO_TOLERANT;
76         SUPPORTS_DAC;
77     }
78     CONTRACTL_END;
79
80     return !m_availableTypesHashtable.IsNull();
81 }
82
83 BOOL ReadyToRunInfo::TryLookupTypeTokenFromName(NameHandle *pName, mdToken * pFoundTypeToken)
84 {
85     CONTRACTL
86     {
87         GC_NOTRIGGER;
88         NOTHROW;
89         SO_INTOLERANT;
90         SUPPORTS_DAC;
91         PRECONDITION(!m_availableTypesHashtable.IsNull());
92     }
93     CONTRACTL_END;
94
95     if (m_availableTypesHashtable.IsNull())
96         return FALSE;
97
98     LPCUTF8 pszName = NULL;
99     LPCUTF8 pszNameSpace = NULL;
100
101     //
102     // Compute the hashcode of the type (hashcode based on type name and namespace name)
103     //
104     int dwHashCode = 0;
105
106     if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
107     {
108         // Name-based lookups (ex: Type.GetType()). 
109
110         pszName = pName->GetName();
111         pszNameSpace = "";
112
113         if (pName->GetNameSpace() != NULL)
114         {
115             pszNameSpace = pName->GetNameSpace();
116         }
117         else
118         {
119             LPCUTF8 p;
120             CQuickBytes szNamespace;
121
122             if ((p = ns::FindSep(pszName)) != NULL)
123             {
124                 SIZE_T d = p - pszName;
125
126                 FAULT_NOT_FATAL();
127                 pszNameSpace = szNamespace.SetStringNoThrow(pszName, d);
128
129                 if (pszNameSpace == NULL)
130                     return FALSE;
131
132                 pszName = (p + 1);
133             }
134         }
135
136         _ASSERT(pszNameSpace != NULL);
137         dwHashCode ^= ComputeNameHashCode(pszNameSpace, pszName);
138
139         // Bucket is not 'null' for a nested type, and it will have information about the nested type's encloser
140         if (!pName->GetBucket().IsNull())
141         {
142             // Must be a token based bucket that we found earlier in the R2R types hashtable
143             _ASSERT(pName->GetBucket().GetEntryType() == HashedTypeEntry::IsHashedTokenEntry);
144
145             const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
146
147             // Token must be a typedef token that we previously resolved (we shouldn't get here with an exported type token)
148             _ASSERT(TypeFromToken(tokenBasedEncloser.m_TypeToken) == mdtTypeDef);
149
150             int dwCurrentHashCode;
151             mdToken mdCurrentTypeToken = tokenBasedEncloser.m_TypeToken;
152             if (!GetVersionResilientTypeHashCode(tokenBasedEncloser.m_pModule->GetMDImport(), mdCurrentTypeToken, &dwCurrentHashCode))
153                 return FALSE;
154             dwHashCode ^= dwCurrentHashCode;
155         }
156     }
157     else
158     {
159         // Token based lookups (ex: tokens from IL code)
160
161         if (!GetVersionResilientTypeHashCode(pName->GetTypeModule()->GetMDImport(), pName->GetTypeToken(), &dwHashCode))
162             return FALSE;
163     }
164
165
166     //
167     // Lookup the type in the native hashtable using the computed token
168     //
169     {
170         NativeHashtable::Enumerator lookup = m_availableTypesHashtable.Lookup((int)dwHashCode);
171         NativeParser entryParser;
172         while (lookup.GetNext(entryParser))
173         {
174             DWORD ridAndFlag = entryParser.GetUnsigned();
175             mdToken cl = ((ridAndFlag & 1) ? ((ridAndFlag >> 1) | mdtExportedType) : ((ridAndFlag >> 1) | mdtTypeDef));
176             _ASSERT(RidFromToken(cl) != 0);
177
178             if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
179             {
180                 // Compare type name and namespace name
181                 LPCUTF8 pszFoundName;
182                 LPCUTF8 pszFoundNameSpace;
183                 if (!GetTypeNameFromToken(m_pModule->GetMDImport(), cl, &pszFoundName, &pszFoundNameSpace))
184                     continue;
185                 if (strcmp(pszName, pszFoundName) != 0 || strcmp(pszNameSpace, pszFoundNameSpace) != 0)
186                     continue;
187
188                 mdToken mdFoundTypeEncloser;
189                 BOOL inputTypeHasEncloser = !pName->GetBucket().IsNull();
190                 BOOL foundTypeHasEncloser = GetEnclosingToken(m_pModule->GetMDImport(), cl, &mdFoundTypeEncloser);
191                 if (inputTypeHasEncloser != foundTypeHasEncloser)
192                     continue;
193
194                 // Compare the enclosing types chain for a match
195                 if (inputTypeHasEncloser)
196                 {
197                     const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
198
199                     if (!CompareTypeNameOfTokens(tokenBasedEncloser.m_TypeToken, tokenBasedEncloser.m_pModule->GetMDImport(), mdFoundTypeEncloser, m_pModule->GetMDImport()))
200                         continue;
201                 }
202             }
203             else
204             {
205                 // Compare type name, namespace name, and enclosing types chain for a match
206                 if (!CompareTypeNameOfTokens(pName->GetTypeToken(), pName->GetTypeModule()->GetMDImport(), cl, m_pModule->GetMDImport()))
207                     continue;
208             }
209
210             // Found a match!
211             *pFoundTypeToken = cl;
212             return TRUE;
213         }
214     }
215
216     return FALSE;   // No matching type found
217 }
218
219 BOOL ReadyToRunInfo::GetTypeNameFromToken(IMDInternalImport * pImport, mdToken mdType, LPCUTF8 * ppszName, LPCUTF8 * ppszNameSpace)
220 {
221     CONTRACTL
222     {
223         GC_NOTRIGGER;
224         NOTHROW;
225         SO_TOLERANT;
226         SUPPORTS_DAC;
227         PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
228     }
229     CONTRACTL_END;
230
231     switch (TypeFromToken(mdType))
232     {
233     case mdtTypeDef: 
234         return SUCCEEDED(pImport->GetNameOfTypeDef(mdType, ppszName, ppszNameSpace));
235     case mdtTypeRef: 
236         return SUCCEEDED(pImport->GetNameOfTypeRef(mdType, ppszNameSpace, ppszName));
237     case mdtExportedType:
238         return SUCCEEDED(pImport->GetExportedTypeProps(mdType, ppszNameSpace, ppszName, NULL, NULL, NULL));
239     }
240
241     return FALSE;
242 }
243
244 BOOL ReadyToRunInfo::GetEnclosingToken(IMDInternalImport * pImport, mdToken mdType, mdToken * pEnclosingToken)
245 {
246     CONTRACTL
247     {
248         GC_NOTRIGGER;
249         NOTHROW;
250         SO_TOLERANT;
251         SUPPORTS_DAC;
252         PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
253     }
254     CONTRACTL_END;
255
256     mdToken mdEncloser;
257     switch (TypeFromToken(mdType))
258     {
259     case mdtTypeDef:
260         return SUCCEEDED(pImport->GetNestedClassProps(mdType, pEnclosingToken));
261
262     case mdtTypeRef:
263         if (SUCCEEDED(pImport->GetResolutionScopeOfTypeRef(mdType, pEnclosingToken)))
264             return ((TypeFromToken(*pEnclosingToken) == mdtTypeRef) && (*pEnclosingToken != mdTypeRefNil));
265
266     case mdtExportedType:
267         if (SUCCEEDED(pImport->GetExportedTypeProps(mdType, NULL, NULL, pEnclosingToken, NULL, NULL)))
268             return ((TypeFromToken(*pEnclosingToken) == mdtExportedType) && (*pEnclosingToken != mdExportedTypeNil));
269     }
270
271     return FALSE;
272 }
273
274 BOOL ReadyToRunInfo::CompareTypeNameOfTokens(mdToken mdToken1, IMDInternalImport * pImport1, mdToken mdToken2, IMDInternalImport * pImport2)
275 {
276     CONTRACTL
277     {
278         GC_NOTRIGGER;
279         NOTHROW;
280         SO_TOLERANT;
281         SUPPORTS_DAC;
282         PRECONDITION(TypeFromToken(mdToken1) == mdtTypeDef || TypeFromToken(mdToken1) == mdtTypeRef || TypeFromToken(mdToken1) == mdtExportedType);
283         PRECONDITION(TypeFromToken(mdToken2) == mdtTypeDef || TypeFromToken(mdToken2) == mdtExportedType);
284     }
285     CONTRACTL_END;
286
287     BOOL hasEncloser;
288     do
289     {
290         LPCUTF8 pszName1;
291         LPCUTF8 pszNameSpace1;
292         if (!GetTypeNameFromToken(pImport1, mdToken1, &pszName1, &pszNameSpace1))
293             return FALSE;
294
295         LPCUTF8 pszName2;
296         LPCUTF8 pszNameSpace2;
297         if (!GetTypeNameFromToken(pImport2, mdToken2, &pszName2, &pszNameSpace2))
298             return FALSE;
299
300         if (strcmp(pszName1, pszName2) != 0 || strcmp(pszNameSpace1, pszNameSpace2) != 0)
301             return FALSE;
302
303         if ((hasEncloser = GetEnclosingToken(pImport1, mdToken1, &mdToken1)) != GetEnclosingToken(pImport2, mdToken2, &mdToken2))
304             return FALSE;
305
306     } while (hasEncloser);
307
308     return TRUE;
309 }
310
311 PTR_BYTE ReadyToRunInfo::GetDebugInfo(PTR_RUNTIME_FUNCTION pRuntimeFunction)
312 {
313     CONTRACTL
314     {
315         GC_NOTRIGGER;
316         THROWS;
317         MODE_ANY;
318         SUPPORTS_DAC;
319     }
320     CONTRACTL_END;
321
322     IMAGE_DATA_DIRECTORY * pDebugInfoDir = FindSection(READYTORUN_SECTION_DEBUG_INFO);
323     if (pDebugInfoDir == NULL)
324         return NULL;
325
326     SIZE_T methodIndex = pRuntimeFunction - m_pRuntimeFunctions;
327     _ASSERTE(methodIndex < m_nRuntimeFunctions);
328
329     NativeArray debugInfoIndex(dac_cast<PTR_NativeReader>(PTR_HOST_INT_TO_TADDR(&m_nativeReader)), pDebugInfoDir->VirtualAddress);
330
331     uint offset;
332     if (!debugInfoIndex.TryGetAt((DWORD)methodIndex, &offset))
333         return NULL;
334
335     uint lookBack;
336     uint debugInfoOffset = m_nativeReader.DecodeUnsigned(offset, &lookBack);
337
338     if (lookBack != 0)
339         debugInfoOffset = offset - lookBack;
340
341     return dac_cast<PTR_BYTE>(m_pLayout->GetBase()) + debugInfoOffset;
342 }
343
344 #ifndef DACCESS_COMPILE
345
346 BOOL ReadyToRunInfo::IsReadyToRunEnabled()
347 {
348     WRAPPER_NO_CONTRACT;
349
350     static ConfigDWORD configReadyToRun;
351     return configReadyToRun.val(CLRConfig::EXTERNAL_ReadyToRun);
352 }
353
354 // A log file to record success/failure of R2R loads. s_r2rLogFile can have the following values:
355 // -1: Logging not yet initialized.
356 // NULL: Logging disabled.
357 // Any other value: Handle of the log file.
358 static  FILE * volatile s_r2rLogFile = (FILE *)(-1);
359
360 static void LogR2r(const char *msg, PEFile *pFile)
361 {
362     STANDARD_VM_CONTRACT;
363
364     // Make a local copy of s_r2rLogFile, so we're not affected by other threads.
365     FILE *r2rLogFile = s_r2rLogFile;
366     if (r2rLogFile == (FILE *)(-1))
367     {
368         // Initialize Ready to Run logging. Any errors cause logging to be disabled.
369         NewArrayHolder<WCHAR> wszReadyToRunLogFile;
370         if (SUCCEEDED(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ReadyToRunLogFile, &wszReadyToRunLogFile)) && wszReadyToRunLogFile)
371         {
372             // Append process ID to the log file name, so multiple processes can log at the same time.
373             StackSString fullname;
374             fullname.Printf(W("%s.%u"), wszReadyToRunLogFile.GetValue(), GetCurrentProcessId());
375             r2rLogFile = _wfopen(fullname.GetUnicode(), W("w"));
376         }
377         else
378             r2rLogFile = NULL;
379
380         if (r2rLogFile != NULL && !ReadyToRunInfo::IsReadyToRunEnabled())
381         {
382             fputs("Ready to Run not enabled.\n", r2rLogFile);
383             fclose(r2rLogFile);
384             r2rLogFile = NULL;
385         }
386
387         if (InterlockedCompareExchangeT(&s_r2rLogFile, r2rLogFile, (FILE *)(-1)) != (FILE *)(-1))
388         {
389             if (r2rLogFile != NULL)
390                 fclose(r2rLogFile);
391             r2rLogFile = s_r2rLogFile;
392         }
393     }
394
395     if (r2rLogFile == NULL)
396         return;
397
398     fprintf(r2rLogFile, "%s: \"%S\".\n", msg, pFile->GetPath().GetUnicode());
399     fflush(r2rLogFile);
400 }
401
402 #define DoLog(msg) if (s_r2rLogFile != NULL) LogR2r(msg, pFile)
403
404 // Try to acquire an R2R image for exclusive use by a particular module.
405 // Returns true if successful. Returns false if the image is already been used
406 // by another module. Each R2R image has a space to store a pointer to the
407 // module that owns it. We set this pointer unless it has already be
408 // initialized to point to another Module.
409 static bool AcquireImage(Module * pModule, PEImageLayout * pLayout, READYTORUN_HEADER * pHeader)
410 {
411     STANDARD_VM_CONTRACT;
412
413     // First find the import sections of the image.
414     READYTORUN_IMPORT_SECTION * pImportSections = NULL;
415     READYTORUN_IMPORT_SECTION * pImportSectionsEnd = NULL;
416     READYTORUN_SECTION * pSections = (READYTORUN_SECTION*)(pHeader + 1);
417     for (DWORD i = 0; i < pHeader->NumberOfSections; i++)
418     {
419         if (pSections[i].Type == READYTORUN_SECTION_IMPORT_SECTIONS)
420         {
421             pImportSections = (READYTORUN_IMPORT_SECTION*)((PBYTE)pLayout->GetBase() + pSections[i].Section.VirtualAddress);
422             pImportSectionsEnd = (READYTORUN_IMPORT_SECTION*)((PBYTE)pImportSections + pSections[i].Section.Size);
423             break;
424         }
425     }
426
427     // Go through the import sections to find the import for the module pointer.
428     for (READYTORUN_IMPORT_SECTION * pCurSection = pImportSections; pCurSection < pImportSectionsEnd; pCurSection++)
429     {
430         // The import for the module pointer is always in an eager fixup section, so skip delayed fixup sections.
431         if ((pCurSection->Flags & READYTORUN_IMPORT_SECTION_FLAGS_EAGER) == 0)
432             continue;
433
434         // Found an eager fixup section. Check the signature of each fixup in this section.
435         PVOID *pFixups = (PVOID *)((PBYTE)pLayout->GetBase() + pCurSection->Section.VirtualAddress);
436         DWORD nFixups = pCurSection->Section.Size / sizeof(PVOID);
437         DWORD *pSignatures = (DWORD *)((PBYTE)pLayout->GetBase() + pCurSection->Signatures);
438         for (DWORD i = 0; i < nFixups; i++)
439         {
440             // See if we found the fixup for the Module pointer.
441             PBYTE pSig = (PBYTE)pLayout->GetBase() + pSignatures[i];
442             if (pSig[0] == READYTORUN_FIXUP_Helper && pSig[1] == READYTORUN_HELPER_Module)
443             {
444                 Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)(pFixups + i)), pModule, NULL);
445                 return pPrevious == NULL || pPrevious == pModule;
446             }
447         }
448     }
449
450     return false;
451 }
452
453 PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker *pamTracker)
454 {
455     STANDARD_VM_CONTRACT;
456
457     PEFile * pFile = pModule->GetFile();
458
459     // Ignore ReadyToRun for introspection-only loads
460     if (pFile->IsIntrospectionOnly())
461     {
462         DoLog("Ready to Run disabled - module loaded for reflection");
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 (!IsReadyToRunEnabled())
480     {
481         // Log message is ignored in this case.
482         DoLog(NULL);
483         return NULL;
484     }
485
486     if (g_pConfig->ExcludeReadyToRun(pModule->GetSimpleName()))
487     {
488         DoLog("Ready to Run disabled - module on exclusion list");
489         return NULL;
490     }
491
492     if (!pLayout->IsNativeMachineFormat())
493     {
494         // For CoreCLR, be strict about disallowing machine mismatches.
495         COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
496     }
497
498 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
499     // Ignore ReadyToRun during NGen
500     if (IsCompilationProcess() && !IsNgenPDBCompilationProcess())
501     {
502         DoLog("Ready to Run disabled - compilation process");
503         return NULL;
504     }
505 #endif
506
507 #ifndef CROSSGEN_COMPILE
508     // The file must have been loaded using LoadLibrary
509     if (!pLayout->IsRelocated())
510     {
511         DoLog("Ready to Run disabled - module not loaded for execution");
512         return NULL;
513     }
514 #endif
515
516     READYTORUN_HEADER * pHeader = pLayout->GetReadyToRunHeader();
517
518     // Ignore the content if the image major version is higher than the major version currently supported by the runtime
519     if (pHeader->MajorVersion > READYTORUN_MAJOR_VERSION)
520     {
521         DoLog("Ready to Run disabled - unsupported header version");
522         return NULL;
523     }
524
525     if (!AcquireImage(pModule, pLayout, pHeader))
526     {
527         DoLog("Ready to Run disabled - module already loaded in another AppDomain");
528         return NULL;
529     }
530
531     LoaderHeap *pHeap = pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
532     void * pMemory = pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(ReadyToRunInfo)));
533
534     DoLog("Ready to Run initialized successfully");
535
536     return new (pMemory) ReadyToRunInfo(pModule, pLayout, pHeader);
537 }
538
539 ReadyToRunInfo::ReadyToRunInfo(Module * pModule, PEImageLayout * pLayout, READYTORUN_HEADER * pHeader)
540     : m_pModule(pModule), m_pLayout(pLayout), m_pHeader(pHeader), m_Crst(CrstLeafLock)
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
594 static bool SigMatchesMethodDesc(MethodDesc* pMD, SigPointer &sig, Module * pModule)
595 {
596     STANDARD_VM_CONTRACT;
597
598     ZapSig::Context    zapSigContext(pModule, (void *)pModule, ZapSig::NormalTokens);
599     ZapSig::Context *  pZapSigContext = &zapSigContext;
600
601     DWORD methodFlags;
602     IfFailThrow(sig.GetData(&methodFlags));
603
604     if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
605     {
606         PCCOR_SIGNATURE pSigType;
607         DWORD cbSigType;
608         sig.GetSignature(&pSigType, &cbSigType);
609         if (!ZapSig::CompareSignatureToTypeHandle(pSigType, pModule, TypeHandle(pMD->GetMethodTable()), pZapSigContext))
610             return false;
611
612         IfFailThrow(sig.SkipExactlyOne());
613     }
614
615     _ASSERTE((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0);
616     _ASSERTE((methodFlags & ENCODE_METHOD_SIG_MemberRefToken) == 0);
617
618     RID rid;
619     IfFailThrow(sig.GetData(&rid));
620     if (RidFromToken(pMD->GetMemberDef()) != rid)
621         return false;
622
623     if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
624     {
625         DWORD numGenericArgs;
626         IfFailThrow(sig.GetData(&numGenericArgs));
627         Instantiation inst = pMD->GetMethodInstantiation();
628         if (numGenericArgs != inst.GetNumArgs())
629             return false;
630
631         for (DWORD i = 0; i < numGenericArgs; i++)
632         {
633             PCCOR_SIGNATURE pSigArg;
634             DWORD cbSigArg;
635             sig.GetSignature(&pSigArg, &cbSigArg);
636             if (!ZapSig::CompareSignatureToTypeHandle(pSigArg, pModule, inst[i], pZapSigContext))
637                 return false;
638
639             IfFailThrow(sig.SkipExactlyOne());
640         }
641     }
642
643     return true;
644 }
645
646 PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, BOOL fFixups /*=TRUE*/)
647 {
648     STANDARD_VM_CONTRACT;
649
650     mdToken token = pMD->GetMemberDef();
651     int rid = RidFromToken(token);
652     if (rid == 0)
653         return NULL;
654
655     uint offset;
656     if (pMD->HasClassOrMethodInstantiation())
657     {
658         if (m_instMethodEntryPoints.IsNull())
659             return NULL;
660
661         NativeHashtable::Enumerator lookup = m_instMethodEntryPoints.Lookup(GetVersionResilientMethodHashCode(pMD));
662         NativeParser entryParser;
663         offset = -1;
664         while (lookup.GetNext(entryParser))
665         {
666             PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)entryParser.GetBlob();
667             SigPointer sig(pBlob);
668             if (SigMatchesMethodDesc(pMD, sig, m_pModule))
669             {
670                 // Get the updated SigPointer location, so we can calculate the size of the blob,
671                 // in order to skip the blob and find the entry point data.
672                 PCCOR_SIGNATURE pSigNew;
673                 DWORD cbSigNew;
674                 sig.GetSignature(&pSigNew, &cbSigNew);
675                 offset = entryParser.GetOffset() + (uint)(pSigNew - pBlob);
676                 break;
677             }
678         }
679
680         if (offset == -1)
681             return NULL;
682     }
683     else
684     {
685         if (!m_methodDefEntryPoints.TryGetAt(rid - 1, &offset))
686             return NULL;
687     }
688
689 #ifndef CROSSGEN_COMPILE
690 #ifdef PROFILING_SUPPORTED
691         BOOL fShouldSearchCache = TRUE;
692         {
693             BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
694             g_profControlBlock.pProfInterface->
695                 JITCachedFunctionSearchStarted((FunctionID)pMD, &fShouldSearchCache);
696             END_PIN_PROFILER();
697         }
698         if (!fShouldSearchCache)
699         {
700             return NULL;
701         }
702 #endif // PROFILING_SUPPORTED
703 #endif // CROSSGEN_COMPILE
704
705     uint id;
706     offset = m_nativeReader.DecodeUnsigned(offset, &id);
707
708     if (id & 1)
709     {
710         if (id & 2)
711         {
712             uint val;
713             m_nativeReader.DecodeUnsigned(offset, &val);
714             offset -= val;
715         }
716
717         if (fFixups)
718         {
719             if (!m_pModule->FixupDelayList(dac_cast<TADDR>(m_pLayout->GetBase()) + offset))
720                 return NULL;
721         }
722
723         id >>= 2;
724     }
725     else
726     {
727         id >>= 1;
728     }
729
730     _ASSERTE(id < m_nRuntimeFunctions);
731     PCODE pEntryPoint = dac_cast<TADDR>(m_pLayout->GetBase()) + m_pRuntimeFunctions[id].BeginAddress;
732
733     {
734         CrstHolder ch(&m_Crst);
735
736         if (m_entryPointToMethodDescMap.LookupValue(PCODEToPINSTR(pEntryPoint), (LPVOID)PCODEToPINSTR(pEntryPoint)) == (LPVOID)INVALIDENTRY)
737             m_entryPointToMethodDescMap.InsertValue(PCODEToPINSTR(pEntryPoint), pMD);
738     }
739
740 #ifndef CROSSGEN_COMPILE
741 #ifdef PROFILING_SUPPORTED
742         {
743             BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
744             g_profControlBlock.pProfInterface->
745                 JITCachedFunctionSearchFinished((FunctionID)pMD, COR_PRF_CACHED_FUNCTION_FOUND);
746             END_PIN_PROFILER();
747         }
748 #endif // PROFILING_SUPPORTED
749 #endif // CROSSGEN_COMPILE
750
751     if (g_pDebugInterface != NULL)
752     {
753         g_pDebugInterface->JITComplete(pMD, pEntryPoint);
754     }
755
756     return pEntryPoint;
757 }
758
759 BOOL ReadyToRunInfo::MethodIterator::Next()
760 {
761     CONTRACTL
762     {
763         GC_TRIGGERS;
764         THROWS;
765         MODE_ANY;
766     }
767     CONTRACTL_END;
768
769     while (++m_methodDefIndex < (int)m_pInfo->m_methodDefEntryPoints.GetCount())
770     {
771         uint offset;
772         if (m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
773             return TRUE;
774     }
775     return FALSE;
776 }
777
778 MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc()
779 {
780     STANDARD_VM_CONTRACT;
781
782     return MemberLoader::GetMethodDescFromMethodDef(m_pInfo->m_pModule, mdtMethodDef | (m_methodDefIndex + 1), FALSE);
783 }
784
785 MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc_NoRestore()
786 {
787     CONTRACTL
788     {
789         GC_TRIGGERS;
790         THROWS;
791         MODE_ANY;
792     }
793     CONTRACTL_END;
794
795     uint offset;
796     if (!m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
797     {
798         return NULL;
799     }
800
801     uint id;
802     offset = m_pInfo->m_nativeReader.DecodeUnsigned(offset, &id);
803
804     if (id & 1)
805     {
806         if (id & 2)
807         {
808             uint val;
809             m_pInfo->m_nativeReader.DecodeUnsigned(offset, &val);
810             offset -= val;
811         }
812
813         id >>= 2;
814     }
815     else
816     {
817         id >>= 1;
818     }
819
820     _ASSERTE(id < m_pInfo->m_nRuntimeFunctions);
821     PCODE pEntryPoint = dac_cast<TADDR>(m_pInfo->m_pLayout->GetBase()) + m_pInfo->m_pRuntimeFunctions[id].BeginAddress;
822
823     return m_pInfo->GetMethodDescForEntryPoint(pEntryPoint);
824 }
825
826 PCODE ReadyToRunInfo::MethodIterator::GetMethodStartAddress()
827 {
828     STANDARD_VM_CONTRACT;
829
830     PCODE ret = m_pInfo->GetEntryPoint(GetMethodDesc(), FALSE);
831     _ASSERTE(ret != NULL);
832     return ret;
833 }
834
835 DWORD ReadyToRunInfo::GetFieldBaseOffset(MethodTable * pMT)
836 {
837     STANDARD_VM_CONTRACT;
838
839     DWORD dwAlignment = DATA_ALIGNMENT;
840     DWORD dwOffsetBias = 0;
841 #ifdef FEATURE_64BIT_ALIGNMENT
842     dwOffsetBias = 4;
843     if (pMT->RequiresAlign8())
844         dwAlignment = 8;
845 #endif
846
847     MethodTable * pParentMT = pMT->GetParentMethodTable();
848     DWORD dwCumulativeInstanceFieldPos = (pParentMT != NULL) ? pParentMT->GetNumInstanceFieldBytes() : 0;
849
850     dwCumulativeInstanceFieldPos += dwOffsetBias;
851
852     dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwAlignment);
853
854     return (DWORD)sizeof(Object) + dwCumulativeInstanceFieldPos - dwOffsetBias;
855 }
856
857 #endif // DACCESS_COMPILE