Skip to content

Commit 904c439

Browse files
PlaceInterfaceMethod is now more optimized (#96703)
* PlaceInterfaceMethod is now more optimized - It naturally has an O(N*M) algorithm, we reduce it to O(N*(Msmaller)), and make the constant factor faster - We take a local copy of the declared methods and name hashes, and the scan is now a straight linear scan of 32 bit memory DWORDS, and naturally skips nonpublic and non virtual methods. --------- Co-authored-by: Aaron Robinson <arobins@microsoft.com>
1 parent a3775a4 commit 904c439

File tree

2 files changed

+58
-24
lines changed

2 files changed

+58
-24
lines changed

src/coreclr/vm/methodtablebuilder.cpp

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7530,6 +7530,14 @@ MethodTableBuilder::PlaceInterfaceMethods()
75307530
BOOL fParentInterface;
75317531
DispatchMapTypeID * rgInterfaceDispatchMapTypeIDs = NULL;
75327532

7533+
// Optimization for fast discovery of possible matches below
7534+
// Lazily initialized the first time we want to walk the list of methods
7535+
// The memory allocated for these pointers is on the StackingAllocator, which
7536+
// has the same lifetime as the MethodTableBuilder
7537+
uint32_t *pNameHashArray = NULL;
7538+
bmtMDMethod **pMDMethodArray = NULL;
7539+
DWORD interfaceImplCandidateArraySize = 0;
7540+
75337541
for (DWORD dwCurInterface = 0;
75347542
dwCurInterface < bmtInterface->dwInterfaceMapSize;
75357543
dwCurInterface++)
@@ -7719,33 +7727,58 @@ MethodTableBuilder::PlaceInterfaceMethods()
77197727
// First, try to find the method explicitly declared in our class
77207728
//
77217729

7722-
DeclaredMethodIterator methIt(*this);
7723-
while (methIt.Next())
7730+
if (pNameHashArray == NULL)
77247731
{
7725-
// Note that non-publics can legally be exposed via an interface, but only
7726-
// through methodImpls.
7727-
if (IsMdVirtual(methIt.Attrs()) && IsMdPublic(methIt.Attrs()))
7732+
S_SIZE_T cbAllocPointers = S_SIZE_T(NumDeclaredMethods()) * S_SIZE_T(sizeof(bmtMDMethod*));
7733+
S_SIZE_T cbAllocHashes = S_SIZE_T(NumDeclaredMethods()) * S_SIZE_T(sizeof(uint32_t));
7734+
7735+
pNameHashArray = (uint32_t *)GetStackingAllocator()->Alloc(cbAllocHashes);
7736+
pMDMethodArray = (bmtMDMethod **)GetStackingAllocator()->Alloc(cbAllocPointers);
7737+
7738+
DeclaredMethodIterator methIt(*this);
7739+
while (methIt.Next())
77287740
{
7741+
// Note that non-publics and statics can legally be exposed via an interface, but only
7742+
// through methodImpls.
7743+
bmtMDMethod* mdMethod = methIt.GetMDMethod();
7744+
DWORD attrs = mdMethod->GetDeclAttrs();
7745+
if (IsMdVirtual(attrs) && IsMdPublic(attrs))
7746+
{
7747+
pNameHashArray[interfaceImplCandidateArraySize] = mdMethod->GetMethodSignature().GetNameHash();
7748+
pMDMethodArray[interfaceImplCandidateArraySize++] = mdMethod;
7749+
}
7750+
}
7751+
}
7752+
7753+
DeclaredMethodIterator methIt(*this);
7754+
UINT32 nameHashItfMethod = pCurItfMethod->GetMethodSignature().GetNameHash();
7755+
7756+
for (DWORD iPublicVirtualNonStaticMethod = 0; iPublicVirtualNonStaticMethod < interfaceImplCandidateArraySize; ++iPublicVirtualNonStaticMethod)
7757+
{
7758+
if (pNameHashArray[iPublicVirtualNonStaticMethod] != nameHashItfMethod)
7759+
continue;
7760+
7761+
bmtMDMethod* declaredMethod = pMDMethodArray[iPublicVirtualNonStaticMethod];
7762+
const MethodSignature& declaredMethodSig = declaredMethod->GetMethodSignature();
77297763
#ifdef _DEBUG
7730-
if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(methIt.Name()))
7731-
CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", methIt.Name()));
7764+
if(GetHalfBakedClass()->m_fDebuggingClass && g_pConfig->ShouldBreakOnMethod(declaredMethodSig.GetName()))
7765+
CONSISTENCY_CHECK_MSGF(false, ("BreakOnMethodName: '%s' ", declaredMethodSig.GetName()));
77327766
#endif // _DEBUG
77337767

7734-
if (pCurItfMethod->GetMethodSignature().Equivalent(methIt->GetMethodSignature()))
7735-
{
7736-
fFoundMatchInBuildingClass = TRUE;
7737-
curItfSlot.Impl() = methIt->GetSlotIndex();
7768+
if (pCurItfMethod->GetMethodSignature().Equivalent(declaredMethodSig))
7769+
{
7770+
fFoundMatchInBuildingClass = TRUE;
7771+
curItfSlot.Impl() = declaredMethod->GetSlotIndex();
77387772

7739-
DispatchMapTypeID dispatchMapTypeID =
7740-
DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7741-
bmtVT->pDispatchMapBuilder->InsertMDMapping(
7742-
dispatchMapTypeID,
7743-
static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7744-
methIt->GetMethodDesc(),
7745-
FALSE);
7773+
DispatchMapTypeID dispatchMapTypeID =
7774+
DispatchMapTypeID::InterfaceClassID(dwCurInterface);
7775+
bmtVT->pDispatchMapBuilder->InsertMDMapping(
7776+
dispatchMapTypeID,
7777+
static_cast<UINT32>(itfSlotIt.CurrentIndex()),
7778+
declaredMethod->GetMethodDesc(),
7779+
FALSE);
77467780

7747-
break;
7748-
}
7781+
break;
77497782
}
77507783
} // end ... try to find method
77517784

src/coreclr/vm/methodtablebuilder.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,11 @@ class MethodTableBuilder
808808
operator PCCOR_SIGNATURE() const
809809
{ return GetSignature(); }
810810

811+
//-----------------------------------------------------------------------------------------
812+
// Get a hash of the Name that can be compared with hashes from other MethodSignatures
813+
UINT32
814+
GetNameHash() const;
815+
811816
protected:
812817
//-----------------------------------------------------------------------------------------
813818
Module * m_pModule;
@@ -835,10 +840,6 @@ class MethodTableBuilder
835840
void
836841
GetMethodAttributes() const;
837842

838-
//-----------------------------------------------------------------------------------------
839-
UINT32
840-
GetNameHash() const;
841-
842843
private:
843844
//-----------------------------------------------------------------------------------
844845
// Private to prevent use.

0 commit comments

Comments
 (0)