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
9 // Runtime support for Ready to Run
10 // ===========================================================================
14 #include "dbginterface.h"
16 #include "versionresilienthashcode.h"
17 #include "typehashingalgorithms.h"
19 #include "wellknownattributes.h"
21 using namespace NativeFormat;
23 IMAGE_DATA_DIRECTORY * ReadyToRunInfo::FindSection(DWORD type)
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++)
36 // Verify that section types are sorted
37 _ASSERTE(i == 0 || (pSections[i-1].Type < pSections[i].Type));
39 READYTORUN_SECTION * pSection = pSections + i;
40 if (pSection->Type == type)
41 return &pSection->Section;
46 MethodDesc * ReadyToRunInfo::GetMethodDescForEntryPoint(PCODE entryPoint)
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)
63 TADDR val = (TADDR)m_entryPointToMethodDescMap.LookupValue(PCODEToPINSTR(entryPoint), (LPVOID)PCODEToPINSTR(entryPoint));
64 if (val == (TADDR)INVALIDENTRY)
66 return dac_cast<PTR_MethodDesc>(val);
69 BOOL ReadyToRunInfo::HasHashtableOfTypes()
79 return !m_availableTypesHashtable.IsNull();
82 BOOL ReadyToRunInfo::TryLookupTypeTokenFromName(const NameHandle *pName, mdToken * pFoundTypeToken)
89 PRECONDITION(!m_availableTypesHashtable.IsNull());
93 if (m_availableTypesHashtable.IsNull())
96 LPCUTF8 pszName = NULL;
97 LPCUTF8 pszNameSpace = NULL;
100 // Compute the hashcode of the type (hashcode based on type name and namespace name)
104 if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
106 // Name-based lookups (ex: Type.GetType()).
108 pszName = pName->GetName();
111 if (pName->GetNameSpace() != NULL)
113 pszNameSpace = pName->GetNameSpace();
118 CQuickBytes szNamespace;
120 if ((p = ns::FindSep(pszName)) != NULL)
122 SIZE_T d = p - pszName;
125 pszNameSpace = szNamespace.SetStringNoThrow(pszName, d);
127 if (pszNameSpace == NULL)
134 _ASSERT(pszNameSpace != NULL);
135 dwHashCode ^= ComputeNameHashCode(pszNameSpace, pszName);
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())
140 // Must be a token based bucket that we found earlier in the R2R types hashtable
141 _ASSERT(pName->GetBucket().GetEntryType() == HashedTypeEntry::IsHashedTokenEntry);
143 const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
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);
148 int dwCurrentHashCode;
149 mdToken mdCurrentTypeToken = tokenBasedEncloser.m_TypeToken;
150 if (!GetVersionResilientTypeHashCode(tokenBasedEncloser.m_pModule->GetMDImport(), mdCurrentTypeToken, &dwCurrentHashCode))
152 dwHashCode ^= dwCurrentHashCode;
157 // Token based lookups (ex: tokens from IL code)
159 if (!GetVersionResilientTypeHashCode(pName->GetTypeModule()->GetMDImport(), pName->GetTypeToken(), &dwHashCode))
165 // Lookup the type in the native hashtable using the computed token
168 NativeHashtable::Enumerator lookup = m_availableTypesHashtable.Lookup((int)dwHashCode);
169 NativeParser entryParser;
170 while (lookup.GetNext(entryParser))
172 DWORD ridAndFlag = entryParser.GetUnsigned();
173 mdToken cl = ((ridAndFlag & 1) ? ((ridAndFlag >> 1) | mdtExportedType) : ((ridAndFlag >> 1) | mdtTypeDef));
174 _ASSERT(RidFromToken(cl) != 0);
176 if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
178 // Compare type name and namespace name
179 LPCUTF8 pszFoundName;
180 LPCUTF8 pszFoundNameSpace;
181 if (!GetTypeNameFromToken(m_pModule->GetMDImport(), cl, &pszFoundName, &pszFoundNameSpace))
183 if (strcmp(pszName, pszFoundName) != 0 || strcmp(pszNameSpace, pszFoundNameSpace) != 0)
186 mdToken mdFoundTypeEncloser;
187 BOOL inputTypeHasEncloser = !pName->GetBucket().IsNull();
188 BOOL foundTypeHasEncloser = GetEnclosingToken(m_pModule->GetMDImport(), cl, &mdFoundTypeEncloser);
189 if (inputTypeHasEncloser != foundTypeHasEncloser)
192 // Compare the enclosing types chain for a match
193 if (inputTypeHasEncloser)
195 const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
197 if (!CompareTypeNameOfTokens(tokenBasedEncloser.m_TypeToken, tokenBasedEncloser.m_pModule->GetMDImport(), mdFoundTypeEncloser, m_pModule->GetMDImport()))
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()))
209 *pFoundTypeToken = cl;
214 return FALSE; // No matching type found
217 BOOL ReadyToRunInfo::GetTypeNameFromToken(IMDInternalImport * pImport, mdToken mdType, LPCUTF8 * ppszName, LPCUTF8 * ppszNameSpace)
224 PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
228 switch (TypeFromToken(mdType))
231 return SUCCEEDED(pImport->GetNameOfTypeDef(mdType, ppszName, ppszNameSpace));
233 return SUCCEEDED(pImport->GetNameOfTypeRef(mdType, ppszNameSpace, ppszName));
234 case mdtExportedType:
235 return SUCCEEDED(pImport->GetExportedTypeProps(mdType, ppszNameSpace, ppszName, NULL, NULL, NULL));
241 BOOL ReadyToRunInfo::GetEnclosingToken(IMDInternalImport * pImport, mdToken mdType, mdToken * pEnclosingToken)
248 PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
252 switch (TypeFromToken(mdType))
255 return SUCCEEDED(pImport->GetNestedClassProps(mdType, pEnclosingToken));
258 if (SUCCEEDED(pImport->GetResolutionScopeOfTypeRef(mdType, pEnclosingToken)))
259 return ((TypeFromToken(*pEnclosingToken) == mdtTypeRef) && (*pEnclosingToken != mdTypeRefNil));
261 case mdtExportedType:
262 if (SUCCEEDED(pImport->GetExportedTypeProps(mdType, NULL, NULL, pEnclosingToken, NULL, NULL)))
263 return ((TypeFromToken(*pEnclosingToken) == mdtExportedType) && (*pEnclosingToken != mdExportedTypeNil));
269 BOOL ReadyToRunInfo::CompareTypeNameOfTokens(mdToken mdToken1, IMDInternalImport * pImport1, mdToken mdToken2, IMDInternalImport * pImport2)
276 PRECONDITION(TypeFromToken(mdToken1) == mdtTypeDef || TypeFromToken(mdToken1) == mdtTypeRef || TypeFromToken(mdToken1) == mdtExportedType);
277 PRECONDITION(TypeFromToken(mdToken2) == mdtTypeDef || TypeFromToken(mdToken2) == mdtExportedType);
285 LPCUTF8 pszNameSpace1;
286 if (!GetTypeNameFromToken(pImport1, mdToken1, &pszName1, &pszNameSpace1))
290 LPCUTF8 pszNameSpace2;
291 if (!GetTypeNameFromToken(pImport2, mdToken2, &pszName2, &pszNameSpace2))
294 if (strcmp(pszName1, pszName2) != 0 || strcmp(pszNameSpace1, pszNameSpace2) != 0)
297 if ((hasEncloser = GetEnclosingToken(pImport1, mdToken1, &mdToken1)) != GetEnclosingToken(pImport2, mdToken2, &mdToken2))
300 } while (hasEncloser);
305 PTR_BYTE ReadyToRunInfo::GetDebugInfo(PTR_RUNTIME_FUNCTION pRuntimeFunction)
316 IMAGE_DATA_DIRECTORY * pDebugInfoDir = FindSection(READYTORUN_SECTION_DEBUG_INFO);
317 if (pDebugInfoDir == NULL)
320 SIZE_T methodIndex = pRuntimeFunction - m_pRuntimeFunctions;
321 _ASSERTE(methodIndex < m_nRuntimeFunctions);
323 NativeArray debugInfoIndex(dac_cast<PTR_NativeReader>(PTR_HOST_INT_TO_TADDR(&m_nativeReader)), pDebugInfoDir->VirtualAddress);
326 if (!debugInfoIndex.TryGetAt((DWORD)methodIndex, &offset))
330 uint debugInfoOffset = m_nativeReader.DecodeUnsigned(offset, &lookBack);
333 debugInfoOffset = offset - lookBack;
335 return dac_cast<PTR_BYTE>(m_pLayout->GetBase()) + debugInfoOffset;
338 #ifndef DACCESS_COMPILE
340 BOOL ReadyToRunInfo::IsReadyToRunEnabled()
344 static ConfigDWORD configReadyToRun;
345 return configReadyToRun.val(CLRConfig::EXTERNAL_ReadyToRun);
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);
354 static void LogR2r(const char *msg, PEFile *pFile)
356 STANDARD_VM_CONTRACT;
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))
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)
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"));
374 if (r2rLogFile != NULL && !ReadyToRunInfo::IsReadyToRunEnabled())
376 fputs("Ready to Run not enabled.\n", r2rLogFile);
381 if (InterlockedCompareExchangeT(&s_r2rLogFile, r2rLogFile, (FILE *)(-1)) != (FILE *)(-1))
383 if (r2rLogFile != NULL)
385 r2rLogFile = s_r2rLogFile;
389 if (r2rLogFile == NULL)
392 fprintf(r2rLogFile, "%s: \"%S\".\n", msg, pFile->GetPath().GetUnicode());
396 #define DoLog(msg) if (s_r2rLogFile != NULL) LogR2r(msg, pFile)
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)
405 STANDARD_VM_CONTRACT;
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++)
413 if (pSections[i].Type == READYTORUN_SECTION_IMPORT_SECTIONS)
415 pImportSections = (READYTORUN_IMPORT_SECTION*)((PBYTE)pLayout->GetBase() + pSections[i].Section.VirtualAddress);
416 pImportSectionsEnd = (READYTORUN_IMPORT_SECTION*)((PBYTE)pImportSections + pSections[i].Section.Size);
421 // Go through the import sections to find the import for the module pointer.
422 for (READYTORUN_IMPORT_SECTION * pCurSection = pImportSections; pCurSection < pImportSectionsEnd; pCurSection++)
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)
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++)
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)
438 Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)(pFixups + i)), pModule, NULL);
439 return pPrevious == NULL || pPrevious == pModule;
447 PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker *pamTracker)
449 STANDARD_VM_CONTRACT;
451 PEFile * pFile = pModule->GetFile();
453 if (!IsReadyToRunEnabled())
455 // Log message is ignored in this case.
460 if (pModule->IsCollectible())
462 DoLog("Ready to Run disabled - collectible module");
466 if (!pFile->HasLoadedIL())
468 DoLog("Ready to Run disabled - no loaded IL image");
472 PEImageLayout * pLayout = pFile->GetLoadedIL();
473 if (!pLayout->HasReadyToRunHeader())
475 DoLog("Ready to Run header not found");
479 if (CORProfilerDisableAllNGenImages() || CORProfilerUseProfileImages())
481 DoLog("Ready to Run disabled - profiler disabled native images");
485 if (g_pConfig->ExcludeReadyToRun(pModule->GetSimpleName()))
487 DoLog("Ready to Run disabled - module on exclusion list");
491 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
492 // Ignore ReadyToRun during NGen
493 if (IsCompilationProcess() && !IsNgenPDBCompilationProcess())
495 DoLog("Ready to Run disabled - compilation process");
500 if (!pLayout->IsNativeMachineFormat())
502 // For CoreCLR, be strict about disallowing machine mismatches.
503 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
506 #ifndef CROSSGEN_COMPILE
507 // The file must have been loaded using LoadLibrary
508 if (!pLayout->IsRelocated())
510 DoLog("Ready to Run disabled - module not loaded for execution");
515 READYTORUN_HEADER * pHeader = pLayout->GetReadyToRunHeader();
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)
520 DoLog("Ready to Run disabled - unsupported header version");
524 if (!AcquireImage(pModule, pLayout, pHeader))
526 DoLog("Ready to Run disabled - module already loaded in another AppDomain");
530 LoaderHeap *pHeap = pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
531 void * pMemory = pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(ReadyToRunInfo)));
533 DoLog("Ready to Run initialized successfully");
535 return new (pMemory) ReadyToRunInfo(pModule, pLayout, pHeader, pamTracker);
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)
542 STANDARD_VM_CONTRACT;
544 IMAGE_DATA_DIRECTORY * pRuntimeFunctionsDir = FindSection(READYTORUN_SECTION_RUNTIME_FUNCTIONS);
545 if (pRuntimeFunctionsDir != NULL)
547 m_pRuntimeFunctions = (T_RUNTIME_FUNCTION *)pLayout->GetDirectoryData(pRuntimeFunctionsDir);
548 m_nRuntimeFunctions = pRuntimeFunctionsDir->Size / sizeof(T_RUNTIME_FUNCTION);
552 m_nRuntimeFunctions = 0;
555 IMAGE_DATA_DIRECTORY * pImportSectionsDir = FindSection(READYTORUN_SECTION_IMPORT_SECTIONS);
556 if (pImportSectionsDir != NULL)
558 m_pImportSections = (CORCOMPILE_IMPORT_SECTION*)pLayout->GetDirectoryData(pImportSectionsDir);
559 m_nImportSections = pImportSectionsDir->Size / sizeof(CORCOMPILE_IMPORT_SECTION);
563 m_nImportSections = 0;
566 m_nativeReader = NativeReader((byte *)pLayout->GetBase(), pLayout->GetVirtualSize());
568 IMAGE_DATA_DIRECTORY * pEntryPointsDir = FindSection(READYTORUN_SECTION_METHODDEF_ENTRYPOINTS);
569 if (pEntryPointsDir != NULL)
571 m_methodDefEntryPoints = NativeArray(&m_nativeReader, pEntryPointsDir->VirtualAddress);
574 IMAGE_DATA_DIRECTORY * pinstMethodsDir = FindSection(READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS);
575 if (pinstMethodsDir != NULL)
577 NativeParser parser = NativeParser(&m_nativeReader, pinstMethodsDir->VirtualAddress);
578 m_instMethodEntryPoints = NativeHashtable(parser);
581 IMAGE_DATA_DIRECTORY * pAvailableTypesDir = FindSection(READYTORUN_SECTION_AVAILABLE_TYPES);
582 if (pAvailableTypesDir != NULL)
584 NativeParser parser = NativeParser(&m_nativeReader, pAvailableTypesDir->VirtualAddress);
585 m_availableTypesHashtable = NativeHashtable(parser);
589 LockOwner lock = {&m_Crst, IsOwnerOfCrst};
590 m_entryPointToMethodDescMap.Init(TRUE, &lock);
593 // For format version 2.1 and later, there is an optional inlining table
594 if (IsImageVersionAtLeast(2, 1))
596 IMAGE_DATA_DIRECTORY * pInlineTrackingInfoDir = FindSection(READYTORUN_SECTION_INLINING_INFO);
597 if (pInlineTrackingInfoDir != NULL)
599 const BYTE* pInlineTrackingMapData = (const BYTE*)GetImage()->GetDirectoryData(pInlineTrackingInfoDir);
600 PersistentInlineTrackingMapR2R::TryLoad(pModule, pInlineTrackingMapData, pInlineTrackingInfoDir->Size,
601 pamTracker, &m_pPersistentInlineTrackingMap);
605 // For format version 2.2 and later, there is an optional profile-data section
606 if (IsImageVersionAtLeast(2, 2))
608 IMAGE_DATA_DIRECTORY * pProfileDataInfoDir = FindSection(READYTORUN_SECTION_PROFILEDATA_INFO);
609 if (pProfileDataInfoDir != NULL)
611 CORCOMPILE_METHOD_PROFILE_LIST * pMethodProfileList;
612 pMethodProfileList = (CORCOMPILE_METHOD_PROFILE_LIST *)GetImage()->GetDirectoryData(pProfileDataInfoDir);
614 pModule->SetMethodProfileList(pMethodProfileList);
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)
622 NativeCuckooFilter newFilter(
623 (byte *)pLayout->GetBase(),
624 pLayout->GetVirtualSize(),
625 attributesPresenceDataInfoDir->VirtualAddress,
626 attributesPresenceDataInfoDir->Size);
628 m_attributesPresence = newFilter;
632 static bool SigMatchesMethodDesc(MethodDesc* pMD, SigPointer &sig, Module * pModule)
634 STANDARD_VM_CONTRACT;
636 ZapSig::Context zapSigContext(pModule, (void *)pModule, ZapSig::NormalTokens);
637 ZapSig::Context * pZapSigContext = &zapSigContext;
640 IfFailThrow(sig.GetData(&methodFlags));
642 if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
644 PCCOR_SIGNATURE pSigType;
646 sig.GetSignature(&pSigType, &cbSigType);
647 if (!ZapSig::CompareSignatureToTypeHandle(pSigType, pModule, TypeHandle(pMD->GetMethodTable()), pZapSigContext))
650 IfFailThrow(sig.SkipExactlyOne());
653 _ASSERTE((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0);
654 _ASSERTE((methodFlags & ENCODE_METHOD_SIG_MemberRefToken) == 0);
657 IfFailThrow(sig.GetData(&rid));
658 if (RidFromToken(pMD->GetMemberDef()) != rid)
661 if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
663 DWORD numGenericArgs;
664 IfFailThrow(sig.GetData(&numGenericArgs));
665 Instantiation inst = pMD->GetMethodInstantiation();
666 if (numGenericArgs != inst.GetNumArgs())
669 for (DWORD i = 0; i < numGenericArgs; i++)
671 PCCOR_SIGNATURE pSigArg;
673 sig.GetSignature(&pSigArg, &cbSigArg);
674 if (!ZapSig::CompareSignatureToTypeHandle(pSigArg, pModule, inst[i], pZapSigContext))
677 IfFailThrow(sig.SkipExactlyOne());
684 PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, PrepareCodeConfig* pConfig, BOOL fFixups)
686 STANDARD_VM_CONTRACT;
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);
700 if (pMD->HasClassOrMethodInstantiation())
702 if (m_instMethodEntryPoints.IsNull())
705 NativeHashtable::Enumerator lookup = m_instMethodEntryPoints.Lookup(GetVersionResilientMethodHashCode(pMD));
706 NativeParser entryParser;
708 while (lookup.GetNext(entryParser))
710 PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)entryParser.GetBlob();
711 SigPointer sig(pBlob);
712 if (SigMatchesMethodDesc(pMD, sig, m_pModule))
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;
718 sig.GetSignature(&pSigNew, &cbSigNew);
719 offset = entryParser.GetOffset() + (uint)(pSigNew - pBlob);
724 if (offset == (uint)-1)
729 if (!m_methodDefEntryPoints.TryGetAt(rid - 1, &offset))
733 #ifndef CROSSGEN_COMPILE
734 #ifdef PROFILING_SUPPORTED
736 BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
737 g_profControlBlock.pProfInterface->
738 JITCachedFunctionSearchStarted((FunctionID)pMD, &fShouldSearchCache);
741 if (!fShouldSearchCache)
743 pConfig->SetProfilerRejectedPrecompiledCode();
746 #endif // PROFILING_SUPPORTED
747 #endif // CROSSGEN_COMPILE
750 offset = m_nativeReader.DecodeUnsigned(offset, &id);
757 m_nativeReader.DecodeUnsigned(offset, &val);
763 if (!m_pModule->FixupDelayList(dac_cast<TADDR>(m_pLayout->GetBase()) + offset))
765 #ifndef CROSSGEN_COMPILE
766 pConfig->SetReadyToRunRejectedPrecompiledCode();
767 #endif // CROSSGEN_COMPILE
779 _ASSERTE(id < m_nRuntimeFunctions);
780 pEntryPoint = dac_cast<TADDR>(m_pLayout->GetBase()) + m_pRuntimeFunctions[id].BeginAddress;
783 CrstHolder ch(&m_Crst);
785 if (m_entryPointToMethodDescMap.LookupValue(PCODEToPINSTR(pEntryPoint), (LPVOID)PCODEToPINSTR(pEntryPoint)) == (LPVOID)INVALIDENTRY)
786 m_entryPointToMethodDescMap.InsertValue(PCODEToPINSTR(pEntryPoint), pMD);
789 #ifndef CROSSGEN_COMPILE
790 #ifdef PROFILING_SUPPORTED
792 BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
793 g_profControlBlock.pProfInterface->
794 JITCachedFunctionSearchFinished((FunctionID)pMD, COR_PRF_CACHED_FUNCTION_FOUND);
797 #endif // PROFILING_SUPPORTED
798 #endif // CROSSGEN_COMPILE
800 if (g_pDebugInterface != NULL)
802 #if defined(CROSSGEN_COMPILE)
803 g_pDebugInterface->JITComplete(NativeCodeVersion(pMD), pEntryPoint);
805 g_pDebugInterface->JITComplete(pConfig->GetCodeVersion(), pEntryPoint);
810 if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, R2RGetEntryPoint))
812 ETW::MethodLog::GetR2RGetEntryPoint(pMD, pEntryPoint);
818 void ReadyToRunInfo::MethodIterator::ParseGenericMethodSignatureAndRid(uint *pOffset, RID *pRid)
820 _ASSERTE(!m_genericParser.IsNull());
826 PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)m_genericParser.GetBlob();
827 SigPointer sig(pBlob);
829 DWORD methodFlags = 0;
830 // Skip the signature so we can get to the offset
831 hr = sig.GetData(&methodFlags);
837 if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
839 hr = sig.SkipExactlyOne();
846 _ASSERTE((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0);
847 _ASSERTE((methodFlags & ENCODE_METHOD_SIG_MemberRefToken) == 0);
849 hr = sig.GetData(pRid);
855 if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
857 DWORD numGenericArgs;
858 hr = sig.GetData(&numGenericArgs);
864 for (DWORD i = 0; i < numGenericArgs; i++)
866 hr = sig.SkipExactlyOne();
874 // Now that we have the size of the signature we can grab the offset and decode it
875 PCCOR_SIGNATURE pSigNew;
877 sig.GetSignature(&pSigNew, &cbSigNew);
879 m_genericCurrentSig = pBlob;
880 *pOffset = m_genericParser.GetOffset() + (uint)(pSigNew - pBlob);
883 BOOL ReadyToRunInfo::MethodIterator::Next()
893 // Enumerate non-generic methods
894 while (++m_methodDefIndex < (int)m_pInfo->m_methodDefEntryPoints.GetCount())
897 if (m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
903 // Enumerate generic instantiations
904 m_genericParser = m_genericEnum.GetNext();
905 if (!m_genericParser.IsNull())
907 ParseGenericMethodSignatureAndRid(&m_genericCurrentOffset, &m_genericCurrentRid);
914 MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc()
916 STANDARD_VM_CONTRACT;
918 mdMethodDef methodToken = mdTokenNil;
919 if (m_methodDefIndex < (int)m_pInfo->m_methodDefEntryPoints.GetCount())
921 methodToken = mdtMethodDef | (m_methodDefIndex + 1);
922 return MemberLoader::GetMethodDescFromMethodDef(m_pInfo->m_pModule, methodToken, FALSE);
926 _ASSERTE(m_genericCurrentOffset > 0 && m_genericCurrentSig != NULL);
927 return ZapSig::DecodeMethod(m_pInfo->m_pModule, m_pInfo->m_pModule, m_genericCurrentSig);
932 MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc_NoRestore()
943 if (m_methodDefIndex < (int)m_pInfo->m_methodDefEntryPoints.GetCount())
945 if (!m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
952 if (m_genericCurrentOffset <= 0)
954 // Failed to parse generic info.
958 offset = m_genericCurrentOffset;
962 offset = m_pInfo->m_nativeReader.DecodeUnsigned(offset, &id);
969 m_pInfo->m_nativeReader.DecodeUnsigned(offset, &val);
980 _ASSERTE(id < m_pInfo->m_nRuntimeFunctions);
981 PCODE pEntryPoint = dac_cast<TADDR>(m_pInfo->m_pLayout->GetBase()) + m_pInfo->m_pRuntimeFunctions[id].BeginAddress;
983 return m_pInfo->GetMethodDescForEntryPoint(pEntryPoint);
986 PCODE ReadyToRunInfo::MethodIterator::GetMethodStartAddress()
988 STANDARD_VM_CONTRACT;
990 PCODE ret = m_pInfo->GetEntryPoint(GetMethodDesc(), NULL, FALSE);
991 _ASSERTE(ret != NULL);
995 DWORD ReadyToRunInfo::GetFieldBaseOffset(MethodTable * pMT)
997 STANDARD_VM_CONTRACT;
999 DWORD dwAlignment = DATA_ALIGNMENT;
1000 DWORD dwOffsetBias = 0;
1001 #ifdef FEATURE_64BIT_ALIGNMENT
1003 if (pMT->RequiresAlign8())
1007 MethodTable * pParentMT = pMT->GetParentMethodTable();
1008 DWORD dwCumulativeInstanceFieldPos = (pParentMT != NULL) ? pParentMT->GetNumInstanceFieldBytes() : 0;
1010 dwCumulativeInstanceFieldPos += dwOffsetBias;
1012 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwAlignment);
1014 return OBJECT_SIZE + dwCumulativeInstanceFieldPos - dwOffsetBias;
1017 BOOL ReadyToRunInfo::IsImageVersionAtLeast(int majorVersion, int minorVersion)
1019 LIMITED_METHOD_CONTRACT;
1020 return (m_pHeader->MajorVersion == majorVersion && m_pHeader->MinorVersion >= minorVersion) ||
1021 (m_pHeader->MajorVersion > majorVersion);
1025 static DWORD s_wellKnownAttributeHashes[(DWORD)WellKnownAttribute::CountOfWellKnownAttributes];
1027 bool ReadyToRunInfo::MayHaveCustomAttribute(WellKnownAttribute attribute, mdToken token)
1030 UINT16 fingerprint = 0;
1031 if (!m_attributesPresence.HashComputationImmaterial())
1033 DWORD wellKnownHash = s_wellKnownAttributeHashes[(DWORD)attribute];
1034 if (wellKnownHash == 0)
1036 // TODO, investigate using constexpr to compute string hashes at compile time initially
1037 s_wellKnownAttributeHashes[(DWORD)attribute] = wellKnownHash = ComputeNameHashCode(GetWellKnownAttributeName(attribute));
1040 hash = CombineTwoValuesIntoHash(wellKnownHash, token);
1041 fingerprint = hash >> 16;
1044 return m_attributesPresence.MayExist(hash, fingerprint);
1047 void ReadyToRunInfo::DisableCustomAttributeFilter()
1049 m_attributesPresence.DisableFilter();
1052 #endif // DACCESS_COMPILE