summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGaurav Khanna <gkhanna@microsoft.com>2016-01-21 16:18:42 -0800
committerGaurav Khanna <gkhanna@microsoft.com>2016-01-21 16:18:42 -0800
commit237ce93fd240e6f0c18a45b2f740bb2a7ab417fc (patch)
tree0dae8daf915734501b7bfd7bb7fbcb1dd979e698
parent2fe9dc9dc33b62ae7eeca1e0578955cd481721c4 (diff)
parent7e1a3b532dc2fb2eab2d41994c971759243def19 (diff)
downloadcoreclr-237ce93fd240e6f0c18a45b2f740bb2a7ab417fc.tar.gz
coreclr-237ce93fd240e6f0c18a45b2f740bb2a7ab417fc.tar.bz2
coreclr-237ce93fd240e6f0c18a45b2f740bb2a7ab417fc.zip
Merge pull request #2696 from gkhanna79/AssemblyResolve
AssemblyResolve support
-rw-r--r--src/binder/assemblybinder.cpp12
-rw-r--r--src/binder/clrprivbinderassemblyloadcontext.cpp2
-rw-r--r--src/binder/clrprivbindercoreclr.cpp36
-rw-r--r--src/binder/inc/assemblybinder.hpp2
-rw-r--r--src/binder/inc/clrprivbindercoreclr.h4
-rw-r--r--src/mscorlib/model.xml1
-rw-r--r--src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs38
-rw-r--r--src/vm/appdomain.cpp7
-rw-r--r--src/vm/assemblynative.cpp4
9 files changed, 85 insertions, 21 deletions
diff --git a/src/binder/assemblybinder.cpp b/src/binder/assemblybinder.cpp
index 46f393b95e..139a66cbe8 100644
--- a/src/binder/assemblybinder.cpp
+++ b/src/binder/assemblybinder.cpp
@@ -56,7 +56,7 @@ extern BOOL RuntimeIsLegacyNetCF(DWORD adid);
#include "clrprivbindercoreclr.h"
#include "clrprivbinderassemblyloadcontext.h"
// Helper function in the VM, invoked by the Binder, to invoke the host assembly resolver
-extern HRESULT RuntimeInvokeHostAssemblyResolver(CLRPrivBinderAssemblyLoadContext *pLoadContextToBindWithin, IAssemblyName *pIAssemblyName, ICLRPrivAssembly **ppLoadedAssembly);
+extern HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, IAssemblyName *pIAssemblyName, ICLRPrivAssembly **ppLoadedAssembly);
// Helper to check if we have a host assembly resolver set
extern BOOL RuntimeCanUseAppPathAssemblyResolver(DWORD adid);
@@ -1856,7 +1856,7 @@ namespace BINDER_SPACE
#endif //CROSSGEN_COMPILE
#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) && !defined(MDILNIGEN)
-HRESULT AssemblyBinder::BindUsingHostAssemblyResolver (/* in */ CLRPrivBinderAssemblyLoadContext *pLoadContextToBindWithin,
+HRESULT AssemblyBinder::BindUsingHostAssemblyResolver (/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin,
/* in */ AssemblyName *pAssemblyName,
/* in */ IAssemblyName *pIAssemblyName,
/* out */ Assembly **ppAssembly)
@@ -1864,15 +1864,11 @@ HRESULT AssemblyBinder::BindUsingHostAssemblyResolver (/* in */ CLRPrivBinderAss
HRESULT hr = E_FAIL;
BINDER_LOG_ENTER(W("AssemblyBinder::BindUsingHostAssemblyResolver"));
- _ASSERTE(pLoadContextToBindWithin != NULL);
-
- // Get the application context within which the assembly will be bound and loaded
- ApplicationContext *pApplicationContext = pLoadContextToBindWithin->GetAppContext();
- _ASSERTE(pApplicationContext != NULL);
+ _ASSERTE(pManagedAssemblyLoadContextToBindWithin != NULL);
// Call into the VM to use the HostAssemblyResolver and load the assembly
ICLRPrivAssembly *pLoadedAssembly = NULL;
- hr = RuntimeInvokeHostAssemblyResolver(pLoadContextToBindWithin, pIAssemblyName, &pLoadedAssembly);
+ hr = RuntimeInvokeHostAssemblyResolver(pManagedAssemblyLoadContextToBindWithin, pIAssemblyName, &pLoadedAssembly);
if (SUCCEEDED(hr))
{
_ASSERTE(pLoadedAssembly != NULL);
diff --git a/src/binder/clrprivbinderassemblyloadcontext.cpp b/src/binder/clrprivbinderassemblyloadcontext.cpp
index f2ed7e1f6d..344801a081 100644
--- a/src/binder/clrprivbinderassemblyloadcontext.cpp
+++ b/src/binder/clrprivbinderassemblyloadcontext.cpp
@@ -83,7 +83,7 @@ HRESULT CLRPrivBinderAssemblyLoadContext::BindAssemblyByName(IAssemblyName *
// Thus, if default binder has been overridden, then invoke it in an attempt to perform the binding for it make the call
// 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(this, pAssemblyName, pIAssemblyName, &pCoreCLRFoundAssembly);
+ hr = AssemblyBinder::BindUsingHostAssemblyResolver(GetManagedAssemblyLoadContext(), pAssemblyName, pIAssemblyName, &pCoreCLRFoundAssembly);
if (SUCCEEDED(hr))
{
// We maybe returned an assembly that was bound to a different AssemblyLoadContext instance.
diff --git a/src/binder/clrprivbindercoreclr.cpp b/src/binder/clrprivbindercoreclr.cpp
index 238c5225cf..4958875bf5 100644
--- a/src/binder/clrprivbindercoreclr.cpp
+++ b/src/binder/clrprivbindercoreclr.cpp
@@ -62,8 +62,42 @@ HRESULT CLRPrivBinderCoreCLR::BindAssemblyByName(IAssemblyName *pIAssemblyNa
IF_FAIL_GO(pAssemblyName->Init(pIAssemblyName));
hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly, false /* excludeAppPaths */);
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) && !defined(MDILNIGEN)
+ if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) ||
+ (hr == FUSION_E_APP_DOMAIN_LOCKED) || (hr == FUSION_E_REF_DEF_MISMATCH))
+ {
+ // If we are here, one of the following is possible:
+ //
+ // 1) The assembly has not been found in the current binder's application context (i.e. it has not already been loaded), OR
+ // 2) An assembly with the same simple name was already loaded in the context of the current binder but we ran into a Ref/Def
+ // mismatch (either due to version difference or strong-name difference).
+ //
+ // Thus, if default binder has been overridden, then invoke it in an attempt to perform the binding for it make the call
+ // 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.
+
+ // Attempt to resolve the assembly via managed TPA ALC instance if one exists
+ INT_PTR pManagedAssemblyLoadContext = GetManagedAssemblyLoadContext();
+ if (pManagedAssemblyLoadContext != NULL)
+ {
+ hr = AssemblyBinder::BindUsingHostAssemblyResolver(pManagedAssemblyLoadContext, pAssemblyName, pIAssemblyName, &pCoreCLRFoundAssembly);
+ if (SUCCEEDED(hr))
+ {
+ // We maybe returned an assembly that was bound to a different AssemblyLoadContext instance.
+ // In such a case, we will not overwrite the binding context (which would be wrong since it would not
+ // be present in the cache of the current binding context).
+ if (pCoreCLRFoundAssembly->GetBinder() == NULL)
+ {
+ pCoreCLRFoundAssembly->SetBinder(this);
+ }
+ }
+ }
+ }
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) && !defined(MDILNIGEN)
+
IF_FAIL_GO(hr);
-
+
*ppAssembly = pCoreCLRFoundAssembly.Extract();
Exit:;
diff --git a/src/binder/inc/assemblybinder.hpp b/src/binder/inc/assemblybinder.hpp
index 4ca0c4f18c..bfe851d8e9 100644
--- a/src/binder/inc/assemblybinder.hpp
+++ b/src/binder/inc/assemblybinder.hpp
@@ -76,7 +76,7 @@ namespace BINDER_SPACE
/* in */ LPCTSTR szMDAssemblyPath = NULL);
#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE) && !defined(MDILNIGEN)
- static HRESULT BindUsingHostAssemblyResolver (/* in */ CLRPrivBinderAssemblyLoadContext *pLoadContextToBindWithin,
+ static HRESULT BindUsingHostAssemblyResolver (/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin,
/* in */ AssemblyName *pAssemblyName,
/* in */ IAssemblyName *pIAssemblyName,
/* out */ Assembly **ppAssembly);
diff --git a/src/binder/inc/clrprivbindercoreclr.h b/src/binder/inc/clrprivbindercoreclr.h
index 4d98c9b55a..ce545561f2 100644
--- a/src/binder/inc/clrprivbindercoreclr.h
+++ b/src/binder/inc/clrprivbindercoreclr.h
@@ -79,12 +79,12 @@ public:
BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly,
bool excludeAppPaths);
- INT_PTR GetManagedTPABinderInstance()
+ INT_PTR GetManagedAssemblyLoadContext()
{
return m_ptrManagedAssemblyLoadContext;
}
- void SetManagedTPABinderInstance(INT_PTR ptrManagedTPABinderInstance)
+ void SetManagedAssemblyLoadContext(INT_PTR ptrManagedTPABinderInstance)
{
_ASSERTE(m_ptrManagedAssemblyLoadContext == NULL);
diff --git a/src/mscorlib/model.xml b/src/mscorlib/model.xml
index 1628cc24fa..8397d355e4 100644
--- a/src/mscorlib/model.xml
+++ b/src/mscorlib/model.xml
@@ -1023,6 +1023,7 @@
<Member Name="get_Default" />
<Member Name="SetProfileOptimizationRoot(System.String)" />
<Member Name="StartProfileOptimization(System.String)" />
+ <Member MemberType="Event" Name="Resolving" />
</Type>
<Type Name="System.Reflection.Metadata.AssemblyExtensions">
<Member Name="TryGetRawMetadata(System.Reflection.Assembly,System.Byte*@,System.Int32@)"/>
diff --git a/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs b/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs
index c3cdd810e1..c44365e1ff 100644
--- a/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs
+++ b/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs
@@ -64,6 +64,9 @@ namespace System.Runtime.Loader
GCHandle gchALC = GCHandle.Alloc(this);
IntPtr ptrALC = GCHandle.ToIntPtr(gchALC);
m_pNativeAssemblyLoadContext = InitializeAssemblyLoadContext(ptrALC, fRepresentsTPALoadContext);
+
+ // Initialize the resolve event handler to be null by default
+ Resolving = null;
}
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
@@ -177,6 +180,29 @@ namespace System.Runtime.Loader
return context.LoadFromAssemblyName(assemblyName);
}
+ private Assembly GetFirstResolvedAssembly(AssemblyName assemblyName)
+ {
+ Assembly resolvedAssembly = null;
+
+ Func<AssemblyLoadContext, AssemblyName, Assembly> assemblyResolveHandler = Resolving;
+
+ if (assemblyResolveHandler != null)
+ {
+ // Loop through the event subscribers and return the first non-null Assembly instance
+ Delegate [] arrSubscribers = assemblyResolveHandler.GetInvocationList();
+ for(int i = 0; i < arrSubscribers.Length; i++)
+ {
+ resolvedAssembly = ((Func<AssemblyLoadContext, AssemblyName, Assembly>)arrSubscribers[i])(this, assemblyName);
+ if (resolvedAssembly != null)
+ {
+ break;
+ }
+ }
+ }
+
+ return resolvedAssembly;
+ }
+
public Assembly LoadFromAssemblyName(AssemblyName assemblyName)
{
// AssemblyName is mutable. Cache the expected name before anybody gets a chance to modify it.
@@ -185,6 +211,12 @@ namespace System.Runtime.Loader
Assembly assembly = Load(assemblyName);
if (assembly == null)
{
+ // Invoke the AssemblyResolve event callbacks if wired up
+ assembly = GetFirstResolvedAssembly(assemblyName);
+ }
+
+ if (assembly == null)
+ {
throw new FileNotFoundException(Environment.GetResourceString("IO.FileLoad"), requestedSimpleName);
}
@@ -355,6 +387,8 @@ namespace System.Runtime.Loader
#endif // FEATURE_MULTICOREJI
}
+ public event Func<AssemblyLoadContext, AssemblyName, Assembly> Resolving;
+
// Contains the reference to VM's representation of the AssemblyLoadContext
private IntPtr m_pNativeAssemblyLoadContext;
@@ -374,7 +408,9 @@ namespace System.Runtime.Loader
[System.Security.SecuritySafeCritical]
protected override Assembly Load(AssemblyName assemblyName)
{
- return Assembly.Load(assemblyName);
+ // We were loading an assembly into TPA ALC that was not found on TPA list. As a result we are here.
+ // Returning null will result in the AssemblyResolve event subscribers to be invoked to help resolve the assembly.
+ return null;
}
}
}
diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp
index 997363e7e9..dd7406c916 100644
--- a/src/vm/appdomain.cpp
+++ b/src/vm/appdomain.cpp
@@ -14227,7 +14227,7 @@ BOOL RuntimeCanUseAppPathAssemblyResolver(DWORD adid)
}
// Returns S_OK if the assembly was successfully loaded
-HRESULT RuntimeInvokeHostAssemblyResolver(CLRPrivBinderAssemblyLoadContext *pLoadContextToBindWithin, IAssemblyName *pIAssemblyName, ICLRPrivAssembly **ppLoadedAssembly)
+HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, IAssemblyName *pIAssemblyName, ICLRPrivAssembly **ppLoadedAssembly)
{
CONTRACTL
{
@@ -14256,9 +14256,6 @@ HRESULT RuntimeInvokeHostAssemblyResolver(CLRPrivBinderAssemblyLoadContext *pLoa
GCPROTECT_BEGIN(_gcRefs);
- // Get the pointer to the managed assembly load context
- INT_PTR ptrManagedAssemblyLoadContext = pLoadContextToBindWithin->GetManagedAssemblyLoadContext();
-
// Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.Resolve method.
//
// First, initialize an assembly spec for the requested assembly
@@ -14280,7 +14277,7 @@ HRESULT RuntimeInvokeHostAssemblyResolver(CLRPrivBinderAssemblyLoadContext *pLoa
// Setup the arguments for the call
ARG_SLOT args[2] =
{
- PtrToArgSlot(ptrManagedAssemblyLoadContext), // IntPtr for managed assembly load context instance
+ PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance
ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance
};
diff --git a/src/vm/assemblynative.cpp b/src/vm/assemblynative.cpp
index 70bccccf76..c96923ded6 100644
--- a/src/vm/assemblynative.cpp
+++ b/src/vm/assemblynative.cpp
@@ -2533,14 +2533,14 @@ INT_PTR QCALLTYPE AssemblyNative::InitializeAssemblyLoadContext(INT_PTR ptrManag
{
// We are initializing the managed instance of Assembly Load Context that would represent the TPA binder.
// First, confirm we do not have an existing managed ALC attached to the TPA binder.
- INT_PTR ptrTPAAssemblyLoadContext = pTPABinderContext->GetManagedTPABinderInstance();
+ INT_PTR ptrTPAAssemblyLoadContext = pTPABinderContext->GetManagedAssemblyLoadContext();
if ((ptrTPAAssemblyLoadContext != NULL) && (ptrTPAAssemblyLoadContext != ptrManagedAssemblyLoadContext))
{
COMPlusThrow(kInvalidOperationException, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_TPA_BINDING_CONTEXT);
}
// Attach the managed TPA binding context with the native one.
- pTPABinderContext->SetManagedTPABinderInstance(ptrManagedAssemblyLoadContext);
+ pTPABinderContext->SetManagedAssemblyLoadContext(ptrManagedAssemblyLoadContext);
ptrNativeAssemblyLoadContext = reinterpret_cast<INT_PTR>(pTPABinderContext);
}