summaryrefslogtreecommitdiff
path: root/src/vm/readytoruninfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/readytoruninfo.cpp')
-rw-r--r--src/vm/readytoruninfo.cpp780
1 files changed, 780 insertions, 0 deletions
diff --git a/src/vm/readytoruninfo.cpp b/src/vm/readytoruninfo.cpp
new file mode 100644
index 0000000000..f867036823
--- /dev/null
+++ b/src/vm/readytoruninfo.cpp
@@ -0,0 +1,780 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: ReadyToRunInfo.cpp
+//
+
+//
+// Runtime support for Ready to Run
+// ===========================================================================
+
+#include "common.h"
+
+#include "dbginterface.h"
+#include "compile.h"
+#include "versionresilienthashcode.h"
+#include "typehashingalgorithms.h"
+
+using namespace NativeFormat;
+
+IMAGE_DATA_DIRECTORY * ReadyToRunInfo::FindSection(DWORD type)
+{
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+ NOTHROW;
+ SO_TOLERANT;
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+ PTR_READYTORUN_SECTION pSections = dac_cast<PTR_READYTORUN_SECTION>(dac_cast<TADDR>(m_pHeader) + sizeof(READYTORUN_HEADER));
+ for (DWORD i = 0; i < m_pHeader->NumberOfSections; i++)
+ {
+ // Verify that section types are sorted
+ _ASSERTE(i == 0 || (pSections[i-1].Type < pSections[i].Type));
+
+ READYTORUN_SECTION * pSection = pSections + i;
+ if (pSection->Type == type)
+ return &pSection->Section;
+ }
+ return NULL;
+}
+
+MethodDesc * ReadyToRunInfo::GetMethodDescForEntryPoint(PCODE entryPoint)
+{
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+ NOTHROW;
+ SO_TOLERANT;
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+#ifdef _TARGET_AMD64_
+ // A normal method entry point is always 8 byte aligned, but a funclet can start at an odd address.
+ // Since PtrHashMap can't handle odd pointers, check for this case and return NULL.
+ if ((entryPoint & 0x1) != 0)
+ return NULL;
+#endif
+
+ TADDR val = (TADDR)m_entryPointToMethodDescMap.LookupValue(PCODEToPINSTR(entryPoint), (LPVOID)PCODEToPINSTR(entryPoint));
+ if (val == (TADDR)INVALIDENTRY)
+ return NULL;
+ return dac_cast<PTR_MethodDesc>(val);
+}
+
+BOOL ReadyToRunInfo::HasHashtableOfTypes()
+{
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+ NOTHROW;
+ SO_TOLERANT;
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+ return !m_availableTypesHashtable.IsNull();
+}
+
+BOOL ReadyToRunInfo::TryLookupTypeTokenFromName(NameHandle *pName, mdToken * pFoundTypeToken)
+{
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+ NOTHROW;
+ SO_INTOLERANT;
+ SUPPORTS_DAC;
+ PRECONDITION(!m_availableTypesHashtable.IsNull());
+ }
+ CONTRACTL_END;
+
+ if (m_availableTypesHashtable.IsNull())
+ return FALSE;
+
+ LPCUTF8 pszName = NULL;
+ LPCUTF8 pszNameSpace = NULL;
+
+ //
+ // Compute the hashcode of the type (hashcode based on type name and namespace name)
+ //
+ int dwHashCode = 0;
+
+ if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
+ {
+ // Name-based lookups (ex: Type.GetType()).
+
+ pszName = pName->GetName();
+ pszNameSpace = "";
+
+ if (pName->GetNameSpace() != NULL)
+ {
+ pszNameSpace = pName->GetNameSpace();
+ }
+ else
+ {
+ LPCUTF8 p;
+ CQuickBytes szNamespace;
+
+ if ((p = ns::FindSep(pszName)) != NULL)
+ {
+ SIZE_T d = p - pszName;
+
+ FAULT_NOT_FATAL();
+ pszNameSpace = szNamespace.SetStringNoThrow(pszName, d);
+
+ if (pszNameSpace == NULL)
+ return FALSE;
+
+ pszName = (p + 1);
+ }
+ }
+
+ _ASSERT(pszNameSpace != NULL);
+ dwHashCode ^= ComputeNameHashCode(pszNameSpace, pszName);
+
+ // Bucket is not 'null' for a nested type, and it will have information about the nested type's encloser
+ if (!pName->GetBucket().IsNull())
+ {
+ // Must be a token based bucket that we found earlier in the R2R types hashtable
+ _ASSERT(pName->GetBucket().GetEntryType() == HashedTypeEntry::IsHashedTokenEntry);
+
+ const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
+
+ // Token must be a typedef token that we previously resolved (we shouldn't get here with an exported type token)
+ _ASSERT(TypeFromToken(tokenBasedEncloser.m_TypeToken) == mdtTypeDef);
+
+ int dwCurrentHashCode;
+ mdToken mdCurrentTypeToken = tokenBasedEncloser.m_TypeToken;
+ if (!GetVersionResilientTypeHashCode(tokenBasedEncloser.m_pModule->GetMDImport(), mdCurrentTypeToken, &dwCurrentHashCode))
+ return FALSE;
+ dwHashCode ^= dwCurrentHashCode;
+ }
+ }
+ else
+ {
+ // Token based lookups (ex: tokens from IL code)
+
+ if (!GetVersionResilientTypeHashCode(pName->GetTypeModule()->GetMDImport(), pName->GetTypeToken(), &dwHashCode))
+ return FALSE;
+ }
+
+
+ //
+ // Lookup the type in the native hashtable using the computed token
+ //
+ {
+ NativeHashtable::Enumerator lookup = m_availableTypesHashtable.Lookup((int)dwHashCode);
+ NativeParser entryParser;
+ while (lookup.GetNext(entryParser))
+ {
+ DWORD ridAndFlag = entryParser.GetUnsigned();
+ mdToken cl = ((ridAndFlag & 1) ? ((ridAndFlag >> 1) | mdtExportedType) : ((ridAndFlag >> 1) | mdtTypeDef));
+ _ASSERT(RidFromToken(cl) != 0);
+
+ if (pName->GetTypeToken() == mdtBaseType || pName->GetTypeModule() == NULL)
+ {
+ // Compare type name and namespace name
+ LPCUTF8 pszFoundName;
+ LPCUTF8 pszFoundNameSpace;
+ if (!GetTypeNameFromToken(m_pModule->GetMDImport(), cl, &pszFoundName, &pszFoundNameSpace))
+ continue;
+ if (strcmp(pszName, pszFoundName) != 0 || strcmp(pszNameSpace, pszFoundNameSpace) != 0)
+ continue;
+
+ mdToken mdFoundTypeEncloser;
+ BOOL inputTypeHasEncloser = !pName->GetBucket().IsNull();
+ BOOL foundTypeHasEncloser = GetEnclosingToken(m_pModule->GetMDImport(), cl, &mdFoundTypeEncloser);
+ if (inputTypeHasEncloser != foundTypeHasEncloser)
+ continue;
+
+ // Compare the enclosing types chain for a match
+ if (inputTypeHasEncloser)
+ {
+ const HashedTypeEntry::TokenTypeEntry& tokenBasedEncloser = pName->GetBucket().GetTokenBasedEntryValue();
+
+ if (!CompareTypeNameOfTokens(tokenBasedEncloser.m_TypeToken, tokenBasedEncloser.m_pModule->GetMDImport(), mdFoundTypeEncloser, m_pModule->GetMDImport()))
+ continue;
+ }
+ }
+ else
+ {
+ // Compare type name, namespace name, and enclosing types chain for a match
+ if (!CompareTypeNameOfTokens(pName->GetTypeToken(), pName->GetTypeModule()->GetMDImport(), cl, m_pModule->GetMDImport()))
+ continue;
+ }
+
+ // Found a match!
+ *pFoundTypeToken = cl;
+ return TRUE;
+ }
+ }
+
+ return FALSE; // No matching type found
+}
+
+BOOL ReadyToRunInfo::GetTypeNameFromToken(IMDInternalImport * pImport, mdToken mdType, LPCUTF8 * ppszName, LPCUTF8 * ppszNameSpace)
+{
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+ NOTHROW;
+ SO_TOLERANT;
+ SUPPORTS_DAC;
+ PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
+ }
+ CONTRACTL_END;
+
+ switch (TypeFromToken(mdType))
+ {
+ case mdtTypeDef:
+ return SUCCEEDED(pImport->GetNameOfTypeDef(mdType, ppszName, ppszNameSpace));
+ case mdtTypeRef:
+ return SUCCEEDED(pImport->GetNameOfTypeRef(mdType, ppszNameSpace, ppszName));
+ case mdtExportedType:
+ return SUCCEEDED(pImport->GetExportedTypeProps(mdType, ppszNameSpace, ppszName, NULL, NULL, NULL));
+ }
+
+ return FALSE;
+}
+
+BOOL ReadyToRunInfo::GetEnclosingToken(IMDInternalImport * pImport, mdToken mdType, mdToken * pEnclosingToken)
+{
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+ NOTHROW;
+ SO_TOLERANT;
+ SUPPORTS_DAC;
+ PRECONDITION(TypeFromToken(mdType) == mdtTypeDef || TypeFromToken(mdType) == mdtTypeRef || TypeFromToken(mdType) == mdtExportedType);
+ }
+ CONTRACTL_END;
+
+ mdToken mdEncloser;
+ switch (TypeFromToken(mdType))
+ {
+ case mdtTypeDef:
+ return SUCCEEDED(pImport->GetNestedClassProps(mdType, pEnclosingToken));
+
+ case mdtTypeRef:
+ if (SUCCEEDED(pImport->GetResolutionScopeOfTypeRef(mdType, pEnclosingToken)))
+ return ((TypeFromToken(*pEnclosingToken) == mdtTypeRef) && (*pEnclosingToken != mdTypeRefNil));
+
+ case mdtExportedType:
+ if (SUCCEEDED(pImport->GetExportedTypeProps(mdType, NULL, NULL, pEnclosingToken, NULL, NULL)))
+ return ((TypeFromToken(*pEnclosingToken) == mdtExportedType) && (*pEnclosingToken != mdExportedTypeNil));
+ }
+
+ return FALSE;
+}
+
+BOOL ReadyToRunInfo::CompareTypeNameOfTokens(mdToken mdToken1, IMDInternalImport * pImport1, mdToken mdToken2, IMDInternalImport * pImport2)
+{
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+ NOTHROW;
+ SO_TOLERANT;
+ SUPPORTS_DAC;
+ PRECONDITION(TypeFromToken(mdToken1) == mdtTypeDef || TypeFromToken(mdToken1) == mdtTypeRef || TypeFromToken(mdToken1) == mdtExportedType);
+ PRECONDITION(TypeFromToken(mdToken2) == mdtTypeDef || TypeFromToken(mdToken2) == mdtExportedType);
+ }
+ CONTRACTL_END;
+
+ BOOL hasEncloser;
+ do
+ {
+ LPCUTF8 pszName1;
+ LPCUTF8 pszNameSpace1;
+ if (!GetTypeNameFromToken(pImport1, mdToken1, &pszName1, &pszNameSpace1))
+ return FALSE;
+
+ LPCUTF8 pszName2;
+ LPCUTF8 pszNameSpace2;
+ if (!GetTypeNameFromToken(pImport2, mdToken2, &pszName2, &pszNameSpace2))
+ return FALSE;
+
+ if (strcmp(pszName1, pszName2) != 0 || strcmp(pszNameSpace1, pszNameSpace2) != 0)
+ return FALSE;
+
+ if ((hasEncloser = GetEnclosingToken(pImport1, mdToken1, &mdToken1)) != GetEnclosingToken(pImport2, mdToken2, &mdToken2))
+ return FALSE;
+
+ } while (hasEncloser);
+
+ return TRUE;
+}
+
+PTR_BYTE ReadyToRunInfo::GetDebugInfo(PTR_RUNTIME_FUNCTION pRuntimeFunction)
+{
+ CONTRACTL
+ {
+ GC_NOTRIGGER;
+ THROWS;
+ MODE_ANY;
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+
+ IMAGE_DATA_DIRECTORY * pDebugInfoDir = FindSection(READYTORUN_SECTION_DEBUG_INFO);
+ if (pDebugInfoDir == NULL)
+ return NULL;
+
+ SIZE_T methodIndex = pRuntimeFunction - m_pRuntimeFunctions;
+ _ASSERTE(methodIndex < m_nRuntimeFunctions);
+
+ NativeArray debugInfoIndex(dac_cast<PTR_NativeReader>(PTR_HOST_INT_TO_TADDR(&m_nativeReader)), pDebugInfoDir->VirtualAddress);
+
+ uint offset;
+ if (!debugInfoIndex.TryGetAt((DWORD)methodIndex, &offset))
+ return NULL;
+
+ uint lookBack;
+ uint debugInfoOffset = m_nativeReader.DecodeUnsigned(offset, &lookBack);
+
+ if (lookBack != 0)
+ debugInfoOffset = offset - lookBack;
+
+ return dac_cast<PTR_BYTE>(m_pLayout->GetBase()) + debugInfoOffset;
+}
+
+#ifndef DACCESS_COMPILE
+
+BOOL ReadyToRunInfo::IsReadyToRunEnabled()
+{
+ WRAPPER_NO_CONTRACT;
+
+ static ConfigDWORD configReadyToRun;
+ return configReadyToRun.val(CLRConfig::EXTERNAL_ReadyToRun);
+}
+
+// A log file to record success/failure of R2R loads. s_r2rLogFile can have the following values:
+// -1: Logging not yet initialized.
+// NULL: Logging disabled.
+// Any other value: Handle of the log file.
+static FILE * volatile s_r2rLogFile = (FILE *)(-1);
+
+static void LogR2r(const char *msg, PEFile *pFile)
+{
+ STANDARD_VM_CONTRACT;
+
+ // Make a local copy of s_r2rLogFile, so we're not affected by other threads.
+ FILE *r2rLogFile = s_r2rLogFile;
+ if (r2rLogFile == (FILE *)(-1))
+ {
+ // Initialize Ready to Run logging. Any errors cause logging to be disabled.
+ NewArrayHolder<WCHAR> wszReadyToRunLogFile;
+ if (SUCCEEDED(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ReadyToRunLogFile, &wszReadyToRunLogFile)) && wszReadyToRunLogFile)
+ {
+ // Append process ID to the log file name, so multiple processes can log at the same time.
+ StackSString fullname;
+ fullname.Printf(W("%s.%u"), wszReadyToRunLogFile.GetValue(), GetCurrentProcessId());
+ r2rLogFile = _wfopen(fullname.GetUnicode(), W("w"));
+ }
+ else
+ r2rLogFile = NULL;
+
+ if (r2rLogFile != NULL && !ReadyToRunInfo::IsReadyToRunEnabled())
+ {
+ fputs("Ready to Run not enabled.\n", r2rLogFile);
+ fclose(r2rLogFile);
+ r2rLogFile = NULL;
+ }
+
+ if (InterlockedCompareExchangeT(&s_r2rLogFile, r2rLogFile, (FILE *)(-1)) != (FILE *)(-1))
+ {
+ if (r2rLogFile != NULL)
+ fclose(r2rLogFile);
+ r2rLogFile = s_r2rLogFile;
+ }
+ }
+
+ if (r2rLogFile == NULL)
+ return;
+
+ fprintf(r2rLogFile, "%s: \"%S\".\n", msg, pFile->GetPath().GetUnicode());
+ fflush(r2rLogFile);
+}
+
+#define DoLog(msg) if (s_r2rLogFile != NULL) LogR2r(msg, pFile)
+
+PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker *pamTracker)
+{
+ STANDARD_VM_CONTRACT;
+
+ PEFile * pFile = pModule->GetFile();
+
+ // Ignore ReadyToRun for introspection-only loads
+ if (pFile->IsIntrospectionOnly())
+ {
+ DoLog("Ready to Run disabled - module loaded for reflection");
+ return NULL;
+ }
+
+ if (!pFile->HasLoadedIL())
+ {
+ DoLog("Ready to Run disabled - no loaded IL image");
+ return NULL;
+ }
+
+ PEImageLayout * pLayout = pFile->GetLoadedIL();
+ if (!pLayout->HasReadyToRunHeader())
+ {
+ DoLog("Ready to Run header not found");
+ return NULL;
+ }
+
+ if (!IsReadyToRunEnabled())
+ {
+ // Log message is ignored in this case.
+ DoLog(NULL);
+ return NULL;
+ }
+
+ if (g_pConfig->ExcludeReadyToRun(pModule->GetSimpleName()))
+ {
+ DoLog("Ready to Run disabled - module on exclusion list");
+ return NULL;
+ }
+
+ if (!pLayout->IsNativeMachineFormat())
+ {
+#ifdef FEATURE_CORECLR
+ // For CoreCLR, be strict about disallowing machine mismatches.
+ COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
+#else
+ DoLog("Ready to Run disabled - mismatched architecture");
+ return NULL;
+#endif
+ }
+
+#ifdef FEATURE_NATIVE_IMAGE_GENERATION
+ // Ignore ReadyToRun during NGen
+ if (IsCompilationProcess() && !IsNgenPDBCompilationProcess())
+ {
+ DoLog("Ready to Run disabled - compilation process");
+ return NULL;
+ }
+#endif
+
+#ifndef CROSSGEN_COMPILE
+ // The file must have been loaded using LoadLibrary
+ if (!pLayout->IsRelocated())
+ {
+ DoLog("Ready to Run disabled - module not loaded for execution");
+ return NULL;
+ }
+#endif
+
+ READYTORUN_HEADER * pHeader = pLayout->GetReadyToRunHeader();
+
+ // Ignore the content if the image major version is higher than the major version currently supported by the runtime
+ if (pHeader->MajorVersion > READYTORUN_MAJOR_VERSION)
+ {
+ DoLog("Ready to Run disabled - unsupported header version");
+ return NULL;
+ }
+
+ LoaderHeap *pHeap = pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
+ void * pMemory = pamTracker->Track(pHeap->AllocMem((S_SIZE_T)sizeof(ReadyToRunInfo)));
+
+ DoLog("Ready to Run initialized successfully");
+
+ return new (pMemory) ReadyToRunInfo(pModule, pLayout, pHeader);
+}
+
+ReadyToRunInfo::ReadyToRunInfo(Module * pModule, PEImageLayout * pLayout, READYTORUN_HEADER * pHeader)
+ : m_pModule(pModule), m_pLayout(pLayout), m_pHeader(pHeader), m_Crst(CrstLeafLock)
+{
+ STANDARD_VM_CONTRACT;
+
+ IMAGE_DATA_DIRECTORY * pRuntimeFunctionsDir = FindSection(READYTORUN_SECTION_RUNTIME_FUNCTIONS);
+ if (pRuntimeFunctionsDir != NULL)
+ {
+ m_pRuntimeFunctions = (T_RUNTIME_FUNCTION *)pLayout->GetDirectoryData(pRuntimeFunctionsDir);
+ m_nRuntimeFunctions = pRuntimeFunctionsDir->Size / sizeof(T_RUNTIME_FUNCTION);
+ }
+ else
+ {
+ m_nRuntimeFunctions = 0;
+ }
+
+ IMAGE_DATA_DIRECTORY * pImportSectionsDir = FindSection(READYTORUN_SECTION_IMPORT_SECTIONS);
+ if (pImportSectionsDir != NULL)
+ {
+ m_pImportSections = (CORCOMPILE_IMPORT_SECTION*)pLayout->GetDirectoryData(pImportSectionsDir);
+ m_nImportSections = pImportSectionsDir->Size / sizeof(CORCOMPILE_IMPORT_SECTION);
+ }
+ else
+ {
+ m_nImportSections = 0;
+ }
+
+ m_nativeReader = NativeReader((byte *)pLayout->GetBase(), pLayout->GetVirtualSize());
+
+ IMAGE_DATA_DIRECTORY * pEntryPointsDir = FindSection(READYTORUN_SECTION_METHODDEF_ENTRYPOINTS);
+ if (pEntryPointsDir != NULL)
+ {
+ m_methodDefEntryPoints = NativeArray(&m_nativeReader, pEntryPointsDir->VirtualAddress);
+ }
+
+ IMAGE_DATA_DIRECTORY * pinstMethodsDir = FindSection(READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS);
+ if (pinstMethodsDir != NULL)
+ {
+ NativeParser parser = NativeParser(&m_nativeReader, pinstMethodsDir->VirtualAddress);
+ m_instMethodEntryPoints = NativeHashtable(parser);
+ }
+
+ IMAGE_DATA_DIRECTORY * pAvailableTypesDir = FindSection(READYTORUN_SECTION_AVAILABLE_TYPES);
+ if (pAvailableTypesDir != NULL)
+ {
+ NativeParser parser = NativeParser(&m_nativeReader, pAvailableTypesDir->VirtualAddress);
+ m_availableTypesHashtable = NativeHashtable(parser);
+ }
+
+ {
+ LockOwner lock = {&m_Crst, IsOwnerOfCrst};
+ m_entryPointToMethodDescMap.Init(TRUE, &lock);
+ }
+}
+
+static bool SigMatchesMethodDesc(MethodDesc* pMD, SigPointer &sig, Module * pModule)
+{
+ STANDARD_VM_CONTRACT;
+
+ ZapSig::Context zapSigContext(pModule, (void *)pModule, ZapSig::NormalTokens);
+ ZapSig::Context * pZapSigContext = &zapSigContext;
+
+ DWORD methodFlags;
+ IfFailThrow(sig.GetData(&methodFlags));
+
+ if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
+ {
+ PCCOR_SIGNATURE pSigType;
+ DWORD cbSigType;
+ sig.GetSignature(&pSigType, &cbSigType);
+ if (!ZapSig::CompareSignatureToTypeHandle(pSigType, pModule, TypeHandle(pMD->GetMethodTable()), pZapSigContext))
+ return false;
+
+ IfFailThrow(sig.SkipExactlyOne());
+ }
+
+ _ASSERTE((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0);
+ _ASSERTE((methodFlags & ENCODE_METHOD_SIG_MemberRefToken) == 0);
+
+ RID rid;
+ IfFailThrow(sig.GetData(&rid));
+ if (RidFromToken(pMD->GetMemberDef()) != rid)
+ return false;
+
+ if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
+ {
+ DWORD numGenericArgs;
+ IfFailThrow(sig.GetData(&numGenericArgs));
+ Instantiation inst = pMD->GetMethodInstantiation();
+ if (numGenericArgs != inst.GetNumArgs())
+ return false;
+
+ for (DWORD i = 0; i < numGenericArgs; i++)
+ {
+ PCCOR_SIGNATURE pSigArg;
+ DWORD cbSigArg;
+ sig.GetSignature(&pSigArg, &cbSigArg);
+ if (!ZapSig::CompareSignatureToTypeHandle(pSigArg, pModule, inst[i], pZapSigContext))
+ return false;
+
+ IfFailThrow(sig.SkipExactlyOne());
+ }
+ }
+
+ return true;
+}
+
+PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, BOOL fFixups /*=TRUE*/)
+{
+ STANDARD_VM_CONTRACT;
+
+ mdToken token = pMD->GetMemberDef();
+ int rid = RidFromToken(token);
+ if (rid == 0)
+ return NULL;
+
+ uint offset;
+ if (pMD->HasClassOrMethodInstantiation())
+ {
+ if (m_instMethodEntryPoints.IsNull())
+ return NULL;
+
+ NativeHashtable::Enumerator lookup = m_instMethodEntryPoints.Lookup(GetVersionResilientMethodHashCode(pMD));
+ NativeParser entryParser;
+ offset = -1;
+ while (lookup.GetNext(entryParser))
+ {
+ PCCOR_SIGNATURE pBlob = (PCCOR_SIGNATURE)entryParser.GetBlob();
+ SigPointer sig(pBlob);
+ if (SigMatchesMethodDesc(pMD, sig, m_pModule))
+ {
+ // Get the updated SigPointer location, so we can calculate the size of the blob,
+ // in order to skip the blob and find the entry point data.
+ PCCOR_SIGNATURE pSigNew;
+ DWORD cbSigNew;
+ sig.GetSignature(&pSigNew, &cbSigNew);
+ offset = entryParser.GetOffset() + (uint)(pSigNew - pBlob);
+ break;
+ }
+ }
+
+ if (offset == -1)
+ return NULL;
+ }
+ else
+ {
+ if (!m_methodDefEntryPoints.TryGetAt(rid - 1, &offset))
+ return NULL;
+ }
+
+ uint id;
+ offset = m_nativeReader.DecodeUnsigned(offset, &id);
+
+ if (id & 1)
+ {
+ if (id & 2)
+ {
+ uint val;
+ m_nativeReader.DecodeUnsigned(offset, &val);
+ offset -= val;
+ }
+
+ if (fFixups)
+ {
+ if (!m_pModule->FixupDelayList(dac_cast<TADDR>(m_pLayout->GetBase()) + offset))
+ return NULL;
+ }
+
+ id >>= 2;
+ }
+ else
+ {
+ id >>= 1;
+ }
+
+ _ASSERTE(id < m_nRuntimeFunctions);
+ PCODE pEntryPoint = dac_cast<TADDR>(m_pLayout->GetBase()) + m_pRuntimeFunctions[id].BeginAddress;
+
+ {
+ CrstHolder ch(&m_Crst);
+
+ if (m_entryPointToMethodDescMap.LookupValue(PCODEToPINSTR(pEntryPoint), (LPVOID)PCODEToPINSTR(pEntryPoint)) == (LPVOID)INVALIDENTRY)
+ m_entryPointToMethodDescMap.InsertValue(PCODEToPINSTR(pEntryPoint), pMD);
+ }
+
+ if (g_pDebugInterface != NULL)
+ {
+ g_pDebugInterface->JITComplete(pMD, pEntryPoint);
+ }
+
+ return pEntryPoint;
+}
+
+BOOL ReadyToRunInfo::MethodIterator::Next()
+{
+ CONTRACTL
+ {
+ GC_TRIGGERS;
+ THROWS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ while (++m_methodDefIndex < (int)m_pInfo->m_methodDefEntryPoints.GetCount())
+ {
+ uint offset;
+ if (m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc()
+{
+ STANDARD_VM_CONTRACT;
+
+ return MemberLoader::GetMethodDescFromMethodDef(m_pInfo->m_pModule, mdtMethodDef | (m_methodDefIndex + 1), FALSE);
+}
+
+MethodDesc * ReadyToRunInfo::MethodIterator::GetMethodDesc_NoRestore()
+{
+ CONTRACTL
+ {
+ GC_TRIGGERS;
+ THROWS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ uint offset;
+ if (!m_pInfo->m_methodDefEntryPoints.TryGetAt(m_methodDefIndex, &offset))
+ {
+ return NULL;
+ }
+
+ uint id;
+ offset = m_pInfo->m_nativeReader.DecodeUnsigned(offset, &id);
+
+ if (id & 1)
+ {
+ if (id & 2)
+ {
+ uint val;
+ m_pInfo->m_nativeReader.DecodeUnsigned(offset, &val);
+ offset -= val;
+ }
+
+ id >>= 2;
+ }
+ else
+ {
+ id >>= 1;
+ }
+
+ _ASSERTE(id < m_pInfo->m_nRuntimeFunctions);
+ PCODE pEntryPoint = dac_cast<TADDR>(m_pInfo->m_pLayout->GetBase()) + m_pInfo->m_pRuntimeFunctions[id].BeginAddress;
+
+ return m_pInfo->GetMethodDescForEntryPoint(pEntryPoint);
+}
+
+PCODE ReadyToRunInfo::MethodIterator::GetMethodStartAddress()
+{
+ STANDARD_VM_CONTRACT;
+
+ PCODE ret = m_pInfo->GetEntryPoint(GetMethodDesc(), FALSE);
+ _ASSERTE(ret != NULL);
+ return ret;
+}
+
+DWORD ReadyToRunInfo::GetFieldBaseOffset(MethodTable * pMT)
+{
+ STANDARD_VM_CONTRACT;
+
+ DWORD dwAlignment = DATA_ALIGNMENT;
+ DWORD dwOffsetBias = 0;
+#ifdef FEATURE_64BIT_ALIGNMENT
+ dwOffsetBias = 4;
+ if (pMT->RequiresAlign8())
+ dwAlignment = 8;
+#endif
+
+ MethodTable * pParentMT = pMT->GetParentMethodTable();
+ DWORD dwCumulativeInstanceFieldPos = (pParentMT != NULL) ? pParentMT->GetNumInstanceFieldBytes() : 0;
+
+ dwCumulativeInstanceFieldPos += dwOffsetBias;
+
+ dwCumulativeInstanceFieldPos = (DWORD)ALIGN_UP(dwCumulativeInstanceFieldPos, dwAlignment);
+
+ return (DWORD)sizeof(Object) + dwCumulativeInstanceFieldPos - dwOffsetBias;
+}
+
+#endif // DACCESS_COMPILE