Skip to content

Commit 0df375b

Browse files
committed
Cache Late-bound CLR->COM stubs by MethodDesc
1 parent 25e2d7f commit 0df375b

File tree

1 file changed

+23
-9
lines changed

1 file changed

+23
-9
lines changed

src/coreclr/vm/dllimport.cpp

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4300,29 +4300,43 @@ namespace
43004300
{
43014301
STANDARD_VM_CONTRACT;
43024302

4303-
// The hash blob for a forward P/Invoke stub is just the target MethodDesc pointer.
4304-
// In order to help avoid collisions, ensure various blob sizes are different.
4305-
// See asserts below.
4306-
constexpr size_t forwardPInvokeHashBlobSize = sizeof(ILStubHashBlobBase) + sizeof(MethodDesc*);
4303+
// Some stubs (forward P/Invoke non-varags, late bound COM) each target a specific method.
4304+
// The hash blob for an unshared stub is just the target MethodDesc pointer and the stub flags.
4305+
constexpr size_t unsharedStubHashBlobSize = sizeof(ILStubHashBlobBase) + sizeof(DWORD) + sizeof(MethodDesc*);
43074306

43084307
DWORD dwStubFlags = pParams->m_dwStubFlags;
43094308

4309+
bool isNonSharedStub = false;
4310+
43104311
// The target MethodDesc may be NULL for field marshalling.
43114312
// Forward P/Invoke stubs (non-CALLI, non-vararg) each target a specific method,
43124313
// so the hash blob is just the target MethodDesc pointer. This ensures racing
43134314
// threads for the same P/Invoke converge on the same DynamicMethodDesc in the
43144315
// ILStubCache, while different P/Invoke methods get distinct cache entries.
4315-
if (pTargetMD != NULL
4316-
&& SF_IsForwardPInvokeStub(dwStubFlags)
4316+
if (SF_IsForwardPInvokeStub(dwStubFlags)
43174317
&& !SF_IsCALLIStub(dwStubFlags)
43184318
&& !SF_IsVarArgStub(dwStubFlags))
43194319
{
4320-
const size_t blobSize = forwardPInvokeHashBlobSize;
4320+
isNonSharedStub = true;
4321+
}
4322+
4323+
// Late-bound COM stubs depend on metadata on the target MethodDesc (DispIdAttribute, associated properties) in addition to just the signature.
4324+
// Cache based on the target MethodDesc and stub flags instead of the signature to avoid false sharing.
4325+
if (SF_IsCOMLateBoundStub(dwStubFlags))
4326+
{
4327+
isNonSharedStub = true;
4328+
}
4329+
4330+
if (isNonSharedStub)
4331+
{
4332+
_ASSERTE(pTargetMD != NULL);
4333+
const size_t blobSize = unsharedStubHashBlobSize;
43214334
NewArrayHolder<BYTE> pBytes = new BYTE[blobSize];
43224335
ZeroMemory(pBytes, blobSize);
43234336
ILStubHashBlob* pBlob = (ILStubHashBlob*)(BYTE*)pBytes;
43244337
pBlob->m_cbSizeOfBlob = blobSize;
4325-
memcpy(pBlob->m_rgbBlobData, &pTargetMD, sizeof(pTargetMD));
4338+
memcpy(pBlob->m_rgbBlobData, &dwStubFlags, sizeof(dwStubFlags));
4339+
memcpy(pBlob->m_rgbBlobData + sizeof(dwStubFlags), &pTargetMD, sizeof(pTargetMD));
43264340
pBytes.SuppressRelease();
43274341
return pBlob;
43284342
}
@@ -4381,7 +4395,7 @@ namespace
43814395
if (cbSizeOfBlob.IsOverflow())
43824396
COMPlusThrowHR(COR_E_OVERFLOW);
43834397

4384-
_ASSERTE(cbSizeOfBlob.Value() != forwardPInvokeHashBlobSize);
4398+
_ASSERTE(cbSizeOfBlob.Value() != unsharedStubHashBlobSize);
43854399

43864400
static_assert(nltMaxValue <= 0xFF);
43874401
static_assert(nlfMaxValue <= 0xFF);

0 commit comments

Comments
 (0)