Skip to content

Commit

Permalink
Change MethodDesc::GetLoaderModule and `MethodDesc::GetLoaderAlloca…
Browse files Browse the repository at this point in the history
…tor` into O(1) operations (#106212)

- Today these are dependent on calling into `ClassLoader::ComputerLoaderModule`, which can be a very complex operation, and always requires walking all of the method's instantiation arguments.
- This change makes puts a pointer to the Loader Module onto the `MethodDescChunk` and removes the need for running the potentially complex `ComputeLoaderModule` algorithm.
  • Loading branch information
davidwrighton committed Aug 13, 2024
1 parent ca4000c commit d228238
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 23 deletions.
7 changes: 6 additions & 1 deletion src/coreclr/vm/genmeth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@

// Helper method that creates a method-desc off a template method desc
static MethodDesc* CreateMethodDesc(LoaderAllocator *pAllocator,
Module* pLoaderModule,
MethodTable *pMT,
MethodDesc *pTemplateMD,
DWORD classification,
Expand Down Expand Up @@ -91,7 +92,8 @@ static MethodDesc* CreateMethodDesc(LoaderAllocator *pAllocator,
TRUE /* fNonVtableSlot*/,
fNativeCodeSlot,
pMT,
pamTracker);
pamTracker,
pLoaderModule);

// Now initialize the MDesc at the single method descriptor in
// the new chunk
Expand Down Expand Up @@ -415,6 +417,7 @@ InstantiatedMethodDesc::NewInstantiatedMethodDesc(MethodTable *pExactMT,
// used in some of the subsequent setup methods for method descs.
//
pNewMD = (InstantiatedMethodDesc*) (CreateMethodDesc(pAllocator,
pExactMDLoaderModule,
pExactMT,
pGenericMDescInRepMT,
mcInstantiated,
Expand Down Expand Up @@ -894,6 +897,7 @@ MethodDesc::FindOrCreateAssociatedMethodDesc(MethodDesc* pDefMD,
AllocMemTracker amt;

pResultMD = CreateMethodDesc(pAllocator,
pLoaderModule,
pRepMT,
pMDescInCanonMT,
mcInstantiated,
Expand Down Expand Up @@ -975,6 +979,7 @@ MethodDesc::FindOrCreateAssociatedMethodDesc(MethodDesc* pDefMD,
_ASSERTE(pDefMD->GetClassification() == mcInstantiated);

pResultMD = CreateMethodDesc(pAllocator,
pLoaderModule,
pExactMT,
pNonUnboxingStub,
mcInstantiated,
Expand Down
41 changes: 36 additions & 5 deletions src/coreclr/vm/method.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1506,6 +1506,20 @@ DWORD MethodDesc::GetImplAttrs()
return props;
}

PTR_Module MethodDescChunk::GetLoaderModule()
{
LIMITED_METHOD_DAC_CONTRACT;
if (IsLoaderModuleAttachedToChunk())
{
TADDR ppLoaderModule = dac_cast<TADDR>(this) + SizeOf() - sizeof(PTR_Module);
return *dac_cast<DPTR(PTR_Module)>(ppLoaderModule);
}
else
{
return GetMethodTable()->GetLoaderModule();
}
}

//*******************************************************************************
Module* MethodDesc::GetLoaderModule()
{
Expand All @@ -1517,17 +1531,24 @@ Module* MethodDesc::GetLoaderModule()
}
CONTRACTL_END;

Module* pLoaderModule = GetMethodDescChunk()->GetLoaderModule();

#ifdef _DEBUG
// Verify that the LoaderModule stored in the MethodDescChunk matches the result achieved by computation
if (HasMethodInstantiation() && !IsGenericMethodDefinition())
{
Module *retVal = ClassLoader::ComputeLoaderModule(GetMethodTable(),
Module *computeLoaderModuleAlgorithmResult = ClassLoader::ComputeLoaderModule(GetMethodTable(),
GetMemberDef(),
GetMethodInstantiation());
return retVal;
_ASSERTE(computeLoaderModuleAlgorithmResult == pLoaderModule);
}
else
{
return GetMethodTable()->GetLoaderModule();
_ASSERTE(pLoaderModule == GetMethodTable()->GetLoaderModule());
}
#endif // _DEBUG

return pLoaderModule;
}

//*******************************************************************************
Expand Down Expand Up @@ -1845,7 +1866,7 @@ MethodDesc* MethodDesc::StripMethodInstantiation()

//*******************************************************************************
MethodDescChunk *MethodDescChunk::CreateChunk(LoaderHeap *pHeap, DWORD methodDescCount,
DWORD classification, BOOL fNonVtableSlot, BOOL fNativeCodeSlot, MethodTable *pInitialMT, AllocMemTracker *pamTracker)
DWORD classification, BOOL fNonVtableSlot, BOOL fNativeCodeSlot, MethodTable *pInitialMT, AllocMemTracker *pamTracker, Module *pLoaderModule)
{
CONTRACT(MethodDescChunk *)
{
Expand Down Expand Up @@ -1878,18 +1899,28 @@ MethodDescChunk *MethodDescChunk::CreateChunk(LoaderHeap *pHeap, DWORD methodDes

MethodDescChunk * pFirstChunk = NULL;

bool needsExplicitLoaderModule = false;
if (pLoaderModule != NULL && pLoaderModule != pInitialMT->GetLoaderModule())
{
needsExplicitLoaderModule = true;
}

do
{
DWORD count = min(methodDescCount, maxMethodDescsPerChunk);

void * pMem = pamTracker->Track(
pHeap->AllocMem(S_SIZE_T(sizeof(MethodDescChunk) + oneSize * count)));
pHeap->AllocMem(S_SIZE_T(sizeof(MethodDescChunk) + oneSize * count + (needsExplicitLoaderModule ? sizeof(Module *) : 0))));

// Skip pointer to temporary entrypoints
MethodDescChunk * pChunk = (MethodDescChunk *)((BYTE*)pMem);

pChunk->SetSizeAndCount(oneSize * count, count);
pChunk->SetMethodTable(pInitialMT);
if (needsExplicitLoaderModule)
{
pChunk->SetLoaderModuleAttachedToChunk(pLoaderModule);
}

MethodDesc * pMD = pChunk->GetFirstMethodDesc();
for (DWORD i = 0; i < count; i++)
Expand Down
35 changes: 18 additions & 17 deletions src/coreclr/vm/method.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1001,8 +1001,6 @@ class MethodDesc

inline PTR_MethodTable GetMethodTable() const;

inline DPTR(PTR_MethodTable) GetMethodTablePtr() const;

public:
inline MethodDescChunk* GetMethodDescChunk() const;
inline int GetMethodDescChunkIndex() const;
Expand Down Expand Up @@ -2214,7 +2212,8 @@ class MethodDescChunk
// and for the logic that splits the token to be algorithmically generated based on the
// #define
enum_flag_DeterminedIsEligibleForTieredCompilation = 0x4000, // Has this chunk had its methods been determined eligible for tiered compilation or not
// unused = 0x8000,
enum_flag_LoaderModuleAttachedToChunk = 0x8000, // Is this chunk associated with a LoaderModule directly? If this flag is set, then the
// LoaderModule pointer is placed at the end of the chunk.
};

#ifndef DACCESS_COMPILE
Expand All @@ -2231,7 +2230,8 @@ class MethodDescChunk
BOOL fNonVtableSlot,
BOOL fNativeCodeSlot,
MethodTable *initialMT,
class AllocMemTracker *pamTracker);
class AllocMemTracker *pamTracker,
Module* pLoaderModule = NULL);

bool DeterminedIfMethodsAreEligibleForTieredCompilation()
{
Expand All @@ -2247,10 +2247,13 @@ class MethodDescChunk
return m_methodTable;
}

inline DPTR(PTR_MethodTable) GetMethodTablePtr() const
public:
PTR_Module GetLoaderModule();

inline bool IsLoaderModuleAttachedToChunk() const
{
LIMITED_METHOD_DAC_CONTRACT;
return dac_cast<DPTR(PTR_MethodTable)>(PTR_HOST_MEMBER_TADDR(MethodDescChunk, this, m_methodTable));
return (m_flagsAndTokenRange & enum_flag_LoaderModuleAttachedToChunk) != 0;
}

#ifndef DACCESS_COMPILE
Expand Down Expand Up @@ -2280,6 +2283,13 @@ class MethodDescChunk
LIMITED_METHOD_CONTRACT;
m_next = chunk;
}

void SetLoaderModuleAttachedToChunk(Module* pModule)
{
m_flagsAndTokenRange |= enum_flag_LoaderModuleAttachedToChunk;
TADDR ppLoaderModule = dac_cast<TADDR>(this) + SizeOf() - sizeof(PTR_Module);
*(Module**)ppLoaderModule = pModule;
}
#endif // !DACCESS_COMPILE

PTR_MethodDescChunk GetNextChunk()
Expand All @@ -2300,10 +2310,10 @@ class MethodDescChunk
return m_flagsAndTokenRange & enum_flag_TokenRangeMask;
}

inline SIZE_T SizeOf()
inline SIZE_T SizeOf() const
{
LIMITED_METHOD_DAC_CONTRACT;
return sizeof(MethodDescChunk) + (m_size + 1) * MethodDesc::ALIGNMENT;
return sizeof(MethodDescChunk) + (m_size + 1) * MethodDesc::ALIGNMENT + (IsLoaderModuleAttachedToChunk() ? sizeof(PTR_Module) : 0);
}

inline MethodDesc *GetFirstMethodDesc()
Expand Down Expand Up @@ -3430,15 +3440,6 @@ inline PTR_MethodTable MethodDesc::GetMethodTable() const
return pChunk->GetMethodTable();
}

inline DPTR(PTR_MethodTable) MethodDesc::GetMethodTablePtr() const
{
LIMITED_METHOD_DAC_CONTRACT;

MethodDescChunk *pChunk = GetMethodDescChunk();
PREFIX_ASSUME(pChunk != NULL);
return pChunk->GetMethodTablePtr();
}

inline MethodTable* MethodDesc::GetCanonicalMethodTable()
{
LIMITED_METHOD_DAC_CONTRACT;
Expand Down

0 comments on commit d228238

Please sign in to comment.