diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 458a4d881e86da..3b80403294518c 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -5282,6 +5282,14 @@ MethodDesc* NDirect::CreateStructMarshalILStub(MethodTable* pMT) } CONTRACT_END; + LoaderAllocator* pLoaderAllocator = pMT->GetLoaderAllocator(); + + EEMarshalingData* pMarshallingData = pLoaderAllocator->GetMarshalingData(); + + MethodDesc* pCachedStubMD = pMarshallingData->LookupStructILStub(pMT); + if (pCachedStubMD != NULL) + RETURN pCachedStubMD; + DWORD dwStubFlags = NDIRECTSTUB_FL_STRUCT_MARSHAL; BOOL bestFit, throwOnUnmappableChar; @@ -5340,7 +5348,7 @@ MethodDesc* NDirect::CreateStructMarshalILStub(MethodTable* pMT) sigBuilder.NewArg(&cleanupWorkList); DWORD cbMetaSigSize = sigBuilder.GetSigSize(); - AllocMemHolder szMetaSig(pMT->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(cbMetaSigSize))); + AllocMemHolder szMetaSig(pLoaderAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(cbMetaSigSize))); sigBuilder.GetSig(szMetaSig, cbMetaSigSize); StubSigDesc sigDesc(pMT, Signature(szMetaSig, cbMetaSigSize), pMT->GetModule()); @@ -5373,6 +5381,11 @@ MethodDesc* NDirect::CreateStructMarshalILStub(MethodTable* pMT) szMetaSig.SuppressRelease(); } + // The CreateInteropILStub() handles only creating a single stub. + // The stub returned will be okay to return even if the call below loses + // the race to insert into the cache. + pMarshallingData->CacheStructILStub(pMT, pStubMD); + RETURN pStubMD; } @@ -5784,17 +5797,7 @@ void MarshalStructViaILStub(MethodDesc* pStubMD, void* pManagedData, void* pNati } CONTRACTL_END; - ARG_SLOT args[] = - { - PtrToArgSlot(pManagedData), - PtrToArgSlot(pNativeData), - (ARG_SLOT)operation, - PtrToArgSlot(ppCleanupWorkList) - }; - - MethodDescCallSite callSite(pStubMD); - - callSite.Call(args); + MarshalStructViaILStubCode(pStubMD->GetSingleCallableAddrOfCode(), pManagedData, pNativeData, operation, ppCleanupWorkList); } void MarshalStructViaILStubCode(PCODE pStubCode, void* pManagedData, void* pNativeData, StructMarshalStubs::MarshalOperation operation, void** ppCleanupWorkList /* = nullptr */) diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 9b6f17f0533fa6..c38e495087218f 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -624,6 +624,12 @@ class LoaderAllocator // basis. EEMarshalingData *GetMarshalingData(); + EEMarshalingData* GetMarshalingDataIfAvailable() + { + LIMITED_METHOD_CONTRACT; + return m_pMarshalingData; + } + private: // Deletes marshaling data at shutdown (which contains cached factories that needs to be released) void DeleteMarshalingData(); diff --git a/src/coreclr/vm/marshalnative.cpp b/src/coreclr/vm/marshalnative.cpp index dadb391fc225ec..81fc962a04f568 100644 --- a/src/coreclr/vm/marshalnative.cpp +++ b/src/coreclr/vm/marshalnative.cpp @@ -123,8 +123,10 @@ FCIMPL3(VOID, MarshalNative::StructureToPtr, Object* pObjUNSAFE, LPVOID ptr, CLR } else if (pMT->HasLayout()) { - MethodDesc* structMarshalStub; + EEMarshalingData* pEEMarshalingData = pMT->GetLoaderAllocator()->GetMarshalingDataIfAvailable(); + MethodDesc* structMarshalStub = (pEEMarshalingData != NULL) ? pEEMarshalingData->LookupStructILStubSpeculative(pMT) : NULL; + if (structMarshalStub == NULL) { GCX_PREEMP(); structMarshalStub = NDirect::CreateStructMarshalILStub(pMT); @@ -178,8 +180,10 @@ FCIMPL3(VOID, MarshalNative::PtrToStructureHelper, LPVOID ptr, Object* pObjIn, C } else if (pMT->HasLayout()) { - MethodDesc* structMarshalStub; + EEMarshalingData* pEEMarshalingData = pMT->GetLoaderAllocator()->GetMarshalingDataIfAvailable(); + MethodDesc* structMarshalStub = (pEEMarshalingData != NULL) ? pEEMarshalingData->LookupStructILStubSpeculative(pMT) : NULL; + if (structMarshalStub == NULL) { GCX_PREEMP(); structMarshalStub = NDirect::CreateStructMarshalILStub(pMT); @@ -227,11 +231,14 @@ FCIMPL2(VOID, MarshalNative::DestroyStructure, LPVOID ptr, ReflectClassBaseObjec } else if (th.HasLayout()) { - MethodDesc* structMarshalStub; + MethodTable* pMT = th.GetMethodTable(); + EEMarshalingData* pEEMarshalingData = pMT->GetLoaderAllocator()->GetMarshalingDataIfAvailable(); + MethodDesc* structMarshalStub = (pEEMarshalingData != NULL) ? pEEMarshalingData->LookupStructILStubSpeculative(pMT) : NULL; + if (structMarshalStub == NULL) { GCX_PREEMP(); - structMarshalStub = NDirect::CreateStructMarshalILStub(th.GetMethodTable()); + structMarshalStub = NDirect::CreateStructMarshalILStub(pMT); } MarshalStructViaILStub(structMarshalStub, nullptr, ptr, StructMarshalStubs::MarshalOperation::Cleanup); diff --git a/src/coreclr/vm/mlinfo.cpp b/src/coreclr/vm/mlinfo.cpp index 3f74772e014c4f..bace44dfc66ed2 100644 --- a/src/coreclr/vm/mlinfo.cpp +++ b/src/coreclr/vm/mlinfo.cpp @@ -41,6 +41,7 @@ +#define INITIAL_NUM_STRUCT_ILSTUB_HASHTABLE_BUCKETS 32 #define INITIAL_NUM_CMHELPER_HASHTABLE_BUCKETS 32 #define INITIAL_NUM_CMINFO_HASHTABLE_BUCKETS 32 #define DEBUG_CONTEXT_STR_LEN 2000 @@ -822,6 +823,7 @@ EEMarshalingData::EEMarshalingData(LoaderAllocator* pAllocator, CrstBase *pCrst) CONTRACTL_END; LockOwner lock = {pCrst, IsOwnerOfCrst}; + m_structILStubCache.Init(INITIAL_NUM_STRUCT_ILSTUB_HASHTABLE_BUCKETS, &lock); m_CMHelperHashtable.Init(INITIAL_NUM_CMHELPER_HASHTABLE_BUCKETS, &lock); m_SharedCMHelperToCMInfoMap.Init(INITIAL_NUM_CMINFO_HASHTABLE_BUCKETS, &lock); } @@ -879,6 +881,23 @@ void EEMarshalingData::operator delete(void *pMem) } +void EEMarshalingData::CacheStructILStub(MethodTable* pMT, MethodDesc* pStubMD) +{ + STANDARD_VM_CONTRACT; + + CrstHolder lock(m_lock); + + // Verify that the stub has not already been added by another thread. + HashDatum res = 0; + if (m_structILStubCache.GetValue(pMT, &res)) + { + return; + } + + m_structILStubCache.InsertValue(pMT, pStubMD); +} + + CustomMarshalerHelper *EEMarshalingData::GetCustomMarshalerHelper(Assembly *pAssembly, TypeHandle hndManagedType, LPCUTF8 strMarshalerTypeName, DWORD cMarshalerTypeNameBytes, LPCUTF8 strCookie, DWORD cCookieStrBytes) { CONTRACT (CustomMarshalerHelper*) diff --git a/src/coreclr/vm/mlinfo.h b/src/coreclr/vm/mlinfo.h index 9516014e5b9888..326c31c8ba465d 100644 --- a/src/coreclr/vm/mlinfo.h +++ b/src/coreclr/vm/mlinfo.h @@ -240,6 +240,26 @@ class EEMarshalingData void *operator new(size_t size, LoaderHeap *pHeap); void operator delete(void *pMem); +#ifndef DACCESS_COMPILE + MethodDesc* LookupStructILStubSpeculative(MethodTable* pMT) + { + WRAPPER_NO_CONTRACT; + HashDatum res = 0; + m_structILStubCache.GetValueSpeculative(pMT, &res); + return (MethodDesc*)res; + } + + MethodDesc* LookupStructILStub(MethodTable* pMT) + { + WRAPPER_NO_CONTRACT; + HashDatum res = 0; + m_structILStubCache.GetValue(pMT, &res); + return (MethodDesc*)res; + } + + void CacheStructILStub(MethodTable* pMT, MethodDesc* pStubMD); +#endif + // This method returns the custom marshaling helper associated with the name cookie pair. If the // CM info has not been created yet for this pair then it will be created and returned. CustomMarshalerHelper *GetCustomMarshalerHelper(Assembly *pAssembly, TypeHandle hndManagedType, LPCUTF8 strMarshalerTypeName, DWORD cMarshalerTypeNameBytes, LPCUTF8 strCookie, DWORD cCookieStrBytes); @@ -250,11 +270,10 @@ class EEMarshalingData #ifdef FEATURE_COMINTEROP // This method retrieves OLE_COLOR marshaling info. OleColorMarshalingInfo *GetOleColorMarshalingInfo(); - - #endif // FEATURE_COMINTEROP private: + EEPtrHashTable m_structILStubCache; EECMHelperHashTable m_CMHelperHashtable; EEPtrHashTable m_SharedCMHelperToCMInfoMap; LoaderAllocator* m_pAllocator;