diff --git a/Disasmo/Resources/DisasmoLoader4.cs_template b/Disasmo/Resources/DisasmoLoader4.cs_template
index 320a3b7..6bf9d11 100644
--- a/Disasmo/Resources/DisasmoLoader4.cs_template
+++ b/Disasmo/Resources/DisasmoLoader4.cs_template
@@ -10,87 +10,81 @@ using System.Runtime.Loader;
public class DisasmoLoader
{
- public static void Main(string[] args)
- {
- PrecompileAllMethodsInType(args);
- }
+ const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
- private static void PrecompileAllMethodsInType(string[] args)
+ static void Main(string[] args)
{
- string assemblyName = args[0];
- string typeName = args[1];
- string methodName = args[2];
- string unloadable = args[3];
+ var (assemblyName, typeName, methodName, unloadable) = (args[0], args[1], args[2], args[3]);
// Another ugly workaround for mangled names till I figure out a proper solution
if (typeName.Contains('_') && typeName.Contains('.'))
typeName = typeName.Substring(typeName.LastIndexOf('.') + 1);
var alc = new AssemblyLoadContext("DisasmoALC", unloadable == "True");
- Assembly asm = alc.LoadFromAssemblyPath(Path.Combine(Environment.CurrentDirectory, assemblyName));
- Type fastType = asm.GetType(typeName);
- if (fastType != null)
+ var asm = alc.LoadFromAssemblyPath(Path.Combine(Environment.CurrentDirectory, assemblyName));
+ if (asm.GetType(typeName) is { } fastType)
{
PrecompileMethods(fastType, methodName);
- PrecompileProperties(fastType, methodName);
- return;
}
-
- foreach (Type type in asm.GetTypes())
+ else
{
- // We replace pluses with dots because 'typeName' is a C#'y name of the type
- // Unfortunately, Roslyn doesn't have a display option to output the runtime name of the type
- // And we do not want to complicate things by formatting the type's name ourselves
- // This is the easiest solution to that problem
- if (type.FullName?.Replace('+', '.').Contains(typeName) == true)
+ foreach (var type in asm.GetTypes())
{
- PrecompileMethods(type, methodName);
- PrecompileProperties(type, methodName);
+ // We replace pluses with dots because 'typeName' is a C#'y name of the type
+ // Unfortunately, Roslyn doesn't have a display option to output the runtime name of the type
+ // And we do not want to complicate things by formatting the type's name ourselves
+ // This is the easiest solution to that problem
+ if (type.FullName?.Replace('+', '.').Contains(typeName) is true)
+ {
+ PrecompileMethods(type, methodName);
+ break;
+ }
}
}
}
- private static void PrecompileProperties(Type type, string propertyName)
+ static void PrecompileMethods(Type type, string methodName)
{
- foreach (PropertyInfo propInfo in type.GetProperties((BindingFlags)60))
+ foreach (var method in type.GetMethods(bindingFlags))
{
- if (propInfo.Name == "*" || propInfo.Name == propertyName)
- {
- if (propInfo.GetMethod != null)
- RuntimeHelpers.PrepareMethod(propInfo.GetMethod.MethodHandle);
- if (propInfo.SetMethod != null)
- RuntimeHelpers.PrepareMethod(propInfo.SetMethod.MethodHandle);
- }
+ if (method.IsGenericMethod)
+ continue;
+
+ if (method.DeclaringType != type && method.DeclaringType is not null)
+ continue;
+
+ if (methodName == "*" || method.Name == methodName)
+ CompileMethod(method);
+ else if (method.Name.Contains(">g__" + methodName)) // Local functions
+ CompileMethod(method);
}
- }
- private static void PrecompileMethods(Type type, string methodName)
- {
- foreach (MethodBase method in
- type.GetMethods((BindingFlags)60).Concat(
- type.GetConstructors((BindingFlags)60).Select(c => (MethodBase)c)))
+ foreach (var constructor in type.GetConstructors(bindingFlags))
{
- if (method.IsGenericMethod)
+ if (methodName == "*" || constructor.Name == methodName)
+ CompileMethod(constructor);
+ }
+
+ foreach (var property in type.GetProperties(bindingFlags))
+ {
+ if (property.DeclaringType != type)
continue;
- try
- {
- if (method.DeclaringType == type || method.DeclaringType == null)
- {
- if (methodName == "*" || method.Name == methodName)
- {
- RuntimeHelpers.PrepareMethod(method.MethodHandle);
- }
- else if (method.Name.Contains(">g__" + methodName))
- {
- // Special case for local functions
- RuntimeHelpers.PrepareMethod(method.MethodHandle);
- }
- }
- }
- catch
+ if (methodName == "*" || property.Name == methodName)
{
+ if (property.GetMethod is { } getMethod)
+ CompileMethod(getMethod);
+
+ if (property.SetMethod is { } setMethod)
+ CompileMethod(setMethod);
}
}
}
-}
+
+ static void CompileMethod(MethodBase methodBase)
+ {
+ if (methodBase is MethodInfo methodInfo)
+ methodInfo.GetBaseDefinition(); // Magic. Forcing the runtime to trigger virtual slots so PrepareMethod also account for interface method implementations
+ RuntimeHelpers.PrepareMethod(methodBase.MethodHandle);
+ }
+}
\ No newline at end of file
diff --git a/Disasmo/Resources/DisasmoLoader4.csproj_template b/Disasmo/Resources/DisasmoLoader4.csproj_template
index 3246253..bfdd267 100644
--- a/Disasmo/Resources/DisasmoLoader4.csproj_template
+++ b/Disasmo/Resources/DisasmoLoader4.csproj_template
@@ -6,6 +6,6 @@
false
false
out
- DisasmoLoader4
+ DisasmoLoader4
diff --git a/Disasmo/Utils/DisassemblyPrettifier.cs b/Disasmo/Utils/DisassemblyPrettifier.cs
index b63612b..7a9b185 100644
--- a/Disasmo/Utils/DisassemblyPrettifier.cs
+++ b/Disasmo/Utils/DisassemblyPrettifier.cs
@@ -24,16 +24,19 @@ public static class DisassemblyPrettifier
/// G_M42249_IG03:
/// C3 ret
///
- /// ; Total bytes of code 76, prolog size 5 for method Program:SelectBucketIndex_old(int):int
+ /// ; Total bytes of code 76, prolog size 5, PerfScore 41.52, instruction count 3, bla-bla for method Program:MyMethod():int (Tier0)
/// ; ============================================================
///
- public static string Prettify(string rawAsm, bool minimalComments)
+ public static string Prettify(string rawAsm, bool minimalComments, bool isInRunMode)
{
+ const string MethodStartedMarker = "; Assembly listing for method ";
+
if (!minimalComments)
return rawAsm;
+
try
- {
- var lines = rawAsm.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
+ {
+ var lines = rawAsm.Split(["\r\n", "\n", "\t"], StringSplitOptions.RemoveEmptyEntries);
var blocks = new List();
var prevBlock = BlockType.Unknown;
@@ -41,20 +44,26 @@ public static string Prettify(string rawAsm, bool minimalComments)
foreach (var line in lines)
{
- if (line.Contains("; Assembly listing for method "))
- currentMethod = line.Remove(0, "; Assembly listing for method ".Length);
- else if (currentMethod == "")
- return rawAsm; // in case if format is changed
+ if (line.StartsWith(MethodStartedMarker))
+ {
+ currentMethod = line.Remove(0, MethodStartedMarker.Length);
+ }
+ else if (currentMethod == "") // In case disasm's output format has changed
+ {
+ Log($"Wrong disasm's output format was detected. isInRunMode: {isInRunMode}");
+ return rawAsm;
+ }
var currentBlock = BlockType.Unknown;
-
if (line.StartsWith(";"))
+ {
currentBlock = BlockType.Comments;
+ }
else if (string.IsNullOrWhiteSpace(line))
{
continue;
}
- else
+ else
{
currentBlock = BlockType.Code;
if (Regex.IsMatch(line, @"^\w+:"))
@@ -65,11 +74,19 @@ public static string Prettify(string rawAsm, bool minimalComments)
if (currentBlock != prevBlock)
{
- blocks.Add(new Block { MethodName = currentMethod, Type = currentBlock, Data = $"\n{line}\n" });
+ var block = new Block(methodName: currentMethod, type: currentBlock);
+ var data = block.MutableData;
+ data.AppendLine().Append(line).AppendLine();
+
+ blocks.Add(block);
prevBlock = currentBlock;
}
else
- blocks[blocks.Count - 1].Data += line + "\n";
+ {
+ var block = blocks[blocks.Count - 1];
+ var data = block.MutableData;
+ data.Append(line).AppendLine();
+ }
}
var blocksByMethods = blocks.GroupBy(b => b.MethodName);
@@ -77,47 +94,62 @@ public static string Prettify(string rawAsm, bool minimalComments)
foreach (var method in blocksByMethods)
{
- List methodBlocks = method.ToList();
+ var methodBlocks = (IEnumerable)method;
- int size = ParseMethodTotalSizes(methodBlocks);
+ var size = ParseMethodTotalSizes(methodBlocks);
- if (minimalComments)
- {
- methodBlocks = methodBlocks.Where(m => m.Type != BlockType.Comments).ToList();
- output.Append($"; Method {method.Key}");
- }
+ methodBlocks = methodBlocks.Where(m => m.Type != BlockType.Comments);
+ output.AppendLine($"; Method {method.Key}");
+
+ output.Append("; Total bytes of code: ")
+ .Append(size)
+ .AppendLine();
foreach (var block in methodBlocks)
- output.Append(block.Data);
+ output.Append(block.ImmutableData);
- if (minimalComments)
- {
- output.Append("; Total bytes of code: ")
- .Append(size)
- .AppendLine()
- .AppendLine();
- }
+ output.AppendLine()
+ .AppendLine();
}
return output.ToString();
}
- catch
+ catch (Exception ex) when (ex is not MemberAccessException) // In case disasm's output format has changed
{
- return rawAsm; // format is changed - leave it as is
+ Log($"Exception. Disasm's output format may have changed. isInRunMode: {isInRunMode}");
}
- }
+ catch { }
- private static int ParseMethodTotalSizes(List methodBlocks)
- {
- const string marker = "; Total bytes of code ";
- string lineToParse = methodBlocks.First(b => b.Data.Contains(marker)).Data;
- int comma = lineToParse.IndexOf(',');
- string size = comma == -1 ?
- lineToParse.Substring(marker.Length) :
- lineToParse.Substring(marker.Length, lineToParse.IndexOf(',') - marker.Length);
- return int.Parse(size);
+ return rawAsm;
+
+ static int ParseMethodTotalSizes(IEnumerable methodBlocks)
+ {
+ const string Marker = "; Total bytes of code ";
+
+ var reversedMethodBlocks = methodBlocks.Reverse();
+ foreach (var methodBlock in reversedMethodBlocks)
+ {
+ var lineToParse = methodBlock.ImmutableData;
+ var markerStartIndex = lineToParse.IndexOf(Marker);
+ if (markerStartIndex == -1)
+ continue;
+
+ var sizePartStartIndex = markerStartIndex + Marker.Length;
+ var commaIndex = lineToParse.IndexOf(',', sizePartStartIndex);
+
+ var sizePartString = commaIndex == -1 ?
+ lineToParse.Substring(sizePartStartIndex) :
+ lineToParse.Substring(sizePartStartIndex, commaIndex - sizePartStartIndex);
+
+ return int.Parse(sizePartString);
+ }
+
+ throw new Exception();
+ }
}
+ private static void Log(string message) => UserLogger.Log($"[{nameof(DisassemblyPrettifier)}] {message}");
+
private enum BlockType
{
Unknown,
@@ -127,8 +159,52 @@ private enum BlockType
private class Block
{
- public string MethodName { get; set; }
- public BlockType Type { get; set; }
- public string Data { get; set; }
+ public Block(string methodName, BlockType type)
+ {
+ MethodName = methodName;
+ Type = type;
+
+ _mutableData = new StringBuilder(64);
+ }
+
+ private StringBuilder _mutableData;
+ private string _immutableData;
+
+ public string MethodName { get; private set; }
+ public BlockType Type { get; private set; }
+
+ public StringBuilder MutableData
+ {
+ get
+ {
+ if (_mutableData is null)
+ {
+ var message = "Undefined behavior was detected. An attempt was made to access cleared data.";
+
+ Log($"Exception. {message}");
+ throw new MemberAccessException(message);
+ }
+
+ return _mutableData;
+ }
+ }
+
+ public string ImmutableData
+ {
+ get
+ {
+ if (_immutableData is null)
+ {
+ _immutableData = _mutableData.ToString();
+
+ // Clear the mutable string field after accessing the immutable string field for the first time
+ _mutableData = null;
+ }
+
+ return _immutableData;
+ }
+ }
+
+ private static void Log(string message) => UserLogger.Log($"[{typeof(DisassemblyPrettifier)}.{typeof(Block)}] {message}");
}
}
\ No newline at end of file
diff --git a/Disasmo/Utils/IntrinsicsSourcesService.cs b/Disasmo/Utils/IntrinsicsSourcesService.cs
index 5da98ef..0584315 100644
--- a/Disasmo/Utils/IntrinsicsSourcesService.cs
+++ b/Disasmo/Utils/IntrinsicsSourcesService.cs
@@ -1,125 +1,206 @@
-using System;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
+using System.Threading;
using System.Threading.Tasks;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Microsoft.CodeAnalysis.Text;
-namespace Disasmo.Utils
+namespace Disasmo.Utils;
+
+public static class IntrinsicsSourcesService
{
- public static class IntrinsicsSourcesService
+ public static async Task> ParseIntrinsics(Action progressReporter)
{
- public static async Task> ParseIntrinsics(Action progressReporter)
+ progressReporter("Fetching data from Github...");
+
+ string[] files =
+ [
+ "X86/Aes.cs",
+ "X86/Avx.cs",
+ "X86/Avx2.cs",
+ "X86/Bmi1.cs",
+ "X86/Bmi2.cs",
+ "X86/Fma.cs",
+ "X86/Lzcnt.cs",
+ "X86/Pclmulqdq.cs",
+ "X86/Popcnt.cs",
+ "X86/Sse.cs",
+ "X86/Sse2.cs",
+ "X86/Sse3.cs",
+ "X86/Sse41.cs",
+ "X86/Sse42.cs",
+ "X86/Ssse3.cs",
+ "X86/X86Base.cs",
+ "X86/X86Serialize.cs",
+ "X86/AvxVnni.cs",
+
+ "X86/Avx512BW.cs",
+ "X86/Avx512CD.cs",
+ "X86/Avx512DQ.cs",
+ "X86/Avx512F.cs",
+ "X86/Avx512Vbmi.cs",
+
+ "Arm/AdvSimd.cs",
+ "Arm/Aes.cs",
+ "Arm/ArmBase.cs",
+ "Arm/Crc32.cs",
+ "Arm/Dp.cs",
+ "Arm/Rdm.cs",
+ "Arm/Sha1.cs",
+ "Arm/Sha256.cs",
+
+ "Vector64.cs",
+ "Vector64_1.cs",
+ "Vector128.cs",
+ "Vector128_1.cs",
+ "Vector256.cs",
+ "Vector256_1.cs",
+ "Vector512.cs",
+ "Vector512_1.cs",
+ ];
+
+ var contents = await DownloadContents(progressReporter, files);
+
+ var progressReport = $"Compiling source code...";
+ progressReporter(progressReport);
+
+ var result = await ParseSourceFile(contents);
+
+ return result;
+ }
+
+ private static async Task DownloadContents(Action progressReporter, string[] files)
+ {
+ using var client = new HttpClient();
+ var contents = new string[files.Length];
+ var tasks = new Task[files.Length];
+
+ var taskIndex = 0;
+ var counter = new ProgressCounter();
+ foreach (var file in files)
{
- List result = new List(600);
- const string baseUrl =
- "https://raw.githubusercontent.com/dotnet/runtime/main/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/";
- string[] files = {
- "X86/Aes.cs",
- "X86/Avx.cs",
- "X86/Avx2.cs",
- "X86/Bmi1.cs",
- "X86/Bmi2.cs",
- "X86/Fma.cs",
- "X86/Lzcnt.cs",
- "X86/Pclmulqdq.cs",
- "X86/Popcnt.cs",
- "X86/Sse.cs",
- "X86/Sse2.cs",
- "X86/Sse3.cs",
- "X86/Sse41.cs",
- "X86/Sse42.cs",
- "X86/Ssse3.cs",
- "X86/X86Base.cs",
- "X86/X86Serialize.cs",
- "X86/AvxVnni.cs",
-
- "X86/Avx512BW.cs",
- "X86/Avx512CD.cs",
- "X86/Avx512DQ.cs",
- "X86/Avx512F.cs",
- "X86/Avx512Vbmi.cs",
-
- "Arm/AdvSimd.cs",
- "Arm/Aes.cs",
- "Arm/ArmBase.cs",
- "Arm/Crc32.cs",
- "Arm/Dp.cs",
- "Arm/Rdm.cs",
- "Arm/Sha1.cs",
- "Arm/Sha256.cs",
-
- "Vector64.cs",
- "Vector64_1.cs",
- "Vector128.cs",
- "Vector128_1.cs",
- "Vector256.cs",
- "Vector256_1.cs",
- "Vector512.cs",
- "Vector512_1.cs",
- };
- foreach (var file in files)
- {
- progressReporter(file);
- result.AddRange(await ParseSourceFile(baseUrl + file));
- }
- return result;
+ tasks[taskIndex] = DownloadContent(
+ progressReporter,
+ client,
+ file,
+ contents,
+ taskIndex++,
+ counter,
+ files.Length);
}
- public static async Task> ParseSourceFile(string url)
+ await Task.WhenAll(tasks);
+
+ return contents;
+
+ static async Task DownloadContent(
+ Action progressReporter,
+ HttpClient client,
+ string file,
+ string[] contents,
+ int contentIndex,
+ ProgressCounter counter,
+ int totalFiles)
{
- var client = new HttpClient();
- string content = await client.GetStringAsync(url);
- var result = new List();
- using (var workspace = new AdhocWorkspace())
- {
- Project proj = workspace.AddProject("ParseIntrinsics", LanguageNames.CSharp)
- .WithMetadataReferences(new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) });
- Document doc = proj.AddDocument("foo", SourceText.From(content));
- Compilation compilation = await doc.Project.GetCompilationAsync();
- SyntaxNode root = await doc.GetSyntaxRootAsync();
- var model = compilation.GetSemanticModel(root.SyntaxTree);
- var methods = root.DescendantNodes().OfType().ToList();
-
- foreach (var method in methods)
- {
- var tokens = method.ChildTokens().ToArray();
- if (tokens.Length > 0)
- {
- var trivia = tokens.FirstOrDefault().LeadingTrivia;
- string comments = string.Join("\n",
- trivia.ToString().Split('\n').Select(i => i.Trim(' ', '\r', '\t'))
- .Where(i => !string.IsNullOrWhiteSpace(i)));
- var symbol = model.GetDeclaredSymbol(method);
- var methodName = symbol.ToString()
- .Replace("System.Runtime.Intrinsics.X86.", "")
- .Replace("System.Runtime.Intrinsics.Arm.", "")
- .Replace("System.Runtime.Intrinsics.", "");
-
- var returnType = method.ReturnType.ToString();
- result.Add(new IntrinsicsInfo { Method = returnType + " " + methodName, Comments = comments });
- }
- }
- }
+ const string RuntimeUrl = "https://raw.githubusercontent.com/dotnet/runtime/main/src/";
+ const string IntrinsicsBaseUrl = RuntimeUrl + "libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/";
+
+ var fileUrl = IntrinsicsBaseUrl + file;
+ contents[contentIndex] = await client.GetStringAsync(fileUrl);
- return result;
+ var progressReport = $"Fetching data from Github...\nFetched {++counter.Count} of {totalFiles} files.";
+ progressReporter(progressReport);
}
}
-
- public class IntrinsicsInfo
+ private static async Task> ParseSourceFile(string[] contents)
{
- public string Comments { get; set; }
- public string Method { get; set; }
+ var intrinsicsInfos = new List(8192);
+ using var workspace = new AdhocWorkspace();
+
+ var project =
+ workspace
+ .AddProject("ParseIntrinsicsProject", LanguageNames.CSharp)
+ .WithMetadataReferences([MetadataReference.CreateFromFile(typeof(object).Assembly.Location)]);
+
+ foreach (var content in contents)
+ {
+ var document = project.AddDocument(name: Guid.NewGuid().ToString(), content);
+ project = document.Project;
+ }
- public bool Contains(string str)
+ var compilation = await project.GetCompilationAsync();
+ foreach (var document in project.Documents)
{
- return Comments.ToLowerInvariant().Contains(str.ToLowerInvariant()) ||
- Method.ToLowerInvariant().Contains(str.ToLowerInvariant());
+ var documentSyntaxRoot = await document.GetSyntaxRootAsync();
+ var model = compilation.GetSemanticModel(documentSyntaxRoot.SyntaxTree);
+ var methods = documentSyntaxRoot.DescendantNodes().OfType();
+
+ foreach (var method in methods)
+ {
+ var tokens = method.ChildTokens();
+ if (!tokens.Any())
+ continue;
+
+ var rootToken = tokens.FirstOrDefault();
+
+ var triviaToken = rootToken.LeadingTrivia;
+ var commentsParts =
+ triviaToken.ToString()
+ .Split('\n')
+ .Select(i => i.Trim(' ', '\r', '\t'))
+ .Where(i => !string.IsNullOrWhiteSpace(i));
+
+ var comments = string.Join("\n", commentsParts);
+ var symbol = model.GetDeclaredSymbol(method);
+ var methodName =
+ symbol.ToString()
+ .Replace("System.Runtime.Intrinsics.X86.", "")
+ .Replace("System.Runtime.Intrinsics.Arm.", "")
+ .Replace("System.Runtime.Intrinsics.", "");
+
+ var returnType = method.ReturnType.ToString();
+
+ var intrinsicsInfo = new IntrinsicsInfo(method: returnType + " " + methodName, comments);
+ intrinsicsInfos.Add(intrinsicsInfo);
+ }
}
- public override string ToString() => Method;
+ return intrinsicsInfos;
+ }
+
+ private class ProgressCounter
+ {
+ private int count;
+
+ public int Count
+ {
+ get => count;
+ set => Interlocked.Exchange(ref count, value);
+ }
}
}
+
+public class IntrinsicsInfo
+{
+ public IntrinsicsInfo(string method, string comments)
+ {
+ _method = method;
+ _comments = comments;
+
+ _cachedDataToCompare = method.ToLower() + '.' + comments.ToLower();
+ }
+
+ private readonly string _method;
+ private readonly string _comments;
+ private readonly string _cachedDataToCompare;
+
+ public string Method { get => _method; set => throw new NotImplementedException(); }
+ public string Comments { get => _comments; set => throw new NotImplementedException(); }
+
+ public bool Contains(string content) => _cachedDataToCompare.Contains(content.ToLowerInvariant());
+
+ public override string ToString() => Method;
+}
\ No newline at end of file
diff --git a/Disasmo/Utils/LoaderAppManager.cs b/Disasmo/Utils/LoaderAppManager.cs
index 99ea4e4..f2dfe22 100644
--- a/Disasmo/Utils/LoaderAppManager.cs
+++ b/Disasmo/Utils/LoaderAppManager.cs
@@ -12,82 +12,90 @@ public static class LoaderAppManager
{
public static readonly string DisasmoLoaderName = "DisasmoLoader4";
- private static async Task GetPathToLoader(string tf, Version addinVersion, CancellationToken ct)
+ private static async Task GetPathToLoader(
+ string targetFramework,
+ Version disasmoVersion,
+ CancellationToken cancellationToken)
{
- ProcessResult dotnetVersion = await ProcessUtils.RunProcess("dotnet", "--version", cancellationToken: ct);
+ var dotnetVersion = await ProcessUtils.RunProcess("dotnet", "--version", cancellationToken: cancellationToken);
UserLogger.Log($"dotnet --version: {dotnetVersion.Output} ({dotnetVersion.Error})");
- string version = dotnetVersion.Output.Trim();
+ var version = dotnetVersion.Output.Trim();
if (!char.IsDigit(version[0]))
{
// Something went wrong, use a random to proceed
version = Guid.NewGuid().ToString("N");
}
- string folderName = $"{addinVersion}_{tf}_{version}";
+ var folderName = $"{disasmoVersion}_{targetFramework}_{version}";
UserLogger.Log($"LoaderAppManager.GetPathToLoader: {folderName}");
return Path.Combine(Path.GetTempPath(), DisasmoLoaderName, folderName);
}
- public static async Task InitLoaderAndCopyTo(string tf, string dest, Action logger, Version addinVersion, CancellationToken ct)
+ public static async Task InitLoaderAndCopyTo(
+ string targetFramework,
+ string destination,
+ Action logger,
+ Version disasmoVersion,
+ CancellationToken cancellationToken)
{
- if (!Directory.Exists(dest))
- throw new InvalidOperationException($"ERROR: dest dir was not found: {dest}");
+ if (!Directory.Exists(destination))
+ throw new InvalidOperationException($"ERROR: destination directory was not found: {destination}");
- string dir;
+ string directory;
try
{
logger("Getting SDK version...");
- dir = await GetPathToLoader(tf, addinVersion, ct);
+ directory = await GetPathToLoader(targetFramework, disasmoVersion, cancellationToken);
}
- catch (Exception exc)
+ catch (Exception ex)
{
- throw new InvalidOperationException("ERROR in LoaderAppManager.GetPathToLoader: " + exc);
+ throw new InvalidOperationException("ERROR in LoaderAppManager.GetPathToLoader: " + ex);
}
- string csproj = Path.Combine(dir, $"{DisasmoLoaderName}.csproj");
- string csfile = Path.Combine(dir, $"{DisasmoLoaderName}.cs");
- string outDll = Path.Combine(dir, "out", $"{DisasmoLoaderName}.dll");
- string outJson = Path.Combine(dir, "out", $"{DisasmoLoaderName}.runtimeconfig.json");
- string outDllDest = Path.Combine(dest, DisasmoLoaderName + ".dll");
- string outJsonDest = Path.Combine(dest, DisasmoLoaderName + ".runtimeconfig.json");
+ var csproj = Path.Combine(directory, $"{DisasmoLoaderName}.csproj");
+ var csfile = Path.Combine(directory, $"{DisasmoLoaderName}.cs");
+ var outDll = Path.Combine(directory, "out", $"{DisasmoLoaderName}.dll");
+ var outJson = Path.Combine(directory, "out", $"{DisasmoLoaderName}.runtimeconfig.json");
+ var outDllDestination = Path.Combine(destination, DisasmoLoaderName + ".dll");
+ var outJsonDestination = Path.Combine(destination, DisasmoLoaderName + ".runtimeconfig.json");
- if (File.Exists(outDllDest) && File.Exists(outJsonDest))
- {
+ if (File.Exists(outDllDestination) && File.Exists(outJsonDestination))
return;
- }
- if (!Directory.Exists(dir))
+ if (!Directory.Exists(directory))
{
- Directory.CreateDirectory(dir);
+ Directory.CreateDirectory(directory);
}
else if (File.Exists(outDll) && File.Exists(outJson))
{
- File.Copy(outDll, outDllDest, true);
- File.Copy(outJson, outJsonDest, true);
+ File.Copy(outDll, outDllDestination, overwrite: true);
+ File.Copy(outJson, outJsonDestination, overwrite: true);
return;
}
logger($"Building '{DisasmoLoaderName}' project...");
- ct.ThrowIfCancellationRequested();
+ cancellationToken.ThrowIfCancellationRequested();
if (!File.Exists(csfile))
- TextUtils.SaveEmbeddedResourceTo($"{DisasmoLoaderName}.cs_template", dir);
+ TextUtils.SaveEmbeddedResourceTo($"{DisasmoLoaderName}.cs_template", directory);
if (!File.Exists(csproj))
- TextUtils.SaveEmbeddedResourceTo($"{DisasmoLoaderName}.csproj_template", dir, content => content.Replace("%tfm%", tf));
+ TextUtils.SaveEmbeddedResourceTo($"{DisasmoLoaderName}.csproj_template", directory, content => content.Replace("%tfm%", targetFramework));
Debug.Assert(File.Exists(csfile));
Debug.Assert(File.Exists(csproj));
- ct.ThrowIfCancellationRequested();
+ cancellationToken.ThrowIfCancellationRequested();
- var msg = await ProcessUtils.RunProcess("dotnet", "build -c Release", workingDir: dir, cancellationToken: ct);
+ var message = await ProcessUtils.RunProcess("dotnet", "build -c Release", workingDirectory: directory, cancellationToken: cancellationToken);
if (!File.Exists(outDll) || !File.Exists(outJson))
- throw new InvalidOperationException($"ERROR: 'dotnet build' did not produce expected binaries ('{outDll}'" +
- $" and '{outJson}'):\n{msg.Output}\n\n{msg.Error}");
+ {
+ var errorMessage = $"ERROR: 'dotnet build' did not produce expected binaries ('{outDll}' and '{outJson}'):\n{message.Output}\n\n{message.Error}";
+ throw new InvalidOperationException(errorMessage);
+ }
- ct.ThrowIfCancellationRequested();
- File.Copy(outDll, outDllDest, true);
- File.Copy(outJson, outJsonDest, true);
+ cancellationToken.ThrowIfCancellationRequested();
+ File.Copy(outDll, outDllDestination, overwrite: true);
+ File.Copy(outJson, outJsonDestination, overwrite: true);
}
}
\ No newline at end of file
diff --git a/Disasmo/Utils/ProcessUtils.cs b/Disasmo/Utils/ProcessUtils.cs
index e7d8708..323b669 100644
--- a/Disasmo/Utils/ProcessUtils.cs
+++ b/Disasmo/Utils/ProcessUtils.cs
@@ -10,14 +10,14 @@ namespace Disasmo;
public static class ProcessUtils
{
public static async Task RunProcess(
- string path,
+ string path,
string args = "",
Dictionary envVars = null,
- string workingDir = null,
+ string workingDirectory = null,
Action outputLogger = null,
CancellationToken cancellationToken = default)
{
- UserLogger.Log($"\nExecuting a command in directory \"{workingDir}\":\n\t{path} {args}\nEnv.vars:\n{DumpEnvVars(envVars)}");
+ UserLogger.Log($"\nExecuting a command in directory \"{workingDirectory}\":\n\t{path} {args}\nEnv.vars:\n{DumpEnvVars(envVars)}");
var logger = new StringBuilder();
var loggerForErrors = new StringBuilder();
@@ -34,10 +34,10 @@ public static async Task RunProcess(
Arguments = args,
};
- if (workingDir != null)
- processStartInfo.WorkingDirectory = workingDir;
+ if (workingDirectory is not null)
+ processStartInfo.WorkingDirectory = workingDirectory;
- if (envVars != null)
+ if (envVars is not null)
{
foreach (var envVar in envVars)
processStartInfo.EnvironmentVariables[envVar.Key] = envVar.Value;
@@ -53,11 +53,13 @@ public static async Task RunProcess(
logger.AppendLine(e.Data);
loggerForErrors.AppendLine(e.Data);
};
+
process.OutputDataReceived += (sender, e) =>
{
outputLogger?.Invoke(false, e.Data + "\n");
logger.AppendLine(e.Data);
};
+
process.BeginOutputReadLine();
process.BeginErrorReadLine();
@@ -67,9 +69,12 @@ public static async Task RunProcess(
return new ProcessResult { Error = loggerForErrors.ToString().Trim('\r', '\n'), Output = logger.ToString().Trim('\r', '\n') };
}
- catch (Exception e)
+ catch (Exception ex)
{
- return new ProcessResult { Error = $"RunProcess failed:{e.Message}.\npath={path}\nargs={args}\nworkingdir={workingDir ?? Environment.CurrentDirectory}\n{loggerForErrors}" };
+ workingDirectory ??= Environment.CurrentDirectory;
+ var errorMessage = $"RunProcess failed:{ex.Message}.\npath={path}\nargs={args}\nworkingdir={workingDirectory}\n{loggerForErrors}";
+
+ return new ProcessResult { Error = errorMessage };
}
finally
{
@@ -78,42 +83,46 @@ public static async Task RunProcess(
}
}
- public static Task WaitForExitAsync(this Process process,
- CancellationToken cancellationToken = default(CancellationToken))
+ public static Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default)
{
if (process.HasExited)
return Task.CompletedTask;
- var tcs = new TaskCompletionSource