CoreCLRRuntimeEnvironment.cs 6.7 KB
Newer Older
J
Jonathon Marolf 已提交
1 2 3
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
J
Jared Parsons 已提交
4
#if NETCOREAPP
T
Ty Overby 已提交
5
using System;
6
using System.Linq;
7 8
using System.Collections.Generic;
using System.Collections.Immutable;
9
using Microsoft.CodeAnalysis;
10
using Microsoft.CodeAnalysis.CodeGen;
11
using Microsoft.CodeAnalysis.Emit;
J
Jared Parsons 已提交
12
using Microsoft.CodeAnalysis.Test.Utilities;
J
Jared Parsons 已提交
13
using static Roslyn.Test.Utilities.RuntimeEnvironmentUtilities;
14

15
namespace Roslyn.Test.Utilities.CoreClr
16
{
T
Ty Overby 已提交
17
    public class CoreCLRRuntimeEnvironment : IRuntimeEnvironment, IInternalRuntimeEnvironment
18
    {
19 20 21 22 23 24 25
        static CoreCLRRuntimeEnvironment()
        {
            SharedConsole.OverrideConsole();
        }

        private readonly IEnumerable<ModuleData> _additionalDependencies;
        private EmitData _emitData;
26 27 28 29 30 31 32
        private CompilationTestData _testData = new CompilationTestData();

        public CoreCLRRuntimeEnvironment(IEnumerable<ModuleData> additionalDependencies = null)
        {
            _additionalDependencies = additionalDependencies;
        }

33 34 35 36 37
        public void Emit(
            Compilation mainCompilation,
            IEnumerable<ResourceDescription> manifestResources,
            EmitOptions emitOptions,
            bool usePdbForDebugging = false)
38 39
        {
            _testData.Methods.Clear();
40

41 42
            var diagnostics = DiagnosticBag.GetInstance();
            var dependencies = new List<ModuleData>();
43 44 45 46
            var mainOutput = EmitCompilation(mainCompilation, manifestResources, dependencies, diagnostics, _testData, emitOptions);

            _emitData = new EmitData();
            _emitData.Diagnostics = diagnostics.ToReadOnlyAndFree();
47 48 49

            if (mainOutput.HasValue)
            {
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
                var mainImage = mainOutput.Value.Assembly;
                var mainPdb = mainOutput.Value.Pdb;
                _emitData.MainModule = new ModuleData(
                    mainCompilation.Assembly.Identity,
                    mainCompilation.Options.OutputKind,
                    mainImage,
                    pdb: usePdbForDebugging ? mainPdb : default(ImmutableArray<byte>),
                    inMemoryModule: true);
                _emitData.MainModulePdb = mainPdb;
                _emitData.AllModuleData = dependencies;

                // We need to add the main module so that it gets checked against already loaded assembly names.
                // If an assembly is loaded directly via PEVerify(image) another assembly of the same full name
                // can't be loaded as a dependency (via Assembly.ReflectionOnlyLoad) in the same domain.
                _emitData.AllModuleData.Insert(0, _emitData.MainModule);
                _emitData.RuntimeData = new RuntimeData(dependencies);
66 67 68
            }
            else
            {
C
CyrusNajmabadi 已提交
69
                DumpAssemblyData(dependencies, out var dumpDir);
70 71 72 73

                // This method MUST throw if compilation did not succeed.  If compilation succeeded and there were errors, that is bad.
                // Please see KevinH if you intend to change this behavior as many tests expect the Exception to indicate failure.
                throw new EmitException(_emitData.Diagnostics, dumpDir);
74 75 76
            }
        }

T
Ty Overby 已提交
77
        public int Execute(string moduleName, string[] args, string expectedOutput)
78
        {
79 80
            var emitData = GetEmitData();
            emitData.RuntimeData.ExecuteRequested = true;
T
Ty Overby 已提交
81
            var (ExitCode, Output) = emitData.LoadContext.Execute(GetMainImage(), args, expectedOutput?.Length);
82

T
Ty Overby 已提交
83
            if (expectedOutput != null && expectedOutput.Trim() != Output.Trim())
84
            {
T
Ty Overby 已提交
85
                throw new ExecutionException(expectedOutput, Output, moduleName);
86 87
            }

T
Ty Overby 已提交
88
            return ExitCode;
89 90
        }

91 92 93 94 95 96 97 98 99
        private EmitData GetEmitData() => _emitData ?? throw new InvalidOperationException("Must call Emit before calling this method");

        public IList<ModuleData> GetAllModuleData() => GetEmitData().AllModuleData;

        public ImmutableArray<Diagnostic> GetDiagnostics() => GetEmitData().Diagnostics;

        public ImmutableArray<byte> GetMainImage() => GetEmitData().MainModule.Image;

        public ImmutableArray<byte> GetMainPdb() => GetEmitData().MainModulePdb;
100

D
dotnet-bot 已提交
101
        public SortedSet<string> GetMemberSignaturesFromMetadata(string fullyQualifiedTypeName, string memberName) =>
J
Jared Parsons 已提交
102
            GetEmitData().GetMemberSignaturesFromMetadata(fullyQualifiedTypeName, memberName);
103

J
Jared Parsons 已提交
104
        public void Verify(Verification verification)
105
        {
106 107
            var emitData = GetEmitData();
            emitData.RuntimeData.PeverifyRequested = true;
A
Andy Gocke 已提交
108
            // TODO(https://github.com/dotnet/coreclr/issues/295): Implement peverify
109 110
        }

J
Jared Parsons 已提交
111
        public string[] VerifyModules(string[] modulesToVerify)
112
        {
A
Andy Gocke 已提交
113
            // TODO(https://github.com/dotnet/coreclr/issues/295): Implement peverify
114
            return null;
115 116
        }

T
Ty Overby 已提交
117
        CompilationTestData IInternalRuntimeEnvironment.GetCompilationTestData()
118 119 120 121 122 123
        {
            return _testData;
        }

        public void Dispose()
        {
T
Ty Overby 已提交
124 125
            // We need Dispose to satisfy the IRuntimeEnvironment interface, but 
            // we don't really need it.
126
        }
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158

        public void CaptureOutput(Action action, int expectedLength, out string output, out string errorOutput)
            => SharedConsole.CaptureOutput(action, expectedLength, out output, out errorOutput);

        private sealed class RuntimeData
        {
            internal TestExecutionLoadContext LoadContext { get; }
            internal bool PeverifyRequested { get; set; }
            internal bool ExecuteRequested { get; set; }
            internal bool Disposed { get; set; }
            internal int ConflictCount { get; set; }

            public RuntimeData(IList<ModuleData> dependencies)
            {
                LoadContext = new TestExecutionLoadContext(dependencies);
            }
        }

        private sealed class EmitData
        {
            internal RuntimeData RuntimeData;

            internal TestExecutionLoadContext LoadContext => RuntimeData?.LoadContext;

            // All of the <see cref="ModuleData"/> created for this Emit
            internal List<ModuleData> AllModuleData;

            // Main module for this emit
            internal ModuleData MainModule;
            internal ImmutableArray<byte> MainModulePdb;

            internal ImmutableArray<Diagnostic> Diagnostics;
159 160 161 162 163

            public SortedSet<string> GetMemberSignaturesFromMetadata(string fullyQualifiedTypeName, string memberName)
            {
                return LoadContext.GetMemberSignaturesFromMetadata(fullyQualifiedTypeName, memberName, AllModuleData.Select(x => x.Id));
            }
164
        }
165 166
    }
}
167
#endif