From f216102eff923329c432c2f17e7c89ce40ef45c6 Mon Sep 17 00:00:00 2001 From: Tomas Matousek Date: Tue, 29 Sep 2015 05:40:49 -0700 Subject: [PATCH] Avoid accessing GAC when not available (on CoreCLR) --- src/Compilers/Core/Portable/CorLightup.cs | 6 ++-- .../InternalUtilities/ReflectionUtilities.cs | 17 +++++++-- src/Compilers/Helpers/CoreClrShim.cs | 18 ++++++---- .../GacFileResolver.cs | 35 ++++++++++++------- .../GlobalAssemblyCache.cs | 18 ++++++---- .../Interactive/InteractiveEvaluator.cs | 5 ++- .../Core/InteractiveHost.Service.cs | 9 +++-- src/Scripting/CSharp/CommandLine/Csi.cs | 2 +- .../RuntimeMetadataReferenceResolver.cs | 2 +- src/Scripting/VisualBasic/CommandLine/Vbi.vb | 2 +- 10 files changed, 73 insertions(+), 41 deletions(-) diff --git a/src/Compilers/Core/Portable/CorLightup.cs b/src/Compilers/Core/Portable/CorLightup.cs index 020a6c42316..3ee67635fbc 100644 --- a/src/Compilers/Core/Portable/CorLightup.cs +++ b/src/Compilers/Core/Portable/CorLightup.cs @@ -76,7 +76,7 @@ private static class _Assembly private static class _ResolveEventArgs { - internal static readonly Type Type = Type.GetType("System.ResolveEventArgs", throwOnError: false); + internal static readonly Type Type = ReflectionUtilities.TryGetType("System.ResolveEventArgs"); internal static readonly MethodInfo get_Name = Type .GetTypeInfo() @@ -89,8 +89,8 @@ private static class _ResolveEventArgs private static class _AppDomain { - internal static readonly Type Type = Type.GetType("System.AppDomain", throwOnError: false); - internal static readonly Type ResolveEventHandlerType = Type.GetType("System.ResolveEventHandler", throwOnError: false); + internal static readonly Type Type = ReflectionUtilities.TryGetType("System.AppDomain"); + internal static readonly Type ResolveEventHandlerType = ReflectionUtilities.TryGetType("System.ResolveEventHandler"); internal static readonly MethodInfo get_CurrentDomain = Type .GetTypeInfo() diff --git a/src/Compilers/Core/Portable/InternalUtilities/ReflectionUtilities.cs b/src/Compilers/Core/Portable/InternalUtilities/ReflectionUtilities.cs index d02f73be257..a631c962a27 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/ReflectionUtilities.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/ReflectionUtilities.cs @@ -10,17 +10,30 @@ namespace Roslyn.Utilities { internal static class ReflectionUtilities { + public static Type TryGetType(string assemblyQualifiedName) + { + try + { + // Note that throwOnError=false only suppresses some exceptions, not all. + return Type.GetType(assemblyQualifiedName, throwOnError: false); + } + catch + { + return null; + } + } + /// /// Find a instance by first probing the contract name and then the name as it /// would exist in mscorlib. This helps satisfy both the CoreCLR and Desktop scenarios. /// public static Type GetTypeFromEither(string contractName, string desktopName) { - var type = Type.GetType(contractName, throwOnError: false); + var type = TryGetType(contractName); if (type == null) { - type = Type.GetType(desktopName, throwOnError: false); + type = TryGetType(desktopName); } return type; diff --git a/src/Compilers/Helpers/CoreClrShim.cs b/src/Compilers/Helpers/CoreClrShim.cs index a933bd3be07..8cacb35aa95 100644 --- a/src/Compilers/Helpers/CoreClrShim.cs +++ b/src/Compilers/Helpers/CoreClrShim.cs @@ -6,7 +6,6 @@ namespace Roslyn.Utilities { - /// /// This is a bridge for APIs that are only available on CoreCLR or .NET 4.6 /// and NOT on .NET 4.5. The compiler currently targets .NET 4.5 and CoreCLR @@ -14,13 +13,20 @@ namespace Roslyn.Utilities /// internal static class CoreClrShim { + + internal static class AssemblyLoadContext + { + internal static readonly Type Type = ReflectionUtilities.TryGetType( + "System.Runtime.Loader.AssemblyLoadContext, System.Runtime.Loader, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); + } + internal static class CodePagesEncodingProvider { - internal static readonly Type Type = - Type.GetType("System.Text.CodePagesEncodingProvider, " + - "System.Text.Encoding.CodePages, " + - "Version=4.0.0.0, Culture=neutral, " + - "PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false); + internal static readonly Type Type = ReflectionUtilities.TryGetType( + "System.Text.CodePagesEncodingProvider, " + + "System.Text.Encoding.CodePages, " + + "Version=4.0.0.0, Culture=neutral, " + + "PublicKeyToken=b03f5f7f11d50a3a"); private static PropertyInfo s_instance = Type ?.GetTypeInfo() diff --git a/src/Compilers/Helpers/GlobalAssemblyCacheHelpers/GacFileResolver.cs b/src/Compilers/Helpers/GlobalAssemblyCacheHelpers/GacFileResolver.cs index 4b67edef9c6..33eac41a07c 100644 --- a/src/Compilers/Helpers/GlobalAssemblyCacheHelpers/GacFileResolver.cs +++ b/src/Compilers/Helpers/GlobalAssemblyCacheHelpers/GacFileResolver.cs @@ -11,37 +11,46 @@ namespace Microsoft.CodeAnalysis.Scripting.Hosting { /// - /// Extends MetadataFileReferenceResolver to enable resolution of assembly - /// simple names in the GAC. + /// Resolves assembly identities in Global Assembly Cache. /// internal sealed class GacFileResolver : IEquatable { /// - /// Architecture filter used when resolving assembly references. + /// Returns true if GAC is available on the platform. /// - public ImmutableArray Architectures { get; } + public static bool IsAvailable => CoreClrShim.AssemblyLoadContext.Type == null; /// - /// CultureInfo used when resolving assembly references. + /// Architecture filter used when resolving assembly references. /// - public CultureInfo PreferredCulture { get; } + public ImmutableArray Architectures { get; } /// - /// A resolver that is configured to resolve against the GAC associated - /// with the bitness of the currently executing process. + /// used when resolving assembly references, or null to prefer no culture. /// - internal static GacFileResolver Default = new GacFileResolver( - architectures: GlobalAssemblyCache.CurrentArchitectures, - preferredCulture: null); + public CultureInfo PreferredCulture { get; } /// - /// Constructs an instance of a + /// Creates an instance of a , if available on the platform (check ). /// /// Supported architectures used to filter GAC assemblies. /// A culture to use when choosing the best assembly from /// among the set filtered by - public GacFileResolver(ImmutableArray architectures, CultureInfo preferredCulture) + /// The platform doesn't support GAC. + public GacFileResolver( + ImmutableArray architectures = default(ImmutableArray), + CultureInfo preferredCulture = null) { + if (!IsAvailable) + { + throw new PlatformNotSupportedException(); + } + + if (architectures.IsDefault) + { + architectures = GlobalAssemblyCache.CurrentArchitectures; + } + Architectures = architectures; PreferredCulture = preferredCulture; } diff --git a/src/Compilers/Helpers/GlobalAssemblyCacheHelpers/GlobalAssemblyCache.cs b/src/Compilers/Helpers/GlobalAssemblyCacheHelpers/GlobalAssemblyCache.cs index fa011b769af..8ce0fd252d6 100644 --- a/src/Compilers/Helpers/GlobalAssemblyCacheHelpers/GlobalAssemblyCache.cs +++ b/src/Compilers/Helpers/GlobalAssemblyCacheHelpers/GlobalAssemblyCache.cs @@ -87,13 +87,19 @@ private enum ASM_CACHE private const int ERROR_INSUFFICIENT_BUFFER = unchecked((int)0x8007007A); - public static readonly ImmutableArray RootLocations; + public static ImmutableArray s_rootLocations; - static GlobalAssemblyCache() + public static ImmutableArray RootLocations { - RootLocations = ImmutableArray.Create( - GetLocation(ASM_CACHE.ROOT), - GetLocation(ASM_CACHE.ROOT_EX)); + get + { + if (s_rootLocations.IsDefault) + { + s_rootLocations = ImmutableArray.Create(GetLocation(ASM_CACHE.ROOT), GetLocation(ASM_CACHE.ROOT_EX)); + } + + return s_rootLocations; + } } private static unsafe string GetLocation(ASM_CACHE gacId) @@ -105,7 +111,7 @@ private static unsafe string GetLocation(ASM_CACHE gacId) throw Marshal.GetExceptionForHR(hr); } - byte[] data = new byte[((int)characterCount + 1) * 2]; + byte[] data = new byte[(characterCount + 1) * 2]; fixed (byte* p = data) { hr = GetCachePath(gacId, p, ref characterCount); diff --git a/src/Interactive/EditorFeatures/Core/Extensibility/Interactive/InteractiveEvaluator.cs b/src/Interactive/EditorFeatures/Core/Extensibility/Interactive/InteractiveEvaluator.cs index 3cb76a586a5..2f1012938c8 100644 --- a/src/Interactive/EditorFeatures/Core/Extensibility/Interactive/InteractiveEvaluator.cs +++ b/src/Interactive/EditorFeatures/Core/Extensibility/Interactive/InteractiveEvaluator.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -257,9 +258,7 @@ private static MetadataReferenceResolver CreateMetadataReferenceResolver(IMetada return new RuntimeMetadataReferenceResolver( new RelativePathResolver(searchPaths, baseDirectory), string.IsNullOrEmpty(packagesDirectory) ? null : new NuGetPackageResolverImpl(packagesDirectory), - new GacFileResolver( - architectures: GacFileResolver.Default.Architectures, // TODO (tomat) - preferredCulture: System.Globalization.CultureInfo.CurrentCulture), // TODO (tomat) + GacFileResolver.IsAvailable ? new GacFileResolver(preferredCulture: CultureInfo.CurrentCulture) : null, (path, properties) => metadataService.GetReference(path, properties)); } diff --git a/src/Interactive/Features/Interactive/Core/InteractiveHost.Service.cs b/src/Interactive/Features/Interactive/Core/InteractiveHost.Service.cs index dc6879f0746..23429f13f13 100644 --- a/src/Interactive/Features/Interactive/Core/InteractiveHost.Service.cs +++ b/src/Interactive/Features/Interactive/Core/InteractiveHost.Service.cs @@ -169,13 +169,12 @@ private MetadataReferenceResolver CreateMetadataReferenceResolver(ImmutableArray var packagesDirectory = string.IsNullOrEmpty(userProfilePath) ? null : Path.Combine(userProfilePath, Path.Combine(".nuget", "packages")); + return new RuntimeMetadataReferenceResolver( - new RelativePathResolver(searchPaths, baseDirectory), + new RelativePathResolver(searchPaths, baseDirectory), string.IsNullOrEmpty(packagesDirectory) ? null : new NuGetPackageResolverImpl(packagesDirectory), - new GacFileResolver( - architectures: GacFileResolver.Default.Architectures, // TODO (tomat) - preferredCulture: CultureInfo.CurrentCulture), // TODO (tomat) - (path, properties) => _metadataFileProvider.GetReference(path, properties)); + GacFileResolver.IsAvailable ? new GacFileResolver(preferredCulture: CultureInfo.CurrentCulture) : null, + (path, properties) => _metadataFileProvider.GetReference(path, properties)); } private SourceReferenceResolver CreateSourceReferenceResolver(ImmutableArray searchPaths, string baseDirectory) diff --git a/src/Scripting/CSharp/CommandLine/Csi.cs b/src/Scripting/CSharp/CommandLine/Csi.cs index 7f294babced..3062598a59e 100644 --- a/src/Scripting/CSharp/CommandLine/Csi.cs +++ b/src/Scripting/CSharp/CommandLine/Csi.cs @@ -23,7 +23,7 @@ internal override MetadataReferenceResolver GetCommandLineMetadataReferenceResol return new RuntimeMetadataReferenceResolver( new RelativePathResolver(Arguments.ReferencePaths, Arguments.BaseDirectory), null, - new GacFileResolver(GacFileResolver.Default.Architectures, CultureInfo.CurrentCulture), + GacFileResolver.IsAvailable ? new GacFileResolver(preferredCulture: CultureInfo.CurrentCulture) : null, (path, properties) => { loggerOpt?.AddRead(path); diff --git a/src/Scripting/Core/Resolvers/RuntimeMetadataReferenceResolver.cs b/src/Scripting/Core/Resolvers/RuntimeMetadataReferenceResolver.cs index 4edd31612e5..2707340bd26 100644 --- a/src/Scripting/Core/Resolvers/RuntimeMetadataReferenceResolver.cs +++ b/src/Scripting/Core/Resolvers/RuntimeMetadataReferenceResolver.cs @@ -25,7 +25,7 @@ internal sealed class RuntimeMetadataReferenceResolver : MetadataReferenceResolv internal RuntimeMetadataReferenceResolver( ImmutableArray searchPaths, string baseDirectory) - : this(new RelativePathResolver(searchPaths, baseDirectory), null, GacFileResolver.Default) + : this(new RelativePathResolver(searchPaths, baseDirectory), null, GacFileResolver.IsAvailable ? new GacFileResolver() : null) { } diff --git a/src/Scripting/VisualBasic/CommandLine/Vbi.vb b/src/Scripting/VisualBasic/CommandLine/Vbi.vb index 279f59f693d..23796a7edc1 100644 --- a/src/Scripting/VisualBasic/CommandLine/Vbi.vb +++ b/src/Scripting/VisualBasic/CommandLine/Vbi.vb @@ -19,7 +19,7 @@ Namespace Microsoft.CodeAnalysis.Scripting.Hosting.VisualBasic Return New RuntimeMetadataReferenceResolver( New RelativePathResolver(Arguments.ReferencePaths, Arguments.BaseDirectory), Nothing, - New GacFileResolver(GacFileResolver.Default.Architectures, CultureInfo.CurrentCulture), + If(GacFileResolver.IsAvailable, New GacFileResolver(preferredCulture:=CultureInfo.CurrentCulture), Nothing), Function(path, properties) loggerOpt?.AddRead(path) Return MetadataReference.CreateFromFile(path) -- GitLab