From 34f308003b087ecfa69acb2f94bde3563334ebc5 Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Thu, 22 Dec 2016 15:14:06 -0800 Subject: [PATCH] Re-arranging portable TestUtilities part 4 Fix the factored out runtime code to properly execute the compiler compiled test code in AppDomains. --- .../CodeRuntime/AppDomainAssemblyCache.cs | 3 +- .../CodeRuntime/DesktopRuntimeEnvironment.cs | 11 ++- .../CodeRuntime/RuntimeAssemblyManager.cs | 54 ++++--------- .../Desktop/CodeRuntime/RuntimeModuleData.cs | 76 +++++++++++++++++++ .../Utilities/Desktop/DesktopRuntimeUtil.cs | 29 +++++++ .../Desktop/TestUtilities.Desktop.csproj | 1 + .../Compilation/IRuntimeEnvironment.cs | 2 +- .../Portable/Metadata/IlasmUtilities.cs | 2 +- .../Utilities/Portable/Metadata/ModuleData.cs | 14 +++- 9 files changed, 143 insertions(+), 49 deletions(-) create mode 100644 src/Test/Utilities/Desktop/CodeRuntime/RuntimeModuleData.cs diff --git a/src/Test/Utilities/Desktop/CodeRuntime/AppDomainAssemblyCache.cs b/src/Test/Utilities/Desktop/CodeRuntime/AppDomainAssemblyCache.cs index faf6e4672fb..a2195957e01 100644 --- a/src/Test/Utilities/Desktop/CodeRuntime/AppDomainAssemblyCache.cs +++ b/src/Test/Utilities/Desktop/CodeRuntime/AppDomainAssemblyCache.cs @@ -7,6 +7,7 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; +using Roslyn.Test.Utilities; namespace Microsoft.CodeAnalysis.Test.Utilities.CodeRuntime { @@ -73,7 +74,7 @@ internal Assembly GetOrLoad(ModuleData moduleData, bool reflectionOnly) return assembly; } - var loadedAssembly = RuntimeAssemblyManager.LoadAsAssembly(moduleData.SimpleName, moduleData.Image, reflectionOnly); + var loadedAssembly = DesktopRuntimeUtil.LoadAsAssembly(moduleData.SimpleName, moduleData.Image, reflectionOnly); // Validate the loaded assembly matches the value that we now have in the cache. if (!cache.TryGetValue(moduleData.Mvid, out assembly)) diff --git a/src/Test/Utilities/Desktop/CodeRuntime/DesktopRuntimeEnvironment.cs b/src/Test/Utilities/Desktop/CodeRuntime/DesktopRuntimeEnvironment.cs index 23cca68d4a2..b22b640b81f 100644 --- a/src/Test/Utilities/Desktop/CodeRuntime/DesktopRuntimeEnvironment.cs +++ b/src/Test/Utilities/Desktop/CodeRuntime/DesktopRuntimeEnvironment.cs @@ -106,8 +106,13 @@ private RuntimeData CreateAndInitializeRuntimeData(IEnumerable compi // Many prominent assemblys like mscorlib are already in the RuntimeAssemblyManager. Only // add in the delta values to reduce serialization overhead going across AppDomains. var manager = runtimeData.Manager; - var missingList = manager.GetMissing(allModules.Select(x => x.Id).ToList()); - var deltaList = allModules.Where(x => missingList.Contains(x.Id)).ToList(); + var missingList = manager + .GetMissing(allModules.Select(x => new RuntimeModuleDataId(x.Id)).ToList()) + .Select(x => x.Id); + var deltaList = allModules + .Where(x => missingList.Contains(x.Id)) + .Select(x => new RuntimeModuleData(x)) + .ToList(); manager.AddModuleData(deltaList); manager.AddMainModuleMvid(mainModuleId.Mvid); @@ -141,7 +146,7 @@ private static RuntimeData TryGetCachedRuntimeData(IEnumerable modul { var data = s_runtimeDataCache[i]; var manager = data.Manager; - if (!manager.HasConflicts(modules.Select(x => x.Id).ToList())) + if (!manager.HasConflicts(modules.Select(x => new RuntimeModuleDataId(x.Id)).ToList())) { s_runtimeDataCache.RemoveAt(i); return data; diff --git a/src/Test/Utilities/Desktop/CodeRuntime/RuntimeAssemblyManager.cs b/src/Test/Utilities/Desktop/CodeRuntime/RuntimeAssemblyManager.cs index 83165ee12b2..4ddc0b08bce 100644 --- a/src/Test/Utilities/Desktop/CodeRuntime/RuntimeAssemblyManager.cs +++ b/src/Test/Utilities/Desktop/CodeRuntime/RuntimeAssemblyManager.cs @@ -24,7 +24,7 @@ private struct AssemblyData internal ModuleData ModuleData { get; } internal Assembly Assembly { get; } internal Kind Kind => Assembly != null ? Kind.Assembly : Kind.ModuleData; - internal ModuleDataId Id => Assembly != null ? new ModuleDataId(Assembly) : ModuleData.Id; + internal ModuleDataId Id => Assembly != null ? new ModuleDataId(Assembly, Assembly.ManifestModule.ModuleVersionId) : ModuleData.Id; internal AssemblyData(ModuleData moduleData) { @@ -138,7 +138,7 @@ private bool IsOwned(Assembly assembly) || _loadedAssemblies.Contains(assembly); } - internal bool ContainsNetModules() + public bool ContainsNetModules() { return _containsNetModules; } @@ -153,9 +153,9 @@ public override object InitializeLifetimeService() /// return values that are already present. /// /// - internal void AddModuleData(IEnumerable modules) + public void AddModuleData(List modules) { - foreach (var module in modules) + foreach (var module in modules.Select(x => x.Data)) { // If the module is already added then nothing else to do AssemblyData assemblyData; @@ -179,9 +179,9 @@ internal void AddModuleData(IEnumerable modules) } } - public bool HasConflicts(IEnumerable moduleDataIds) + public bool HasConflicts(List moduleDataIds) { - foreach (var id in moduleDataIds) + foreach (var id in moduleDataIds.Select(x => x.Id)) { AssemblyData assemblyData; bool fullMatch; @@ -203,16 +203,16 @@ private void AddAssemblyData(AssemblyData assemblyData) /// /// Return the subset of IDs passed in which are not currently tracked by this instance. /// - public List GetMissing(IEnumerable moduleIds) + public List GetMissing(List moduleIds) { - var list = new List(); - foreach (var id in moduleIds) + var list = new List(); + foreach (var id in moduleIds.Select(x => x.Id)) { AssemblyData other; bool fullMatch; if (!TryGetMatchingByFullName(id, out other, out fullMatch) || !fullMatch) { - list.Add(id); + list.Add(new RuntimeModuleDataId(id)); } } @@ -284,33 +284,7 @@ private Assembly AssemblyResolve(ResolveEventArgs args, bool reflectionOnly) return null; } - /// - /// Loads given array of bytes as an assembly image using or . - /// - internal static Assembly LoadAsAssembly(string moduleName, ImmutableArray rawAssembly, bool reflectionOnly = false) - { - Debug.Assert(!rawAssembly.IsDefault); - - byte[] bytes = rawAssembly.ToArray(); - - try - { - if (reflectionOnly) - { - return Assembly.ReflectionOnlyLoad(bytes); - } - else - { - return Assembly.Load(bytes); - } - } - catch (Exception ex) - { - throw new Exception($"Exception loading {moduleName} reflectionOnly:{reflectionOnly}", ex); - } - } - - internal Assembly GetAssembly(string fullName, bool reflectionOnly) + private Assembly GetAssembly(string fullName, bool reflectionOnly) { AssemblyData data; if (!_fullNameToAssemblyDataMap.TryGetValue(fullName, out data)) @@ -355,7 +329,7 @@ private Module ModuleResolve(object sender, ResolveEventArgs args) return assembly.LoadModule(args.Name, rawModule.ToArray()); } - internal SortedSet GetMemberSignaturesFromMetadata(string fullyQualifiedTypeName, string memberName, IEnumerable searchModules) + public SortedSet GetMemberSignaturesFromMetadata(string fullyQualifiedTypeName, string memberName, List searchModules) { try { @@ -384,7 +358,7 @@ internal SortedSet GetMemberSignaturesFromMetadata(string fullyQualified } } - internal SortedSet GetFullyQualifiedTypeNames(string assemblyName) + private SortedSet GetFullyQualifiedTypeNames(string assemblyName) { var typeNames = new SortedSet(); Assembly assembly = GetAssembly(assemblyName, true); @@ -396,7 +370,7 @@ internal SortedSet GetFullyQualifiedTypeNames(string assemblyName) public int Execute(string moduleName, int expectedOutputLength, out string output) { ImmutableArray bytes = GetModuleBytesByName(moduleName); - Assembly assembly = LoadAsAssembly(moduleName, bytes); + Assembly assembly = DesktopRuntimeUtil.LoadAsAssembly(moduleName, bytes); MethodInfo entryPoint = assembly.EntryPoint; Debug.Assert(entryPoint != null, "Attempting to execute an assembly that has no entrypoint; is your test trying to execute a DLL?"); diff --git a/src/Test/Utilities/Desktop/CodeRuntime/RuntimeModuleData.cs b/src/Test/Utilities/Desktop/CodeRuntime/RuntimeModuleData.cs new file mode 100644 index 00000000000..0d5c2838e8a --- /dev/null +++ b/src/Test/Utilities/Desktop/CodeRuntime/RuntimeModuleData.cs @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using System.Text; +using System.Threading; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.Emit; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.Test.Utilities.CodeRuntime +{ + [Serializable] + public struct RuntimeModuleDataId : ISerializable + { + public ModuleDataId Id { get; } + + public RuntimeModuleDataId(ModuleDataId id) + { + Id = id; + } + + private RuntimeModuleDataId(SerializationInfo info, StreamingContext context) + { + var simpleName = info.GetString(nameof(Id.SimpleName)); + var fullName = info.GetString(nameof(Id.FullName)); + var mvid = (Guid)info.GetValue(nameof(Id.Mvid), typeof(Guid)); + Id = new ModuleDataId(simpleName, fullName, mvid); + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue(nameof(Id.SimpleName), Id.SimpleName); + info.AddValue(nameof(Id.FullName), Id.FullName); + info.AddValue(nameof(Id.Mvid), Id.Mvid); + } + } + + [Serializable, DebuggerDisplay("{GetDebuggerDisplay()}")] + public sealed class RuntimeModuleData : ISerializable + { + public ModuleData Data { get; } + + public RuntimeModuleData(ModuleData data) + { + Data = data; + } + + private RuntimeModuleData(SerializationInfo info, StreamingContext context) + { + var id = (RuntimeModuleDataId)info.GetValue(nameof(ModuleData.Id), typeof(RuntimeModuleDataId)); + var kind = (OutputKind)info.GetInt32(nameof(ModuleData.Kind)); + var image = info.GetByteArray(nameof(ModuleData.Image)); + var pdb = info.GetByteArray(nameof(ModuleData.Pdb)); + var inMemoryModule = info.GetBoolean(nameof(ModuleData.InMemoryModule)); + Data = new ModuleData(id.Id, kind, image, pdb, inMemoryModule); + } + + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue(nameof(ModuleData.Id), new RuntimeModuleDataId(Data.Id)); + info.AddValue(nameof(ModuleData.Kind), (int)Data.Kind); + info.AddByteArray(nameof(ModuleData.Image), Data.Image); + info.AddByteArray(nameof(ModuleData.Pdb), Data.Pdb); + info.AddValue(nameof(ModuleData.InMemoryModule), Data.InMemoryModule); + } + } +} diff --git a/src/Test/Utilities/Desktop/DesktopRuntimeUtil.cs b/src/Test/Utilities/Desktop/DesktopRuntimeUtil.cs index ac74fc7500f..17a2c8abd05 100644 --- a/src/Test/Utilities/Desktop/DesktopRuntimeUtil.cs +++ b/src/Test/Utilities/Desktop/DesktopRuntimeUtil.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; @@ -63,5 +65,32 @@ internal static MetadataReference CreateReflectionEmitAssembly(Action + /// Loads given array of bytes as an assembly image using or . + /// + internal static Assembly LoadAsAssembly(string moduleName, ImmutableArray rawAssembly, bool reflectionOnly = false) + { + Debug.Assert(!rawAssembly.IsDefault); + + byte[] bytes = rawAssembly.ToArray(); + + try + { + if (reflectionOnly) + { + return Assembly.ReflectionOnlyLoad(bytes); + } + else + { + return Assembly.Load(bytes); + } + } + catch (Exception ex) + { + throw new Exception($"Exception loading {moduleName} reflectionOnly:{reflectionOnly}", ex); + } + } + } } diff --git a/src/Test/Utilities/Desktop/TestUtilities.Desktop.csproj b/src/Test/Utilities/Desktop/TestUtilities.Desktop.csproj index 228eaec101a..5ee4bc4ad20 100644 --- a/src/Test/Utilities/Desktop/TestUtilities.Desktop.csproj +++ b/src/Test/Utilities/Desktop/TestUtilities.Desktop.csproj @@ -88,6 +88,7 @@ + diff --git a/src/Test/Utilities/Portable/Compilation/IRuntimeEnvironment.cs b/src/Test/Utilities/Portable/Compilation/IRuntimeEnvironment.cs index 225cb4a85fe..bee66b9519f 100644 --- a/src/Test/Utilities/Portable/Compilation/IRuntimeEnvironment.cs +++ b/src/Test/Utilities/Portable/Compilation/IRuntimeEnvironment.cs @@ -31,7 +31,7 @@ private static IRuntimeEnvironmentFactory GetFactoryImplementation() if (DesktopShim.FileNotFoundException.Type != null) { assemblyName = "Roslyn.Test.Utilities.Desktop"; - typeName = "Roslyn.Test.Utilities.DesktopRuntimeEnvironmentFactory"; + typeName = "Microsoft.CodeAnalysis.Test.Utilities.CodeRuntime.DesktopRuntimeEnvironmentFactory"; } else { diff --git a/src/Test/Utilities/Portable/Metadata/IlasmUtilities.cs b/src/Test/Utilities/Portable/Metadata/IlasmUtilities.cs index a02500fecb3..613fac17882 100644 --- a/src/Test/Utilities/Portable/Metadata/IlasmUtilities.cs +++ b/src/Test/Utilities/Portable/Metadata/IlasmUtilities.cs @@ -57,7 +57,7 @@ public static void IlasmTempAssembly(string declarations, bool appendDefaultHead sourceFile.WriteAllText(completeIL); var ilasmPath = Path.Combine( - CorLightup.Desktop.GetAssemblyLocation(typeof(object).GetTypeInfo().Assembly), + Path.GetDirectoryName(CorLightup.Desktop.GetAssemblyLocation(typeof(object).GetTypeInfo().Assembly)), "ilasm.exe"); var arguments = string.Format( diff --git a/src/Test/Utilities/Portable/Metadata/ModuleData.cs b/src/Test/Utilities/Portable/Metadata/ModuleData.cs index e1530f7a413..18a98d8ed24 100644 --- a/src/Test/Utilities/Portable/Metadata/ModuleData.cs +++ b/src/Test/Utilities/Portable/Metadata/ModuleData.cs @@ -24,12 +24,11 @@ public struct ModuleDataId public string FullName { get; } public Guid Mvid { get; } - public ModuleDataId(Assembly assembly) + public ModuleDataId(Assembly assembly, Guid mvid) { SimpleName = assembly.GetName().Name; FullName = assembly.FullName; - // Replace with mvid - Mvid = default(Guid); + Mvid = mvid; } public ModuleDataId(string simpleName, string fullName, Guid mvid) @@ -77,6 +76,15 @@ public ModuleData(AssemblyIdentity identity, OutputKind kind, ImmutableArray image, ImmutableArray pdb, bool inMemoryModule) + { + this.Id = id; + this.Kind = kind; + this.Image = image; + this.Pdb = pdb; + this.InMemoryModule = inMemoryModule; + } + private static Guid GetMvid(ImmutableArray image) { using (var metadata = ModuleMetadata.CreateFromImage(image)) -- GitLab