From a080169f6f9f1b8df9cef9c0fb47c1dd1d37a87c Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Sun, 28 May 2017 23:12:51 -0700 Subject: [PATCH 1/4] Refactoring - Set 1 --- .../CoreCLR/CorePsAssemblyLoadContext.cs | 429 +++++------------- .../cimSupport/cmdletization/EnumWriter.cs | 4 +- .../utils/ClrFacade.cs | 54 +-- src/TypeCatalogGen/TypeCatalogGen.cs | 2 +- src/powershell/Program.cs | 13 - 5 files changed, 123 insertions(+), 379 deletions(-) diff --git a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs index 703431d60a2..ddfc7935a47 100644 --- a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs +++ b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs @@ -19,7 +19,7 @@ namespace System.Management.Automation /// /// The powershell custom AssemblyLoadContext implementation /// - internal partial class PowerShellAssemblyLoadContext : AssemblyLoadContext + internal partial class PowerShellAssemblyLoadContext { #region Resource_Strings @@ -44,14 +44,14 @@ internal partial class PowerShellAssemblyLoadContext : AssemblyLoadContext /// /// Initialize a singleton of PowerShellAssemblyLoadContext /// - internal static PowerShellAssemblyLoadContext InitializeSingleton(string basePaths, bool useResolvingHandlerOnly) + internal static PowerShellAssemblyLoadContext InitializeSingleton(string basePaths) { lock (s_syncObj) { if (Instance != null) throw new InvalidOperationException(SingletonAlreadyInitialized); - Instance = new PowerShellAssemblyLoadContext(basePaths, useResolvingHandlerOnly); + Instance = new PowerShellAssemblyLoadContext(basePaths); return Instance; } } @@ -60,48 +60,32 @@ internal static PowerShellAssemblyLoadContext InitializeSingleton(string basePat /// Constructor /// /// - /// Base directory paths that are separated by semicolon ';'. - /// They will be the default paths to probe assemblies. + /// Base directory paths that are separated by semicolon ';'. They will be the default paths to probe assemblies. + /// The passed-in argument could be null or an empty string, in which case there is no default paths to probe assemblies. /// - /// - /// Indicate whether this instance is going to be used as a - /// full fledged ALC, or only its 'Resolve' handler is going - /// to be used. - /// - /// - /// When is true, we will register to the 'Resolving' event of the default - /// load context with our 'Resolve' method, and depend on the default load context to resolve/load assemblies for PS. - /// This mode is used when TPA list of the native host only contains .NET Core libraries. - /// In this case, TPA binder will be consulted before hitting our resolving logic. The binding order of Assembly.Load is: - /// TPA binder --> Resolving event - /// - /// When is false, we will use this instance as a full fledged load context - /// to resolve/load assemblies for PS. This mode is used when TPA list of the native host contains both .NET Core libraries - /// and PS assemblies. - /// In this case, our Load override will kick in before consulting the TPA binder. The binding order of Assembly.Load is: - /// Load override --> TPA binder --> Resolving event - /// - private PowerShellAssemblyLoadContext(string basePaths, bool useResolvingHandlerOnly) + private PowerShellAssemblyLoadContext(string basePaths) { #region Validation if (string.IsNullOrEmpty(basePaths)) { - throw new ArgumentNullException("basePaths"); + _basePaths = Array.Empty(); } - - _basePaths = basePaths.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - for (int i = 0; i < _basePaths.Length; i++) + else { - string basePath = _basePaths[i]; - if (!Directory.Exists(basePath)) + _basePaths = basePaths.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < _basePaths.Length; i++) { - string message = string.Format( - CultureInfo.CurrentCulture, - BaseFolderDoesNotExist, - basePath); - throw new ArgumentException(message, "basePaths"); + string basePath = _basePaths[i]; + if (!Directory.Exists(basePath)) + { + string message = string.Format( + CultureInfo.CurrentCulture, + BaseFolderDoesNotExist, + basePath); + throw new ArgumentException(message, "basePaths"); + } + _basePaths[i] = basePath.Trim(); } - _basePaths[i] = basePath.Trim(); } #endregion Validation @@ -111,31 +95,14 @@ private PowerShellAssemblyLoadContext(string basePaths, bool useResolvingHandler // NEXT: Initialize the CoreCLR type catalog dictionary [OrdinalIgnoreCase] _coreClrTypeCatalog = InitializeTypeCatalog(); - // LAST: Handle useResolvingHandlerOnly flag - _useResolvingHandlerOnly = useResolvingHandlerOnly; - _activeLoadContext = useResolvingHandlerOnly ? Default : this; - if (useResolvingHandlerOnly) - { - Default.Resolving += Resolve; - } - else - { - var tempSet = new HashSet(_coreClrTypeCatalog.Values, StringComparer.OrdinalIgnoreCase); - _tpaSet = new HashSet(StringComparer.OrdinalIgnoreCase) { "Microsoft.PowerShell.CoreCLR.AssemblyLoadContext" }; - foreach (string tpa in tempSet) - { - string shortName = tpa.Substring(0, tpa.IndexOf(',')); - _tpaSet.Add(shortName); - } - } + // LAST: Register 'Resolving' handler on the default load context. + AssemblyLoadContext.Default.Resolving += Resolve; } #endregion Constructor #region Fields - private readonly bool _useResolvingHandlerOnly; - private readonly AssemblyLoadContext _activeLoadContext; private readonly static object s_syncObj = new object(); private readonly string[] _basePaths; // Initially, 'probingPaths' only contains psbase path. But every time we load an assembly through 'LoadFrom(string AssemblyPath)', we @@ -148,7 +115,6 @@ private PowerShellAssemblyLoadContext(string basePaths, bool useResolvingHandler // - Key: namespace qualified type name (FullName) // - Value: strong name of the TPA that contains the type represented by Key. private readonly Dictionary _coreClrTypeCatalog; - private readonly HashSet _tpaSet; private readonly string[] _extensions = new string[] { ".ni.dll", ".dll" }; /// @@ -191,98 +157,7 @@ internal static PowerShellAssemblyLoadContext Instance #endregion Events - #region Protected_Internal_Methods - - /// - /// Implement the AssemblyLoadContext.Load(AssemblyName). Search the requested assembly in probing paths. - /// Search the file "[assemblyName.Name][.ni].dll" in probing paths. If the file is found and it matches the requested AssemblyName, load it with LoadFromAssemblyPath. - /// - protected override Assembly Load(AssemblyName assemblyName) - { - if (_useResolvingHandlerOnly) - throw new NotSupportedException(UseResolvingEventHandlerOnly); - - // We let the default context load the assemblies included in the type catalog as there - // appears to be a bug in .NET with method resolution with system libraries loaded by our - // context and not the default. We use the short name because some packages have inconsistent - // versions between reference and runtime assemblies. - if (_tpaSet.Contains(assemblyName.Name)) - return null; - - return Resolve(this, assemblyName); - } - - /// - /// The handler for the Resolving event - /// - private Assembly Resolve(AssemblyLoadContext loadContext, AssemblyName assemblyName) - { - // Probe the assembly cache - Assembly asmLoaded; - if (TryGetAssemblyFromCache(assemblyName, out asmLoaded)) - return asmLoaded; - - // Prepare to load the assembly - lock (s_syncObj) - { - // Probe the cache again in case it's already loaded - if (TryGetAssemblyFromCache(assemblyName, out asmLoaded)) - return asmLoaded; - - // Search the specified assembly in probing paths, and load it through 'LoadFromAssemblyPath' if the file exists and matches the requested AssemblyName. - // If the CultureName of the requested assembly is not NullOrEmpty, then it's a resources.dll and we need to search corresponding culture sub-folder. - bool isAssemblyFileFound = false, isAssemblyFileMatching = false; - string asmCultureName = assemblyName.CultureName ?? string.Empty; - string asmFilePath = null; - - for (int i = 0; i < _probingPaths.Count; i++) - { - string probingPath = _probingPaths[i]; - string asmCulturePath = Path.Combine(probingPath, asmCultureName); - for (int k = 0; k < _extensions.Length; k++) - { - string asmFileName = assemblyName.Name + _extensions[k]; - asmFilePath = Path.Combine(asmCulturePath, asmFileName); - - if (File.Exists(asmFilePath)) - { - isAssemblyFileFound = true; - AssemblyName asmNameFound = GetAssemblyName(asmFilePath); - if (IsAssemblyMatching(assemblyName, asmNameFound)) - { - isAssemblyFileMatching = true; - break; - } - } - } - - if (isAssemblyFileFound && isAssemblyFileMatching) - { - break; - } - } - - // We failed to find the assembly file; or we found the file, but the assembly file doesn't match the request. - // In this case, return null so that other Resolving event handlers can kick in to resolve the request. - if (!isAssemblyFileFound || !isAssemblyFileMatching) - { - return null; - } - - asmLoaded = asmFilePath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase) - ? loadContext.LoadFromNativeImagePath(asmFilePath, null) - : loadContext.LoadFromAssemblyPath(asmFilePath); - if (asmLoaded != null) - { - // Add the loaded assembly to the cache - s_assemblyCache.TryAdd(assemblyName.Name, asmLoaded); - } - } - - // Raise AssemblyLoad event - OnAssemblyLoaded(asmLoaded); - return asmLoaded; - } + #region Internal_Methods /// /// Load an IL or NI assembly from its file path. @@ -292,7 +167,7 @@ internal Assembly LoadFrom(string assemblyPath) ValidateAssemblyPath(assemblyPath, "assemblyPath"); Assembly asmLoaded; - AssemblyName assemblyName = GetAssemblyName(assemblyPath); + AssemblyName assemblyName = AssemblyLoadContext.GetAssemblyName(assemblyPath); // Probe the assembly cache if (TryGetAssemblyFromCache(assemblyName, out asmLoaded)) @@ -307,8 +182,8 @@ internal Assembly LoadFrom(string assemblyPath) // Load the assembly through 'LoadFromNativeImagePath' or 'LoadFromAssemblyPath' asmLoaded = assemblyPath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase) - ? _activeLoadContext.LoadFromNativeImagePath(assemblyPath, null) - : _activeLoadContext.LoadFromAssemblyPath(assemblyPath); + ? AssemblyLoadContext.Default.LoadFromNativeImagePath(assemblyPath, null) + : AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); if (asmLoaded != null) { @@ -351,7 +226,7 @@ internal Assembly LoadFrom(Stream assembly) return asmLoaded; // Load the assembly through 'LoadFromStream' - asmLoaded = _activeLoadContext.LoadFromStream(assembly); + asmLoaded = AssemblyLoadContext.Default.LoadFromStream(assembly); if (asmLoaded != null) { // Add the loaded assembly to the cache @@ -367,7 +242,7 @@ internal Assembly LoadFrom(Stream assembly) /// /// Get the current loaded assemblies /// - internal IEnumerable GetAssemblies(string namespaceQualifiedTypeName) + internal IEnumerable GetAssembly(string namespaceQualifiedTypeName) { // If 'namespaceQualifiedTypeName' is specified and it's a CoreCLR framework type, // then we only return that specific TPA assembly. @@ -392,70 +267,7 @@ internal IEnumerable GetAssemblies(string namespaceQualifiedTypeName) } } - // Otherwise, we return all assemblies from the AssemblyCache - return s_assemblyCache.Values; - } - - /// - /// Try adding a new assembly to the cache - /// - /// - /// This is for adding a dynamic assembly to the cache. - /// PowerShell generates dynamic assemblies by directly emitting IL, and this API - /// is to add such assemblies to the cache so that types in them are discoverable. - /// - internal bool TryAddAssemblyToCache(Assembly assembly) - { - AssemblyName asmName = assembly.GetName(); - bool success = s_assemblyCache.TryAdd(asmName.Name, assembly); - // Raise AssemblyLoad event - if (success) { OnAssemblyLoaded(assembly); } - return success; - } - - /// - /// Probe for the assembly file with the specified short name for metadata analysis purpose - /// - internal string ProbeAssemblyFileForMetadataAnalysis(string assemblyShortName, string additionalSearchPath) - { - if (string.IsNullOrEmpty(assemblyShortName)) - { - throw new ArgumentNullException("assemblyShortName"); - } - - bool useAdditionalSearchPath = false; - if (!string.IsNullOrEmpty(additionalSearchPath)) - { - if (!Path.IsPathRooted(additionalSearchPath)) - { - throw new ArgumentException(AbsolutePathRequired, "additionalSearchPath"); - } - useAdditionalSearchPath = Directory.Exists(additionalSearchPath); - } - - // Construct the probing paths for searching the specified assembly file - string[] metadataProbingPaths = _basePaths; - if (useAdditionalSearchPath) - { - var searchPaths = new List() { additionalSearchPath }; - searchPaths.AddRange(_basePaths); - metadataProbingPaths = searchPaths.ToArray(); - } - - for (int i = 0; i < metadataProbingPaths.Length; i++) - { - string metadataProbingPath = metadataProbingPaths[i]; - for (int k = 0; k < _extensions.Length; k++) - { - string asmFileName = assemblyShortName + _extensions[k]; - string asmFilePath = Path.Combine(metadataProbingPath, asmFileName); - if (File.Exists(asmFilePath)) - { - return asmFilePath; - } - } - } - + // Otherwise, we return null return null; } @@ -482,8 +294,7 @@ internal IEnumerable GetAvailableDotNetTypes() /// internal void SetProfileOptimizationRootImpl(string directoryPath) { - if (_useResolvingHandlerOnly) - _activeLoadContext.SetProfileOptimizationRoot(directoryPath); + AssemblyLoadContext.Default.SetProfileOptimizationRoot(directoryPath); } /// @@ -500,14 +311,85 @@ internal void SetProfileOptimizationRootImpl(string directoryPath) /// internal void StartProfileOptimizationImpl(string profile) { - if (_useResolvingHandlerOnly) - _activeLoadContext.StartProfileOptimization(profile); + AssemblyLoadContext.Default.StartProfileOptimization(profile); } - #endregion Protected_Internal_Methods + #endregion Internal_Methods #region Private_Methods + /// + /// The handler for the Resolving event + /// + private Assembly Resolve(AssemblyLoadContext loadContext, AssemblyName assemblyName) + { + // Probe the assembly cache + Assembly asmLoaded; + if (TryGetAssemblyFromCache(assemblyName, out asmLoaded)) + return asmLoaded; + + // Prepare to load the assembly + lock (s_syncObj) + { + // Probe the cache again in case it's already loaded + if (TryGetAssemblyFromCache(assemblyName, out asmLoaded)) + return asmLoaded; + + // Search the specified assembly in probing paths, and load it through 'LoadFromAssemblyPath' if the file exists and matches the requested AssemblyName. + // If the CultureName of the requested assembly is not NullOrEmpty, then it's a resources.dll and we need to search corresponding culture sub-folder. + bool isAssemblyFileFound = false, isAssemblyFileMatching = false; + string asmCultureName = assemblyName.CultureName ?? string.Empty; + string asmFilePath = null; + + for (int i = 0; i < _probingPaths.Count; i++) + { + string probingPath = _probingPaths[i]; + string asmCulturePath = Path.Combine(probingPath, asmCultureName); + for (int k = 0; k < _extensions.Length; k++) + { + string asmFileName = assemblyName.Name + _extensions[k]; + asmFilePath = Path.Combine(asmCulturePath, asmFileName); + + if (File.Exists(asmFilePath)) + { + isAssemblyFileFound = true; + AssemblyName asmNameFound = AssemblyLoadContext.GetAssemblyName(asmFilePath); + if (IsAssemblyMatching(assemblyName, asmNameFound)) + { + isAssemblyFileMatching = true; + break; + } + } + } + + if (isAssemblyFileFound && isAssemblyFileMatching) + { + break; + } + } + + // We failed to find the assembly file; or we found the file, but the assembly file doesn't match the request. + // In this case, return null so that other Resolving event handlers can kick in to resolve the request. + if (!isAssemblyFileFound || !isAssemblyFileMatching) + { + return null; + } + + asmLoaded = asmFilePath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase) + ? loadContext.LoadFromNativeImagePath(asmFilePath, null) + : loadContext.LoadFromAssemblyPath(asmFilePath); + if (asmLoaded != null) + { + // Add the loaded assembly to the cache + s_assemblyCache.TryAdd(assemblyName.Name, asmLoaded); + } + } + + // Raise AssemblyLoad event + OnAssemblyLoaded(asmLoaded); + return asmLoaded; + } + /// /// Handle the AssemblyLoad event /// @@ -689,8 +571,6 @@ private void ThrowFileNotFoundException(string errorTemplate, params object[] ar /// public class PowerShellAssemblyLoadContextInitializer { - private static object[] s_emptyArray = new object[0]; - /// /// Create a singleton of PowerShellAssemblyLoadContext. /// Then register to the Resolving event of the load context that loads this assembly. @@ -708,106 +588,7 @@ public static void SetPowerShellAssemblyLoadContext([MarshalAs(UnmanagedType.LPW if (string.IsNullOrEmpty(basePaths)) throw new ArgumentNullException("basePaths"); - PowerShellAssemblyLoadContext.InitializeSingleton(basePaths, useResolvingHandlerOnly: true); - } - - /// - /// Create a singleton of PowerShellAssemblyLoadContext. - /// Then load System.Management.Automation and call the WSManPluginManagedEntryWrapper delegate. - /// - /// - /// This method is used by the native host of the PSRP plugin. - /// - /// - /// Passed to delegate. - /// - public static int WSManPluginWrapper(IntPtr wkrPtrs) - { - string basePaths = System.IO.Path.GetDirectoryName(typeof(PowerShellAssemblyLoadContextInitializer).GetTypeInfo().Assembly.Location); - string entryAssemblyName = "System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; - string entryTypeName = "System.Management.Automation.Remoting.WSManPluginManagedEntryWrapper"; - string entryMethodName = "InitPlugin"; - object[] args = { wkrPtrs }; - - var psLoadContext = PowerShellAssemblyLoadContext.InitializeSingleton(basePaths, useResolvingHandlerOnly: false); - var entryAssembly = psLoadContext.LoadFromAssemblyName(new AssemblyName(entryAssemblyName)); - var entryType = entryAssembly.GetType(entryTypeName, throwOnError: true, ignoreCase: true); - var methodInfo = entryType.GetMethod(entryMethodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase); - - return (int)methodInfo.Invoke(null, args); - } - - /// - /// Create a singleton of PowerShellAssemblyLoadContext. - /// Then load the assembly containing the actual entry point using it. - /// - /// - /// Base directory paths that are separated by semicolon ';'. - /// They will be the default paths to probe assemblies. - /// - /// - /// Name of the assembly that contains the actual entry point. - /// - /// - /// The assembly that contains the actual entry point. - /// - public static Assembly InitializeAndLoadEntryAssembly(string basePaths, AssemblyName entryAssemblyName) - { - if (string.IsNullOrEmpty(basePaths)) - throw new ArgumentNullException("basePaths"); - - if (entryAssemblyName == null) - throw new ArgumentNullException("entryAssemblyName"); - - var psLoadContext = PowerShellAssemblyLoadContext.InitializeSingleton(basePaths, useResolvingHandlerOnly: false); - return psLoadContext.LoadFromAssemblyName(entryAssemblyName); - } - - /// - /// Create a singleton of PowerShellAssemblyLoadContext. - /// Then call into the actual entry point based on the given assembly name, type name, method name and arguments. - /// - /// - /// Base directory paths that are separated by semicolon ';'. - /// They will be the default paths to probe assemblies. - /// - /// - /// Name of the assembly that contains the actual entry point. - /// - /// - /// Name of the type that contains the actual entry point. - /// - /// - /// Name of the actual entry point method. - /// - /// - /// An array of arguments passed to the entry point method. - /// - /// - /// The return value of running the entry point method. - /// - public static object InitializeAndCallEntryMethod(string basePaths, AssemblyName entryAssemblyName, string entryTypeName, string entryMethodName, object[] args) - { - if (string.IsNullOrEmpty(basePaths)) - throw new ArgumentNullException("basePaths"); - - if (entryAssemblyName == null) - throw new ArgumentNullException("entryAssemblyName"); - - if (string.IsNullOrEmpty(entryTypeName)) - throw new ArgumentNullException("entryTypeName"); - - if (string.IsNullOrEmpty(entryMethodName)) - throw new ArgumentNullException("entryMethodName"); - - args = args ?? s_emptyArray; - - var psLoadContext = PowerShellAssemblyLoadContext.InitializeSingleton(basePaths, useResolvingHandlerOnly: false); - var entryAssembly = psLoadContext.LoadFromAssemblyName(entryAssemblyName); - var entryType = entryAssembly.GetType(entryTypeName, throwOnError: true, ignoreCase: true); - var methodInfo = entryType.GetMethod(entryMethodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase); - - return methodInfo.Invoke(null, args); + PowerShellAssemblyLoadContext.InitializeSingleton(basePaths); } } } diff --git a/src/System.Management.Automation/cimSupport/cmdletization/EnumWriter.cs b/src/System.Management.Automation/cimSupport/cmdletization/EnumWriter.cs index d07c1621b6c..d24c3f55e7e 100644 --- a/src/System.Management.Automation/cimSupport/cmdletization/EnumWriter.cs +++ b/src/System.Management.Automation/cimSupport/cmdletization/EnumWriter.cs @@ -64,8 +64,8 @@ internal static void Compile(EnumMetadataEnum enumMetadata) object integerValue = LanguagePrimitives.ConvertTo(value.Value, underlyingType, CultureInfo.InvariantCulture); eb.DefineLiteral(name, integerValue); } - - ClrFacade.CreateEnumType(eb); + + eb.CreateTypeInfo(); } } } diff --git a/src/System.Management.Automation/utils/ClrFacade.cs b/src/System.Management.Automation/utils/ClrFacade.cs index d037485bc4d..7f8312cd899 100644 --- a/src/System.Management.Automation/utils/ClrFacade.cs +++ b/src/System.Management.Automation/utils/ClrFacade.cs @@ -10,7 +10,6 @@ using System.Linq; using System.Management.Automation.Language; using System.Reflection; -using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; @@ -37,6 +36,18 @@ namespace System.Management.Automation /// internal static class ClrFacade { + /// + /// Initialize powershell AssemblyLoadContext and register the 'Resolving' event, if it's not done already. + /// If powershell is hosted by a native host such as DSC, then PS ALC might be initialized via 'SetPowerShellAssemblyLoadContext' before loading S.M.A. + /// + static ClrFacade() + { + if (PowerShellAssemblyLoadContext.Instance == null) + { + PowerShellAssemblyLoadContext.InitializeSingleton(string.Empty); + } + } + /// /// We need it to avoid calling lookups inside dynamic assemblies with PS Types, so we exclude it from GetAssemblies(). /// We use this convention for names to archive it. @@ -217,11 +228,11 @@ internal static IEnumerable GetAssemblies(TypeResolutionState typeReso /// internal static IEnumerable GetAssemblies(string namespaceQualifiedTypeName = null) { + return #if CORECLR - return PSAssemblyLoadContext.GetAssemblies(namespaceQualifiedTypeName); -#else - return AppDomain.CurrentDomain.GetAssemblies().Where(a => !(a.FullName.Length > 0 && a.FullName[0] == FIRST_CHAR_PSASSEMBLY_MARK)); + PSAssemblyLoadContext.GetAssembly(namespaceQualifiedTypeName) ?? #endif + AppDomain.CurrentDomain.GetAssemblies().Where(a => !(a.FullName.Length > 0 && a.FullName[0] == FIRST_CHAR_PSASSEMBLY_MARK)); } /// @@ -237,42 +248,7 @@ internal static Assembly LoadFrom(string assemblyPath) #endif } - /// - /// Facade for EnumBuilder.CreateTypeInfo - /// - /// - /// In Core PowerShell, we need to track the dynamic assemblies that powershell generates. - /// - internal static void CreateEnumType(EnumBuilder enumBuilder) - { #if CORECLR - // Create the enum type and add the dynamic assembly to assembly cache. - TypeInfo enumTypeinfo = enumBuilder.CreateTypeInfo(); - PSAssemblyLoadContext.TryAddAssemblyToCache(enumTypeinfo.Assembly); -#else - enumBuilder.CreateTypeInfo(); -#endif - } - -#if CORECLR - /// - /// Probe (look for) the assembly file with the specified short name. - /// - /// - /// In Core PowerShell, we need to analyze the metadata of assembly files for binary modules. Sometimes we - /// need to find an assembly file that is referenced by the assembly file that is being processed. To find - /// the reference assembly file, we need to probe the PSBase and the additional searching path if it's specified. - /// - internal static string ProbeAssemblyPath(string assemblyShortName, string additionalSearchPath = null) - { - if (string.IsNullOrWhiteSpace(assemblyShortName)) - { - throw new ArgumentNullException("assemblyShortName"); - } - - return PSAssemblyLoadContext.ProbeAssemblyFileForMetadataAnalysis(assemblyShortName, additionalSearchPath); - } - /// /// Get the namespace-qualified type names of all available CoreCLR .NET types. /// This is used for type name auto-completion in PS engine. diff --git a/src/TypeCatalogGen/TypeCatalogGen.cs b/src/TypeCatalogGen/TypeCatalogGen.cs index 7d3522a6f5c..2078ab07ddd 100644 --- a/src/TypeCatalogGen/TypeCatalogGen.cs +++ b/src/TypeCatalogGen/TypeCatalogGen.cs @@ -424,7 +424,7 @@ private static void WritePowerShellAssemblyLoadContextPartialClass(string target namespace System.Management.Automation {{ - internal partial class PowerShellAssemblyLoadContext : AssemblyLoadContext + internal partial class PowerShellAssemblyLoadContext {{ private Dictionary InitializeTypeCatalog() {{ diff --git a/src/powershell/Program.cs b/src/powershell/Program.cs index 573e1ead870..20b84250da8 100644 --- a/src/powershell/Program.cs +++ b/src/powershell/Program.cs @@ -3,7 +3,6 @@ --********************************************************************/ using System; -using System.Management.Automation; using System.Reflection; namespace Microsoft.PowerShell @@ -21,19 +20,7 @@ public sealed class ManagedPSEntry /// public static int Main(string[] args) { -#if CORECLR - // PowerShell has to set the ALC here, since we don't own the native host - string appBase = System.IO.Path.GetDirectoryName(typeof(ManagedPSEntry).GetTypeInfo().Assembly.Location); - return (int)PowerShellAssemblyLoadContextInitializer. - InitializeAndCallEntryMethod( - appBase, - new AssemblyName("Microsoft.PowerShell.ConsoleHost, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"), - "Microsoft.PowerShell.UnmanagedPSEntry", - "Start", - new object[] { string.Empty, args, args.Length }); -#else return UnmanagedPSEntry.Start(string.Empty, args, args.Length); -#endif } } } From 042631a62e75bc33e15fd5bb34176664273e7e16 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Sun, 28 May 2017 23:13:21 -0700 Subject: [PATCH 2/4] Refactoring - Set 2 --- .../cmdletization/cim/cimConverter.cs | 2 +- .../commands/management/Process.cs | 23 +- .../commands/management/Service.cs | 2 +- .../commands/utility/AddType.cs | 18 +- .../commands/utility/Import-LocalizedData.cs | 2 +- .../host/msh/ConsoleHost.cs | 4 +- .../host/msh/ManagedEntrance.cs | 5 +- .../CoreCLR/CorePsAssemblyLoadContext.cs | 163 -------------- .../CoreCLR/CorePsExtensions.cs | 16 +- .../CommandCompletion/CompletionCompleters.cs | 8 - .../engine/CommandInfo.cs | 3 +- .../engine/ExecutionContext.cs | 2 +- .../engine/InitialSessionState.cs | 6 +- .../engine/Utils.cs | 2 +- .../engine/hostifaces/LocalPipeline.cs | 4 +- .../engine/parser/Compiler.cs | 2 +- .../fanin/InitialSessionStateProvider.cs | 2 +- .../engine/remoting/fanin/WSManNativeAPI.cs | 2 +- .../engine/remoting/fanin/WSManPlugin.cs | 6 +- .../remoting/fanin/WSManPluginShellSession.cs | 2 +- .../fanin/WSManPluginTransportManager.cs | 2 +- .../help/UpdateHelpCommand.cs | 2 +- .../minishell/api/RunspaceConfiguration.cs | 2 +- .../resources/ParserStrings.resx | 3 - .../security/SecureStringHelper.cs | 2 +- .../security/SecuritySupport.cs | 2 +- .../config/RunspaceConfigForSingleShell.cs | 4 +- .../utils/ClrFacade.cs | 199 +----------------- .../utils/CryptoUtils.cs | 2 +- 29 files changed, 49 insertions(+), 443 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs index 35e968d4d3b..6792eb6568e 100644 --- a/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs +++ b/src/Microsoft.PowerShell.Commands.Management/cimSupport/cmdletization/cim/cimConverter.cs @@ -80,7 +80,7 @@ internal void Copy(string source, int offset) internal void Copy(SecureString source, int offset) { - IntPtr plainTextString = ClrFacade.SecureStringToCoTaskMemUnicode(source); + IntPtr plainTextString = Marshal.SecureStringToCoTaskMemUnicode(source); try { unsafe diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs index ed1b0881ab1..a7a24588708 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs @@ -641,7 +641,7 @@ protected override void ProcessRecord() { //assigning to tempmodule to rethrow for exceptions on 64 bit machines tempmodule = pmodule; - WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(pmodule), true); + WriteObject(pmodule.FileVersionInfo, true); } } catch (InvalidOperationException exception) @@ -658,7 +658,7 @@ protected override void ProcessRecord() { if (exception.HResult == 299) { - WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(tempmodule), true); + WriteObject(tempmodule.FileVersionInfo, true); } else { @@ -710,7 +710,7 @@ protected override void ProcessRecord() //if fileversion of each process is to be displayed try { - WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(PsUtils.GetMainModule(process)), true); + WriteObject(PsUtils.GetMainModule(process).FileVersionInfo, true); } catch (InvalidOperationException exception) { @@ -726,7 +726,7 @@ protected override void ProcessRecord() { if (exception.HResult == 299) { - WriteObject(ClrFacade.GetProcessModuleFileVersionInfo(PsUtils.GetMainModule(process)), true); + WriteObject(PsUtils.GetMainModule(process).FileVersionInfo, true); } else { @@ -1966,7 +1966,7 @@ protected override void BeginProcessing() //UseNewEnvironment if (_UseNewEnvironment) { - ClrFacade.GetProcessEnvironment(startInfo).Clear(); + startInfo.EnvironmentVariables.Clear(); LoadEnvironmentVariable(startInfo, Environment.GetEnvironmentVariables(EnvironmentVariableTarget.Machine)); LoadEnvironmentVariable(startInfo, Environment.GetEnvironmentVariables(EnvironmentVariableTarget.User)); } @@ -2173,7 +2173,7 @@ private string ResolveFilePath(string path) private void LoadEnvironmentVariable(ProcessStartInfo startinfo, IDictionary EnvironmentVariables) { - var processEnvironment = ClrFacade.GetProcessEnvironment(startinfo); + var processEnvironment = startinfo.EnvironmentVariables; foreach (DictionaryEntry entry in EnvironmentVariables) { if (processEnvironment.ContainsKey(entry.Key.ToString())) @@ -2373,12 +2373,7 @@ private static StringBuilder BuildCommandLine(string executableFileName, string return builder; } - private static byte[] ConvertEnvVarsToByteArray( -#if CORECLR - IDictionary sd) -#else - StringDictionary sd) -#endif + private static byte[] ConvertEnvVarsToByteArray(StringDictionary sd) { string[] array = new string[sd.Count]; byte[] bytes = null; @@ -2497,7 +2492,7 @@ private Process StartWithCreateProcess(ProcessStartInfo startinfo) creationFlags |= 0x00000004; IntPtr AddressOfEnvironmentBlock = IntPtr.Zero; - var environmentVars = ClrFacade.GetProcessEnvironment(startinfo); + var environmentVars = startinfo.EnvironmentVariables; if (environmentVars != null) { if (this.UseNewEnvironment) @@ -2647,7 +2642,7 @@ internal ProcessCollection() internal bool AssignProcessToJobObject(Process process) { // Add the process to the job object - bool result = NativeMethods.AssignProcessToJobObject(_jobObjectHandle, ClrFacade.GetRawProcessHandle(process)); + bool result = NativeMethods.AssignProcessToJobObject(_jobObjectHandle, process.Handle); return result; } diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs index fb6bedc6586..67a6da5df81 100644 --- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs +++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Service.cs @@ -2054,7 +2054,7 @@ protected override void BeginProcessing() if (null != Credential) { username = Credential.UserName; - password = ClrFacade.SecureStringToCoTaskMemUnicode(Credential.Password); + password = Marshal.SecureStringToCoTaskMemUnicode(Credential.Password); } // Create the service diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs index ef824f8b659..8876ede0153 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/AddType.cs @@ -964,7 +964,7 @@ private void LoadAssemblies(IEnumerable assemblies) Assembly assembly = LoadAssemblyHelper(assemblyName); if (assembly == null) { - assembly = LoadFrom(ResolveAssemblyName(assemblyName, false)); + assembly = Assembly.LoadFrom(ResolveAssemblyName(assemblyName, false)); } if (passThru) @@ -1276,7 +1276,7 @@ private void CompileSourceToAssembly(string source) { ms.Flush(); ms.Seek(0, SeekOrigin.Begin); - Assembly assembly = LoadFrom(ms); + Assembly assembly = Assembly.Load(ms.ToArray()); CheckTypesForDuplicates(assembly); if (passThru) { @@ -1292,7 +1292,7 @@ private void CompileSourceToAssembly(string source) { if (passThru) { - Assembly assembly = LoadFrom(outputAssembly); + Assembly assembly = Assembly.LoadFrom(outputAssembly); CheckTypesForDuplicates(assembly); WriteTypes(assembly); } @@ -1318,16 +1318,6 @@ private AddTypeCompilerError[] GetErrors(ImmutableArray diagnostics) ErrorNumber = d.Id }).ToArray(); } - - private Assembly LoadFrom(Stream assembly) - { - return ClrFacade.LoadFrom(assembly); - } - - private Assembly LoadFrom(string path) - { - return ClrFacade.LoadFrom(path); - } } @@ -1955,7 +1945,7 @@ private void LoadAssemblyFromPathOrName(List generatedTypes) { foreach (string path in paths) { - generatedTypes.AddRange(ClrFacade.LoadFrom(path).GetTypes()); + generatedTypes.AddRange(Assembly.LoadFrom(path).GetTypes()); } } // Load the assembly by name diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs index 9130ea32701..fdcbb57a166 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Import-LocalizedData.cs @@ -285,7 +285,7 @@ private string GetFilePath() { try { - culture = ClrFacade.GetCultureInfo(_uiculture); + culture = CultureInfo.GetCultureInfo(_uiculture); } catch (ArgumentException) { diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index e1ab4f607d0..5dc6229832e 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -1079,8 +1079,8 @@ internal ConsoleHost(RunspaceConfiguration configuration) } #endif - ClrFacade.SetCurrentThreadUiCulture(this.CurrentUICulture); - ClrFacade.SetCurrentThreadCulture(this.CurrentCulture); + Thread.CurrentThread.CurrentUICulture = this.CurrentUICulture; + Thread.CurrentThread.CurrentCulture = this.CurrentCulture; // BUG: 610329. Tell PowerShell engine to apply console // related properties while launching Pipeline Execution // Thread. diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs index f7a0688199d..e6365ae8c2f 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ManagedEntrance.cs @@ -9,6 +9,7 @@ using System.Management.Automation.Runspaces; using System.Management.Automation.Tracing; using System.Globalization; +using System.Threading; #if CORECLR using System.Runtime.InteropServices; @@ -65,8 +66,8 @@ public int Start(string consoleFilePath, string[] args) // The currentUICulture returned NativeCultureResolver supports this non // traditional fallback on Vista. So it is important to set currentUICulture // in the beginning before we do anything. - ClrFacade.SetCurrentThreadUiCulture(NativeCultureResolver.UICulture); - ClrFacade.SetCurrentThreadCulture(NativeCultureResolver.Culture); + Thread.CurrentThread.CurrentUICulture = NativeCultureResolver.UICulture; + Thread.CurrentThread.CurrentCulture = NativeCultureResolver.Culture; RunspaceConfigForSingleShell configuration = null; PSConsoleLoadException warning = null; diff --git a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs index ddfc7935a47..b215d69dcd7 100644 --- a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs +++ b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs @@ -31,11 +31,7 @@ internal partial class PowerShellAssemblyLoadContext // When the first attempt fails, we again need to retrieve the resource string to construct another exception, which ends up with an infinite loop. private const string BaseFolderDoesNotExist = "The base directory '{0}' does not exist."; private const string ManifestDefinitionDoesNotMatch = "Could not load file or assembly '{0}' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference."; - private const string AssemblyPathDoesNotExist = "Could not load file or assembly '{0}' or one of its dependencies. The system cannot find the file specified."; - private const string InvalidAssemblyExtensionName = "Could not load file or assembly '{0}' or one of its dependencies. The file specified is not a DLL file."; - private const string AbsolutePathRequired = "Absolute path information is required."; private const string SingletonAlreadyInitialized = "The singleton of PowerShellAssemblyLoadContext has already been initialized."; - private const string UseResolvingEventHandlerOnly = "PowerShellAssemblyLoadContext was initialized to use its 'Resolving' event handler only."; #endregion Resource_Strings @@ -148,97 +144,8 @@ internal static PowerShellAssemblyLoadContext Instance #endregion Properties - #region Events - - /// - /// Assembly load event - /// - internal event Action AssemblyLoad; - - #endregion Events - #region Internal_Methods - /// - /// Load an IL or NI assembly from its file path. - /// - internal Assembly LoadFrom(string assemblyPath) - { - ValidateAssemblyPath(assemblyPath, "assemblyPath"); - - Assembly asmLoaded; - AssemblyName assemblyName = AssemblyLoadContext.GetAssemblyName(assemblyPath); - - // Probe the assembly cache - if (TryGetAssemblyFromCache(assemblyName, out asmLoaded)) - return asmLoaded; - - // Prepare to load the assembly - lock (s_syncObj) - { - // Probe the cache again in case it's already loaded - if (TryGetAssemblyFromCache(assemblyName, out asmLoaded)) - return asmLoaded; - - // Load the assembly through 'LoadFromNativeImagePath' or 'LoadFromAssemblyPath' - asmLoaded = assemblyPath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase) - ? AssemblyLoadContext.Default.LoadFromNativeImagePath(assemblyPath, null) - : AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); - - if (asmLoaded != null) - { - // Add the loaded assembly to the cache - s_assemblyCache.TryAdd(assemblyName.Name, asmLoaded); - // Add its parent path to our probing paths - string parentPath = Path.GetDirectoryName(assemblyPath); - if (!_probingPaths.Contains(parentPath)) - { - _probingPaths.Add(parentPath); - } - } - } - - // Raise AssemblyLoad event - OnAssemblyLoaded(asmLoaded); - return asmLoaded; - } - - /// - /// Load assembly from byte stream. - /// - internal Assembly LoadFrom(Stream assembly) - { - if (assembly == null) - throw new ArgumentNullException("assembly"); - - Assembly asmLoaded; - AssemblyName assemblyName = GetAssemblyName(assembly); - - // Probe the assembly cache - if (TryGetAssemblyFromCache(assemblyName, out asmLoaded)) - return asmLoaded; - - // Prepare to load the assembly - lock (s_syncObj) - { - // Probe the cache again in case it's already loaded - if (TryGetAssemblyFromCache(assemblyName, out asmLoaded)) - return asmLoaded; - - // Load the assembly through 'LoadFromStream' - asmLoaded = AssemblyLoadContext.Default.LoadFromStream(assembly); - if (asmLoaded != null) - { - // Add the loaded assembly to the cache - s_assemblyCache.TryAdd(assemblyName.Name, asmLoaded); - } - } - - // Raise AssemblyLoad event - OnAssemblyLoaded(asmLoaded); - return asmLoaded; - } - /// /// Get the current loaded assemblies /// @@ -385,79 +292,9 @@ private Assembly Resolve(AssemblyLoadContext loadContext, AssemblyName assemblyN } } - // Raise AssemblyLoad event - OnAssemblyLoaded(asmLoaded); return asmLoaded; } - /// - /// Handle the AssemblyLoad event - /// - private void OnAssemblyLoaded(Assembly assemblyLoaded) - { - Action assemblyLoadHandler = AssemblyLoad; - if (assemblyLoaded != null && assemblyLoadHandler != null) - { - try - { - assemblyLoadHandler(assemblyLoaded); - } - catch - { - // Catch all exceptions, same behavior as AppDomain.AssemblyLoad - } - } - } - - /// - /// Validate assembly path value for the specified parameter - /// - private void ValidateAssemblyPath(string assemblyPath, string parameterName) - { - if (string.IsNullOrEmpty(assemblyPath)) - { - throw new ArgumentNullException(parameterName); - } - - if (!Path.IsPathRooted(assemblyPath)) - { - throw new ArgumentException(AbsolutePathRequired, parameterName); - } - - if (!File.Exists(assemblyPath)) - { - ThrowFileNotFoundException( - AssemblyPathDoesNotExist, - assemblyPath); - } - - if (!string.Equals(Path.GetExtension(assemblyPath), ".DLL", StringComparison.OrdinalIgnoreCase)) - { - ThrowFileLoadException( - InvalidAssemblyExtensionName, - assemblyPath); - } - } - - /// - /// Get AssemblyName of an assembly stream - /// - private AssemblyName GetAssemblyName(Stream assembly) - { - if (assembly == null) - throw new ArgumentNullException("assembly"); - - string strongAssemblyName = null; - using (PEReader peReader = new PEReader(assembly, PEStreamOptions.LeaveOpen | PEStreamOptions.PrefetchMetadata)) - { - MetadataReader metadataReader = peReader.GetMetadataReader(); - strongAssemblyName = AssemblyMetadataHelper.GetAssemblyStrongName(metadataReader); - } - - assembly.Seek(0, SeekOrigin.Begin); - return new AssemblyName(strongAssemblyName); - } - /// /// Try to get the specified assembly from cache /// diff --git a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs index 7434907a2a8..20d0032ccef 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsExtensions.cs @@ -5,9 +5,8 @@ namespace Microsoft.PowerShell.CoreCLR { - using System.IO; + using System; using System.Reflection; - using System.Management.Automation; /// /// AssemblyExtensions @@ -19,19 +18,10 @@ public static class AssemblyExtensions /// /// The path of the file that contains the manifest of the assembly. /// The loaded assembly. + [ObsoleteAttribute("This method is obsolete. Call Assembly.LoadFrom instead", false)] public static Assembly LoadFrom(string assemblyPath) { - return ClrFacade.LoadFrom(assemblyPath); - } - - /// - /// Load an assembly given its byte stream - /// - /// The byte stream of assembly - /// The loaded assembly - public static Assembly LoadFrom(Stream assembly) - { - return ClrFacade.LoadFrom(assembly); + return Assembly.LoadFrom(assemblyPath); } } } diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index 65d8ee8f152..e6d9978dd0e 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -35,18 +35,10 @@ public static class CompletionCompleters { static CompletionCompleters() { -#if CORECLR - ClrFacade.AddAssemblyLoadHandler(UpdateTypeCacheOnAssemblyLoad); -#else AppDomain.CurrentDomain.AssemblyLoad += UpdateTypeCacheOnAssemblyLoad; -#endif } -#if CORECLR - static void UpdateTypeCacheOnAssemblyLoad(Assembly loadedAssembly) -#else private static void UpdateTypeCacheOnAssemblyLoad(object sender, AssemblyLoadEventArgs args) -#endif { // Just null out the cache - we'll rebuild it the next time someone tries to complete a type. // We could rebuild it now, but we could be loading multiple assemblies (e.g. dependent assemblies) diff --git a/src/System.Management.Automation/engine/CommandInfo.cs b/src/System.Management.Automation/engine/CommandInfo.cs index d07e073fdc3..168fe41cd9f 100644 --- a/src/System.Management.Automation/engine/CommandInfo.cs +++ b/src/System.Management.Automation/engine/CommandInfo.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.Management.Automation.Language; using System.Management.Automation.Runspaces; +using System.Reflection; using System.Runtime.ExceptionServices; using Microsoft.PowerShell.Commands; @@ -227,7 +228,7 @@ public virtual Version Version else if (Module.Path.EndsWith(StringLiterals.DependentWorkflowAssemblyExtension, StringComparison.OrdinalIgnoreCase)) { // Binary module (.dll) - Module.SetVersion(ClrFacade.GetAssemblyName(Module.Path).Version); + Module.SetVersion(AssemblyName.GetAssemblyName(Module.Path).Version); } } diff --git a/src/System.Management.Automation/engine/ExecutionContext.cs b/src/System.Management.Automation/engine/ExecutionContext.cs index 184407858cc..0200aa5920f 100644 --- a/src/System.Management.Automation/engine/ExecutionContext.cs +++ b/src/System.Management.Automation/engine/ExecutionContext.cs @@ -1375,7 +1375,7 @@ internal static Assembly LoadAssembly(string name, string filename, out Exceptio try { - loadedAssembly = ClrFacade.LoadFrom(filename); + loadedAssembly = Assembly.LoadFrom(filename); return loadedAssembly; } catch (FileNotFoundException fileNotFound) diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index dec502579fd..5af8be7ebef 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -4467,7 +4467,7 @@ internal static Assembly LoadAssemblyFromFile(string fileName) { s_PSSnapInTracer.WriteLine("Loading assembly for psSnapIn {0}", fileName); - Assembly assembly = ClrFacade.LoadFrom(fileName); + Assembly assembly = Assembly.LoadFrom(fileName); if (assembly == null) { s_PSSnapInTracer.TraceError("Loading assembly for psSnapIn {0} failed", fileName); @@ -5543,7 +5543,7 @@ internal static Assembly LoadPSSnapInAssembly(PSSnapInInfo psSnapInInfo, try { - AssemblyName assemblyName = ClrFacade.GetAssemblyName(psSnapInInfo.AbsoluteModulePath); + AssemblyName assemblyName = AssemblyName.GetAssemblyName(psSnapInInfo.AbsoluteModulePath); if (!string.Equals(assemblyName.FullName, psSnapInInfo.AssemblyName, StringComparison.OrdinalIgnoreCase)) { @@ -5552,7 +5552,7 @@ internal static Assembly LoadPSSnapInAssembly(PSSnapInInfo psSnapInInfo, throw new PSSnapInException(psSnapInInfo.Name, message); } - assembly = ClrFacade.LoadFrom(psSnapInInfo.AbsoluteModulePath); + assembly = Assembly.LoadFrom(psSnapInInfo.AbsoluteModulePath); } catch (FileLoadException e) { diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 6c1b3bd945f..9b8c4294afc 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -175,7 +175,7 @@ internal static string GetStringFromSecureString(SecureString ss) try { - p = ClrFacade.SecureStringToCoTaskMemUnicode(ss); + p = Marshal.SecureStringToCoTaskMemUnicode(ss); s = Marshal.PtrToStringUni(p); } finally diff --git a/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs b/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs index 3f3b54c3d1c..0a583a9a50c 100644 --- a/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs +++ b/src/System.Management.Automation/engine/hostifaces/LocalPipeline.cs @@ -217,8 +217,8 @@ protected override void StartPipelineExecution() finally { NestedPipelineExecutionThread = oldNestedPipelineThread; - ClrFacade.SetCurrentThreadCulture(oldCurrentCulture); - ClrFacade.SetCurrentThreadUiCulture(oldCurrentUICulture); + Thread.CurrentThread.CurrentCulture = oldCurrentCulture; + Thread.CurrentThread.CurrentUICulture = oldCurrentUICulture; } break; } diff --git a/src/System.Management.Automation/engine/parser/Compiler.cs b/src/System.Management.Automation/engine/parser/Compiler.cs index bb7fc7dc087..34c0828daa3 100644 --- a/src/System.Management.Automation/engine/parser/Compiler.cs +++ b/src/System.Management.Automation/engine/parser/Compiler.cs @@ -2370,7 +2370,7 @@ private static Assembly LoadAssembly(string assemblyName, string scriptFileName) #endif if (File.Exists(assemblyFileName)) { - assembly = ClrFacade.LoadFrom(assemblyFileName); + assembly = Assembly.LoadFrom(assemblyFileName); } } catch diff --git a/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs b/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs index c11c23ffebc..fc82d5c4f4a 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/InitialSessionStateProvider.cs @@ -700,7 +700,7 @@ private static Assembly LoadSsnStateProviderAssembly(string applicationBase, str //Rooted path of dll is provided. assemblyPath = assemblyName; } - result = ClrFacade.LoadFrom(assemblyPath); + result = Assembly.LoadFrom(assemblyPath); } catch (FileLoadException e) { diff --git a/src/System.Management.Automation/engine/remoting/fanin/WSManNativeAPI.cs b/src/System.Management.Automation/engine/remoting/fanin/WSManNativeAPI.cs index 5145ee0d520..9b0e3afe1a1 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/WSManNativeAPI.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/WSManNativeAPI.cs @@ -348,7 +348,7 @@ internal WSManUserNameAuthenticationCredentials(string name, _cred.userName = name; if (null != pwd) { - _cred.password = ClrFacade.SecureStringToCoTaskMemUnicode(pwd); + _cred.password = Marshal.SecureStringToCoTaskMemUnicode(pwd); } _data = MarshalledObject.Create(_cred); diff --git a/src/System.Management.Automation/engine/remoting/fanin/WSManPlugin.cs b/src/System.Management.Automation/engine/remoting/fanin/WSManPlugin.cs index be79b6a1253..4fff020ca0f 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/WSManPlugin.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/WSManPlugin.cs @@ -383,7 +383,7 @@ internal void CreateShell( if (Platform.IsWindows) { SafeWaitHandle safeWaitHandle = new SafeWaitHandle(requestDetails.shutdownNotificationHandle, false); // Owned by WinRM - ClrFacade.SetSafeWaitHandle(eventWaitHandle, safeWaitHandle); + eventWaitHandle.SafeWaitHandle = safeWaitHandle; } else { @@ -1496,7 +1496,7 @@ internal static void SetThreadProperties( if (retrievingLocaleSucceeded && ((uint)WSManNativeApi.WSManDataType.WSMAN_DATA_TYPE_TEXT == localeData.Type)) { CultureInfo uiCultureToUse = new CultureInfo(localeData.Text); - ClrFacade.SetCurrentThreadUiCulture(uiCultureToUse); + Thread.CurrentThread.CurrentUICulture = uiCultureToUse; } } // ignore if there is any exception constructing the culture.. @@ -1510,7 +1510,7 @@ internal static void SetThreadProperties( if (retrievingDataLocaleSucceeded && ((uint)WSManNativeApi.WSManDataType.WSMAN_DATA_TYPE_TEXT == dataLocaleData.Type)) { CultureInfo cultureToUse = new CultureInfo(dataLocaleData.Text); - ClrFacade.SetCurrentThreadCulture(cultureToUse); + Thread.CurrentThread.CurrentCulture = cultureToUse; } } // ignore if there is any exception constructing the culture.. diff --git a/src/System.Management.Automation/engine/remoting/fanin/WSManPluginShellSession.cs b/src/System.Management.Automation/engine/remoting/fanin/WSManPluginShellSession.cs index 73792fa7ffb..9f88316c8a0 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/WSManPluginShellSession.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/WSManPluginShellSession.cs @@ -266,7 +266,7 @@ internal void ReportContext() // Wrap the provided handle so it can be passed to the registration function SafeWaitHandle safeWaitHandle = new SafeWaitHandle(creationRequestDetails.shutdownNotificationHandle, false); // Owned by WinRM EventWaitHandle eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); - ClrFacade.SetSafeWaitHandle(eventWaitHandle, safeWaitHandle); + eventWaitHandle.SafeWaitHandle = safeWaitHandle; // Register shutdown notification handle this.registeredShutDownWaitHandle = ThreadPool.RegisterWaitForSingleObject( diff --git a/src/System.Management.Automation/engine/remoting/fanin/WSManPluginTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/WSManPluginTransportManager.cs index 2d2c2e4e481..6dc38bf9e8d 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/WSManPluginTransportManager.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/WSManPluginTransportManager.cs @@ -337,7 +337,7 @@ internal bool EnableTransportManagerSendDataToClient( // Wrap the provided handle so it can be passed to the registration function SafeWaitHandle safeWaitHandle = new SafeWaitHandle(requestDetails.shutdownNotificationHandle, false); // Owned by WinRM EventWaitHandle eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); - ClrFacade.SetSafeWaitHandle(eventWaitHandle, safeWaitHandle); + eventWaitHandle.SafeWaitHandle = safeWaitHandle; _registeredShutDownWaitHandle = ThreadPool.RegisterWaitForSingleObject( eventWaitHandle, diff --git a/src/System.Management.Automation/help/UpdateHelpCommand.cs b/src/System.Management.Automation/help/UpdateHelpCommand.cs index 8cc6aa12aec..3659485db50 100644 --- a/src/System.Management.Automation/help/UpdateHelpCommand.cs +++ b/src/System.Management.Automation/help/UpdateHelpCommand.cs @@ -379,7 +379,7 @@ internal override bool ProcessModuleWithCulture(UpdatableHelpModuleInfo module, destPaths.Add(module.ModuleBase); #if !CORECLR // Side-By-Side directories are not present in OneCore environments. - if (IsSystemModule(module.ModuleName) && ClrFacade.Is64BitOperatingSystem()) + if (IsSystemModule(module.ModuleName) && Environment.Is64BitOperatingSystem) { string path = Utils.GetApplicationBase(Utils.DefaultPowerShellShellID).Replace("System32", "SysWOW64"); diff --git a/src/System.Management.Automation/minishell/api/RunspaceConfiguration.cs b/src/System.Management.Automation/minishell/api/RunspaceConfiguration.cs index 526191614ec..1c92270fd5b 100644 --- a/src/System.Management.Automation/minishell/api/RunspaceConfiguration.cs +++ b/src/System.Management.Automation/minishell/api/RunspaceConfiguration.cs @@ -246,7 +246,7 @@ private static RunspaceConfiguration Create(Assembly assembly) if (assembly == null) throw PSTraceSource.NewArgumentNullException("assembly"); - object[] attributes = ClrFacade.GetCustomAttributes(assembly); + object[] attributes = assembly.GetCustomAttributes(typeof(RunspaceConfigurationTypeAttribute), false); if (attributes == null || attributes.Length == 0) { diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx index 2cb1226f57c..141c1f278ab 100644 --- a/src/System.Management.Automation/resources/ParserStrings.resx +++ b/src/System.Management.Automation/resources/ParserStrings.resx @@ -1345,9 +1345,6 @@ ModuleVersion : Version of module to import. If used, ModuleName must represent Cannot run a document in PowerShell Core: {0}. - - 'PowerShellAssemblyLoadContext' is not initialized. - Multiple type constraints are not allowed on a method parameter. diff --git a/src/System.Management.Automation/security/SecureStringHelper.cs b/src/System.Management.Automation/security/SecureStringHelper.cs index 7801daa2041..f96881b1de7 100644 --- a/src/System.Management.Automation/security/SecureStringHelper.cs +++ b/src/System.Management.Automation/security/SecureStringHelper.cs @@ -85,7 +85,7 @@ internal static byte[] GetData(SecureString s) if (s.Length > 0) { - IntPtr ptr = ClrFacade.SecureStringToCoTaskMemUnicode(s); + IntPtr ptr = Marshal.SecureStringToCoTaskMemUnicode(s); try { diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 57d29343f8b..d42557b23c1 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1565,7 +1565,7 @@ internal static int Init() { var processModule = PsUtils.GetMainModule(currentProcess); hostname = string.Concat("PowerShell_", processModule.FileName, "_", - ClrFacade.GetProcessModuleFileVersionInfo(processModule).ProductVersion); + processModule.FileVersionInfo.ProductVersion); } catch (ComponentModel.Win32Exception) { diff --git a/src/System.Management.Automation/singleshell/config/RunspaceConfigForSingleShell.cs b/src/System.Management.Automation/singleshell/config/RunspaceConfigForSingleShell.cs index a05dec34233..55895079c41 100644 --- a/src/System.Management.Automation/singleshell/config/RunspaceConfigForSingleShell.cs +++ b/src/System.Management.Automation/singleshell/config/RunspaceConfigForSingleShell.cs @@ -640,7 +640,7 @@ private Assembly LoadMshSnapinAssembly(PSSnapInInfo mshsnapinInfo) try { - AssemblyName assemblyName = ClrFacade.GetAssemblyName(mshsnapinInfo.AbsoluteModulePath); + AssemblyName assemblyName = AssemblyName.GetAssemblyName(mshsnapinInfo.AbsoluteModulePath); if (string.Compare(assemblyName.FullName, mshsnapinInfo.AssemblyName, StringComparison.OrdinalIgnoreCase) != 0) { string message = StringUtil.Format(ConsoleInfoErrorStrings.PSSnapInAssemblyNameMismatch, mshsnapinInfo.AbsoluteModulePath, mshsnapinInfo.AssemblyName); @@ -648,7 +648,7 @@ private Assembly LoadMshSnapinAssembly(PSSnapInInfo mshsnapinInfo) throw new PSSnapInException(mshsnapinInfo.Name, message); } - assembly = ClrFacade.LoadFrom(mshsnapinInfo.AbsoluteModulePath); + assembly = Assembly.LoadFrom(mshsnapinInfo.AbsoluteModulePath); } catch (FileLoadException e) { diff --git a/src/System.Management.Automation/utils/ClrFacade.cs b/src/System.Management.Automation/utils/ClrFacade.cs index 7f8312cd899..1359f32a1a0 100644 --- a/src/System.Management.Automation/utils/ClrFacade.cs +++ b/src/System.Management.Automation/utils/ClrFacade.cs @@ -56,20 +56,6 @@ static ClrFacade() #region Process - /// - /// Facade for ProcessModule FileVersionInfo - /// - /// - /// FileVersionInfo - internal static FileVersionInfo GetProcessModuleFileVersionInfo(ProcessModule processModule) - { -#if CORECLR - return FileVersionInfo.GetVersionInfo(processModule.FileName); -#else - return processModule.FileVersionInfo; -#endif - } - /// /// Facade for Process.Handle to get SafeHandle /// @@ -84,46 +70,6 @@ internal static SafeHandle GetSafeProcessHandle(Process process) #endif } - /// - /// Facade for Process.Handle to get raw handle - /// - internal static IntPtr GetRawProcessHandle(Process process) - { -#if CORECLR - try - { - return process.SafeHandle.DangerousGetHandle(); - } - catch (InvalidOperationException) - { - // It's possible that the process has already exited when we try to get its handle. - // In that case, InvalidOperationException will be thrown from Process.SafeHandle, - // and we return the invalid zero pointer. - return IntPtr.Zero; - } -#else - return process.Handle; -#endif - } - -#if CORECLR - /// - /// Facade for ProcessStartInfo.Environment - /// - internal static IDictionary GetProcessEnvironment(ProcessStartInfo startInfo) - { - return startInfo.Environment; - } -#else - /// - /// Facade for ProcessStartInfo.EnvironmentVariables - /// - internal static System.Collections.Specialized.StringDictionary GetProcessEnvironment(ProcessStartInfo startInfo) - { - return startInfo.EnvironmentVariables; - } -#endif - #endregion Process #region Marshal @@ -182,32 +128,9 @@ internal static void StructureToPtr( #endif } - /// - /// Facade for SecureStringToCoTaskMemUnicode - /// - internal static IntPtr SecureStringToCoTaskMemUnicode(SecureString s) - { -#if CORECLR - return SecureStringMarshal.SecureStringToCoTaskMemUnicode(s); -#else - return Marshal.SecureStringToCoTaskMemUnicode(s); -#endif - } - #endregion Marshal #region Assembly - /// - /// Facade for AssemblyName.GetAssemblyName(string) - /// - internal static AssemblyName GetAssemblyName(string assemblyPath) - { -#if CORECLR // AssemblyName.GetAssemblyName(assemblyPath) is not in CoreCLR - return AssemblyLoadContext.GetAssemblyName(assemblyPath); -#else - return AssemblyName.GetAssemblyName(assemblyPath); -#endif - } internal static IEnumerable GetAssemblies(TypeResolutionState typeResolutionState, TypeName typeName) { @@ -235,19 +158,6 @@ internal static IEnumerable GetAssemblies(string namespaceQualifiedTyp AppDomain.CurrentDomain.GetAssemblies().Where(a => !(a.FullName.Length > 0 && a.FullName[0] == FIRST_CHAR_PSASSEMBLY_MARK)); } - /// - /// Facade for Assembly.LoadFrom - /// - [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFrom")] - internal static Assembly LoadFrom(string assemblyPath) - { -#if CORECLR - return PSAssemblyLoadContext.LoadFrom(assemblyPath); -#else - return Assembly.LoadFrom(assemblyPath); -#endif - } - #if CORECLR /// /// Get the namespace-qualified type names of all available CoreCLR .NET types. @@ -258,46 +168,8 @@ internal static IEnumerable GetAvailableCoreClrDotNetTypes() return PSAssemblyLoadContext.GetAvailableDotNetTypes(); } - /// - /// Load assembly from byte stream. - /// - internal static Assembly LoadFrom(Stream assembly) - { - return PSAssemblyLoadContext.LoadFrom(assembly); - } - - /// - /// Add the AssemblyLoad handler - /// - internal static void AddAssemblyLoadHandler(Action handler) - { - PSAssemblyLoadContext.AssemblyLoad += handler; - } - - private static PowerShellAssemblyLoadContext PSAssemblyLoadContext - { - get - { - if (PowerShellAssemblyLoadContext.Instance == null) - { - throw new InvalidOperationException(ParserStrings.LoadContextNotInitialized); - } - return PowerShellAssemblyLoadContext.Instance; - } - } -#endif - - /// - /// Facade for Assembly.GetCustomAttributes - /// - internal static object[] GetCustomAttributes(Assembly assembly) - { -#if CORECLR // Assembly.GetCustomAttributes(Type, Boolean) is not in CORE CLR - return assembly.GetCustomAttributes(typeof(T)).ToArray(); -#else - return assembly.GetCustomAttributes(typeof(T), false); + private static PowerShellAssemblyLoadContext PSAssemblyLoadContext => PowerShellAssemblyLoadContext.Instance; #endif - } #endregion Assembly @@ -568,48 +440,6 @@ private static SecurityZone MapSecurityZoneWithUrlmon(string filePath) #endregion Security - #region Culture - - /// - /// Facade for CultureInfo.GetCultureInfo(string). - /// - internal static CultureInfo GetCultureInfo(string cultureName) - { -#if CORECLR - return new CultureInfo(cultureName); -#else - return CultureInfo.GetCultureInfo(cultureName); -#endif - } - - /// - /// Facade for setting CurrentCulture for the CurrentThread - /// - internal static void SetCurrentThreadCulture(CultureInfo cultureInfo) - { -#if CORECLR - CultureInfo.CurrentCulture = cultureInfo; -#else - // Setters for 'CultureInfo.CurrentCulture' is introduced in .NET 4.6 - Thread.CurrentThread.CurrentCulture = cultureInfo; -#endif - } - - /// - /// Facade for setting CurrentUICulture for the CurrentThread - /// - internal static void SetCurrentThreadUiCulture(CultureInfo uiCultureInfo) - { -#if CORECLR - CultureInfo.CurrentUICulture = uiCultureInfo; -#else - // Setters for 'CultureInfo.CurrentUICulture' is introduced in .NET 4.6 - Thread.CurrentThread.CurrentUICulture = uiCultureInfo; -#endif - } - - #endregion Culture - #region Misc /// @@ -692,19 +522,6 @@ internal static string ToDmtfDateTime(DateTime date) #endif } - /// - /// Manual implementation of the is 64bit processor check - /// - /// - internal static bool Is64BitOperatingSystem() - { -#if CORECLR - return (8 == IntPtr.Size); // Pointers are 8 bytes on 64-bit machines -#else - return Environment.Is64BitOperatingSystem; -#endif - } - /// /// Facade for FormatterServices.GetUninitializedObject. /// @@ -744,20 +561,6 @@ internal static object GetUninitializedObject(Type type) #endif } - /// - /// Facade for setting WaitHandle.SafeWaitHandle. - /// - /// - /// - internal static void SetSafeWaitHandle(WaitHandle waitHandle, SafeWaitHandle value) - { -#if CORECLR - waitHandle.SetSafeWaitHandle(value); -#else - waitHandle.SafeWaitHandle = value; -#endif - } - /// /// Facade for ProfileOptimization.SetProfileRoot /// diff --git a/src/System.Management.Automation/utils/CryptoUtils.cs b/src/System.Management.Automation/utils/CryptoUtils.cs index f3bcb747a65..8e7fe44ded7 100644 --- a/src/System.Management.Automation/utils/CryptoUtils.cs +++ b/src/System.Management.Automation/utils/CryptoUtils.cs @@ -995,7 +995,7 @@ protected String EncryptSecureStringCore(SecureString secureString) if (_rsaCryptoProvider.CanEncrypt) { - IntPtr ptr = ClrFacade.SecureStringToCoTaskMemUnicode(secureString); + IntPtr ptr = Marshal.SecureStringToCoTaskMemUnicode(secureString); if (ptr != IntPtr.Zero) { From b84c08be1bdca5f4b0f03b609b7e41333e524e76 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 31 May 2017 14:41:44 -0700 Subject: [PATCH 3/4] Refactoring - Set 3 --- .../CoreCLR/CorePsAssemblyLoadContext.cs | 94 +++++++------------ .../CommandCompletion/CompletionCompleters.cs | 49 +++++----- .../utils/ClrFacade.cs | 15 +-- 3 files changed, 68 insertions(+), 90 deletions(-) diff --git a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs index b215d69dcd7..2250b432ddc 100644 --- a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs +++ b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs @@ -61,35 +61,30 @@ internal static PowerShellAssemblyLoadContext InitializeSingleton(string basePat /// private PowerShellAssemblyLoadContext(string basePaths) { - #region Validation + // FIRST: Validate and populate probing paths if (string.IsNullOrEmpty(basePaths)) { - _basePaths = Array.Empty(); + _probingPaths = Array.Empty(); } else { - _basePaths = basePaths.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - for (int i = 0; i < _basePaths.Length; i++) + _probingPaths = basePaths.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < _probingPaths.Length; i++) { - string basePath = _basePaths[i]; + string basePath = _probingPaths[i]; if (!Directory.Exists(basePath)) { - string message = string.Format( - CultureInfo.CurrentCulture, - BaseFolderDoesNotExist, - basePath); + string message = string.Format(CultureInfo.CurrentCulture, BaseFolderDoesNotExist, basePath); throw new ArgumentException(message, "basePaths"); } - _basePaths[i] = basePath.Trim(); + _probingPaths[i] = basePath.Trim(); } } - #endregion Validation - - // FIRST: Add basePaths to probing paths - _probingPaths = new List(_basePaths); // NEXT: Initialize the CoreCLR type catalog dictionary [OrdinalIgnoreCase] _coreClrTypeCatalog = InitializeTypeCatalog(); + _availableDotNetAssemblyNames = new Lazy>( + () => new HashSet(_coreClrTypeCatalog.Values, StringComparer.Ordinal)); // LAST: Register 'Resolving' handler on the default load context. AssemblyLoadContext.Default.Resolving += Resolve; @@ -100,18 +95,13 @@ private PowerShellAssemblyLoadContext(string basePaths) #region Fields private readonly static object s_syncObj = new object(); - private readonly string[] _basePaths; - // Initially, 'probingPaths' only contains psbase path. But every time we load an assembly through 'LoadFrom(string AssemblyPath)', we - // add its parent path to 'probingPaths', so that we are able to support implicit loading of an assembly from the same place where the - // requesting assembly is located. - // We don't need to worry about removing any paths from 'probingPaths', because once an assembly is loaded, it won't be unloaded until - // the current process exits, and thus the assembly itself and its parent folder cannot be deleted or renamed. - private readonly List _probingPaths; + private readonly string[] _probingPaths; + private readonly string[] _extensions = new string[] { ".ni.dll", ".dll" }; // CoreCLR type catalog dictionary // - Key: namespace qualified type name (FullName) // - Value: strong name of the TPA that contains the type represented by Key. private readonly Dictionary _coreClrTypeCatalog; - private readonly string[] _extensions = new string[] { ".ni.dll", ".dll" }; + private readonly Lazy> _availableDotNetAssemblyNames; /// /// Assembly cache across the AppDomain @@ -142,6 +132,24 @@ internal static PowerShellAssemblyLoadContext Instance get; private set; } + /// + /// Get the namespace-qualified type names of all available .NET Core types shipped with PowerShell Core. + /// This is used for type name auto-completion in PS engine. + /// + internal IEnumerable AvailableDotNetTypeNames + { + get { return _coreClrTypeCatalog.Keys; } + } + + /// + /// Get the assembly names of all available .NET Core assemblies shipped with PowerShell Core. + /// This is used for type name auto-completion in PS engine. + /// + internal HashSet AvailableDotNetAssemblyNames + { + get { return _availableDotNetAssemblyNames.Value; } + } + #endregion Properties #region Internal_Methods @@ -155,22 +163,13 @@ internal IEnumerable GetAssembly(string namespaceQualifiedTypeName) // then we only return that specific TPA assembly. if (!string.IsNullOrEmpty(namespaceQualifiedTypeName)) { - string tpaStrongName; - if (_coreClrTypeCatalog.TryGetValue(namespaceQualifiedTypeName, out tpaStrongName)) + if (_coreClrTypeCatalog.TryGetValue(namespaceQualifiedTypeName, out string tpaStrongName)) { try { return new Assembly[] { GetTrustedPlatformAssembly(tpaStrongName) }; } - catch (FileNotFoundException) - { - // It's possible that the type catalog generated in OPS contains more entries than - // the one generated in windows build. This is because in OPS we have more freedom - // to control what packages to depend on, such as Json.NET. - // If we deploy the PSALC.dll generated from OPS to NanoServer, then it's possible - // that 'GetTrustedPlatformAssembly(tpaStrongName)' may fail for such entries. In - // this case, we ignore the exception and return our cached assemblies. - } + catch (FileNotFoundException) { } } } @@ -178,27 +177,9 @@ internal IEnumerable GetAssembly(string namespaceQualifiedTypeName) return null; } - /// - /// Get the namespace-qualified type names of all available CoreCLR .NET types. - /// This is used for type name auto-completion in PS engine. - /// - internal IEnumerable GetAvailableDotNetTypes() - { - return _coreClrTypeCatalog.Keys; - } - /// /// Set the profile optimization root on the appropriate load context /// - /// - /// When using PS ALC as a full fledged ALC in OPS, we don't enable profile optimization. - /// This is because PS assemblies will be recorded in the profile, and the next time OPS - /// starts up, the default context will load the PS assemblies pretty early to ngen them - /// in another CPU core, so our Load override won't track the loading of them, and thus - /// OPS will fail to work. - /// The root cause is that dotnet.exe put all PS assemblies in TPA list. If PS assemblies - /// are not in TPA list, then we can enable profile optimization without a problem. - /// internal void SetProfileOptimizationRootImpl(string directoryPath) { AssemblyLoadContext.Default.SetProfileOptimizationRoot(directoryPath); @@ -207,15 +188,6 @@ internal void SetProfileOptimizationRootImpl(string directoryPath) /// /// Start the profile optimization on the appropriate load context /// - /// - /// When using PS ALC as a full fledged ALC in OPS, we don't enable profile optimization. - /// This is because PS assemblies will be recorded in the profile, and the next time OPS - /// starts up, the default context will load the PS assemblies pretty early to ngen them - /// in another CPU core, so our Load override won't track the loading of them, and thus - /// OPS will fail to work. - /// The root cause is that dotnet.exe put all PS assemblies in TPA list. If PS assemblies - /// are not in TPA list, then we can enable profile optimization without a problem. - /// internal void StartProfileOptimizationImpl(string profile) { AssemblyLoadContext.Default.StartProfileOptimization(profile); @@ -248,7 +220,7 @@ private Assembly Resolve(AssemblyLoadContext loadContext, AssemblyName assemblyN string asmCultureName = assemblyName.CultureName ?? string.Empty; string asmFilePath = null; - for (int i = 0; i < _probingPaths.Count; i++) + for (int i = 0; i < _probingPaths.Length; i++) { string probingPath = _probingPaths[i]; string asmCulturePath = Path.Combine(probingPath, asmCultureName); diff --git a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs index e6d9978dd0e..a6b46b78628 100644 --- a/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs +++ b/src/System.Management.Automation/engine/CommandCompletion/CompletionCompleters.cs @@ -5854,42 +5854,45 @@ private static TypeCompletionMapping[][] InitializeTypeCache() #endregion Process_TypeAccelerators + #region Process_CoreCLR_TypeCatalog +#if CORECLR + // In CoreCLR, we have namespace-qualified type names of all available .NET Core types stored in TypeCatalog. + // Populate the type completion cache using the namespace-qualified type names. + foreach (string fullTypeName in ClrFacade.AvailableDotNetTypeNames) + { + var typeCompInString = new TypeCompletionInStringFormat { FullTypeName = fullTypeName }; + HandleNamespace(entries, typeCompInString.Namespace); + HandleType(entries, fullTypeName, typeCompInString.ShortTypeName, null); + } +#endif + #endregion Process_CoreCLR_TypeCatalog + #region Process_LoadedAssemblies - var assembliesExcludingPSGenerated = ClrFacade.GetAssemblies(); - var allPublicTypes = assembliesExcludingPSGenerated.SelectMany(assembly => + foreach (Assembly assembly in ClrFacade.GetAssemblies()) { +#if CORECLR + // Ignore the assemblies that are already covered by the type catalog + if (ClrFacade.AvailableDotNetAssemblyNames.Contains(assembly.FullName)) { continue; } +#endif try { - return assembly.GetTypes().Where(TypeResolver.IsPublic); + foreach (Type type in assembly.GetTypes()) + { + // Ignore non-public types + if (!TypeResolver.IsPublic(type)) { continue; } + + HandleNamespace(entries, type.Namespace); + HandleType(entries, type.FullName, type.Name, type); + } } catch (ReflectionTypeLoadException) { } - return Type.EmptyTypes; - }); - - foreach (var type in allPublicTypes) - { - HandleNamespace(entries, type.Namespace); - HandleType(entries, type.FullName, type.Name, type); } #endregion Process_LoadedAssemblies - #region Process_CoreCLR_TypeCatalog -#if CORECLR - // In CoreCLR, we have namespace-qualified type names of all available .NET types stored in TypeCatalog of the AssemblyLoadContext. - // Populate the type completion cache using the namespace-qualified type names. - foreach (string fullTypeName in ClrFacade.GetAvailableCoreClrDotNetTypes()) - { - var typeCompInString = new TypeCompletionInStringFormat { FullTypeName = fullTypeName }; - HandleNamespace(entries, typeCompInString.Namespace); - HandleType(entries, fullTypeName, typeCompInString.ShortTypeName, null); - } -#endif - #endregion Process_CoreCLR_TypeCatalog - var grouping = entries.Values.GroupBy(t => t.Key.Count(c => c == '.')).OrderBy(g => g.Key).ToArray(); var localTypeCache = new TypeCompletionMapping[grouping.Last().Key + 1][]; foreach (var group in grouping) diff --git a/src/System.Management.Automation/utils/ClrFacade.cs b/src/System.Management.Automation/utils/ClrFacade.cs index 1359f32a1a0..bfd4797a121 100644 --- a/src/System.Management.Automation/utils/ClrFacade.cs +++ b/src/System.Management.Automation/utils/ClrFacade.cs @@ -46,7 +46,7 @@ static ClrFacade() { PowerShellAssemblyLoadContext.InitializeSingleton(string.Empty); } - } + } /// /// We need it to avoid calling lookups inside dynamic assemblies with PS Types, so we exclude it from GetAssemblies(). @@ -160,13 +160,16 @@ internal static IEnumerable GetAssemblies(string namespaceQualifiedTyp #if CORECLR /// - /// Get the namespace-qualified type names of all available CoreCLR .NET types. + /// Get the namespace-qualified type names of all available .NET Core types shipped with PowerShell Core. /// This is used for type name auto-completion in PS engine. /// - internal static IEnumerable GetAvailableCoreClrDotNetTypes() - { - return PSAssemblyLoadContext.GetAvailableDotNetTypes(); - } + internal static IEnumerable AvailableDotNetTypeNames => PSAssemblyLoadContext.AvailableDotNetTypeNames; + + /// + /// Get the assembly names of all available .NET Core assemblies shipped with PowerShell Core. + /// This is used for type name auto-completion in PS engine. + /// + internal static HashSet AvailableDotNetAssemblyNames => PSAssemblyLoadContext.AvailableDotNetAssemblyNames; private static PowerShellAssemblyLoadContext PSAssemblyLoadContext => PowerShellAssemblyLoadContext.Instance; #endif From 748140186754a132bc884e7037b506a3315bbbe6 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Wed, 31 May 2017 17:03:40 -0700 Subject: [PATCH 4/4] Remove extra spaces in a new line --- .../cimSupport/cmdletization/EnumWriter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/cimSupport/cmdletization/EnumWriter.cs b/src/System.Management.Automation/cimSupport/cmdletization/EnumWriter.cs index d24c3f55e7e..571c3790ab1 100644 --- a/src/System.Management.Automation/cimSupport/cmdletization/EnumWriter.cs +++ b/src/System.Management.Automation/cimSupport/cmdletization/EnumWriter.cs @@ -64,7 +64,7 @@ internal static void Compile(EnumMetadataEnum enumMetadata) object integerValue = LanguagePrimitives.ConvertTo(value.Value, underlyingType, CultureInfo.InvariantCulture); eb.DefineLiteral(name, integerValue); } - + eb.CreateTypeInfo(); } }