extern HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin,
BINDER_SPACE::AssemblyName *pAssemblyName,
CLRPrivBinderCoreCLR *pTPABinder,
+ AssemblyLoadContext *pBinder,
ICLRPrivAssembly **ppLoadedAssembly);
#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
HRESULT AssemblyBinder::BindUsingHostAssemblyResolver(/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin,
/* in */ AssemblyName *pAssemblyName,
/* in */ CLRPrivBinderCoreCLR *pTPABinder,
+ /* in */ AssemblyLoadContext *pBinder,
/* out */ Assembly **ppAssembly)
{
HRESULT hr = E_FAIL;
// RuntimeInvokeHostAssemblyResolver will perform steps 2-4 of CLRPrivBinderAssemblyLoadContext::BindAssemblyByName.
ICLRPrivAssembly *pLoadedAssembly = NULL;
hr = RuntimeInvokeHostAssemblyResolver(pManagedAssemblyLoadContextToBindWithin,
- pAssemblyName, pTPABinder, &pLoadedAssembly);
+ pAssemblyName, pTPABinder, pBinder, &pLoadedAssembly);
if (SUCCEEDED(hr))
{
_ASSERTE(pLoadedAssembly != NULL);
// of what to do next. The host-overridden binder can either fail the bind or return reference to an existing assembly
// that has been loaded.
//
- hr = AssemblyBinder::BindUsingHostAssemblyResolver(GetManagedAssemblyLoadContext(), pAssemblyName, m_pTPABinder, &pCoreCLRFoundAssembly);
+ hr = AssemblyBinder::BindUsingHostAssemblyResolver(GetManagedAssemblyLoadContext(), pAssemblyName, m_pTPABinder, this, &pCoreCLRFoundAssembly);
if (SUCCEEDED(hr))
{
// We maybe returned an assembly that was bound to a different AssemblyLoadContext instance.
_ASSERTE(m_pAssemblyLoaderAllocator != NULL);
_ASSERTE(m_loaderAllocatorHandle != NULL);
- // We cannot delete the binder here as it is used indirectly when comparing assemblies with the same binder
- // It will be deleted when the LoaderAllocator will be deleted
- // But we can release the LoaderAllocator as we are no longer using it here
+ // We need to keep the LoaderAllocator pointer set as it still may be needed for creating references between the
+ // native LoaderAllocators of two collectible contexts in case the AssemblyLoadContext.Unload was called on the current
+ // context before returning from its AssemblyLoadContext.Load override or the context's Resolving event.
+ // But we need to release the LoaderAllocator so that it doesn't prevent completion of the final phase of unloading in
+ // some cases. It is safe to do as the AssemblyLoaderAllocator is guaranteed to be alive at least until the
+ // CustomAssemblyBinder::ReleaseLoadContext is called, where we NULL this pointer.
m_pAssemblyLoaderAllocator->Release();
- m_pAssemblyLoaderAllocator = NULL;
// Destroy the strong handle to the LoaderAllocator in order to let it reach its finalizer
DestroyHandle(reinterpret_cast<OBJECTHANDLE>(m_loaderAllocatorHandle));
handle = reinterpret_cast<OBJECTHANDLE>(m_ptrManagedStrongAssemblyLoadContext);
DestroyHandle(handle);
m_ptrManagedAssemblyLoadContext = NULL;
+
+ // The AssemblyLoaderAllocator is in a process of shutdown and should not be used
+ // after this point.
+ m_pAssemblyLoaderAllocator = NULL;
}
#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
if (pManagedAssemblyLoadContext != NULL)
{
hr = AssemblyBinder::BindUsingHostAssemblyResolver(pManagedAssemblyLoadContext, pAssemblyName,
- NULL, &pCoreCLRFoundAssembly);
+ NULL, this, &pCoreCLRFoundAssembly);
if (SUCCEEDED(hr))
{
// We maybe returned an assembly that was bound to a different AssemblyLoadContext instance.
class CLRPrivBinderCoreCLR;
class PEAssembly;
class PEImage;
+class AssemblyLoadContext;
namespace BINDER_SPACE
{
static HRESULT BindUsingHostAssemblyResolver (/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin,
/* in */ AssemblyName *pAssemblyName,
/* in */ CLRPrivBinderCoreCLR *pTPABinder,
+ /* in */ AssemblyLoadContext *pBinder,
/* out */ Assembly **ppAssembly);
static HRESULT BindUsingPEImage(/* in */ ApplicationContext *pApplicationContext,
#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
// Returns S_OK if the assembly was successfully loaded
-HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, BINDER_SPACE::AssemblyName *pAssemblyName, CLRPrivBinderCoreCLR *pTPABinder, ICLRPrivAssembly **ppLoadedAssembly)
+HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, BINDER_SPACE::AssemblyName *pAssemblyName, CLRPrivBinderCoreCLR *pTPABinder, AssemblyLoadContext *pBinder, ICLRPrivAssembly **ppLoadedAssembly)
{
CONTRACTL
{
COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_DYNAMICALLY_EMITTED_ASSEMBLIES_UNSUPPORTED, name);
}
+ // For collectible assemblies, ensure that the parent loader allocator keeps the assembly's loader allocator
+ // alive for all its lifetime.
+ if (pDomainAssembly->IsCollectible())
+ {
+ LoaderAllocator *pResultAssemblyLoaderAllocator = pDomainAssembly->GetLoaderAllocator();
+ LoaderAllocator *pParentLoaderAllocator = NULL;
+ hr = pBinder->GetLoaderAllocator((LPVOID*)&pParentLoaderAllocator);
+ if (SUCCEEDED(hr))
+ {
+ _ASSERTE(pParentLoaderAllocator);
+ _ASSERTE(pResultAssemblyLoaderAllocator);
+ pParentLoaderAllocator->EnsureReference(pResultAssemblyLoaderAllocator);
+ }
+ }
+
pResolvedAssembly = pLoadedPEAssembly->GetHostAssembly();
}
#endif //0
AppDomain::AssemblyIterator i;
- // Iterate through every loader allocator, marking as we go
{
+ // Iterate through every loader allocator, marking as we go
+ CrstHolder chLoaderAllocatorReferencesLock(pAppDomain->GetLoaderAllocatorReferencesLock());
CrstHolder chAssemblyListLock(pAppDomain->GetAssemblyListLock());
i = pAppDomain->IterateAssembliesEx((AssemblyIterationFlags)(
}
}
}
- }
-
- // Iterate through every loader allocator, unmarking marked loaderallocators, and
- // build a free list of unmarked ones
- {
- CrstHolder chLoaderAllocatorReferencesLock(pAppDomain->GetLoaderAllocatorReferencesLock());
- CrstHolder chAssemblyListLock(pAppDomain->GetAssemblyListLock());
+ // Iterate through every loader allocator, unmarking marked loaderallocators, and
+ // build a free list of unmarked ones
i = pAppDomain->IterateAssembliesEx((AssemblyIterationFlags)(
kIncludeExecution | kIncludeLoaded | kIncludeCollected));
- CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
while (i.Next_Unlocked(pDomainAssembly.This()))
{