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 using namespace NativeFormat;
21 IMAGE_DATA_DIRECTORY * ReadyToRunInfo::FindSection(DWORD type)
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++)
35 // Verify that section types are sorted
36 _ASSERTE(i == 0 || (pSections[i-1].Type < pSections[i].Type));
38 READYTORUN_SECTION * pSection = pSections + i;
39 if (pSection->Type == type)
40 return &pSection->Section;
45 MethodDesc * ReadyToRunInfo::GetMethodDescForEntryPoint(PCODE entryPoint)
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()
80 return !m_availableTypesHashtable.IsNull();
83 BOOL ReadyToRunInfo::TryLookupTypeTokenFromName(NameHandle *pName, mdToken * pFoundTypeToken)
91 PRECONDITION(!m_availableTypesHashtable.IsNull());
95 if (m_availableTypesHashtable.IsNull())
98 LPCUTF8 pszName = NULL;
99 LPCUTF8 pszNameSpace = NULL;
102 // Compute the hashcode of the type (hashcode based on type name and namespace name)
106 if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
108 // Name-based lookups (ex: Type.GetType()).
110 pszName = pName->GetName();
113 if (pName->GetNameSpace() != NULL)
115 pszNameSpace = pName->GetNameSpace();
120 CQuickBytes szNamespace;
122 if ((p = ns::FindSep(pszName)) != NULL)
124 SIZE_T d = p - pszName;
127 pszNameSpace = szNamespace.SetStringNoThrow(pszName, d);
129 if (pszNameSpace == NULL)
136 _ASSERT(pszNameSpace != NULL);
137 dwHashCode ^= ComputeNameHashCode(pszNameSpace, pszName);
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())
142 // Must be a token based bucket that we found earlier in the R2R types hashtable
143 _ASSERT(pName->GetBucket().GetEntryType() == HashedTypeEntry::IsHashedTokenEntry);
145 const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
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);
150 int dwCurrentHashCode;
151 mdToken mdCurrentTypeToken = tokenBasedEncloser.m_TypeToken;
152 if (!GetVersionResilientTypeHashCode(tokenBasedEncloser.m_pModule->GetMDImport(), mdCurrentTypeToken, &dwCurrentHashCode))
154 dwHashCode ^= dwCurrentHashCode;
159 // Token based lookups (ex: tokens from IL code)
161 if (!GetVersionResilientTypeHashCode(pName->GetTypeModule()->GetMDImport(), pName->GetTypeToken(), &dwHashCode))
167 // Lookup the type in the native hashtable using the computed token
170 NativeHashtable::Enumerator lookup = m_availableTypesHashtable.Lookup((int)dwHashCode);
171 NativeParser entryParser;
172 while (lookup.GetNext(entryParser))
174 DWORD ridAndFlag = entryParser.GetUnsigned();
175 mdToken cl = ((ridAndFlag & 1) ? ((ridAndFlag >> 1) | mdtExportedType) : ((ridAndFlag >> 1) | mdtTypeDef));
176 _ASSERT(RidFromToken(cl) != 0);
178 if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
180 // Compare type name and namespace name
181 LPCUTF8 pszFoundName;
182 LPCUTF8 pszFoundNameSpace;
183 if (!GetTypeNameFromToken(m_pModule->GetMDImport(), cl, &pszFoundName, &pszFoundNameSpace))
185 if (strcmp(pszName, pszFoundName) != 0 || strcmp(pszNameSpace, pszFoundNameSpace) != 0)
188 mdToken mdFoundTypeEncloser;
189 BOOL inputTypeHasEncloser = !pName->GetBucket().IsNull();
190 BOOL foundTypeHasEncloser = GetEnclosingToken(m_pModule->GetMDImport(), cl, &mdFoundTypeEncloser);
191 if (inputTypeHasEncloser != foundTypeHasEncloser)
194 // Compare the enclosing types chain for a match
195 if (inputTypeHasEncloser)
197 const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
199 if (!CompareTypeNameOfTokens(tokenBasedEncloser.m_TypeToken, tokenBasedEncloser.m_pModule->GetMDImport(), mdFoundTypeEncloser, m_pModule->GetMDImport()))
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()))
211 *pFoundTypeToken = cl;
216 return FALSE; // No matching type found
219 BOOL ReadyToRunInfo::GetTypeNameFromToken(IMDInternalImport * pImport, mdToken mdType, LPCUTF8 * ppszName, LPCUTF8 * ppszNameSpace)
227 PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
231 switch (TypeFromToken(mdType))
234 return SUCCEEDED(pImport->GetNameOfTypeDef(mdType, ppszName, ppszNameSpace));
236 return SUCCEEDED(pImport->GetNameOfTypeRef(mdType, ppszNameSpace, ppszName));
237 case mdtExportedType:
238 return SUCCEEDED(pImport->GetExportedTypeProps(mdType, ppszNameSpace, ppszName, NULL, NULL, NULL));
244 BOOL ReadyToRunInfo::GetEnclosingToken(IMDInternalImport * pImport, mdToken mdType, mdToken * pEnclosingToken)
252 PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
257 switch (TypeFromToken(mdType))
260 return SUCCEEDED(pImport->GetNestedClassProps(mdType, pEnclosingToken));
263 if (SUCCEEDED(pImport->GetResolutionScopeOfTypeRef(mdType, pEnclosingToken)))
264 return ((TypeFromToken(*pEnclosingToken) == mdtTypeRef) && (*pEnclosingToken != mdTypeRefNil));
266 case mdtExportedType:
267 if (SUCCEEDED(pImport->GetExportedTypeProps(mdType, NULL, NULL, pEnclosingToken, NULL, NULL)))
268 return ((TypeFromToken(*pEnclosingToken) == mdtExportedType) && (*pEnclosingToken != mdExportedTypeNil));
274 BOOL ReadyToRunInfo::CompareTypeNameOfTokens(mdToken mdToken1, IMDInternalImport * pImport1, mdToken mdToken2, IMDInternalImport * pImport2)
282 PRECONDITION(TypeFromToken(mdToken1) == mdtTypeDef || TypeFromToken(mdToken1) == mdtTypeRef || TypeFromToken(mdToken1) == mdtExportedType);
283 PRECONDITION(TypeFromToken(mdToken2) == mdtTypeDef || TypeFromToken(mdToken2) == mdtExportedType);
291 LPCUTF8 pszNameSpace1;
292 if (!GetTypeNameFromToken(pImport1, mdToken1, &pszName1, &pszNameSpace1))
296 LPCUTF8 pszNameSpace2;
297 if (!GetTypeNameFromToken(pImport2, mdToken2, &pszName2, &pszNameSpace2))
300 if (strcmp(pszName1, pszName2) != 0 || strcmp(pszNameSpace1, pszNameSpace2) != 0)
303 if ((hasEncloser = GetEnclosingToken(pImport1, mdToken1, &mdToken1)) != GetEnclosingToken(pImport2, mdToken2, &mdToken2))
306 } while (hasEncloser);
311 PTR_BYTE ReadyToRunInfo::GetDebugInfo(PTR_RUNTIME_FUNCTION pRuntimeFunction)
322 IMAGE_DATA_DIRECTORY * pDebugInfoDir = FindSection(READYTORUN_SECTION_DEBUG_INFO);
323 if (pDebugInfoDir == NULL)
326 SIZE_T methodIndex = pRuntimeFunction - m_pRuntimeFunctions;
327 _ASSERTE(methodIndex < m_nRuntimeFunctions);
329 NativeArray debugInfoIndex(dac_cast<PTR_NativeReader>(PTR_HOST_INT_TO_TADDR(&m_nativeReader)), pDebugInfoDir->VirtualAddress);
332 if (!debugInfoIndex.TryGetAt((DWORD)methodIndex, &offset))
336 uint debugInfoOffset = m_nativeReader.DecodeUnsigned(offset, &lookBack);
339 debugInfoOffset = offset - lookBack;
341 return dac_cast<PTR_BYTE>(m_pLayout->GetBase()) + debugInfoOffset;
344 #ifndef DACCESS_COMPILE
346 BOOL ReadyToRunInfo::IsReadyToRunEnabled()
350 static ConfigDWORD configReadyToRun;
351 return configReadyToRun.val(CLRConfig::EXTERNAL_ReadyToRun);
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);
360 static void LogR2r(const char *msg, PEFile *pFile)
362 STANDARD_VM_CONTRACT;
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))
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)
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"));
380 if (r2rLogFile != NULL && !ReadyToRunInfo::IsReadyToRunEnabled())
382 fputs("Ready to Run not enabled.\n", r2rLogFile);
387 if (InterlockedCompareExchangeT(&s_r2rLogFile, r2rLogFile, (FILE *)(-1)) != (FILE *)(-1))
389 if (r2rLogFile != NULL)
391 r2rLogFile = s_r2rLogFile;
395 if (r2rLogFile == NULL)
398 fprintf(r2rLogFile, "%s: \"%S\".\n", msg, pFile->GetPath().GetUnicode());
402 #define DoLog(msg) if (s_r2rLogFile != NULL) LogR2r(msg, pFile)
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)
411 STANDARD_VM_CONTRACT;
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++)
419 if (pSections[i].Type == READYTORUN_SECTION_IMPORT_SECTIONS)
421 pImportSections = (READYTORUN_IMPORT_SECTION*)((PBYTE)pLayout->GetBase() + pSections[i].Section.VirtualAddress);
422 pImportSectionsEnd = (READYTORUN_IMPORT_SECTION*)((PBYTE)pImportSections + pSections[i].Section.Size);
427 // Go through the import sections to find the import for the module pointer.
428 for (READYTORUN_IMPORT_SECTION * pCurSection = pImportSections; pCurSection < pImportSectionsEnd; pCurSection++)
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)
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++)
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)
444 Module * pPrevious = InterlockedCompareExchangeT(EnsureWritablePages((Module **)(pFixups + i)), pModule, NULL);
445 return pPrevious == NULL || pPrevious == pModule;
453 PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker *pamTracker)
455 STANDARD_VM_CONTRACT;
457 PEFile * pFile = pModule->GetFile();
459 // Ignore ReadyToRun for introspection-only loads
460 if (pFile->IsIntrospectionOnly())
462 DoLog("Ready to Run disabled - module loaded for reflection");
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 (!IsReadyToRunEnabled())
481 // Log message is ignored in this case.
486 if (g_pConfig->ExcludeReadyToRun(pModule->GetSimpleName()))
488 DoLog("Ready to Run disabled - module on exclusion list");
492 if (!pLayout->IsNativeMachineFormat())
494 // For CoreCLR, be strict about disallowing machine mismatches.
495 COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
498 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
499 // Ignore ReadyToRun during NGen
500 if (IsCompilationProcess() && !IsNgenPDBCompilationProcess())
502 DoLog("Ready to Run disabled - compilation process");
507 #ifndef CROSSGEN_COMPILE
508 // The file must have been loaded using LoadLibrary
509 if (!pLayout->IsRelocated())
511 DoLog("Ready to Run disabled - module not loaded for execution");
516 READYTORUN_HEADER * pHeader = pLayout->GetReadyToRunHeader();
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)
521 DoLog("Ready to Run disabled - unsupported header version");
525 if (!AcquireImage(pModule, pLayout, pHeader))
527 DoLog("Ready to Run disabled - module already loaded in another AppDomain");
531 LoaderHeap *pHeap = pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
532 void * pMemory = pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(ReadyToRunInfo)));
534 DoLog("Ready to Run initialized successfully");
536 return new (pMemory) ReadyToRunInfo(pModule, pLayout, pHeader);
539 ReadyToRunInfo::ReadyToRunInfo(Module * pModule, PEImageLayout * pLayout, READYTORUN_HEADER * pHeader)
540 : m_pModule(pModule), m_pLayout(pLayout), m_pHeader(pHeader), m_Crst(CrstLeafLock)
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);
594 static bool SigMatchesMethodDesc(MethodDesc* pMD, SigPointer &sig, Module * pModule)
596 STANDARD_VM_CONTRACT;
598 ZapSig::Context zapSigContext(pModule, (void *)pModule, ZapSig::NormalTokens);
599 ZapSig::Context * pZapSigContext = &zapSigContext;
602 IfFailThrow(sig.GetData(&methodFlags));
604 if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
606 PCCOR_SIGNATURE pSigType;
608 sig.GetSignature(&pSigType, &cbSigType);
609 if (!ZapSig::CompareSignatureToTypeHandle(pSigType, pModule, TypeHandle(pMD->GetMethodTable()), pZapSigContext))
612 IfFailThrow(sig.SkipExactlyOne());
615 _ASSERTE((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0);
616 _ASSERTE((methodFlags & ENCODE_METHOD_SIG_MemberRefToken) == 0);
619 IfFailThrow(sig.GetData(&rid));
620 if (RidFromToken(pMD->GetMemberDef()) != rid)
623 if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
625 DWORD numGenericArgs;
626 IfFailThrow(sig.GetData(&numGenericArgs));
627 Instantiation inst = pMD->GetMethodInstantiation();
628 if (numGenericArgs != inst.GetNumArgs())
631 for (DWORD i = 0; i < numGenericArgs; i++)
633 PCCOR_SIGNATURE pSigArg;
635 sig.GetSignature(&pSigArg, &cbSigArg);
636 if (!ZapSig::CompareSignatureToTypeHandle(pSigArg, pModule, inst[i], pZapSigContext))
639 IfFailThrow(sig.SkipExactlyOne());
646 PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, BOOL fFixups /*=TRUE*/)
648 STANDARD_VM_CONTRACT;
650 mdToken token = pMD->GetMemberDef();
651 int rid = RidFromToken(token);
656 if (pMD->HasClassOrMethodInstantiation())
658 if (m_instMethodEntryPoints.IsNull())
661 NativeHashtable::Enumerator lookup = m_instMethodEntryPoints.Lookup(GetVersionResilientMethodHashCode(pMD));
662 NativeParser entryParser;
664 while (lookup.GetNext(entryParser))
666 PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)entryParser.GetBlob();
667 SigPointer sig(pBlob);
668 if (SigMatchesMethodDesc(pMD, sig, m_pModule))
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;
674 sig.GetSignature(&pSigNew, &cbSigNew);
675 offset = entryParser.GetOffset() + (uint)(pSigNew - pBlob);
685 if (!m_methodDefEntryPoints.TryGetAt(rid - 1, &offset))
689 #ifndef CROSSGEN_COMPILE
690 #ifdef PROFILING_SUPPORTED
691 BOOL fShouldSearchCache = TRUE;
693 BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
694 g_profControlBlock.pProfInterface->
695 JITCachedFunctionSearchStarted((FunctionID)pMD, &fShouldSearchCache);
698 if (!fShouldSearchCache)
702 #endif // PROFILING_SUPPORTED
703 #endif // CROSSGEN_COMPILE
706 offset = m_nativeReader.DecodeUnsigned(offset, &id);
713 m_nativeReader.DecodeUnsigned(offset, &val);
719 if (!m_pModule->FixupDelayList(dac_cast<TADDR>(m_pLayout->GetBase()) + offset))
730 _ASSERTE(id < m_nRuntimeFunctions);
731 PCODE pEntryPoint = dac_cast<TADDR>(m_pLayout->GetBase()) + m_pRuntimeFunctions[id].BeginAddress;
734 CrstHolder ch(&m_Crst);
736 if (m_entryPointToMethodDescMap.LookupValue(PCODEToPINSTR(pEntryPoint), (LPVOID)PCODEToPINSTR(pEntryPoint)) == (LPVOID)INVALIDENTRY)
737 m_entryPointToMethodDescMap.InsertValue(PCODEToPINSTR(pEntryPoint), pMD);
740 #ifndef CROSSGEN_COMPILE
741 #ifdef PROFILING_SUPPORTED
743 BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches());
744 g_profControlBlock.pProfInterface->
745 JITCachedFunctionSearchFinished((FunctionID)pMD, COR_PRF_CACHED_FUNCTION_FOUND);
748 #endif // PROFILING_SUPPORTED
749 #endif // CROSSGEN_COMPILE
751 if (g_pDebugInterface != NULL)
753 g_pDebugInterface->JITComplete(pMD, pEntryPoint);
759 BOOL ReadyToRunInfo::MethodIterator::Next()
769 while (++m_methodDefIndex < (int)m_pInfo->m_methodDefEntryPoints.GetCount())
772 if (m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
778 MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc()
780 STANDARD_VM_CONTRACT;
782 return MemberLoader::GetMethodDescFromMethodDef(m_pInfo->m_pModule, mdtMethodDef | (m_methodDefIndex + 1), FALSE);
785 MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc_NoRestore()
796 if (!m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
802 offset = m_pInfo->m_nativeReader.DecodeUnsigned(offset, &id);
809 m_pInfo->m_nativeReader.DecodeUnsigned(offset, &val);
820 _ASSERTE(id < m_pInfo->m_nRuntimeFunctions);
821 PCODE pEntryPoint = dac_cast<TADDR>(m_pInfo->m_pLayout->GetBase()) + m_pInfo->m_pRuntimeFunctions[id].BeginAddress;
823 return m_pInfo->GetMethodDescForEntryPoint(pEntryPoint);
826 PCODE ReadyToRunInfo::MethodIterator::GetMethodStartAddress()
828 STANDARD_VM_CONTRACT;
830 PCODE ret = m_pInfo->GetEntryPoint(GetMethodDesc(), FALSE);
831 _ASSERTE(ret != NULL);
835 DWORD ReadyToRunInfo::GetFieldBaseOffset(MethodTable * pMT)
837 STANDARD_VM_CONTRACT;
839 DWORD dwAlignment = DATA_ALIGNMENT;
840 DWORD dwOffsetBias = 0;
841 #ifdef FEATURE_64BIT_ALIGNMENT
843 if (pMT->RequiresAlign8())
847 MethodTable * pParentMT = pMT->GetParentMethodTable();
848 DWORD dwCumulativeInstanceFieldPos = (pParentMT != NULL) ? pParentMT->GetNumInstanceFieldBytes() : 0;
850 dwCumulativeInstanceFieldPos += dwOffsetBias;
852 dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwAlignment);
854 return (DWORD)sizeof(Object) + dwCumulativeInstanceFieldPos - dwOffsetBias;
857 #endif // DACCESS_COMPILE