Custom Marshalers in custom-ALC-loaded assemblies results in types loaded from crossi...
authorJeremy Koritzinsky <jkoritzinsky@gmail.com>
Mon, 14 Jan 2019 23:49:45 +0000 (15:49 -0800)
committerGitHub <noreply@github.com>
Mon, 14 Jan 2019 23:49:45 +0000 (15:49 -0800)
* Create repro for dotnet/coreclr#19654

* Update ICustomMarshaler.csproj

* Update ICustomMarshaler.csproj

* Clean up repro per feedback.

* Add test case for different assemblies with the same CustomMarshaler name.

* Move EEMarshalingData cache from AppDomain to LoaderAllocator. This fixes the custom-marshaler conflict when using unloadable assembly contexts.

* Internalize the LoaderHeap* parameter.

* Add the pointer to the requesting assembly to the hashtable key.

* Fix linux-musl build break.

* Move Crst out of FEATURE_COMINTEROP block.

* Make sure to copy over the assembly pointer to the key that's actually stored in the hash table.

* Add comment for m_invokingAssembly.

* Move all usages of EEMarshallingData to hang off the correct loader allocator instead of always the global one.

* Change to m_InteropDataCrst since this EEMarshallingData can be used in preemptive GC mode.

* Always init m_InteropDataCrst (since it's used by EEMarshallingData as well as COM).

* PR Feedback.

* Remove extraneous inlines.

27 files changed:
src/vm/appdomain.cpp
src/vm/appdomain.hpp
src/vm/ceemain.cpp
src/vm/cominterfacemarshaler.cpp
src/vm/custommarshalerinfo.cpp
src/vm/custommarshalerinfo.h
src/vm/dispparammarshaler.cpp
src/vm/ilmarshalers.cpp
src/vm/ilmarshalers.h
src/vm/interopconverter.cpp
src/vm/interoputil.cpp
src/vm/loaderallocator.cpp
src/vm/loaderallocator.hpp
src/vm/mlinfo.cpp
src/vm/mlinfo.h
tests/src/Interop/CMakeLists.txt
tests/src/Interop/ICustomMarshaler/ConflictingNames/CMakeLists.txt [new file with mode: 0644]
tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshaler.cs [new file with mode: 0644]
tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshaler.csproj [new file with mode: 0644]
tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshaler2.csproj [new file with mode: 0644]
tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshalerNative.cpp [new file with mode: 0644]
tests/src/Interop/ICustomMarshaler/ConflictingNames/MultipleALCs.csproj [new file with mode: 0644]
tests/src/Interop/ICustomMarshaler/ConflictingNames/RunInALC.cs [new file with mode: 0644]
tests/src/Interop/ICustomMarshaler/ConflictingNames/SameNameDifferentAssembly.cs [new file with mode: 0644]
tests/src/Interop/ICustomMarshaler/ConflictingNames/SameNameDifferentAssembly.csproj [new file with mode: 0644]
tests/src/Interop/ICustomMarshaler/Primitives/ICustomMarshaler.cs [moved from tests/src/Interop/ICustomMarshaler/ICustomMarshaler.cs with 100% similarity]
tests/src/Interop/ICustomMarshaler/Primitives/ICustomMarshaler.csproj [moved from tests/src/Interop/ICustomMarshaler/ICustomMarshaler.csproj with 92% similarity]

index 37d9c84..0c2ebd6 100644 (file)
@@ -711,8 +711,6 @@ BaseDomain::BaseDomain()
     m_handleStore = NULL;
 #endif
 
-    m_pMarshalingData = NULL;
-
 #ifdef FEATURE_COMINTEROP
     m_pMngStdInterfacesInfo = NULL;
     m_pWinRtBinder = NULL;
@@ -785,9 +783,6 @@ void BaseDomain::Init()
     m_crstAssemblyList.Init(CrstAssemblyList, CrstFlags(
         CRST_GC_NOTRIGGER_WHEN_TAKEN | CRST_DEBUGGER_THREAD | CRST_TAKEN_DURING_SHUTDOWN));
 
-    // Initialize the EE marshaling data to NULL.
-    m_pMarshalingData = NULL;
-
 #ifdef FEATURE_COMINTEROP
     // Allocate the managed standard interfaces information.
     m_pMngStdInterfacesInfo = new MngStdInterfacesInfo();
@@ -1805,51 +1800,6 @@ OBJECTREF AppDomain::GetMissingObject()
 
 #ifndef DACCESS_COMPILE
 
-EEMarshalingData *BaseDomain::GetMarshalingData()
-{
-    CONTRACT (EEMarshalingData*)
-    {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-        INJECT_FAULT(COMPlusThrowOM());
-        POSTCONDITION(CheckPointer(m_pMarshalingData));
-    }
-    CONTRACT_END;
-
-    if (!m_pMarshalingData)
-    {
-        // Take the lock
-        CrstHolder holder(&m_InteropDataCrst);
-
-        if (!m_pMarshalingData)
-        {
-            LoaderHeap* pHeap = GetLoaderAllocator()->GetLowFrequencyHeap();
-            m_pMarshalingData = new (pHeap) EEMarshalingData(this, pHeap, &m_DomainCrst);
-        }
-    }
-
-    RETURN m_pMarshalingData;
-}
-
-void BaseDomain::DeleteMarshalingData()
-{
-    CONTRACTL
-    {
-        NOTHROW;
-        GC_TRIGGERS;
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-
-    // We are in shutdown - no need to take any lock
-    if (m_pMarshalingData)
-    {
-        delete m_pMarshalingData;
-        m_pMarshalingData = NULL;
-    }
-}
-
 #ifndef CROSSGEN_COMPILE
 
 STRINGREF *BaseDomain::IsStringInterned(STRINGREF *pString)
index 9b5d01a..8e13b51 100644 (file)
@@ -1121,14 +1121,6 @@ public:
         return m_pWinRtBinder;
     }
 #endif // FEATURE_COMINTEROP
-
-    //****************************************************************************************
-    // This method returns marshaling data that the EE uses that is stored on a per app domain
-    // basis.
-    EEMarshalingData *GetMarshalingData();
-
-    // Deletes marshaling data at shutdown (which contains cached factories that needs to be released)
-    void DeleteMarshalingData();
     
 #ifdef _DEBUG
     BOOL OwnDomainLocalBlockLock()
@@ -1329,8 +1321,6 @@ protected:
     // The large heap handle table critical section.
     CrstExplicitInit             m_LargeHeapHandleTableCrst;
 
-    EEMarshalingData            *m_pMarshalingData;
-
 #ifdef FEATURE_COMINTEROP
     // Information regarding the managed standard interfaces.
     MngStdInterfacesInfo        *m_pMngStdInterfacesInfo;
index defa4ac..6186a0c 100644 (file)
@@ -1189,11 +1189,6 @@ void InnerCoEEShutDownCOM()
     // Release all of the RCWs in all contexts in all caches.
     ReleaseRCWsInCaches(NULL);
 
-    // Release all marshaling data in all AppDomains
-    AppDomainIterator i(TRUE);
-    while (i.Next())
-        i.GetDomain()->DeleteMarshalingData();
-
 #ifdef FEATURE_APPX    
     // Cleanup cached factory pointer in SynchronizationContextNative
     SynchronizationContextNative::Cleanup();
index a206222..5ee831c 100644 (file)
@@ -745,7 +745,7 @@ void COMInterfaceMarshaler::MarshalToNonRCWType(OBJECTREF *poref)
             LPCWSTR pwszRawUri = hsRawUri.GetRawBuffer(&cchRawUri);
             gc.refRawURI = StringObject::NewString(pwszRawUri, cchRawUri);
 
-            UriMarshalingInfo *pUriMarshalingInfo = GetAppDomain()->GetMarshalingData()->GetUriMarshalingInfo();
+            UriMarshalingInfo *pUriMarshalingInfo = GetAppDomain()->GetLoaderAllocator()->GetMarshalingData()->GetUriMarshalingInfo();
             MethodDesc* pSystemUriCtorMD = pUriMarshalingInfo->GetSystemUriCtorMD();
 
             MethodTable *pMTSystemUri = pUriMarshalingInfo->GetSystemUriType().AsMethodTable();
@@ -787,7 +787,7 @@ void COMInterfaceMarshaler::MarshalToNonRCWType(OBJECTREF *poref)
         case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs:
         {
             MethodDesc *pMD;
-            EventArgsMarshalingInfo *pInfo = GetAppDomain()->GetMarshalingData()->GetEventArgsMarshalingInfo();
+            EventArgsMarshalingInfo *pInfo = GetAppDomain()->GetLoaderAllocator()->GetMarshalingData()->GetEventArgsMarshalingInfo();
             
             if (index == WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs)
                 pMD = pInfo->GetWinRTNCCEventArgsToSystemNCCEventArgsMD();
index 9848487..d2d9ef2 100644 (file)
@@ -23,7 +23,7 @@
 // Implementation of the custom marshaler info class.
 //==========================================================================
 
-CustomMarshalerInfo::CustomMarshalerInfo(BaseDomain *pDomain, TypeHandle hndCustomMarshalerType, TypeHandle hndManagedType, LPCUTF8 strCookie, DWORD cCookieStrBytes)
+CustomMarshalerInfo::CustomMarshalerInfo(LoaderAllocator *pLoaderAllocator, TypeHandle hndCustomMarshalerType, TypeHandle hndManagedType, LPCUTF8 strCookie, DWORD cCookieStrBytes)
 : m_NativeSize(0)
 , m_hndManagedType(hndManagedType)
 , m_hndCustomMarshaler(NULL)
@@ -38,7 +38,7 @@ CustomMarshalerInfo::CustomMarshalerInfo(BaseDomain *pDomain, TypeHandle hndCust
         THROWS;
         GC_TRIGGERS;
         MODE_COOPERATIVE;
-        PRECONDITION(CheckPointer(pDomain));
+        PRECONDITION(CheckPointer(pLoaderAllocator));
     }
     CONTRACTL_END;
 
@@ -112,7 +112,7 @@ CustomMarshalerInfo::CustomMarshalerInfo(BaseDomain *pDomain, TypeHandle hndCust
                      IDS_EE_NOCUSTOMMARSHALER,
                      GetFullyQualifiedNameForClassW(hndCustomMarshalerType.GetMethodTable()));
     }
-    m_hndCustomMarshaler = pDomain->CreateHandle(CustomMarshalerObj);
+    m_hndCustomMarshaler = pLoaderAllocator->GetDomain()->CreateHandle(CustomMarshalerObj);
 
     // Retrieve the size of the native data.
     if (m_bDataIsByValue)
@@ -367,6 +367,7 @@ EEHashEntry_t * EECMHelperHashtableHelper::AllocateEntry(EECMHelperHashtableKey
         cbEntry += S_SIZE_T(pKey->GetMarshalerTypeNameByteCount());
         cbEntry += S_SIZE_T(pKey->GetCookieStringByteCount());
         cbEntry += S_SIZE_T(pKey->GetMarshalerInstantiation().GetNumArgs()) * S_SIZE_T(sizeof(LPVOID));
+        cbEntry += S_SIZE_T(sizeof(LPVOID)); // For EECMHelperHashtableKey::m_invokingAssembly
 
         if (cbEntry.IsOverflow())
             return NULL;
@@ -387,6 +388,7 @@ EEHashEntry_t * EECMHelperHashtableHelper::AllocateEntry(EECMHelperHashtableKey
         memcpy((void*)pEntryKey->m_strCookie, pKey->GetCookieString(), pKey->GetCookieStringByteCount()); 
         memcpy((void*)pEntryKey->m_Instantiation.GetRawArgs(), pKey->GetMarshalerInstantiation().GetRawArgs(),
             pEntryKey->m_Instantiation.GetNumArgs() * sizeof(LPVOID)); 
+        pEntryKey->m_invokingAssembly = pKey->GetInvokingAssembly();
     }
     else
     {
@@ -401,6 +403,7 @@ EEHashEntry_t * EECMHelperHashtableHelper::AllocateEntry(EECMHelperHashtableKey
         pEntryKey->m_cCookieStrBytes = pKey->GetCookieStringByteCount();
         pEntryKey->m_strCookie = pKey->GetCookieString();
         pEntryKey->m_Instantiation = Instantiation(pKey->GetMarshalerInstantiation());
+        pEntryKey->m_invokingAssembly = pKey->GetInvokingAssembly();
     }
 
     return pEntry;
@@ -458,6 +461,9 @@ BOOL EECMHelperHashtableHelper::CompareKeys(EEHashEntry_t *pEntry, EECMHelperHas
             return FALSE;
     }
 
+    if (pEntryKey->GetInvokingAssembly() != pKey->GetInvokingAssembly())
+        return FALSE;
+
     return TRUE;
 }
 
@@ -628,7 +634,7 @@ CustomMarshalerInfo *SharedCustomMarshalerHelper::GetCustomMarshalerInfo()
     CONTRACTL_END;
     
     // Retrieve the marshalling data for the current app domain.
-    EEMarshalingData *pMarshalingData = GetThread()->GetDomain()->GetMarshalingData();
+    EEMarshalingData *pMarshalingData = GetThread()->GetDomain()->GetLoaderAllocator()->GetMarshalingData();
 
     // Retrieve the custom marshaling information for the current shared custom
     // marshaling helper.
index aecedf4..95390f2 100644 (file)
@@ -36,7 +36,7 @@ class CustomMarshalerInfo
 {
 public:
     // Constructor and destructor.
-    CustomMarshalerInfo(BaseDomain* pDomain, TypeHandle hndCustomMarshalerType, TypeHandle hndManagedType, LPCUTF8 strCookie, DWORD cCookieStrBytes);
+    CustomMarshalerInfo(LoaderAllocator* pLoaderAllocator, TypeHandle hndCustomMarshalerType, TypeHandle hndManagedType, LPCUTF8 strCookie, DWORD cCookieStrBytes);
     ~CustomMarshalerInfo();
 
     // CustomMarshalerInfo's are always allocated on the loader heap so we need to redefine
@@ -114,51 +114,59 @@ private:
 
 typedef SList<CustomMarshalerInfo, true> CMINFOLIST;
 
+class Assembly;
 
 class EECMHelperHashtableKey
 {
 public:
-    EECMHelperHashtableKey(DWORD cMarshalerTypeNameBytes, LPCSTR strMarshalerTypeName, DWORD cCookieStrBytes, LPCSTR strCookie, Instantiation instantiation)
+    EECMHelperHashtableKey(DWORD cMarshalerTypeNameBytes, LPCSTR strMarshalerTypeName, DWORD cCookieStrBytes, LPCSTR strCookie, Instantiation instantiation, Assembly* invokingAssembly)
     : m_cMarshalerTypeNameBytes(cMarshalerTypeNameBytes)
     , m_strMarshalerTypeName(strMarshalerTypeName)
     , m_cCookieStrBytes(cCookieStrBytes)
     , m_strCookie(strCookie)
     , m_Instantiation(instantiation)
+    , m_invokingAssembly(invokingAssembly)
     {
         LIMITED_METHOD_CONTRACT;
     }
 
-    inline DWORD GetMarshalerTypeNameByteCount() const
+    DWORD GetMarshalerTypeNameByteCount() const
     {
         LIMITED_METHOD_CONTRACT;
         return m_cMarshalerTypeNameBytes;
     }
-    inline LPCSTR GetMarshalerTypeName() const
+    LPCSTR GetMarshalerTypeName() const
     {
         LIMITED_METHOD_CONTRACT;
         return m_strMarshalerTypeName;
     }
-    inline LPCSTR GetCookieString() const
+    LPCSTR GetCookieString() const
     {
         LIMITED_METHOD_CONTRACT;
         return m_strCookie;
     }
-    inline ULONG GetCookieStringByteCount() const
+    ULONG GetCookieStringByteCount() const
     {
         LIMITED_METHOD_CONTRACT;
         return m_cCookieStrBytes;
     }
-    inline Instantiation GetMarshalerInstantiation() const
+    Instantiation GetMarshalerInstantiation() const
     {
         LIMITED_METHOD_CONTRACT;
         return m_Instantiation;
     }
+    Assembly* GetInvokingAssembly() const
+    {
+        LIMITED_METHOD_CONTRACT;
+        return m_invokingAssembly;
+    }
 
     DWORD           m_cMarshalerTypeNameBytes;
     LPCSTR          m_strMarshalerTypeName;
     DWORD           m_cCookieStrBytes;
     LPCSTR          m_strCookie;
     Instantiation   m_Instantiation;
+    Assembly*       m_invokingAssembly;
 };
 
 
index 04d1566..06ae5bb 100644 (file)
@@ -102,7 +102,7 @@ void DispParamOleColorMarshaler::MarshalNativeToManaged(VARIANT *pSrcVar, OBJECT
 
     // Box the System.Drawing.Color value class and give back the boxed object.
     TypeHandle hndColorType = 
-        GetThread()->GetDomain()->GetMarshalingData()->GetOleColorMarshalingInfo()->GetColorType();
+        GetThread()->GetDomain()->GetLoaderAllocator()->GetMarshalingData()->GetOleColorMarshalingInfo()->GetColorType();
     
     *pDestObj = hndColorType.GetMethodTable()->Box(&MngColor);
 }
index 1912e02..ea39f94 100644 (file)
@@ -1511,8 +1511,8 @@ LocalDesc ILOleColorMarshaler::GetManagedType()
 {
     STANDARD_VM_CONTRACT;
 
-    BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
-    TypeHandle  hndColorType = pDomain->GetMarshalingData()->GetOleColorMarshalingInfo()->GetColorType();
+    LoaderAllocator* pLoader = m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator();
+    TypeHandle  hndColorType = pLoader->GetMarshalingData()->GetOleColorMarshalingInfo()->GetColorType();
 
     //
     // value class
@@ -1524,8 +1524,8 @@ void ILOleColorMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit
 {
     STANDARD_VM_CONTRACT;
 
-    BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
-    MethodDesc* pConvertMD = pDomain->GetMarshalingData()->GetOleColorMarshalingInfo()->GetSystemColorToOleColorMD();
+    LoaderAllocator* pLoader = m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator();
+    MethodDesc* pConvertMD = pLoader->GetMarshalingData()->GetOleColorMarshalingInfo()->GetSystemColorToOleColorMD();
 
     EmitLoadManagedValue(pslILEmit);
     // int System.Drawing.ColorTranslator.ToOle(System.Drawing.Color c)
@@ -1537,8 +1537,8 @@ void ILOleColorMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit
 {
     STANDARD_VM_CONTRACT;
 
-    BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
-    MethodDesc* pConvertMD = pDomain->GetMarshalingData()->GetOleColorMarshalingInfo()->GetOleColorToSystemColorMD();
+    LoaderAllocator* pLoader = m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator();
+    MethodDesc* pConvertMD = pLoader->GetMarshalingData()->GetOleColorMarshalingInfo()->GetOleColorToSystemColorMD();
 
     EmitLoadNativeValue(pslILEmit);
     // System.Drawing.Color System.Drawing.ColorTranslator.FromOle(int oleColor)
@@ -4802,15 +4802,15 @@ void ILHiddenLengthArrayMarshaler::EmitConvertContentsCLRToNative(ILCodeStream*
             switch (m_pargs->na.m_redirectedTypeIndex)
             {
                 case WinMDAdapter::RedirectedTypeIndex_System_Uri:
-                    ILUriMarshaler::EmitConvertCLRUriToWinRTUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+                    ILUriMarshaler::EmitConvertCLRUriToWinRTUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
                     break;
 
                 case WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs:
-                    ILNCCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+                    ILNCCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
                     break;
 
                 case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs:
-                    ILPCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+                    ILPCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
                     break;
 
                 default: UNREACHABLE();
@@ -4875,15 +4875,15 @@ void ILHiddenLengthArrayMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream*
             switch (m_pargs->na.m_redirectedTypeIndex)
             {
                 case WinMDAdapter::RedirectedTypeIndex_System_Uri:
-                    ILUriMarshaler::EmitConvertWinRTUriToCLRUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+                    ILUriMarshaler::EmitConvertWinRTUriToCLRUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
                     break;
 
                 case WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs:
-                    ILNCCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+                    ILNCCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
                     break;
 
                 case WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs:
-                    ILPCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+                    ILPCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
                     break;
 
                 default: UNREACHABLE();
@@ -5674,8 +5674,8 @@ LocalDesc ILUriMarshaler::GetNativeType()
 LocalDesc ILUriMarshaler::GetManagedType()
 {
     STANDARD_VM_CONTRACT;;    
-    BaseDomain* pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
-    TypeHandle  hndUriType = pDomain->GetMarshalingData()->GetUriMarshalingInfo()->GetSystemUriType();
+    LoaderAllocator* pLoader = m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator();
+    TypeHandle  hndUriType = pLoader->GetMarshalingData()->GetUriMarshalingInfo()->GetSystemUriType();
 
     return LocalDesc(hndUriType); // System.Uri
 }
@@ -5688,11 +5688,11 @@ bool ILUriMarshaler::NeedsClearNative()
 
 // Note that this method expects the CLR Uri on top of the evaluation stack and leaves the WinRT Uri there.
 //static
-void ILUriMarshaler::EmitConvertCLRUriToWinRTUri(ILCodeStream* pslILEmit, BaseDomain* pDomain)
+void ILUriMarshaler::EmitConvertCLRUriToWinRTUri(ILCodeStream* pslILEmit, LoaderAllocator* pLoader)
 {
     STANDARD_VM_CONTRACT;
 
-    UriMarshalingInfo* marshalingInfo = pDomain->GetMarshalingData()->GetUriMarshalingInfo();
+    UriMarshalingInfo* marshalingInfo = pLoader->GetMarshalingData()->GetUriMarshalingInfo();
 
     ILCodeLabel *pNotNullLabel = pslILEmit->NewCodeLabel();
     ILCodeLabel *pDoneLabel = pslILEmit->NewCodeLabel();
@@ -5720,17 +5720,17 @@ void ILUriMarshaler::EmitConvertContentsCLRToNative(ILCodeStream* pslILEmit)
     STANDARD_VM_CONTRACT;
 
     EmitLoadManagedValue(pslILEmit);
-    EmitConvertCLRUriToWinRTUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+    EmitConvertCLRUriToWinRTUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
     EmitStoreNativeValue(pslILEmit);
 }
 
 // Note that this method expects the WinRT Uri on top of the evaluation stack and leaves the CLR Uri there.
 //static
-void ILUriMarshaler::EmitConvertWinRTUriToCLRUri(ILCodeStream* pslILEmit, BaseDomain* pDomain)
+void ILUriMarshaler::EmitConvertWinRTUriToCLRUri(ILCodeStream* pslILEmit, LoaderAllocator* pLoader)
 {
     STANDARD_VM_CONTRACT;
 
-    MethodDesc* pSystemUriCtorMD = pDomain->GetMarshalingData()->GetUriMarshalingInfo()->GetSystemUriCtorMD();
+    MethodDesc* pSystemUriCtorMD = pLoader->GetMarshalingData()->GetUriMarshalingInfo()->GetSystemUriCtorMD();
 
     ILCodeLabel *pNotNullLabel = pslILEmit->NewCodeLabel();
     ILCodeLabel *pDoneLabel = pslILEmit->NewCodeLabel();
@@ -5758,7 +5758,7 @@ void ILUriMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit)
     STANDARD_VM_CONTRACT;
 
     EmitLoadNativeValue(pslILEmit);
-    EmitConvertWinRTUriToCLRUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+    EmitConvertWinRTUriToCLRUri(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
     EmitStoreManagedValue(pslILEmit);
 }
 
@@ -5782,8 +5782,8 @@ LocalDesc ILNCCEventArgsMarshaler::GetManagedType()
 {
     STANDARD_VM_CONTRACT;;    
     
-    BaseDomain *pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
-    TypeHandle  hndNCCEventArgType = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemNCCEventArgsType();
+    LoaderAllocator *pLoader = m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator();
+    TypeHandle  hndNCCEventArgType = pLoader->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemNCCEventArgsType();
 
     return LocalDesc(hndNCCEventArgType); // System.Collections.Specialized.NotifyCollectionChangedEventArgs
 }
@@ -5797,11 +5797,11 @@ bool ILNCCEventArgsMarshaler::NeedsClearNative()
 // Note that this method expects the CLR NotifyCollectionChangedEventArgs on top of the evaluation stack and
 // leaves the WinRT NotifyCollectionChangedEventArgs IP there.
 //static
-void ILNCCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream *pslILEmit, BaseDomain *pDomain)
+void ILNCCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream *pslILEmit, LoaderAllocator* pLoader)
 {
     STANDARD_VM_CONTRACT;
 
-    MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemNCCEventArgsToWinRTNCCEventArgsMD();
+    MethodDesc *pConvertMD = pLoader->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemNCCEventArgsToWinRTNCCEventArgsMD();
 
     // IntPtr System.Runtime.InteropServices.WindowsRuntime.NotifyCollectionChangedEventArgsMarshaler.ConvertToNative(NotifyCollectionChangedEventArgs)
     pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
@@ -5812,18 +5812,18 @@ void ILNCCEventArgsMarshaler::EmitConvertContentsCLRToNative(ILCodeStream *pslIL
     STANDARD_VM_CONTRACT;
 
     EmitLoadManagedValue(pslILEmit);
-    EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+    EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
     EmitStoreNativeValue(pslILEmit);
 }
 
 // Note that this method expects the WinRT NotifyCollectionChangedEventArgs on top of the evaluation stack and
 // leaves the CLR NotifyCollectionChangedEventArgs there.
 //static
-void ILNCCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain)
+void ILNCCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, LoaderAllocator* pLoader)
 {
     STANDARD_VM_CONTRACT;
 
-    MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetWinRTNCCEventArgsToSystemNCCEventArgsMD();
+    MethodDesc *pConvertMD = pLoader->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetWinRTNCCEventArgsToSystemNCCEventArgsMD();
 
     // NotifyCollectionChangedEventArgs System.Runtime.InteropServices.WindowsRuntime.NotifyCollectionChangedEventArgsMarshaler.ConvertToManaged(IntPtr)
     pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
@@ -5834,7 +5834,7 @@ void ILNCCEventArgsMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslIL
     STANDARD_VM_CONTRACT;
 
     EmitLoadNativeValue(pslILEmit);
-    EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+    EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
     EmitStoreManagedValue(pslILEmit);
 }
 
@@ -5858,8 +5858,8 @@ LocalDesc ILPCEventArgsMarshaler::GetManagedType()
 {
     STANDARD_VM_CONTRACT;;    
     
-    BaseDomain *pDomain = m_pargs->m_pMarshalInfo->GetModule()->GetDomain();
-    TypeHandle  hndPCEventArgType = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemPCEventArgsType();
+    LoaderAllocator* pLoader = m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator();
+    TypeHandle  hndPCEventArgType = pLoader->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemPCEventArgsType();
 
     return LocalDesc(hndPCEventArgType); // System.ComponentModel.PropertyChangedEventArgs
 }
@@ -5873,11 +5873,11 @@ bool ILPCEventArgsMarshaler::NeedsClearNative()
 // Note that this method expects the CLR PropertyChangedEventArgs on top of the evaluation stack and
 // leaves the WinRT PropertyChangedEventArgs IP there.
 //static
-void ILPCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream *pslILEmit, BaseDomain *pDomain)
+void ILPCEventArgsMarshaler::EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream *pslILEmit, LoaderAllocator* pLoader)
 {
     STANDARD_VM_CONTRACT;
 
-    MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemPCEventArgsToWinRTPCEventArgsMD();
+    MethodDesc *pConvertMD = pLoader->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetSystemPCEventArgsToWinRTPCEventArgsMD();
 
     // IntPtr System.Runtime.InteropServices.WindowsRuntime.PropertyChangedEventArgsMarshaler.ConvertToNative(PropertyChangedEventArgs)
     pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
@@ -5888,18 +5888,18 @@ void ILPCEventArgsMarshaler::EmitConvertContentsCLRToNative(ILCodeStream *pslILE
     STANDARD_VM_CONTRACT;
 
     EmitLoadManagedValue(pslILEmit);
-    EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+    EmitConvertCLREventArgsToWinRTEventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
     EmitStoreNativeValue(pslILEmit);
 }
 
 // Note that this method expects the WinRT PropertyChangedEventArgs on top of the evaluation stack and
 // leaves the CLR PropertyChangedEventArgs there.
 //static
-void ILPCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain)
+void ILPCEventArgsMarshaler::EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, LoaderAllocator* pLoader)
 {
     STANDARD_VM_CONTRACT;
 
-    MethodDesc *pConvertMD = pDomain->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetWinRTPCEventArgsToSystemPCEventArgsMD();
+    MethodDesc *pConvertMD = pLoader->GetMarshalingData()->GetEventArgsMarshalingInfo()->GetWinRTPCEventArgsToSystemPCEventArgsMD();
 
     // PropertyChangedEventArgs System.Runtime.InteropServices.WindowsRuntime.PropertyChangedEventArgsMarshaler.ConvertToManaged(IntPtr)
     pslILEmit->EmitCALL(pslILEmit->GetToken(pConvertMD), 1, 1);
@@ -5910,7 +5910,7 @@ void ILPCEventArgsMarshaler::EmitConvertContentsNativeToCLR(ILCodeStream* pslILE
     STANDARD_VM_CONTRACT;
 
     EmitLoadNativeValue(pslILEmit);
-    EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetDomain());
+    EmitConvertWinRTEventArgsToCLREventArgs(pslILEmit, m_pargs->m_pMarshalInfo->GetModule()->GetLoaderAllocator());
     EmitStoreManagedValue(pslILEmit);
 }
 
index 0566903..1c58c0c 100644 (file)
@@ -3234,8 +3234,8 @@ public:
         c_CLRSize               = sizeof(OBJECTREF),
     };
 
-    static void EmitConvertCLRUriToWinRTUri(ILCodeStream* pslILEmit, BaseDomain* pDomain);
-    static void EmitConvertWinRTUriToCLRUri(ILCodeStream* pslILEmit, BaseDomain* pDomain);
+    static void EmitConvertCLRUriToWinRTUri(ILCodeStream* pslILEmit, LoaderAllocator* pLoader);
+    static void EmitConvertWinRTUriToCLRUri(ILCodeStream* pslILEmit, LoaderAllocator* pLoader);
 
 protected:
     virtual LocalDesc GetNativeType();
@@ -3258,8 +3258,8 @@ public:
         c_CLRSize               = sizeof(OBJECTREF),
     };
 
-    static void EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
-    static void EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
+    static void EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream* pslILEmit, LoaderAllocator* pLoader);
+    static void EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, LoaderAllocator* pLoader);
 
 protected:
     virtual LocalDesc GetNativeType();
@@ -3282,8 +3282,8 @@ public:
         c_CLRSize               = sizeof(OBJECTREF),
     };
 
-    static void EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
-    static void EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, BaseDomain* pDomain);
+    static void EmitConvertCLREventArgsToWinRTEventArgs(ILCodeStream* pslILEmit, LoaderAllocator* pLoader);
+    static void EmitConvertWinRTEventArgsToCLREventArgs(ILCodeStream* pslILEmit, LoaderAllocator* pLoader);
 
 protected:
     virtual LocalDesc GetNativeType();
index c681023..26254e1 100644 (file)
@@ -207,7 +207,7 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, ComIpType ReqIpType, ComIpType
                     // This is a redirected type - see if we need to manually marshal it                    
                     if (redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_Uri)
                     {
-                        UriMarshalingInfo *pUriMarshalInfo = GetAppDomain()->GetMarshalingData()->GetUriMarshalingInfo();
+                        UriMarshalingInfo *pUriMarshalInfo = GetAppDomain()->GetLoaderAllocator()->GetMarshalingData()->GetUriMarshalingInfo();
                         struct
                         {
                             OBJECTREF ref;
@@ -241,7 +241,7 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, ComIpType ReqIpType, ComIpType
                              redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_ComponentModel_PropertyChangedEventArgs)
                     {
                         MethodDesc *pMD;
-                        EventArgsMarshalingInfo *pInfo = GetAppDomain()->GetMarshalingData()->GetEventArgsMarshalingInfo();
+                        EventArgsMarshalingInfo *pInfo = GetAppDomain()->GetLoaderAllocator()->GetMarshalingData()->GetEventArgsMarshalingInfo();
 
                         if (redirectedTypeIndex == WinMDAdapter::RedirectedTypeIndex_System_Collections_Specialized_NotifyCollectionChangedEventArgs)
                             pMD = pInfo->GetSystemNCCEventArgsToWinRTNCCEventArgsMD();
index a21e68b..b84670b 100644 (file)
@@ -3261,7 +3261,7 @@ void ConvertOleColorToSystemColor(OLE_COLOR SrcOleColor, SYSTEMCOLOR *pDestSysCo
 
     // Retrieve the method desc to use for the current AD.
     MethodDesc *pOleColorToSystemColorMD = 
-        GetAppDomain()->GetMarshalingData()->GetOleColorMarshalingInfo()->GetOleColorToSystemColorMD();
+        GetAppDomain()->GetLoaderAllocator()->GetMarshalingData()->GetOleColorMarshalingInfo()->GetOleColorToSystemColorMD();
 
     MethodDescCallSite oleColorToSystemColor(pOleColorToSystemColorMD);
 
@@ -3290,7 +3290,7 @@ OLE_COLOR ConvertSystemColorToOleColor(OBJECTREF *pSrcObj)
     
     // Retrieve the method desc to use for the current AD.
     MethodDesc *pSystemColorToOleColorMD = 
-        GetAppDomain()->GetMarshalingData()->GetOleColorMarshalingInfo()->GetSystemColorToOleColorMD();
+        GetAppDomain()->GetLoaderAllocator()->GetMarshalingData()->GetOleColorMarshalingInfo()->GetSystemColorToOleColorMD();
     MethodDescCallSite systemColorToOleColor(pSystemColorToOleColorMD);
 
     // Set up the args and call the method.
@@ -6732,7 +6732,7 @@ ABI::Windows::Foundation::IUriRuntimeClass *CreateWinRTUri(LPCWSTR wszUri, INT32
 {
     STANDARD_VM_CONTRACT;
 
-    UriMarshalingInfo* marshalingInfo = GetAppDomain()->GetMarshalingData()->GetUriMarshalingInfo();
+    UriMarshalingInfo* marshalingInfo = GetAppDomain()->GetLoaderAllocator()->GetMarshalingData()->GetUriMarshalingInfo();
         
     // Get the cached factory from the UriMarshalingInfo object of the current appdomain
     ABI::Windows::Foundation::IUriRuntimeClassFactory* pFactory = marshalingInfo->GetUriFactory();
index 7b2ef1e..21c6f27 100644 (file)
@@ -73,6 +73,8 @@ LoaderAllocator::LoaderAllocator()
     m_pJumpStubCache = NULL;
     m_IsCollectible = false;
 
+    m_pMarshalingData = NULL;
+
 #ifdef FEATURE_COMINTEROP
     m_pComCallWrapperCache = NULL;
 #endif
@@ -1079,8 +1081,8 @@ void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory)
     m_pDomain = pDomain;
 
     m_crstLoaderAllocator.Init(CrstLoaderAllocator, (CrstFlags)CRST_UNSAFE_COOPGC);
-#ifdef FEATURE_COMINTEROP
     m_InteropDataCrst.Init(CrstInteropData, CRST_REENTRANCY);
+#ifdef FEATURE_COMINTEROP
     m_ComCallWrapperCrst.Init(CrstCOMCallWrapper);
 #endif
 
@@ -1227,6 +1229,9 @@ void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory)
     m_pPrecodeHeap = new (&m_PrecodeHeapInstance) CodeFragmentHeap(this, STUB_CODE_BLOCK_PRECODE);
 #endif
 
+    // Initialize the EE marshaling data to NULL.
+    m_pMarshalingData = NULL;
+
     // Set up the IL stub cache
     m_ILStubCache.Init(m_pHighFrequencyHeap);
 
@@ -1332,6 +1337,8 @@ void LoaderAllocator::Terminate()
 
     LOG((LF_CLASSLOADER, LL_INFO100, "Begin LoaderAllocator::Terminate for loader allocator %p\n", reinterpret_cast<void *>(static_cast<PTR_LoaderAllocator>(this))));
 
+    DeleteMarshalingData();
+
     if (m_fGCPressure)
     {
         GCX_PREEMP();
@@ -1632,6 +1639,50 @@ void LoaderAllocator::UninitVirtualCallStubManager()
 
 #endif // !CROSSGEN_COMPILE
 
+EEMarshalingData *LoaderAllocator::GetMarshalingData()
+{
+    CONTRACT (EEMarshalingData*)
+    {
+        THROWS;
+        GC_TRIGGERS;
+        MODE_ANY;
+        INJECT_FAULT(COMPlusThrowOM());
+        POSTCONDITION(CheckPointer(m_pMarshalingData));
+    }
+    CONTRACT_END;
+
+    if (!m_pMarshalingData)
+    {
+        // Take the lock
+        CrstHolder holder(&m_InteropDataCrst);
+
+        if (!m_pMarshalingData)
+        {
+            m_pMarshalingData = new (GetLowFrequencyHeap()) EEMarshalingData(this, &m_InteropDataCrst);
+        }
+    }
+
+    RETURN m_pMarshalingData;
+}
+
+void LoaderAllocator::DeleteMarshalingData()
+{
+    CONTRACTL
+    {
+        NOTHROW;
+        GC_TRIGGERS;
+        MODE_ANY;
+    }
+    CONTRACTL_END;
+
+    // We are in shutdown - no need to take any lock
+    if (m_pMarshalingData)
+    {
+        delete m_pMarshalingData;
+        m_pMarshalingData = NULL;
+    }
+}
+
 #endif // !DACCESS_COMPILE
 
 BOOL GlobalLoaderAllocator::CanUnload()
index e2c5dc5..dc63ab9 100644 (file)
@@ -135,6 +135,7 @@ class UMEntryThunkCache;
 #ifdef FEATURE_COMINTEROP
 class ComCallWrapperCache;
 #endif // FEATURE_COMINTEROP
+class EEMarshalingData;
 
 class LoaderAllocator
 {
@@ -262,10 +263,13 @@ private:
     CrstExplicitInit m_ComCallWrapperCrst;
     // Hash table that maps a MethodTable to COM Interop compatibility data.
     PtrHashMap m_interopDataHash;
-    // Used for synchronizing access to the m_interopDataHash
-    CrstExplicitInit m_InteropDataCrst;
+
 #endif
 
+    // Used for synchronizing access to the m_interopDataHash and m_pMarshalingData
+    CrstExplicitInit m_InteropDataCrst;
+    EEMarshalingData* m_pMarshalingData;
+
 #ifdef FEATURE_TIERED_COMPILATION
     CallCounter m_callCounter;
 #endif
@@ -556,6 +560,17 @@ public:
         return &m_ILStubCache;
     }
 
+    //****************************************************************************************
+    // This method returns marshaling data that the EE uses that is stored on a per LoaderAllocator
+    // basis.
+    EEMarshalingData *GetMarshalingData();
+
+private:
+    // Deletes marshaling data at shutdown (which contains cached factories that needs to be released)
+    void DeleteMarshalingData();
+
+public:
+
 #ifdef FEATURE_COMINTEROP
 
     ComCallWrapperCache * GetComCallWrapperCache();
index cc9760a..32f77cd 100644 (file)
@@ -429,7 +429,7 @@ CustomMarshalerHelper *SetupCustomMarshalerHelper(LPCUTF8 strMarshalerTypeName,
     EEMarshalingData *pMarshalingData = NULL;
 
     // The assembly is not shared so we use the current app domain's marshaling data.
-    pMarshalingData = GetThread()->GetDomain()->GetMarshalingData();
+    pMarshalingData = pAssembly->GetLoaderAllocator()->GetMarshalingData();
 
     // Retrieve the custom marshaler helper from the EE marshaling data.
     RETURN pMarshalingData->GetCustomMarshalerHelper(pAssembly, hndManagedType, strMarshalerTypeName, cMarshalerTypeNameBytes, strCookie, cCookieStrBytes);
@@ -1072,9 +1072,10 @@ void OleColorMarshalingInfo::operator delete(void *pMem)
 
 #endif // FEATURE_COMINTEROP
 
-EEMarshalingData::EEMarshalingData(BaseDomain *pDomain, LoaderHeap *pHeap, CrstBase *pCrst) :
-    m_pHeap(pHeap),
-    m_pDomain(pDomain)
+EEMarshalingData::EEMarshalingData(LoaderAllocator* pAllocator, CrstBase *pCrst) :
+    m_pAllocator(pAllocator),
+    m_pHeap(pAllocator->GetLowFrequencyHeap()),
+    m_lock(pCrst)
 {
     CONTRACTL
     {
@@ -1177,7 +1178,7 @@ CustomMarshalerHelper *EEMarshalingData::GetCustomMarshalerHelper(Assembly *pAss
     TypeHandle hndCustomMarshalerType;
 
     // Create the key that will be used to lookup in the hashtable.
-    EECMHelperHashtableKey Key(cMarshalerTypeNameBytes, strMarshalerTypeName, cCookieStrBytes, strCookie, hndManagedType.GetInstantiation());
+    EECMHelperHashtableKey Key(cMarshalerTypeNameBytes, strMarshalerTypeName, cCookieStrBytes, strCookie, hndManagedType.GetInstantiation(), pAssembly);
 
     // Lookup the custom marshaler helper in the hashtable.
     if (m_CMHelperHashtable.GetValue(&Key, (HashDatum*)&pCMHelper))
@@ -1209,15 +1210,14 @@ CustomMarshalerHelper *EEMarshalingData::GetCustomMarshalerHelper(Assembly *pAss
 
 
         // Create the custom marshaler info in the specified heap.
-        pNewCMInfo = new (m_pHeap) CustomMarshalerInfo(m_pDomain, hndCustomMarshalerType, hndManagedType, strCookie, cCookieStrBytes);
+        pNewCMInfo = new (m_pHeap) CustomMarshalerInfo(m_pAllocator, hndCustomMarshalerType, hndManagedType, strCookie, cCookieStrBytes);
 
         // Create the custom marshaler helper in the specified heap.
         pNewCMHelper = new (m_pHeap) NonSharedCustomMarshalerHelper(pNewCMInfo);
     }
 
-    // Take the app domain lock before we insert the custom marshaler info into the hashtable.
     {
-        BaseDomain::LockHolder lh(m_pDomain);
+        CrstHolder lock(m_lock);
 
         // Verify that the custom marshaler helper has not already been added by another thread.
         if (m_CMHelperHashtable.GetValue(&Key, (HashDatum*)&pCMHelper))
@@ -1277,15 +1277,14 @@ CustomMarshalerInfo *EEMarshalingData::GetCustomMarshalerInfo(SharedCustomMarsha
     }
 
     // Create the custom marshaler info in the specified heap.
-    pNewCMInfo = new (m_pHeap) CustomMarshalerInfo(m_pDomain
+    pNewCMInfo = new (m_pHeap) CustomMarshalerInfo(m_pAllocator
                                                    hndCustomMarshalerType, 
                                                    pSharedCMHelper->GetManagedType(), 
                                                    pSharedCMHelper->GetCookieString(), 
                                                    pSharedCMHelper->GetCookieStringByteCount());
 
     {
-        // Take the app domain lock before we insert the custom marshaler info into the hashtable.
-        BaseDomain::LockHolder lh(m_pDomain);
+        CrstHolder lock(m_lock);
 
         // Verify that the custom marshaler info has not already been added by another thread.
         if (m_SharedCMHelperToCMInfoMap.GetValue(pSharedCMHelper, (HashDatum*)&pCMInfo))
index 91afec9..00a417b 100644 (file)
@@ -371,7 +371,7 @@ private:
 class EEMarshalingData
 {
 public:
-    EEMarshalingData(BaseDomain *pDomain, LoaderHeap *pHeap, CrstBase *pCrst);
+    EEMarshalingData(LoaderAllocator *pAllocator, CrstBase *pCrst);
     ~EEMarshalingData();
 
     // EEMarshalingData's are always allocated on the loader heap so we need to redefine
@@ -400,14 +400,15 @@ private:
     EECMHelperHashTable                 m_CMHelperHashtable;
     EEPtrHashTable                      m_SharedCMHelperToCMInfoMap;
 #endif // CROSSGEN_COMPILE
+    LoaderAllocator*                    m_pAllocator;
     LoaderHeap*                         m_pHeap;
-    BaseDomain*                         m_pDomain;
     CMINFOLIST                          m_pCMInfoList;
 #ifdef FEATURE_COMINTEROP
     OleColorMarshalingInfo*             m_pOleColorInfo;
     UriMarshalingInfo*                  m_pUriInfo;
     EventArgsMarshalingInfo*            m_pEventArgsInfo;
 #endif // FEATURE_COMINTEROP
+    CrstBase*                           m_lock;
 };
 
 struct ItfMarshalInfo;
index e46e78a..9b67844 100644 (file)
@@ -62,6 +62,7 @@ add_subdirectory(DllImportAttribute/ExeFile)
 add_subdirectory(DllImportAttribute/FileNameContainDot)
 add_subdirectory(DllImportAttribute/Simple)
 add_subdirectory(ExecInDefAppDom)
+add_subdirectory(ICustomMarshaler/ConflictingNames)
 add_subdirectory(LayoutClass)
 
 if(WIN32)
diff --git a/tests/src/Interop/ICustomMarshaler/ConflictingNames/CMakeLists.txt b/tests/src/Interop/ICustomMarshaler/ConflictingNames/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b1743b7
--- /dev/null
@@ -0,0 +1,11 @@
+cmake_minimum_required (VERSION 2.6)
+project (CustomMarshalersConflictingNames)
+include_directories(${INC_PLATFORM_DIR})
+set(SOURCES CustomMarshalerNative.cpp )
+
+# add the executable
+add_library (CustomMarshalerNative SHARED ${SOURCES})
+target_link_libraries(CustomMarshalerNative ${LINK_LIBRARIES_ADDITIONAL}) 
+
+# add the install targets
+install (TARGETS CustomMarshalerNative DESTINATION bin)
diff --git a/tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshaler.cs b/tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshaler.cs
new file mode 100644 (file)
index 0000000..506f8b2
--- /dev/null
@@ -0,0 +1,54 @@
+// 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.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+class WrappedString
+{
+    public WrappedString(string str)
+    {
+        _str = str;
+    }
+
+    internal string _str;
+}
+
+class WrappedStringCustomMarshaler : ICustomMarshaler
+{
+    public void CleanUpManagedData(object ManagedObj) { }
+    public void CleanUpNativeData(IntPtr pNativeData) { Marshal.ZeroFreeCoTaskMemAnsi(pNativeData); }
+
+    public int GetNativeDataSize() => IntPtr.Size;
+
+    public IntPtr MarshalManagedToNative(object ManagedObj) => Marshal.StringToCoTaskMemAnsi(((WrappedString)ManagedObj)._str);
+    public object MarshalNativeToManaged(IntPtr pNativeData) => new WrappedString(Marshal.PtrToStringAnsi(pNativeData));
+
+    public static ICustomMarshaler GetInstance(string cookie) => new WrappedStringCustomMarshaler();
+}
+
+// Use an ifdef here to give us two separate public API surfaces to call while allowing us to have the same implementation code
+// as well as allowing us to share the custom marshaler implementations above.
+// If we wanted to add more tests here, we would want to put the public API surface in the namespace and the private
+// details and marshalers in the global scope as done above.
+#if CUSTOMMARSHALERS2
+namespace CustomMarshalers2
+#else
+namespace CustomMarshalers
+#endif
+{
+    public class CustomMarshalerTest
+    {
+        [DllImport("CustomMarshalerNative", CharSet = CharSet.Ansi)]
+        private static extern int NativeParseInt([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(WrappedStringCustomMarshaler))] WrappedString str);
+
+        public int ParseInt(string str)
+        {
+            return NativeParseInt(new WrappedString(str));
+        }
+    }
+}
+
diff --git a/tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshaler.csproj b/tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshaler.csproj
new file mode 100644 (file)
index 0000000..e04f27f
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Interop.settings.targets))\Interop.settings.targets" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <OutputType>library</OutputType>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="CustomMarshaler.cs" />
+  </ItemGroup>
+  <ItemGroup>
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshaler2.csproj b/tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshaler2.csproj
new file mode 100644 (file)
index 0000000..38c0cba
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Interop.settings.targets))\Interop.settings.targets" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <OutputType>library</OutputType>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+    <DefineConstants>$(DefineConstants);CUSTOMMARSHALERS2</DefineConstants>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="CustomMarshaler.cs" />
+  </ItemGroup>
+  <ItemGroup>
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshalerNative.cpp b/tests/src/Interop/ICustomMarshaler/ConflictingNames/CustomMarshalerNative.cpp
new file mode 100644 (file)
index 0000000..11aee80
--- /dev/null
@@ -0,0 +1,12 @@
+// 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.
+
+#include <stdlib.h>
+#include <xplatform.h>
+
+
+extern "C" int DLL_EXPORT STDMETHODCALLTYPE NativeParseInt(LPCSTR str)
+{
+    return atoi(str);
+}
diff --git a/tests/src/Interop/ICustomMarshaler/ConflictingNames/MultipleALCs.csproj b/tests/src/Interop/ICustomMarshaler/ConflictingNames/MultipleALCs.csproj
new file mode 100644 (file)
index 0000000..045a2b6
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <Import Project="../../Interop.settings.targets" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="RunInALC.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="CMakeLists.txt" />
+    <ProjectReference Include="CustomMarshaler.csproj" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+  <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>
diff --git a/tests/src/Interop/ICustomMarshaler/ConflictingNames/RunInALC.cs b/tests/src/Interop/ICustomMarshaler/ConflictingNames/RunInALC.cs
new file mode 100644 (file)
index 0000000..1d61f2d
--- /dev/null
@@ -0,0 +1,72 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Loader;
+using TestLibrary;
+
+public class RunInALC
+{
+    public static int Main(string[] args)
+    {
+        try
+        {
+            ConflictingCustomMarshalerNamesInCollectibleLoadContexts_Succeeds();
+            ConflictingCustomMarshalerNamesInNoncollectibleLoadContexts_Succeeds();
+        }
+        catch (System.Exception e)
+        {
+            Console.WriteLine(e.ToString());
+            return 101;
+        }
+        return 100;
+    }
+
+    static void ConflictingCustomMarshalerNamesInCollectibleLoadContexts_Succeeds()
+    {
+        Run(new UnloadableLoadContext());
+        Run(new UnloadableLoadContext());
+    }
+
+    static void ConflictingCustomMarshalerNamesInNoncollectibleLoadContexts_Succeeds()
+    {
+        Run(new CustomLoadContext());
+        Run(new CustomLoadContext());
+    }
+
+    static void Run(AssemblyLoadContext context)
+    {
+        string currentAssemblyDirectory = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).AbsolutePath);
+        Assembly inContextAssembly = context.LoadFromAssemblyPath(Path.Combine(currentAssemblyDirectory, "CustomMarshaler.dll"));
+        Type inContextType = inContextAssembly.GetType("CustomMarshalers.CustomMarshalerTest");
+        object instance = Activator.CreateInstance(inContextType);
+        MethodInfo parseIntMethod = inContextType.GetMethod("ParseInt", BindingFlags.Instance | BindingFlags.Public);
+        Assert.AreEqual(1234, (int)parseIntMethod.Invoke(instance, new object[]{"1234"}));
+    }
+}
+
+class UnloadableLoadContext : AssemblyLoadContext
+{
+    public UnloadableLoadContext()
+        :base(true)
+    {
+        
+    }
+
+    protected override Assembly Load(AssemblyName assemblyName)
+    {
+        return null;
+    }
+}
+
+class CustomLoadContext : AssemblyLoadContext
+{
+    protected override Assembly Load(AssemblyName assemblyName)
+    {
+        return null;
+    }
+}
diff --git a/tests/src/Interop/ICustomMarshaler/ConflictingNames/SameNameDifferentAssembly.cs b/tests/src/Interop/ICustomMarshaler/ConflictingNames/SameNameDifferentAssembly.cs
new file mode 100644 (file)
index 0000000..ce91134
--- /dev/null
@@ -0,0 +1,28 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.Loader;
+using TestLibrary;
+
+public class RunInALC
+{
+    public static int Main(string[] args)
+    {
+        try
+        {
+            Assert.AreEqual(123, new CustomMarshalers.CustomMarshalerTest().ParseInt("123"));
+            Assert.AreEqual(123, new CustomMarshalers2.CustomMarshalerTest().ParseInt("123"));
+            return 100;
+        }
+        catch (Exception e)
+        {
+            Console.WriteLine(e);
+            return 101;
+        }
+    }
+}
diff --git a/tests/src/Interop/ICustomMarshaler/ConflictingNames/SameNameDifferentAssembly.csproj b/tests/src/Interop/ICustomMarshaler/ConflictingNames/SameNameDifferentAssembly.csproj
new file mode 100644 (file)
index 0000000..6b1f7df
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <Import Project="../../Interop.settings.targets" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="SameNameDifferentAssembly.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="CMakeLists.txt" />
+    <ProjectReference Include="CustomMarshaler.csproj" />
+    <ProjectReference Include="CustomMarshaler2.csproj" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
     </CodeAnalysisDependentAssemblyPaths>
   </ItemGroup>
   <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
-  </ItemGroup>
-  <ItemGroup>
     <Compile Include="ICustomMarshaler.cs" />
-    <Compile Include="..\common\XunitBase.cs" />
+    <Compile Include="..\..\common\XunitBase.cs" />
   </ItemGroup>
   <ItemGroup>
   </ItemGroup>