diff options
-rw-r--r-- | src/mscorlib/src/System/Reflection/Assembly.cs | 35 | ||||
-rw-r--r-- | src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs | 17 | ||||
-rw-r--r-- | src/vm/appdomain.cpp | 61 | ||||
-rw-r--r-- | src/vm/assemblynative.cpp | 18 | ||||
-rw-r--r-- | src/vm/assemblynative.hpp | 5 | ||||
-rw-r--r-- | src/vm/assemblyspec.cpp | 17 | ||||
-rw-r--r-- | src/vm/assemblyspec.hpp | 24 |
7 files changed, 117 insertions, 60 deletions
diff --git a/src/mscorlib/src/System/Reflection/Assembly.cs b/src/mscorlib/src/System/Reflection/Assembly.cs index b28f8681fc..62ae9b49f6 100644 --- a/src/mscorlib/src/System/Reflection/Assembly.cs +++ b/src/mscorlib/src/System/Reflection/Assembly.cs @@ -327,6 +327,22 @@ namespace System.Reflection Contract.Ensures(Contract.Result<Assembly>() != null); Contract.Ensures(!Contract.Result<Assembly>().ReflectionOnly); + return Load(assemblyRef, IntPtr.Zero); + } + + // Locate an assembly by its name. The name can be strong or + // weak. The assembly is loaded into the domain of the caller. +#if FEATURE_CORECLR + [System.Security.SecurityCritical] // auto-generated +#else + [System.Security.SecuritySafeCritical] +#endif + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable + internal static Assembly Load(AssemblyName assemblyRef, IntPtr ptrLoadContextBinder) + { + Contract.Ensures(Contract.Result<Assembly>() != null); + Contract.Ensures(!Contract.Result<Assembly>().ReflectionOnly); + #if FEATURE_WINDOWSPHONE if (assemblyRef != null && assemblyRef.CodeBase != null) { @@ -335,7 +351,7 @@ namespace System.Reflection #endif StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller; - return RuntimeAssembly.InternalLoadAssemblyName(assemblyRef, null, null, ref stackMark, true /*thrownOnFileNotFound*/, false /*forIntrospection*/, false /*suppressSecurityChecks*/); + return RuntimeAssembly.InternalLoadAssemblyName(assemblyRef, null, null, ref stackMark, true /*thrownOnFileNotFound*/, false /*forIntrospection*/, false /*suppressSecurityChecks*/, ptrLoadContextBinder); } [System.Security.SecuritySafeCritical] // auto-generated @@ -1663,9 +1679,10 @@ namespace System.Reflection ref StackCrawlMark stackMark, bool throwOnFileNotFound, bool forIntrospection, - bool suppressSecurityChecks) + bool suppressSecurityChecks, + IntPtr ptrLoadContextBinder = default(IntPtr)) { - return InternalLoadAssemblyName(assemblyRef, assemblySecurity, reqAssembly, ref stackMark, IntPtr.Zero, true /*throwOnError*/, forIntrospection, suppressSecurityChecks); + return InternalLoadAssemblyName(assemblyRef, assemblySecurity, reqAssembly, ref stackMark, IntPtr.Zero, true /*throwOnError*/, forIntrospection, suppressSecurityChecks, ptrLoadContextBinder); } [System.Security.SecurityCritical] // auto-generated @@ -1677,7 +1694,8 @@ namespace System.Reflection IntPtr pPrivHostBinder, bool throwOnFileNotFound, bool forIntrospection, - bool suppressSecurityChecks) + bool suppressSecurityChecks, + IntPtr ptrLoadContextBinder = default(IntPtr)) { if (assemblyRef == null) @@ -1735,7 +1753,7 @@ namespace System.Reflection return nLoad(assemblyRef, codeBase, assemblySecurity, reqAssembly, ref stackMark, pPrivHostBinder, - throwOnFileNotFound, forIntrospection, suppressSecurityChecks); + throwOnFileNotFound, forIntrospection, suppressSecurityChecks, ptrLoadContextBinder); } // These are the framework assemblies that does reflection invocation @@ -1785,7 +1803,8 @@ namespace System.Reflection IntPtr pPrivHostBinder, bool throwOnFileNotFound, bool forIntrospection, - bool suppressSecurityChecks); + bool suppressSecurityChecks, + IntPtr ptrLoadContextBinder); #if !FEATURE_CORECLR // The NGEN task uses this method, so please do not modify its signature @@ -1807,11 +1826,11 @@ namespace System.Reflection IntPtr pPrivHostBinder, bool throwOnFileNotFound, bool forIntrospection, - bool suppressSecurityChecks) + bool suppressSecurityChecks, IntPtr ptrLoadContextBinder = default(IntPtr)) { return _nLoad(fileName, codeBase, assemblySecurity, locationHint, ref stackMark, pPrivHostBinder, - throwOnFileNotFound, forIntrospection, suppressSecurityChecks); + throwOnFileNotFound, forIntrospection, suppressSecurityChecks, ptrLoadContextBinder); } #if FEATURE_FUSION diff --git a/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs b/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs index c4872e363b..75529868bd 100644 --- a/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs +++ b/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs @@ -31,6 +31,10 @@ namespace System.Runtime.Loader [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] [SuppressUnmanagedCodeSecurity] private static extern IntPtr InitializeAssemblyLoadContext(IntPtr ptrAssemblyLoadContext, bool fRepresentsTPALoadContext); + + [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] + [SuppressUnmanagedCodeSecurity] + private static extern IntPtr LoadFromAssemblyName(IntPtr ptrNativeAssemblyLoadContext, bool fRepresentsTPALoadContext); [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] [SuppressUnmanagedCodeSecurity] @@ -271,17 +275,10 @@ namespace System.Runtime.Loader public Assembly LoadFromAssemblyName(AssemblyName assemblyName) { - // AssemblyName is mutable. Cache the expected name before anybody gets a chance to modify it. - string requestedSimpleName = assemblyName.Name; - - Assembly assembly = ResolveUsingLoad(assemblyName); - if (assembly == null) - { - // Invoke the AssemblyResolve event callbacks if wired up - assembly = ResolveUsingEvent(assemblyName); - } + // Attempt to load the assembly, using the same ordering as static load, in the current load context. + Assembly loadedAssembly = Assembly.Load(assemblyName, m_pNativeAssemblyLoadContext); - return assembly; + return loadedAssembly; } [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp index 4580c5aff5..0ec2c5f2fc 100644 --- a/src/vm/appdomain.cpp +++ b/src/vm/appdomain.cpp @@ -14241,6 +14241,8 @@ HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToB GCPROTECT_BEGIN(_gcRefs); ICLRPrivAssembly *pAssemblyBindingContext = NULL; + + bool fInvokedForTPABinder = (pTPABinder == NULL)?true:false; // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.Resolve method. // @@ -14250,47 +14252,48 @@ HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToB hr = spec.Init(pIAssemblyName); if (SUCCEEDED(hr)) { - // Step 2 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName) - Invoke Load method - // + bool fResolvedAssembly = false; + bool fResolvedAssemblyViaTPALoadContext = false; + // Allocate an AssemblyName managed object _gcRefs.oRefAssemblyName = (ASSEMBLYNAMEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME)); // Initialize the AssemblyName object from the AssemblySpec spec.AssemblyNameInit(&_gcRefs.oRefAssemblyName, NULL); - - // Finally, setup arguments for invocation - BinderMethodID idHAR_Resolve = METHOD__ASSEMBLYLOADCONTEXT__RESOLVE; - MethodDescCallSite methLoadAssembly(idHAR_Resolve); - - // Setup the arguments for the call - ARG_SLOT args[2] = + + if (!fInvokedForTPABinder) { - PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance - ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance - }; + // Step 2 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName) - Invoke Load method + // This is not invoked for TPA Binder since it always returns NULL. - bool fResolvedAssembly = true; - bool fResolvedAssemblyViaTPALoadContext = false; - - // Make the call - _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args); - if (_gcRefs.oRefLoadedAssembly == NULL) - { - fResolvedAssembly = false; - } + // Finally, setup arguments for invocation + BinderMethodID idHAR_Resolve = METHOD__ASSEMBLYLOADCONTEXT__RESOLVE; + MethodDescCallSite methLoadAssembly(idHAR_Resolve); + + // Setup the arguments for the call + ARG_SLOT args[2] = + { + PtrToArgSlot(pManagedAssemblyLoadContextToBindWithin), // IntPtr for managed assembly load context instance + ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance + }; + + // Make the call + _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args); + if (_gcRefs.oRefLoadedAssembly != NULL) + { + fResolvedAssembly = true; + } - if (!fResolvedAssembly) - { // Step 3 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName) - // - // If we could not resolve the assembly using Load method, then bind using TPA binder if present in its - // load context. - if (pTPABinder != NULL) + if (!fResolvedAssembly) { + // If we could not resolve the assembly using Load method, then attempt fallback with TPA Binder. + // Since TPA binder cannot fallback to itself, this fallback does not happen for binds within TPA binder. + // // Switch to pre-emp mode before calling into the binder GCX_PREEMP(); - BINDER_SPACE::Assembly *pCoreCLRFoundAssembly = NULL; - hr = pTPABinder->BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly, true /* excludeAppPaths */); + ICLRPrivAssembly *pCoreCLRFoundAssembly = NULL; + hr = pTPABinder->BindAssemblyByName(pIAssemblyName, &pCoreCLRFoundAssembly); if (SUCCEEDED(hr)) { pAssemblyBindingContext = pCoreCLRFoundAssembly; diff --git a/src/vm/assemblynative.cpp b/src/vm/assemblynative.cpp index 29e0a451f0..90c58fc59c 100644 --- a/src/vm/assemblynative.cpp +++ b/src/vm/assemblynative.cpp @@ -137,7 +137,7 @@ FCIMPL1(FC_BOOL_RET, AssemblyNative::IsNewPortableAssembly, AssemblyNameBaseObje FCIMPLEND #endif // FEATURE_FUSION -FCIMPL9(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAFE, +FCIMPL10(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAFE, StringObject* codeBaseUNSAFE, Object* securityUNSAFE, AssemblyBaseObject* requestingAssemblyUNSAFE, @@ -145,7 +145,8 @@ FCIMPL9(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAF ICLRPrivBinder * pPrivHostBinder, CLR_BOOL fThrowOnFileNotFound, CLR_BOOL fForIntrospection, - CLR_BOOL fSuppressSecurityChecks) + CLR_BOOL fSuppressSecurityChecks, + INT_PTR ptrLoadContextBinder) { FCALL_CONTRACT; @@ -243,10 +244,17 @@ FCIMPL9(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAF spec.SetParentAssembly(pParentAssembly); #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) - // If the requesting assembly has Fallback LoadContext binder available, - // then set it up in the AssemblySpec. - if (pRefAssembly != NULL) + // Have we been passed the reference to the binder against which this load should be triggered? + // If so, then use it to set the fallback load context binder. + if (ptrLoadContextBinder != NULL) { + spec.SetFallbackLoadContextBinderForRequestingAssembly(reinterpret_cast<ICLRPrivBinder *>(ptrLoadContextBinder)); + spec.SetPreferFallbackLoadContextBinder(); + } + else if (pRefAssembly != NULL) + { + // If the requesting assembly has Fallback LoadContext binder available, + // then set it up in the AssemblySpec. PEFile *pRefAssemblyManifestFile = pRefAssembly->GetManifestFile(); spec.SetFallbackLoadContextBinderForRequestingAssembly(pRefAssemblyManifestFile->GetFallbackLoadContextBinder()); } diff --git a/src/vm/assemblynative.hpp b/src/vm/assemblynative.hpp index 6309ffcf36..ca03239d3e 100644 --- a/src/vm/assemblynative.hpp +++ b/src/vm/assemblynative.hpp @@ -50,7 +50,7 @@ public: Object* securityUNSAFE); static FCDECL6(Object*, LoadImage, U1Array* PEByteArrayUNSAFE, U1Array* SymByteArrayUNSAFE, Object* securityUNSAFE, StackCrawlMark* stackMark, CLR_BOOL fForIntrospection, SecurityContextSource securityContextSource); - static FCDECL9(Object*, Load, AssemblyNameBaseObject* assemblyNameUNSAFE, + static FCDECL10(Object*, Load, AssemblyNameBaseObject* assemblyNameUNSAFE, StringObject* codeBaseUNSAFE, Object* securityUNSAFE, AssemblyBaseObject* requestingAssemblyUNSAFE, @@ -58,7 +58,8 @@ public: ICLRPrivBinder * pPrivHostBinder, CLR_BOOL fThrowOnFileNotFound, CLR_BOOL fForIntrospection, - CLR_BOOL fSuppressSecurityChecks); + CLR_BOOL fSuppressSecurityChecks, + INT_PTR ptrLoadContextBinder); static FCDECL1(FC_BOOL_RET, IsFrameworkAssembly, AssemblyNameBaseObject* refAssemblyNameUNSAFE); static FCDECL1(FC_BOOL_RET, IsNewPortableAssembly, AssemblyNameBaseObject* refAssemblyNameUNSAFE); diff --git a/src/vm/assemblyspec.cpp b/src/vm/assemblyspec.cpp index 3bd6d38861..2b4b1fb480 100644 --- a/src/vm/assemblyspec.cpp +++ b/src/vm/assemblyspec.cpp @@ -1259,19 +1259,28 @@ ICLRPrivBinder* AssemblySpec::GetBindingContextFromParentAssembly(AppDomain *pDo } #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + if (GetPreferFallbackLoadContextBinder()) + { + // If we have been asked to use the fallback load context binder (currently only supported for AssemblyLoadContext.LoadFromAssemblyName), + // then pretend we do not have any binder yet available. + _ASSERTE(GetFallbackLoadContextBinderForRequestingAssembly() != NULL); + pParentAssemblyBinder = NULL; + } + if (pParentAssemblyBinder == NULL) { // If the parent assembly binder is not available, then we maybe dealing with one of the following // assembly scenarios: // // 1) Domain Neutral assembly - // 2) RefEmitted assembly - // 3) Entrypoint assembly + // 2) Entrypoint assembly + // 3) RefEmitted assembly + // 4) AssemblyLoadContext.LoadFromAssemblyName // - // For (1) and (3), we will need to bind against the DefaultContext binder (aka TPA Binder). This happens + // For (1) and (2), we will need to bind against the DefaultContext binder (aka TPA Binder). This happens // below if we do not find the parent assembly binder. // - // For (2), check if we have the fallback load context binder for the requesting dynamic assembly available. + // For (3) and (4), fetch the fallback load context binder reference. pParentAssemblyBinder = GetFallbackLoadContextBinderForRequestingAssembly(); } diff --git a/src/vm/assemblyspec.hpp b/src/vm/assemblyspec.hpp index 84e67dfcc2..a7e9c0f203 100644 --- a/src/vm/assemblyspec.hpp +++ b/src/vm/assemblyspec.hpp @@ -45,6 +45,9 @@ class AssemblySpec : public BaseAssemblySpec #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) // Contains the reference to the fallback load context associated with RefEmitted assembly requesting the load of another assembly (static or dynamic) ICLRPrivBinder *m_pFallbackLoadContextBinder; + + // Flag to indicate if we should prefer the fallback load context binder for binding or not. + bool m_fPreferFallbackLoadContextBinder; #endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) BOOL IsValidAssemblyName(); @@ -74,7 +77,8 @@ class AssemblySpec : public BaseAssemblySpec m_pParentAssembly = NULL; #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) - m_pFallbackLoadContextBinder = NULL; + m_pFallbackLoadContextBinder = NULL; + m_fPreferFallbackLoadContextBinder = false; #endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) } @@ -86,7 +90,8 @@ class AssemblySpec : public BaseAssemblySpec m_pParentAssembly = NULL; #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) - m_pFallbackLoadContextBinder = NULL; + m_pFallbackLoadContextBinder = NULL; + m_fPreferFallbackLoadContextBinder = false; #endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) } @@ -187,6 +192,20 @@ class AssemblySpec : public BaseAssemblySpec return m_pFallbackLoadContextBinder; } + + void SetPreferFallbackLoadContextBinder() + { + LIMITED_METHOD_CONTRACT; + + m_fPreferFallbackLoadContextBinder = true; + } + + bool GetPreferFallbackLoadContextBinder() + { + LIMITED_METHOD_CONTRACT; + + return m_fPreferFallbackLoadContextBinder; + } #endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) // Note that this method does not clone the fields! @@ -208,6 +227,7 @@ class AssemblySpec : public BaseAssemblySpec #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) // Copy the details of the fallback load context binder SetFallbackLoadContextBinderForRequestingAssembly(pSource->GetFallbackLoadContextBinderForRequestingAssembly()); + m_fPreferFallbackLoadContextBinder = pSource->GetPreferFallbackLoadContextBinder(); #endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) m_HashForControl = pSource->m_HashForControl; |