This commit is contained in:
Andrey Shchekin 2017-06-27 22:34:46 +12:00
Родитель f0a6b04bca
Коммит dc708c6880
10 изменённых файлов: 124 добавлений и 16 удалений

Просмотреть файл

@ -43,7 +43,7 @@ namespace SharpLab.Server.Compilation.Setups {
// ReSharper disable HeapView.ObjectAllocation.Evident
options.CSharp.ParseOptions = new CSharpParseOptions(MaxLanguageVersion, preprocessorSymbols: PreprocessorSymbols).WithFeatures(_features);
options.CSharp.CompilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true);
options.CSharp.CompilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary);
options.CSharp.MetadataReferences = _references;
// ReSharper restore HeapView.ObjectAllocation.Evident

Просмотреть файл

@ -0,0 +1,69 @@
using System;
using System.IO;
using System.Reflection;
using AppDomainToolkit;
using AshMind.Extensions;
using Microsoft.IO;
using Unbreakable;
namespace SharpLab.Server.Execution {
public class Executor {
private readonly RecyclableMemoryStreamManager _memoryStreamManager;
public Executor(RecyclableMemoryStreamManager memoryStreamManager) {
_memoryStreamManager = memoryStreamManager;
}
public string Execute(Stream assemblyStream) {
using (var guardedStream = _memoryStreamManager.GetStream()) {
RuntimeGuardToken guardToken;
using (assemblyStream) {
guardToken = AssemblyGuard.Rewrite(assemblyStream, guardedStream);
}
var currentSetup = AppDomain.CurrentDomain.SetupInformation;
using (var context = AppDomainContext.Create(new AppDomainSetup {
ApplicationBase = currentSetup.ApplicationBase,
PrivateBinPath = currentSetup.PrivateBinPath
})) {
context.LoadAssembly(LoadMethod.LoadFrom, Assembly.GetExecutingAssembly().GetAssemblyFile().FullName);
return RemoteFunc.Invoke(context.Domain, guardedStream, guardToken, Remote.Execute);
}
}
}
private static class Remote {
public static string Execute(Stream assemblyStream, RuntimeGuardToken guardToken) {
try {
var assembly = Assembly.Load(ReadAllBytes(assemblyStream));
var c = assembly.GetType("C");
var m = c.GetMethod("M");
using (guardToken.Scope()) {
return m.Invoke(Activator.CreateInstance(c), null)?.ToString();
}
}
catch (Exception ex) {
return ex.ToString();
}
}
private static byte[] ReadAllBytes(Stream stream) {
byte[] bytes;
if (stream is MemoryStream memoryStream) {
bytes = memoryStream.GetBuffer();
if (bytes.Length != memoryStream.Length)
bytes = memoryStream.ToArray();
return bytes;
}
// we can't use ArrayPool here as this method is called in a temp AppDomain
bytes = new byte[stream.Length];
if (stream.Read(bytes, 0, (int)stream.Length) != bytes.Length)
throw new NotSupportedException();
return bytes;
}
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharpLab.Server.MirrorSharp.Internal {
public static class TargetNames {
public const string Ast = "AST";
public const string Run = "Run";
}
}

Просмотреть файл

@ -11,6 +11,10 @@ namespace SharpLab.Server.MirrorSharp {
return false;
session.SetTargetName(value);
//if (value == TargetNames.Run) {
// session.Roslyn.Project.
//}
return true;
}
}

Просмотреть файл

@ -12,34 +12,38 @@ using MirrorSharp.Advanced;
using SharpLab.Server.Compilation;
using SharpLab.Server.Decompilation;
using SharpLab.Server.Decompilation.AstOnly;
using SharpLab.Server.Execution;
using SharpLab.Server.MirrorSharp.Internal;
namespace SharpLab.Server.MirrorSharp {
[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)]
public class SlowUpdate : ISlowUpdateExtension {
private const string AstTargetName = "AST";
private readonly ICompiler _compiler;
private readonly IReadOnlyDictionary<string, IDecompiler> _decompilers;
private readonly RecyclableMemoryStreamManager _memoryStreamManager;
private readonly IReadOnlyDictionary<string, IAstTarget> _astTargets;
private readonly Executor _executor;
private readonly RecyclableMemoryStreamManager _memoryStreamManager;
public SlowUpdate(
ICompiler compiler,
IReadOnlyCollection<IDecompiler> decompilers,
RecyclableMemoryStreamManager memoryStreamManager,
IReadOnlyCollection<IAstTarget> astTargets
IReadOnlyCollection<IAstTarget> astTargets,
Executor executor,
RecyclableMemoryStreamManager memoryStreamManager
) {
_compiler = compiler;
_decompilers = decompilers.ToDictionary(d => d.LanguageName);
_memoryStreamManager = memoryStreamManager;
_astTargets = astTargets
.SelectMany(t => t.SupportedLanguageNames.Select(n => (target: t, languageName: n)))
.ToDictionary(x => x.languageName, x => x.target);
_executor = executor;
_memoryStreamManager = memoryStreamManager;
}
public async Task<object> ProcessAsync(IWorkSession session, IList<Diagnostic> diagnostics, CancellationToken cancellationToken) {
var targetName = session.GetTargetName();
if (targetName == AstTargetName) {
if (targetName == TargetNames.Ast) {
var astTarget = _astTargets.GetValueOrDefault(session.LanguageName);
return await astTarget.GetAstAsync(session, cancellationToken).ConfigureAwait(false);
}
@ -47,7 +51,7 @@ namespace SharpLab.Server.MirrorSharp {
if (diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error))
return null;
if (!_decompilers.ContainsKey(targetName))
if (targetName != TargetNames.Run && !_decompilers.ContainsKey(targetName))
throw new NotSupportedException($"Target '{targetName}' is not (yet?) supported by this branch.");
MemoryStream stream = null;
@ -58,6 +62,9 @@ namespace SharpLab.Server.MirrorSharp {
return null;
}
stream.Seek(0, SeekOrigin.Begin);
if (targetName == TargetNames.Run)
return _executor.Execute(stream);
// it's fine not to Dispose() here -- MirrorSharp will dispose it after calling WriteResult()
return stream;
}
@ -74,12 +81,17 @@ namespace SharpLab.Server.MirrorSharp {
}
var targetName = session.GetTargetName();
if (session.GetTargetName() == AstTargetName) {
if (targetName == TargetNames.Ast) {
var astTarget = _astTargets.GetValueOrDefault(session.LanguageName);
astTarget.SerializeAst(result, writer, session);
return;
}
if (targetName == TargetNames.Run) {
writer.WriteValue((string)result);
return;
}
var decompiler = _decompilers[targetName];
using (var stream = (Stream)result)
using (var stringWriter = writer.OpenString()) {

Просмотреть файл

@ -25,6 +25,7 @@
<PackageReference Include="MirrorSharp.Owin" Version="0.9.0-pre-20170523" />
<PackageReference Include="MirrorSharp.VisualBasic" Version="0.9.0-pre-20170523" />
<PackageReference Include="SharpDisasm" Version="1.1.5" />
<PackageReference Include="Unbreakable" Version="0.1.0-unproven" />
</ItemGroup>
<ItemGroup>

Просмотреть файл

@ -9,6 +9,7 @@ using SharpLab.Server.Compilation.Internal;
using SharpLab.Server.Compilation.Setups;
using SharpLab.Server.Decompilation;
using SharpLab.Server.Decompilation.AstOnly;
using SharpLab.Server.Execution;
using SharpLab.Server.MirrorSharp;
namespace SharpLab.Server {
@ -53,6 +54,8 @@ namespace SharpLab.Server {
builder.RegisterType<ILDecompiler>().As<IDecompiler>().SingleInstance();
builder.RegisterType<JitAsmDecompiler>().As<IDecompiler>().SingleInstance();
builder.RegisterType<Executor>().AsSelf().SingleInstance();
builder.RegisterInstance(new RecyclableMemoryStreamManager())
.AsSelf();

Просмотреть файл

@ -82,11 +82,16 @@
<div class="select-wrapper option-target-language option">
<select v-model="options.target">
<option v-bind:value="targets.csharp">C#</option>
<option v-bind:value="targets.vb">Visual Basic</option>
<option v-bind:value="targets.il">IL</option>
<option v-bind:value="targets.asm">JIT Asm</option>
<option v-bind:value="targets.ast">Syntax Tree</option>
<optgroup label="Decompiled">
<option v-bind:value="targets.csharp">C#</option>
<option v-bind:value="targets.vb">Visual Basic</option>
<option v-bind:value="targets.il">IL</option>
<option v-bind:value="targets.asm">JIT Asm</option>
</optgroup>
<optgroup label="Other">
<option v-bind:value="targets.ast">Syntax Tree</option>
<option v-bind:value="targets.run">[Run]</option>
</optgroup>
</select>
</div>

Просмотреть файл

@ -5,5 +5,6 @@ export default Object.freeze({
vb: languages.vb,
il: 'IL',
asm: 'JIT ASM',
ast: 'AST'
ast: 'AST',
run: 'Run'
});

Просмотреть файл

@ -12,7 +12,8 @@ const languageAndTargetMap = {
[languages.fsharp]: 'fs',
[targets.il]: 'il',
[targets.asm]: 'asm',
[targets.ast]: 'ast'
[targets.ast]: 'ast',
[targets.run]: 'run'
};
const languageAndTargetMapReverse = mapObject(languageAndTargetMap, (key, value) => [value, key]);
const targetMapReverseV1 = mapObject(languageAndTargetMapReverse, (key, value) => ['>' + key, value]); // eslint-disable-line prefer-template