diff options
-rw-r--r-- | src/binder/assemblybinder.cpp | 10 | ||||
-rw-r--r-- | src/binder/clrprivbinderassemblyloadcontext.cpp | 58 | ||||
-rw-r--r-- | src/binder/clrprivbindercoreclr.cpp | 3 | ||||
-rw-r--r-- | src/binder/inc/assemblybinder.hpp | 1 | ||||
-rw-r--r-- | src/mscorlib/model.CoreLib.xml | 1 | ||||
-rw-r--r-- | src/mscorlib/model.xml | 1 | ||||
-rw-r--r-- | src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs | 85 | ||||
-rw-r--r-- | src/vm/appdomain.cpp | 91 | ||||
-rw-r--r-- | src/vm/mscorlib.h | 1 |
9 files changed, 82 insertions, 169 deletions
diff --git a/src/binder/assemblybinder.cpp b/src/binder/assemblybinder.cpp index 517eac99d6..a1982ebb37 100644 --- a/src/binder/assemblybinder.cpp +++ b/src/binder/assemblybinder.cpp @@ -50,9 +50,7 @@ BOOL IsCompilationProcess(); #include "clrprivbindercoreclr.h" #include "clrprivbinderassemblyloadcontext.h" // Helper function in the VM, invoked by the Binder, to invoke the host assembly resolver -extern HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, - IAssemblyName *pIAssemblyName, CLRPrivBinderCoreCLR *pTPABinder, - BINDER_SPACE::AssemblyName *pAssemblyName, 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); @@ -1816,7 +1814,6 @@ namespace BINDER_SPACE HRESULT AssemblyBinder::BindUsingHostAssemblyResolver (/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin, /* in */ AssemblyName *pAssemblyName, /* in */ IAssemblyName *pIAssemblyName, - /* in */ CLRPrivBinderCoreCLR *pTPABinder, /* out */ Assembly **ppAssembly) { HRESULT hr = E_FAIL; @@ -1824,10 +1821,9 @@ HRESULT AssemblyBinder::BindUsingHostAssemblyResolver (/* in */ INT_PTR pManaged _ASSERTE(pManagedAssemblyLoadContextToBindWithin != NULL); - // RuntimeInvokeHostAssemblyResolver will perform steps 2-4 of CLRPrivBinderAssemblyLoadContext::BindAssemblyByName. + // Call into the VM to use the HostAssemblyResolver and load the assembly ICLRPrivAssembly *pLoadedAssembly = NULL; - hr = RuntimeInvokeHostAssemblyResolver(pManagedAssemblyLoadContextToBindWithin, pIAssemblyName, - pTPABinder, pAssemblyName, &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 8f3a3eef49..57f4ee72c4 100644 --- a/src/binder/clrprivbinderassemblyloadcontext.cpp +++ b/src/binder/clrprivbinderassemblyloadcontext.cpp @@ -61,19 +61,14 @@ HRESULT CLRPrivBinderAssemblyLoadContext::BindAssemblyByName(IAssemblyName * SAFE_NEW(pAssemblyName, AssemblyName); IF_FAIL_GO(pAssemblyName->Init(pIAssemblyName)); - // When LoadContext needs to resolve an assembly reference, it will go through the following lookup order: - // - // 1) Lookup the assembly within the LoadContext itself. If assembly is found, use it. - // 2) Invoke the LoadContext's Load method implementation. If assembly is found, use it. - // 3) Lookup the assembly within TPABinder. If assembly is found, use it. - // 4) Invoke the LoadContext's Resolving event. If assembly is found, use it. - // 5) Raise exception. - // - // This approach enables a LoadContext to override assemblies that have been loaded in TPA context by loading - // a different (or even the same!) version. - + // Check if the assembly is in the TPA list or not. Don't search app paths when using the TPA binder because the actual + // binder is using a host assembly resolver. + hr = m_pTPABinder->BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly, true /* excludeAppPaths */); + if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { - // Step 1 - Try to find the assembly within the LoadContext. + // If we could not find the assembly in the TPA list, + // then bind to it in the context of the current binder. + // If we find it already loaded, we will return the reference. hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly); if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || (hr == FUSION_E_APP_DOMAIN_LOCKED) || (hr == FUSION_E_REF_DEF_MISMATCH)) @@ -87,8 +82,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(GetManagedAssemblyLoadContext(), pAssemblyName, pIAssemblyName, m_pTPABinder, &pCoreCLRFoundAssembly); + hr = AssemblyBinder::BindUsingHostAssemblyResolver(GetManagedAssemblyLoadContext(), pAssemblyName, pIAssemblyName, &pCoreCLRFoundAssembly); if (SUCCEEDED(hr)) { // We maybe returned an assembly that was bound to a different AssemblyLoadContext instance. @@ -148,19 +142,41 @@ HRESULT CLRPrivBinderAssemblyLoadContext::BindUsingPEImage( /* in */ PEImage *pP IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT)); } - // Disallow attempt to bind to the core library. Aside from that, - // the LoadContext can load any assembly (even if it was in a different LoadContext like TPA). + // Ensure we are not being asked to bind to a TPA assembly + // + // Easy out for mscorlib if (pAssemblyName->IsMscorlib()) { IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); } - hr = AssemblyBinder::BindUsingPEImage(&m_appContext, pAssemblyName, pPEImage, PeKind, pIMetaDataAssemblyImport, &pCoreCLRFoundAssembly); - if (hr == S_OK) { - _ASSERTE(pCoreCLRFoundAssembly != NULL); - pCoreCLRFoundAssembly->SetBinder(this); - *ppAssembly = pCoreCLRFoundAssembly.Extract(); + SString& simpleName = pAssemblyName->GetSimpleName(); + ApplicationContext *pTPAApplicationContext = m_pTPABinder->GetAppContext(); + SimpleNameToFileNameMap * tpaMap = pTPAApplicationContext->GetTpaList(); + if (tpaMap->LookupPtr(simpleName.GetUnicode()) != NULL) + { + // The simple name of the assembly being requested to be bound was found in the TPA list. + // Now, perform the actual bind to see if the assembly was really in the TPA assembly or not. + // Don't search app paths when using the TPA binder because the actual binder is using a host assembly resolver. + hr = m_pTPABinder->BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly, true /* excludeAppPaths */); + if (SUCCEEDED(hr)) + { + if (pCoreCLRFoundAssembly->GetIsInGAC()) + { + // If we were able to bind to a TPA assembly, then fail the load + IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); + } + } + } + + hr = AssemblyBinder::BindUsingPEImage(&m_appContext, pAssemblyName, pPEImage, PeKind, pIMetaDataAssemblyImport, &pCoreCLRFoundAssembly); + if (hr == S_OK) + { + _ASSERTE(pCoreCLRFoundAssembly != NULL); + pCoreCLRFoundAssembly->SetBinder(this); + *ppAssembly = pCoreCLRFoundAssembly.Extract(); + } } Exit:; } diff --git a/src/binder/clrprivbindercoreclr.cpp b/src/binder/clrprivbindercoreclr.cpp index d62af867ef..a2fb1c8237 100644 --- a/src/binder/clrprivbindercoreclr.cpp +++ b/src/binder/clrprivbindercoreclr.cpp @@ -80,8 +80,7 @@ HRESULT CLRPrivBinderCoreCLR::BindAssemblyByName(IAssemblyName *pIAssemblyNa INT_PTR pManagedAssemblyLoadContext = GetManagedAssemblyLoadContext(); if (pManagedAssemblyLoadContext != NULL) { - hr = AssemblyBinder::BindUsingHostAssemblyResolver(pManagedAssemblyLoadContext, pAssemblyName, pIAssemblyName, - NULL, &pCoreCLRFoundAssembly); + hr = AssemblyBinder::BindUsingHostAssemblyResolver(pManagedAssemblyLoadContext, pAssemblyName, pIAssemblyName, &pCoreCLRFoundAssembly); if (SUCCEEDED(hr)) { // We maybe returned an assembly that was bound to a different AssemblyLoadContext instance. diff --git a/src/binder/inc/assemblybinder.hpp b/src/binder/inc/assemblybinder.hpp index 3a1f1e45fd..87d6491a92 100644 --- a/src/binder/inc/assemblybinder.hpp +++ b/src/binder/inc/assemblybinder.hpp @@ -78,7 +78,6 @@ namespace BINDER_SPACE static HRESULT BindUsingHostAssemblyResolver (/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin, /* in */ AssemblyName *pAssemblyName, /* in */ IAssemblyName *pIAssemblyName, - /* in */ CLRPrivBinderCoreCLR *pTPABinder, /* out */ Assembly **ppAssembly); static HRESULT BindUsingPEImage(/* in */ ApplicationContext *pApplicationContext, diff --git a/src/mscorlib/model.CoreLib.xml b/src/mscorlib/model.CoreLib.xml index 6ea5768f28..d8ab0e0c72 100644 --- a/src/mscorlib/model.CoreLib.xml +++ b/src/mscorlib/model.CoreLib.xml @@ -951,7 +951,6 @@ <Member Name="LoadFromStream(System.IO.Stream)" /> <Member Name="LoadFromStream(System.IO.Stream,System.IO.Stream)" /> <Member Name="Resolve(System.IntPtr,System.Reflection.AssemblyName)" /> - <Member Name="ResolveUsingResolvingEvent(System.IntPtr,System.Reflection.AssemblyName)" /> <Member Name="ResolveUnmanagedDll(System.String,System.IntPtr)" /> <Member Name="LoadUnmanagedDll(System.String)" /> <Member Name="LoadUnmanagedDllFromPath(System.String)" /> diff --git a/src/mscorlib/model.xml b/src/mscorlib/model.xml index ef2774a9f3..225249f83c 100644 --- a/src/mscorlib/model.xml +++ b/src/mscorlib/model.xml @@ -951,7 +951,6 @@ <Member Name="LoadFromStream(System.IO.Stream)" /> <Member Name="LoadFromStream(System.IO.Stream,System.IO.Stream)" /> <Member Name="Resolve(System.IntPtr,System.Reflection.AssemblyName)" /> - <Member Name="ResolveUsingResolvingEvent(System.IntPtr,System.Reflection.AssemblyName)" /> <Member Name="ResolveUnmanagedDll(System.String,System.IntPtr)" /> <Member Name="LoadUnmanagedDll(System.String)" /> <Member Name="LoadUnmanagedDllFromPath(System.String)" /> diff --git a/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs b/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs index 527fbe4d6c..6b53ba3b64 100644 --- a/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs +++ b/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs @@ -111,6 +111,13 @@ namespace System.Runtime.Loader throw new ArgumentException( Environment.GetResourceString("Argument_AbsolutePathRequired"), "nativeImagePath"); } + // Check if the nativeImagePath has ".ni.dll" or ".ni.exe" extension + if (!(nativeImagePath.EndsWith(".ni.dll", StringComparison.InvariantCultureIgnoreCase) || + nativeImagePath.EndsWith(".ni.exe", StringComparison.InvariantCultureIgnoreCase))) + { + throw new ArgumentException("nativeImagePath"); + } + if (assemblyPath != null && Path.IsRelative(assemblyPath)) { throw new ArgumentException(Environment.GetResourceString("Argument_AbsolutePathRequired"), "assemblyPath"); @@ -177,17 +184,7 @@ namespace System.Runtime.Loader { AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target); - return context.ResolveUsingLoad(assemblyName); - } - - // This method is invoked by the VM to resolve an assembly reference using the Resolving event - // after trying assembly resolution via Load override and TPA load context without success. - private static Assembly ResolveUsingResolvingEvent(IntPtr gchManagedAssemblyLoadContext, AssemblyName assemblyName) - { - AssemblyLoadContext context = (AssemblyLoadContext)(GCHandle.FromIntPtr(gchManagedAssemblyLoadContext).Target); - - // Invoke the AssemblyResolve event callbacks if wired up - return context.ResolveUsingEvent(assemblyName); + return context.LoadFromAssemblyName(assemblyName); } private Assembly GetFirstResolvedAssembly(AssemblyName assemblyName) @@ -213,8 +210,23 @@ namespace System.Runtime.Loader return resolvedAssembly; } - private Assembly ValidateAssemblyNameWithSimpleName(Assembly assembly, string requestedSimpleName) + 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 = 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); + } + // Get the name of the loaded assembly string loadedSimpleName = null; @@ -232,56 +244,7 @@ namespace System.Runtime.Loader throw new InvalidOperationException(Environment.GetResourceString("Argument_CustomAssemblyLoadContextRequestedNameMismatch")); return assembly; - - } - - private Assembly ResolveUsingLoad(AssemblyName assemblyName) - { - string simpleName = assemblyName.Name; - Assembly assembly = Load(assemblyName); - - if (assembly != null) - { - assembly = ValidateAssemblyNameWithSimpleName(assembly, simpleName); - } - - return assembly; - } - - private Assembly ResolveUsingEvent(AssemblyName assemblyName) - { - string simpleName = assemblyName.Name; - - // Invoke the AssemblyResolve event callbacks if wired up - Assembly assembly = GetFirstResolvedAssembly(assemblyName); - if (assembly != null) - { - assembly = ValidateAssemblyNameWithSimpleName(assembly, simpleName); - } - - // Since attempt to resolve the assembly via Resolving event is the last option, - // throw an exception if we do not find any assembly. - if (assembly == null) - { - throw new FileNotFoundException(Environment.GetResourceString("IO.FileLoad"), simpleName); - } - - return assembly; - } - - 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); - } - return assembly; } [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp index 53c68776d3..3827d9b0ac 100644 --- a/src/vm/appdomain.cpp +++ b/src/vm/appdomain.cpp @@ -14214,7 +14214,7 @@ BOOL RuntimeCanUseAppPathAssemblyResolver(DWORD adid) } // Returns S_OK if the assembly was successfully loaded -HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, IAssemblyName *pIAssemblyName, CLRPrivBinderCoreCLR *pTPABinder, BINDER_SPACE::AssemblyName *pAssemblyName, ICLRPrivAssembly **ppLoadedAssembly) +HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin, IAssemblyName *pIAssemblyName, ICLRPrivAssembly **ppLoadedAssembly) { CONTRACTL { @@ -14243,8 +14243,6 @@ HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToB GCPROTECT_BEGIN(_gcRefs); - ICLRPrivAssembly *pAssemblyBindingContext = NULL; - // Prepare to invoke System.Runtime.Loader.AssemblyLoadContext.Resolve method. // // First, initialize an assembly spec for the requested assembly @@ -14253,9 +14251,7 @@ HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToB hr = spec.Init(pIAssemblyName); if (SUCCEEDED(hr)) { - // Step 2 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName) - Invoke Load method - // - // Allocate an AssemblyName managed object + // Next, allocate an AssemblyName managed object _gcRefs.oRefAssemblyName = (ASSEMBLYNAMEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__ASSEMBLY_NAME)); // Initialize the AssemblyName object from the AssemblySpec @@ -14272,63 +14268,10 @@ HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToB ObjToArgSlot(_gcRefs.oRefAssemblyName), // AssemblyName instance }; - bool fResolvedAssembly = true; - bool fResolvedAssemblyViaTPALoadContext = false; - // Make the call _gcRefs.oRefLoadedAssembly = (ASSEMBLYREF) methLoadAssembly.Call_RetOBJECTREF(args); - if (_gcRefs.oRefLoadedAssembly == NULL) - { - fResolvedAssembly = false; - } - - 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) - { - // Switch to pre-emp mode before calling into the binder - GCX_PREEMP(); - BINDER_SPACE::Assembly *pCoreCLRFoundAssembly = NULL; - hr = pTPABinder->BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly, true /* excludeAppPaths */); - if (SUCCEEDED(hr)) - { - pAssemblyBindingContext = pCoreCLRFoundAssembly; - fResolvedAssembly = true; - fResolvedAssemblyViaTPALoadContext = true; - } - } - } - - if (!fResolvedAssembly) - { - // Step 4 (of CLRPrivBinderAssemblyLoadContext::BindUsingAssemblyName) - // - // If we couldnt resolve the assembly using TPA LoadContext as well, then - // attempt to resolve it using the Resolving event. - // Finally, setup arguments for invocation - BinderMethodID idHAR_ResolveUsingEvent = METHOD__ASSEMBLYLOADCONTEXT__RESOLVEUSINGEVENT; - MethodDescCallSite methLoadAssembly(idHAR_ResolveUsingEvent); - - // 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 (fResolvedAssembly && !fResolvedAssemblyViaTPALoadContext) + if (_gcRefs.oRefLoadedAssembly != NULL) { - // If we are here, assembly was successfully resolved via Load or Resolving events. - _ASSERTE(_gcRefs.oRefLoadedAssembly != NULL); - // We were able to get the assembly loaded. Now, get its name since the host could have // performed the resolution using an assembly with different name. DomainAssembly *pDomainAssembly = _gcRefs.oRefLoadedAssembly->GetDomainAssembly(); @@ -14359,23 +14302,23 @@ HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToB // Is the assembly already bound using a binding context that will be incompatible? // An example is attempting to consume an assembly bound to WinRT binder. - pAssemblyBindingContext = pLoadedPEAssembly->GetHostAssembly(); - } - + ICLRPrivAssembly *pAssemblyBindingContext = pLoadedPEAssembly->GetHostAssembly(); + #ifdef FEATURE_COMINTEROP - if (AreSameBinderInstance(pAssemblyBindingContext, GetAppDomain()->GetWinRtBinder())) - { - // It is invalid to return an assembly bound to an incompatible binder - *ppLoadedAssembly = NULL; - SString name; - spec.GetFileOrDisplayName(0, name); - COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_BINDING_CONTEXT, name); - } + if (AreSameBinderInstance(pAssemblyBindingContext, GetAppDomain()->GetWinRtBinder())) + { + // It is invalid to return an assembly bound to an incompatible binder + *ppLoadedAssembly = NULL; + SString name; + spec.GetFileOrDisplayName(0, name); + COMPlusThrowHR(COR_E_INVALIDOPERATION, IDS_HOST_ASSEMBLY_RESOLVER_INCOMPATIBLE_BINDING_CONTEXT, name); + } #endif // FEATURE_COMINTEROP - // Get the ICLRPrivAssembly reference to return back to. - *ppLoadedAssembly = clr::SafeAddRef(pAssemblyBindingContext); - hr = S_OK; + // Get the ICLRPrivAssembly reference to return back to. + *ppLoadedAssembly = clr::SafeAddRef(pLoadedPEAssembly->GetHostAssembly()); + hr = S_OK; + } } GCPROTECT_END(); diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h index 4c27965248..9620627bea 100644 --- a/src/vm/mscorlib.h +++ b/src/vm/mscorlib.h @@ -1674,7 +1674,6 @@ DEFINE_METHOD(FIRSTCHANCE_EVENTARGS, CTOR, .ctor, DEFINE_CLASS(ASSEMBLYLOADCONTEXT, Loader, AssemblyLoadContext) DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVE, Resolve, SM_IntPtr_AssemblyName_RetAssemblyBase) DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVEUNMANAGEDDLL, ResolveUnmanagedDll, SM_Str_IntPtr_RetIntPtr) -DEFINE_METHOD(ASSEMBLYLOADCONTEXT, RESOLVEUSINGEVENT, ResolveUsingResolvingEvent, SM_IntPtr_AssemblyName_RetAssemblyBase) #endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) |