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
20using namespace NativeFormat;
21
22IMAGE_DATA_DIRECTORY * ReadyToRunInfo::FindSection(DWORD type)
23{
24 CONTRACTL
25 {
26 GC_NOTRIGGER;
27 NOTHROW;
28 SO_TOLERANT;
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
46MethodDesc * ReadyToRunInfo::GetMethodDescForEntryPoint(PCODE entryPoint)
47{
48 CONTRACTL
49 {
50 GC_NOTRIGGER;
51 NOTHROW;
52 SO_TOLERANT;
53 SUPPORTS_DAC;
54 }
55 CONTRACTL_END;
56
57#if defined(_TARGET_AMD64_) || (defined(_TARGET_X86_) && defined(FEATURE_PAL))
58 // A normal method entry point is always 8 byte aligned, but a funclet can start at an odd address.
59 // Since PtrHashMap can't handle odd pointers, check for this case and return NULL.
60 if ((entryPoint & 0x1) != 0)
61 return NULL;
62#endif
63
64 TADDR val = (TADDR)m_entryPointToMethodDescMap.LookupValue(PCODEToPINSTR(entryPoint), (LPVOID)PCODEToPINSTR(entryPoint));
65 if (val == (TADDR)INVALIDENTRY)
66 return NULL;
67 return dac_cast<PTR_MethodDesc>(val);
68}
69
70BOOL ReadyToRunInfo::HasHashtableOfTypes()
71{
72 CONTRACTL
73 {
74 GC_NOTRIGGER;
75 NOTHROW;
76 SO_TOLERANT;
77 SUPPORTS_DAC;
78 }
79 CONTRACTL_END;
80
81 return !m_availableTypesHashtable.IsNull();
82}
83
84BOOL ReadyToRunInfo::TryLookupTypeTokenFromName(NameHandle *pName, mdToken * pFoundTypeToken)
85{
86 CONTRACTL
87 {
88 GC_NOTRIGGER;
89 NOTHROW;
90 SO_INTOLERANT;
91 SUPPORTS_DAC;
92 PRECONDITION(!m_availableTypesHashtable.IsNull());
93 }
94 CONTRACTL_END;
95
96 if (m_availableTypesHashtable.IsNull())
97 return FALSE;
98
99 LPCUTF8 pszName = NULL;
100 LPCUTF8 pszNameSpace = NULL;
101
102 //
103 // Compute the hashcode of the type (hashcode based on type name and namespace name)
104 //
105 int dwHashCode = 0;
106
107 if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
108 {
109 // Name-based lookups (ex: Type.GetType()).
110
111 pszName = pName->GetName();
112 pszNameSpace = "";
113
114 if (pName->GetNameSpace() != NULL)
115 {
116 pszNameSpace = pName->GetNameSpace();
117 }
118 else
119 {
120 LPCUTF8 p;
121 CQuickBytes szNamespace;
122
123 if ((p = ns::FindSep(pszName)) != NULL)
124 {
125 SIZE_T d = p - pszName;
126
127 FAULT_NOT_FATAL();
128 pszNameSpace = szNamespace.SetStringNoThrow(pszName, d);
129
130 if (pszNameSpace == NULL)
131 return FALSE;
132
133 pszName = (p + 1);
134 }
135 }
136
137 _ASSERT(pszNameSpace != NULL);
138 dwHashCode ^= ComputeNameHashCode(pszNameSpace, pszName);
139
140 // Bucket is not 'null' for a nested type, and it will have information about the nested type's encloser
141 if (!pName->GetBucket().IsNull())
142 {
143 // Must be a token based bucket that we found earlier in the R2R types hashtable
144 _ASSERT(pName->GetBucket().GetEntryType() == HashedTypeEntry::IsHashedTokenEntry);
145
146 const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
147
148 // Token must be a typedef token that we previously resolved (we shouldn't get here with an exported type token)
149 _ASSERT(TypeFromToken(tokenBasedEncloser.m_TypeToken) == mdtTypeDef);
150
151 int dwCurrentHashCode;
152 mdToken mdCurrentTypeToken = tokenBasedEncloser.m_TypeToken;
153 if (!GetVersionResilientTypeHashCode(tokenBasedEncloser.m_pModule->GetMDImport(), mdCurrentTypeToken, &dwCurrentHashCode))
154 return FALSE;
155 dwHashCode ^= dwCurrentHashCode;
156 }
157 }
158 else
159 {
160 // Token based lookups (ex: tokens from IL code)
161
162 if (!GetVersionResilientTypeHashCode(pName->GetTypeModule()->GetMDImport(), pName->GetTypeToken(), &dwHashCode))
163 return FALSE;
164 }
165
166
167 //
168 // Lookup the type in the native hashtable using the computed token
169 //
170 {
171 NativeHashtable::Enumerator lookup = m_availableTypesHashtable.Lookup((int)dwHashCode);
172 NativeParser entryParser;
173 while (lookup.GetNext(entryParser))
174 {
175 DWORD ridAndFlag = entryParser.GetUnsigned();
176 mdToken cl = ((ridAndFlag & 1) ? ((ridAndFlag >> 1) | mdtExportedType) : ((ridAndFlag >> 1) | mdtTypeDef));
177 _ASSERT(RidFromToken(cl) != 0);
178
179 if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
180 {
181 // Compare type name and namespace name
182 LPCUTF8 pszFoundName;
183 LPCUTF8 pszFoundNameSpace;
184 if (!GetTypeNameFromToken(m_pModule->GetMDImport(), cl, &pszFoundName, &pszFoundNameSpace))
185 continue;
186 if (strcmp(pszName, pszFoundName) != 0 || strcmp(pszNameSpace, pszFoundNameSpace) != 0)
187 continue;
188
189 mdToken mdFoundTypeEncloser;
190 BOOL inputTypeHasEncloser = !pName->GetBucket().IsNull();
191 BOOL foundTypeHasEncloser = GetEnclosingToken(m_pModule->GetMDImport(), cl, &mdFoundTypeEncloser);
192 if (inputTypeHasEncloser != foundTypeHasEncloser)
193 continue;
194
195 // Compare the enclosing types chain for a match
196 if (inputTypeHasEncloser)
197 {
198 const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
199
200 if (!CompareTypeNameOfTokens(tokenBasedEncloser.m_TypeToken, tokenBasedEncloser.m_pModule->GetMDImport(), mdFoundTypeEncloser, m_pModule->GetMDImport()))
201 continue;
202 }
203 }
204 else
205 {
206 // Compare type name, namespace name, and enclosing types chain for a match
207 if (!CompareTypeNameOfTokens(pName->GetTypeToken(), pName->GetTypeModule()->GetMDImport(), cl, m_pModule->GetMDImport()))
208 continue;
209 }
210
211 // Found a match!
212 *pFoundTypeToken = cl;
213 return TRUE;
214 }
215 }
216
217 return FALSE; // No matching type found
218}
219
220BOOL ReadyToRunInfo::GetTypeNameFromToken(IMDInternalImport * pImport, mdToken mdType, LPCUTF8 * ppszName, LPCUTF8 * ppszNameSpace)
221{
222 CONTRACTL
223 {
224 GC_NOTRIGGER;
225 NOTHROW;
226 SO_TOLERANT;
227 SUPPORTS_DAC;
228 PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
229 }
230 CONTRACTL_END;
231
232 switch (TypeFromToken(mdType))
233 {
234 case mdtTypeDef:
235 return SUCCEEDED(pImport->GetNameOfTypeDef(mdType, ppszName, ppszNameSpace));
236 case mdtTypeRef:
237 return SUCCEEDED(pImport->GetNameOfTypeRef(mdType, ppszNameSpace, ppszName));
238 case mdtExportedType:
239 return SUCCEEDED(pImport->GetExportedTypeProps(mdType, ppszNameSpace, ppszName, NULL, NULL, NULL));
240 }
241
242 return FALSE;
243}
244
245BOOL ReadyToRunInfo::GetEnclosingToken(IMDInternalImport * pImport, mdToken mdType, mdToken * pEnclosingToken)
246{
247 CONTRACTL
248 {
249 GC_NOTRIGGER;
250 NOTHROW;
251 SO_TOLERANT;
252 SUPPORTS_DAC;
253 PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
254 }
255 CONTRACTL_END;
256
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
274BOOL 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
311PTR_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
346BOOL 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.
358static FILE * volatile s_r2rLogFile = (FILE *)(-1);
359
360static 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.
409static 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 / TARGET_POINTER_SIZE;
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
453PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker *pamTracker)
454{
455 STANDARD_VM_CONTRACT;
456
457 PEFile * pFile = pModule->GetFile();
458
459 if (!IsReadyToRunEnabled())
460 {
461 // Log message is ignored in this case.
462 DoLog(NULL);
463 return NULL;
464 }
465
466 if (pModule->IsCollectible())
467 {
468 DoLog("Ready to Run disabled - collectible module");
469 return NULL;
470 }
471
472 if (!pFile->HasLoadedIL())
473 {
474 DoLog("Ready to Run disabled - no loaded IL image");
475 return NULL;
476 }
477
478 PEImageLayout * pLayout = pFile->GetLoadedIL();
479 if (!pLayout->HasReadyToRunHeader())
480 {
481 DoLog("Ready to Run header not found");
482 return NULL;
483 }
484
485 if (CORProfilerDisableAllNGenImages() || CORProfilerUseProfileImages())
486 {
487 DoLog("Ready to Run disabled - profiler disabled native images");
488 return NULL;
489 }
490
491 if (g_pConfig->ExcludeReadyToRun(pModule->GetSimpleName()))
492 {
493 DoLog("Ready to Run disabled - module on exclusion list");
494 return NULL;
495 }
496
497#ifdef FEATURE_NATIVE_IMAGE_GENERATION
498 // Ignore ReadyToRun during NGen
499 if (IsCompilationProcess() && !IsNgenPDBCompilationProcess())
500 {
501 DoLog("Ready to Run disabled - compilation process");
502 return NULL;
503 }
504#endif
505
506 if (!pLayout->IsNativeMachineFormat())
507 {
508 // For CoreCLR, be strict about disallowing machine mismatches.
509 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
510 }
511
512#ifndef CROSSGEN_COMPILE
513 // The file must have been loaded using LoadLibrary
514 if (!pLayout->IsRelocated())
515 {
516 DoLog("Ready to Run disabled - module not loaded for execution");
517 return NULL;
518 }
519#endif
520
521 READYTORUN_HEADER * pHeader = pLayout->GetReadyToRunHeader();
522
523 // Ignore the content if the image major version is higher than the major version currently supported by the runtime
524 if (pHeader->MajorVersion > READYTORUN_MAJOR_VERSION)
525 {
526 DoLog("Ready to Run disabled - unsupported header version");
527 return NULL;
528 }
529
530 if (!AcquireImage(pModule, pLayout, pHeader))
531 {
532 DoLog("Ready to Run disabled - module already loaded in another AppDomain");
533 return NULL;
534 }
535
536 LoaderHeap *pHeap = pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
537 void * pMemory = pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(ReadyToRunInfo)));
538
539 DoLog("Ready to Run initialized successfully");
540
541 return new (pMemory) ReadyToRunInfo(pModule, pLayout, pHeader, pamTracker);
542}
543
544ReadyToRunInfo::ReadyToRunInfo(Module * pModule, PEImageLayout * pLayout, READYTORUN_HEADER * pHeader, AllocMemTracker *pamTracker)
545 : m_pModule(pModule), m_pLayout(pLayout), m_pHeader(pHeader), m_Crst(CrstReadyToRunEntryPointToMethodDescMap),
546 m_pPersistentInlineTrackingMap(NULL)
547{
548 STANDARD_VM_CONTRACT;
549
550 IMAGE_DATA_DIRECTORY * pRuntimeFunctionsDir = FindSection(READYTORUN_SECTION_RUNTIME_FUNCTIONS);
551 if (pRuntimeFunctionsDir != NULL)
552 {
553 m_pRuntimeFunctions = (T_RUNTIME_FUNCTION *)pLayout->GetDirectoryData(pRuntimeFunctionsDir);
554 m_nRuntimeFunctions = pRuntimeFunctionsDir->Size / sizeof(T_RUNTIME_FUNCTION);
555 }
556 else
557 {
558 m_nRuntimeFunctions = 0;
559 }
560
561 IMAGE_DATA_DIRECTORY * pImportSectionsDir = FindSection(READYTORUN_SECTION_IMPORT_SECTIONS);
562 if (pImportSectionsDir != NULL)
563 {
564 m_pImportSections = (CORCOMPILE_IMPORT_SECTION*)pLayout->GetDirectoryData(pImportSectionsDir);
565 m_nImportSections = pImportSectionsDir->Size / sizeof(CORCOMPILE_IMPORT_SECTION);
566 }
567 else
568 {
569 m_nImportSections = 0;
570 }
571
572 m_nativeReader = NativeReader((byte *)pLayout->GetBase(), pLayout->GetVirtualSize());
573
574 IMAGE_DATA_DIRECTORY * pEntryPointsDir = FindSection(READYTORUN_SECTION_METHODDEF_ENTRYPOINTS);
575 if (pEntryPointsDir != NULL)
576 {
577 m_methodDefEntryPoints = NativeArray(&m_nativeReader, pEntryPointsDir->VirtualAddress);
578 }
579
580 IMAGE_DATA_DIRECTORY * pinstMethodsDir = FindSection(READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS);
581 if (pinstMethodsDir != NULL)
582 {
583 NativeParser parser = NativeParser(&m_nativeReader, pinstMethodsDir->VirtualAddress);
584 m_instMethodEntryPoints = NativeHashtable(parser);
585 }
586
587 IMAGE_DATA_DIRECTORY * pAvailableTypesDir = FindSection(READYTORUN_SECTION_AVAILABLE_TYPES);
588 if (pAvailableTypesDir != NULL)
589 {
590 NativeParser parser = NativeParser(&m_nativeReader, pAvailableTypesDir->VirtualAddress);
591 m_availableTypesHashtable = NativeHashtable(parser);
592 }
593
594 {
595 LockOwner lock = {&m_Crst, IsOwnerOfCrst};
596 m_entryPointToMethodDescMap.Init(TRUE, &lock);
597 }
598
599 // For format version 2.1 and later, there is an optional inlining table
600 if (IsImageVersionAtLeast(2, 1))
601 {
602 IMAGE_DATA_DIRECTORY * pInlineTrackingInfoDir = FindSection(READYTORUN_SECTION_INLINING_INFO);
603 if (pInlineTrackingInfoDir != NULL)
604 {
605 const BYTE* pInlineTrackingMapData = (const BYTE*)GetImage()->GetDirectoryData(pInlineTrackingInfoDir);
606 PersistentInlineTrackingMapR2R::TryLoad(pModule, pInlineTrackingMapData, pInlineTrackingInfoDir->Size,
607 pamTracker, &m_pPersistentInlineTrackingMap);
608 }
609 }
610 // Fpr format version 2.2 and later, there is an optional profile-data section
611 if (IsImageVersionAtLeast(2, 2))
612 {
613 IMAGE_DATA_DIRECTORY * pProfileDataInfoDir = FindSection(READYTORUN_SECTION_PROFILEDATA_INFO);
614 if (pProfileDataInfoDir != NULL)
615 {
616 CORCOMPILE_METHOD_PROFILE_LIST * pMethodProfileList;
617 pMethodProfileList = (CORCOMPILE_METHOD_PROFILE_LIST *)GetImage()->GetDirectoryData(pProfileDataInfoDir);
618
619 pModule->SetMethodProfileList(pMethodProfileList);
620 }
621 }
622}
623
624static bool SigMatchesMethodDesc(MethodDesc* pMD, SigPointer &sig, Module * pModule)
625{
626 STANDARD_VM_CONTRACT;
627
628 ZapSig::Context zapSigContext(pModule, (void *)pModule, ZapSig::NormalTokens);
629 ZapSig::Context * pZapSigContext = &zapSigContext;
630
631 DWORD methodFlags;
632 IfFailThrow(sig.GetData(&methodFlags));
633
634 if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
635 {
636 PCCOR_SIGNATURE pSigType;
637 DWORD cbSigType;
638 sig.GetSignature(&pSigType, &cbSigType);
639 if (!ZapSig::CompareSignatureToTypeHandle(pSigType, pModule, TypeHandle(pMD->GetMethodTable()), pZapSigContext))
640 return false;
641
642 IfFailThrow(sig.SkipExactlyOne());
643 }
644
645 _ASSERTE((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0);
646 _ASSERTE((methodFlags & ENCODE_METHOD_SIG_MemberRefToken) == 0);
647
648 RID rid;
649 IfFailThrow(sig.GetData(&rid));
650 if (RidFromToken(pMD->GetMemberDef()) != rid)
651 return false;
652
653 if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
654 {
655 DWORD numGenericArgs;
656 IfFailThrow(sig.GetData(&numGenericArgs));
657 Instantiation inst = pMD->GetMethodInstantiation();
658 if (numGenericArgs != inst.GetNumArgs())
659 return false;
660
661 for (DWORD i = 0; i < numGenericArgs; i++)
662 {
663 PCCOR_SIGNATURE pSigArg;
664 DWORD cbSigArg;
665 sig.GetSignature(&pSigArg, &cbSigArg);
666 if (!ZapSig::CompareSignatureToTypeHandle(pSigArg, pModule, inst[i], pZapSigContext))
667 return false;
668
669 IfFailThrow(sig.SkipExactlyOne());
670 }
671 }
672
673 return true;
674}
675
676PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, PrepareCodeConfig* pConfig, BOOL fFixups)
677{
678 STANDARD_VM_CONTRACT;
679
680 mdToken token = pMD->GetMemberDef();
681 int rid = RidFromToken(token);
682 if (rid == 0)
683 return NULL;
684
685 uint offset;
686 if (pMD->HasClassOrMethodInstantiation())
687 {
688 if (m_instMethodEntryPoints.IsNull())
689 return NULL;
690
691 NativeHashtable::Enumerator lookup = m_instMethodEntryPoints.Lookup(GetVersionResilientMethodHashCode(pMD));
692 NativeParser entryParser;
693 offset = -1;
694 while (lookup.GetNext(entryParser))
695 {
696 PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)entryParser.GetBlob();
697 SigPointer sig(pBlob);
698 if (SigMatchesMethodDesc(pMD, sig, m_pModule))
699 {
700 // Get the updated SigPointer location, so we can calculate the size of the blob,
701 // in order to skip the blob and find the entry point data.
702 PCCOR_SIGNATURE pSigNew;
703 DWORD cbSigNew;
704 sig.GetSignature(&pSigNew, &cbSigNew);
705 offset = entryParser.GetOffset() + (uint)(pSigNew - pBlob);
706 break;
707 }
708 }
709
710 if (offset == -1)
711 return NULL;
712 }
713 else
714 {
715 if (!m_methodDefEntryPoints.TryGetAt(rid - 1, &offset))
716 return NULL;
717 }
718
719#ifndef CROSSGEN_COMPILE
720#ifdef PROFILING_SUPPORTED
721 BOOL fShouldSearchCache = TRUE;
722 {
723 BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
724 g_profControlBlock.pProfInterface->
725 JITCachedFunctionSearchStarted((FunctionID)pMD, &fShouldSearchCache);
726 END_PIN_PROFILER();
727 }
728 if (!fShouldSearchCache)
729 {
730 pConfig->SetProfilerRejectedPrecompiledCode();
731 return NULL;
732 }
733#endif // PROFILING_SUPPORTED
734#endif // CROSSGEN_COMPILE
735
736 uint id;
737 offset = m_nativeReader.DecodeUnsigned(offset, &id);
738
739 if (id & 1)
740 {
741 if (id & 2)
742 {
743 uint val;
744 m_nativeReader.DecodeUnsigned(offset, &val);
745 offset -= val;
746 }
747
748 if (fFixups)
749 {
750 if (!m_pModule->FixupDelayList(dac_cast<TADDR>(m_pLayout->GetBase()) + offset))
751 {
752#ifndef CROSSGEN_COMPILE
753 pConfig->SetReadyToRunRejectedPrecompiledCode();
754#endif // CROSSGEN_COMPILE
755 return NULL;
756 }
757 }
758
759 id >>= 2;
760 }
761 else
762 {
763 id >>= 1;
764 }
765
766 _ASSERTE(id < m_nRuntimeFunctions);
767 PCODE pEntryPoint = dac_cast<TADDR>(m_pLayout->GetBase()) + m_pRuntimeFunctions[id].BeginAddress;
768
769 {
770 CrstHolder ch(&m_Crst);
771
772 if (m_entryPointToMethodDescMap.LookupValue(PCODEToPINSTR(pEntryPoint), (LPVOID)PCODEToPINSTR(pEntryPoint)) == (LPVOID)INVALIDENTRY)
773 m_entryPointToMethodDescMap.InsertValue(PCODEToPINSTR(pEntryPoint), pMD);
774 }
775
776#ifndef CROSSGEN_COMPILE
777#ifdef PROFILING_SUPPORTED
778 {
779 BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
780 g_profControlBlock.pProfInterface->
781 JITCachedFunctionSearchFinished((FunctionID)pMD, COR_PRF_CACHED_FUNCTION_FOUND);
782 END_PIN_PROFILER();
783 }
784#endif // PROFILING_SUPPORTED
785#endif // CROSSGEN_COMPILE
786
787 if (g_pDebugInterface != NULL)
788 {
789 g_pDebugInterface->JITComplete(pMD, pEntryPoint);
790 }
791
792 return pEntryPoint;
793}
794
795BOOL ReadyToRunInfo::MethodIterator::Next()
796{
797 CONTRACTL
798 {
799 GC_TRIGGERS;
800 THROWS;
801 MODE_ANY;
802 }
803 CONTRACTL_END;
804
805 while (++m_methodDefIndex < (int)m_pInfo->m_methodDefEntryPoints.GetCount())
806 {
807 uint offset;
808 if (m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
809 return TRUE;
810 }
811 return FALSE;
812}
813
814MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc()
815{
816 STANDARD_VM_CONTRACT;
817
818 return MemberLoader::GetMethodDescFromMethodDef(m_pInfo->m_pModule, mdtMethodDef | (m_methodDefIndex + 1), FALSE);
819}
820
821MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc_NoRestore()
822{
823 CONTRACTL
824 {
825 GC_TRIGGERS;
826 THROWS;
827 MODE_ANY;
828 }
829 CONTRACTL_END;
830
831 uint offset;
832 if (!m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
833 {
834 return NULL;
835 }
836
837 uint id;
838 offset = m_pInfo->m_nativeReader.DecodeUnsigned(offset, &id);
839
840 if (id & 1)
841 {
842 if (id & 2)
843 {
844 uint val;
845 m_pInfo->m_nativeReader.DecodeUnsigned(offset, &val);
846 offset -= val;
847 }
848
849 id >>= 2;
850 }
851 else
852 {
853 id >>= 1;
854 }
855
856 _ASSERTE(id < m_pInfo->m_nRuntimeFunctions);
857 PCODE pEntryPoint = dac_cast<TADDR>(m_pInfo->m_pLayout->GetBase()) + m_pInfo->m_pRuntimeFunctions[id].BeginAddress;
858
859 return m_pInfo->GetMethodDescForEntryPoint(pEntryPoint);
860}
861
862PCODE ReadyToRunInfo::MethodIterator::GetMethodStartAddress()
863{
864 STANDARD_VM_CONTRACT;
865
866 PCODE ret = m_pInfo->GetEntryPoint(GetMethodDesc(), NULL, FALSE);
867 _ASSERTE(ret != NULL);
868 return ret;
869}
870
871DWORD ReadyToRunInfo::GetFieldBaseOffset(MethodTable * pMT)
872{
873 STANDARD_VM_CONTRACT;
874
875 DWORD dwAlignment = DATA_ALIGNMENT;
876 DWORD dwOffsetBias = 0;
877#ifdef FEATURE_64BIT_ALIGNMENT
878 dwOffsetBias = 4;
879 if (pMT->RequiresAlign8())
880 dwAlignment = 8;
881#endif
882
883 MethodTable * pParentMT = pMT->GetParentMethodTable();
884 DWORD dwCumulativeInstanceFieldPos = (pParentMT != NULL) ? pParentMT->GetNumInstanceFieldBytes() : 0;
885
886 dwCumulativeInstanceFieldPos += dwOffsetBias;
887
888 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwAlignment);
889
890 return OBJECT_SIZE + dwCumulativeInstanceFieldPos - dwOffsetBias;
891}
892
893BOOL ReadyToRunInfo::IsImageVersionAtLeast(int majorVersion, int minorVersion)
894{
895 LIMITED_METHOD_CONTRACT;
896 return (m_pHeader->MajorVersion == majorVersion && m_pHeader->MinorVersion >= minorVersion) ||
897 (m_pHeader->MajorVersion > majorVersion);
898
899}
900
901#endif // DACCESS_COMPILE
902