diff --git a/Source/Mosa.Packages/Mosa.Tools.Package.Qemu.nuspec b/Source/Mosa.Packages/Mosa.Tools.Package.Qemu.nuspec index 7b8a0df42f..76a85d4643 100644 --- a/Source/Mosa.Packages/Mosa.Tools.Package.Qemu.nuspec +++ b/Source/Mosa.Packages/Mosa.Tools.Package.Qemu.nuspec @@ -49,5 +49,6 @@ + diff --git a/Source/Mosa.Packages/Mosa.Tools.Package.nuspec b/Source/Mosa.Packages/Mosa.Tools.Package.nuspec index 571982e6f5..383cf4d338 100644 --- a/Source/Mosa.Packages/Mosa.Tools.Package.nuspec +++ b/Source/Mosa.Packages/Mosa.Tools.Package.nuspec @@ -48,5 +48,6 @@ + diff --git a/Source/Mosa.Templates/templates/Mosa.Starter.x86/Properties/launchSettings.json b/Source/Mosa.Templates/templates/Mosa.Starter.x86/Properties/launchSettings.json index 91fc0a775e..272a6c4389 100644 --- a/Source/Mosa.Templates/templates/Mosa.Starter.x86/Properties/launchSettings.json +++ b/Source/Mosa.Templates/templates/Mosa.Starter.x86/Properties/launchSettings.json @@ -4,7 +4,7 @@ "commandName": "Executable", "executablePath": "dotnet", "commandLineArgs": "Tools/Mosa.Tool.Launcher.dll Mosa.Starter.x86.dll", - "workingDirectory": "bin" + "workingDirectory": "$(ProjectDir)bin" } } } diff --git a/Source/Mosa.Tool.Debugger/Views/InstructionView.cs b/Source/Mosa.Tool.Debugger/Views/InstructionView.cs index 10b7c73c8a..112a44176d 100644 --- a/Source/Mosa.Tool.Debugger/Views/InstructionView.cs +++ b/Source/Mosa.Tool.Debugger/Views/InstructionView.cs @@ -57,19 +57,20 @@ private void UpdateDisplay(ulong address, byte[] memory) { instructions.Clear(); - var disassembler = new Disassembler("x86"); - disassembler.SetMemory(memory, address); + var disassembler = new Disassembler("x86", memory, address); + var instruction = disassembler.DecodeNext(); - foreach (var instruction in disassembler.Decode()) + while (instruction != null) { var entry = new InstructionEntry() { IP = instruction.Address, - Length = instruction.Length, + Length = (int)instruction.Length, Instruction = instruction.Instruction.ToString() }; instructions.Add(entry); + instruction = disassembler.DecodeNext(); } } diff --git a/Source/Mosa.Tool.Debugger/Views/MethodView.cs b/Source/Mosa.Tool.Debugger/Views/MethodView.cs index cc88d84e29..dc705c87f7 100644 --- a/Source/Mosa.Tool.Debugger/Views/MethodView.cs +++ b/Source/Mosa.Tool.Debugger/Views/MethodView.cs @@ -148,10 +148,10 @@ private void UpdateDisplay(ulong address, byte[] memory) { instructions.Clear(); - var disassembler = new Disassembler("x86"); - disassembler.SetMemory(memory, address); + var disassembler = new Disassembler("x86", memory, address); + var instruction = disassembler.DecodeNext(); - foreach (var instruction in disassembler.Decode()) + while (instruction != null) { var addr = MainForm.ParseAddress(instruction.Instruction); @@ -160,12 +160,13 @@ private void UpdateDisplay(ulong address, byte[] memory) var entry = new MethodInstructionEntry() { IP = instruction.Address, // Offset? - Length = instruction.Length, + Length = (int)instruction.Length, Instruction = instruction.Instruction, Info = info }; instructions.Add(entry); + instruction = disassembler.DecodeNext(); } } diff --git a/Source/Mosa.Tool.Debugger/Views/StatusView.cs b/Source/Mosa.Tool.Debugger/Views/StatusView.cs index 09329ce091..f60039afae 100644 --- a/Source/Mosa.Tool.Debugger/Views/StatusView.cs +++ b/Source/Mosa.Tool.Debugger/Views/StatusView.cs @@ -44,15 +44,15 @@ private void UpdateDisplay(ulong address, byte[] memory) if (address != InstructionPointer) return; - var disassembler = new Disassembler("x86"); - disassembler.SetMemory(memory, address); + var disassembler = new Disassembler("x86", memory, address); tbInstruction.Text = "Unable to decode!"; - foreach (var instruction in disassembler.Decode()) + var instruction = disassembler.DecodeNext(); + while (instruction != null) { tbInstruction.Text = instruction.Instruction; - break; + instruction = disassembler.DecodeNext(); } } } diff --git a/Source/Mosa.Tool.Debugger/Views/TraceView.cs b/Source/Mosa.Tool.Debugger/Views/TraceView.cs index 236e1a3d8a..f746d5d0d7 100644 --- a/Source/Mosa.Tool.Debugger/Views/TraceView.cs +++ b/Source/Mosa.Tool.Debugger/Views/TraceView.cs @@ -68,13 +68,13 @@ private void UpdateDisplay(ulong address, byte[] memory) if (address == InstructionPointer) { - var disassembler = new Disassembler("x86"); - disassembler.SetMemory(memory, address); + var disassembler = new Disassembler("x86", memory, address); + var instruction = disassembler.DecodeNext(); - foreach (var instruction in disassembler.Decode()) + while (instruction != null) { opinstruction = instruction.Instruction; - break; + instruction = disassembler.DecodeNext(); } } diff --git a/Source/Mosa.Tool.Explorer.Avalonia/CompilerData.cs b/Source/Mosa.Tool.Explorer.Avalonia/CompilerData.cs index 0e053b325f..11daa34113 100755 --- a/Source/Mosa.Tool.Explorer.Avalonia/CompilerData.cs +++ b/Source/Mosa.Tool.Explorer.Avalonia/CompilerData.cs @@ -38,9 +38,7 @@ public void UpdateLog(string section, List lines, bool dirty) } lock (log) - { log.AddRange(lines); - } DirtyLog = dirty; } @@ -59,9 +57,7 @@ private void UpdateLog(string section, string line) } lock (log) - { log.Add(line); - } DirtyLog = true; } @@ -70,9 +66,7 @@ private void UpdateLog(string section, string line) public List GetLog(string section) { lock (Logs) - { return Logs.GetValueOrDefault(section); - } } public void AddTraceEvent(CompilerEvent compilerEvent, string message, int threadID) diff --git a/Source/Mosa.Tool.Explorer.Avalonia/CompilerStage/ExplorerMethodCompileTimeStage.cs b/Source/Mosa.Tool.Explorer.Avalonia/CompilerStage/ExplorerMethodCompileTimeStage.cs index 0bdbece160..404ef1139c 100755 --- a/Source/Mosa.Tool.Explorer.Avalonia/CompilerStage/ExplorerMethodCompileTimeStage.cs +++ b/Source/Mosa.Tool.Explorer.Avalonia/CompilerStage/ExplorerMethodCompileTimeStage.cs @@ -17,7 +17,6 @@ protected override void Finalization() var log = new TraceLog(TraceType.GlobalDebug, null, null, "Compiler Time"); log.Log("Ticks\tMilliseconds\tCompiler Count\tMethod"); - foreach (var data in methods) log.Log($"{data.ElapsedTicks}{'\t'}{data.ElapsedTicks / TimeSpan.TicksPerMillisecond}{'\t'}{data.Version}{'\t'}{data.Method.FullName}"); diff --git a/Source/Mosa.Tool.Explorer.Avalonia/FormatInstructions.cs b/Source/Mosa.Tool.Explorer.Avalonia/FormatInstructions.cs new file mode 100644 index 0000000000..8d60d9358d --- /dev/null +++ b/Source/Mosa.Tool.Explorer.Avalonia/FormatInstructions.cs @@ -0,0 +1,193 @@ +// Copyright (c) MOSA Project. Licensed under the New BSD License. + +using System.Text; + +namespace Mosa.Tool.Explorer.Avalonia; + +public static class FormatInstructions +{ + private const int Padding = 34; + + public static string Format(List records, string blockLabel, bool strip, bool removeNop, bool lineBetweenBlocks) + { + var sb = new StringBuilder(); + var blocks = new StringBuilder(); + + if (records == null || records.Count == 0) + return string.Empty; + + var allLines = string.IsNullOrWhiteSpace(blockLabel); + var inBlock = allLines; + + foreach (var record in records) + { + switch (record.Type) + { + case "M": + { + sb.AppendLine($"{record.MethodName} [v{record.Version}] @ {record.Stage}:"); + sb.AppendLine(); + break; + } + case "S": + { + inBlock = record.BlockLabel == blockLabel; + + if (!inBlock && !allLines) + continue; + + sb.Append($"{record.BlockLabel}:"); + + blocks.Clear(); + + // Previous Branch Targets + if (record.PreviousBlockCount != 0) + { + for (var i = 0; i < record.PreviousBlockCount; i++) + { + if (i != 0) + blocks.Append(' '); + + var op = record.GetPreviousBlocks(i); + + blocks.Append(op); + } + + sb.Append("".PadRight(record.PreviousBlockCount == 1 ? Padding : Padding - 8)); + + sb.Append(blocks); + } + + sb.AppendLine(); + break; + } + case "I": + { + if (!inBlock && !allLines) + continue; + + if (record.Instruction is "IR.BlockStart" or "IR.BlockEnd") + break; + + if (removeNop && record.Instruction == "IR.Nop") + continue; + + sb.Append(" "); + + var instruction = record.Instruction; + var condition = !string.IsNullOrEmpty(record.Condition) ? " [" + record.Condition + "]" : string.Empty; + + var both = $"{instruction}{condition}"; + + blocks.Clear(); + + // Branch Targets + if (record.BranchTargetCount != 0) + { + if (condition.Length != 0) + blocks.Append(' '); + + for (var i = 0; i < record.BranchTargetCount; i++) + { + if (i != 0) + blocks.Append(' '); + + var op = record.GetBranchTarget(i); + + blocks.Append(op); + } + } + + var count = Padding + 2 - both.Length - blocks.Length; + if (count < 0) + count = 1; + + var padding = string.Empty.PadRight(count); + + sb.Append($"{record.Label[..5]}:{record.Mark.PadLeft(1)}{both}{padding}{blocks} "); + + // Result + for (var i = 0; i < record.ResultCount; i++) + { + if (i != 0) + sb.Append(", "); + + var op = record.GetResult(i); + + op = Simplify(op); + + if (strip) + op = StripBracketData(op); + + sb.Append(op); + } + + if (record.ResultCount != 0 && record.OperandCount != 0) + sb.Append(" <= "); + + // Operands + for (var i = 0; i < record.OperandCount; i++) + { + if (i != 0) + sb.Append(", "); + + var op = record.GetOperand(i); + + op = Simplify(op); + + if (strip) + op = StripBracketData(op); + + sb.Append(op); + } + + // Phi Blocks + if (record.PhiBlockCount != 0) + { + sb.Append(" ("); + + for (var i = 0; i < record.PhiBlockCount; i++) + { + if (i != 0) + sb.Append(", "); + + var op = record.GetPhilBlock(i); + + sb.Append(op); + } + + sb.Append(") "); + } + + while (sb.Length > 0 && sb[^1] == ' ') + sb.Length--; + + sb.AppendLine(); + break; + } + case "E": + { + inBlock = false; + + if (!inBlock && !allLines) + continue; + + if (lineBetweenBlocks) + sb.AppendLine(); + + break; + } + } + } + + return sb.ToString(); + } + + private static string StripBracketData(string s) + { + var i = s.IndexOf('['); + return i <= 0 ? s : s[..(i - 1)].Trim(); + } + + private static string Simplify(string s) => s.Replace("const=", string.Empty); +} diff --git a/Source/Mosa.Tool.Explorer.Avalonia/InstructionRecord.cs b/Source/Mosa.Tool.Explorer.Avalonia/InstructionRecord.cs new file mode 100644 index 0000000000..08fab30bdb --- /dev/null +++ b/Source/Mosa.Tool.Explorer.Avalonia/InstructionRecord.cs @@ -0,0 +1,95 @@ +// Copyright (c) MOSA Project. Licensed under the New BSD License. + +namespace Mosa.Tool.Explorer.Avalonia; + +public class InstructionRecord +{ + public readonly string Data; + + public readonly string[] Parts; + + public readonly string Type; + + public readonly bool IsInstruction; + + public readonly bool IsMethod; + + public readonly bool IsStartBlock; + + public readonly bool IsEndBlock; + + public string Label => Parts[1]; + + // Block + public string BlockLabel => Parts[1]; + + // Start Block + public string BlockSequence => Parts[2]; + + public string BlockType => Parts[3]; + + public readonly int PreviousBlockCount; + + public string GetPreviousBlocks(int index) => Parts[5 + index]; + + // End Block + public int NextBlockCount => Convert.ToInt32(Parts[2]); + + // Instruction + public string Mark => Parts[2]; + + public string Instruction => Parts[3]; + + public string Condition => Parts[4]; + + public readonly int ResultCount = 0; + + public readonly int OperandCount = 0; + + public readonly int BranchTargetCount = 0; + + public readonly int PhiBlockCount = 0; + + public string GetResult(int index) => Parts[9 + index]; + + public string GetOperand(int index) => Parts[9 + ResultCount + index]; + + public string GetBranchTarget(int index) => Parts[9 + ResultCount + OperandCount + index]; + + public string GetPhilBlock(int index) => Parts[9 + ResultCount + OperandCount + BranchTargetCount + index]; + + // Method + + public string MethodName => Parts[1]; + + public int Version => Convert.ToInt32(Parts[2]); + + public string Stage => Parts[3]; + + public int Step => Convert.ToInt32(Parts[4]); + + public InstructionRecord(string data) + { + Data = data; + Parts = data.Split('\t'); + + Type = Parts[0]; + + IsInstruction = Type == "I"; + IsMethod = Type == "M"; + IsStartBlock = Type == "S"; + IsEndBlock = Type == "E"; + + if (IsInstruction) + { + ResultCount = Convert.ToInt32(Parts[5]); + OperandCount = Convert.ToInt32(Parts[6]); + BranchTargetCount = Convert.ToInt32(Parts[7]); + PhiBlockCount = Convert.ToInt32(Parts[8]); + } + else if (IsStartBlock) + { + PreviousBlockCount = Convert.ToInt32(Parts[4]); + } + } +} diff --git a/Source/Mosa.Tool.Explorer.Avalonia/MainWindow.axaml b/Source/Mosa.Tool.Explorer.Avalonia/MainWindow.axaml index 0b88995dac..41f204125a 100755 --- a/Source/Mosa.Tool.Explorer.Avalonia/MainWindow.axaml +++ b/Source/Mosa.Tool.Explorer.Avalonia/MainWindow.axaml @@ -36,10 +36,10 @@ + + - - @@ -72,7 +72,7 @@ - + @@ -159,24 +159,17 @@ - - - - - - - - - - - + + + + + - + + - - - - + + @@ -193,24 +186,17 @@ - - - - - - - - - - - + + + + + - + + - - - - + + diff --git a/Source/Mosa.Tool.Explorer.Avalonia/MainWindow.axaml.cs b/Source/Mosa.Tool.Explorer.Avalonia/MainWindow.axaml.cs index 4101c94c62..5a9b6eea16 100755 --- a/Source/Mosa.Tool.Explorer.Avalonia/MainWindow.axaml.cs +++ b/Source/Mosa.Tool.Explorer.Avalonia/MainWindow.axaml.cs @@ -15,8 +15,6 @@ using Mosa.Tool.Explorer.Avalonia.CompilerStage; using Mosa.Tool.Explorer.Avalonia.Stages; using Mosa.Utility.Configuration; -using DebugInfoStage = Mosa.Tool.Explorer.Avalonia.Stages.DebugInfoStage; -using GraphVizStage = Mosa.Tool.Explorer.Avalonia.Stages.GraphVizStage; using Timer = System.Timers.Timer; namespace Mosa.Tool.Explorer.Avalonia; @@ -31,7 +29,7 @@ public partial class MainWindow : Window private readonly ObservableCollection counterCollection = new ObservableCollection(); private readonly ObservableCollection compilerCounterCollection = new ObservableCollection(); - private MosaSettings mosaSettings = new MosaSettings(); + private readonly MosaSettings mosaSettings = new MosaSettings(); private MosaCompiler compiler; private int completedMethods; @@ -316,7 +314,15 @@ private void TreeView_OnSelectionChanged(object _, SelectionChangedEventArgs e) return; compilerData.Stopwatch.Reset(); - compiler.CompileSingleMethod(currentMethod); + ThreadPool.QueueUserWorkItem(_ => compiler.CompileSingleMethod(currentMethod)); + } + + private void TabControl_OnSelectionChanged(object _, SelectionChangedEventArgs e) + { + compilerData.DirtyLog = true; + + if (TabControl != null) + RefreshCompilerLog(); } private void InstructionsStage_OnSelectionChanged(object _, SelectionChangedEventArgs e) => UpdateInstructionStageSelection(); @@ -337,12 +343,12 @@ private void UpdateInstructionStageSelection() private void UpdateInstructionBlocks() { - var lines = GetCurrentInstructionLines(); + var records = GetCurrentInstructionLines(); InstructionsBlock.Items.Clear(); InstructionsBlock.Items.Add("All"); - var labels = ExtractLabels(lines); + var labels = ExtractLabels(records); if (labels == null) return; @@ -350,20 +356,16 @@ private void UpdateInstructionBlocks() InstructionsBlock.Items.Add(label); } - private static List ExtractLabels(List lines) + private static List ExtractLabels(List records) { - if (lines == null) + if (records == null) return null; var labels = new List(); - foreach (var line in lines) - { - if (!line.StartsWith("Block #")) - continue; - - labels.Add(line[line.IndexOf("L_", StringComparison.Ordinal)..]); - } + foreach (var record in records) + if (record.IsStartBlock) + labels.Add(record.BlockLabel); return labels; } @@ -429,6 +431,18 @@ private void TransformsGrid_OnSelectionChanged(object _, SelectionChangedEventAr private void CountersGridFilter_OnTextChanged(object _, TextChangedEventArgs e) => UpdateCounters(); + private async void CopyCountersText_OnClick(object _, RoutedEventArgs e) + { + if (Clipboard == null) + { + SetStatus("Error: No Clipboard Detected."); + return; + } + + await Clipboard.SetTextAsync(CreateText(currentMethodData.Counters)); + SetStatus("Text Copied!"); + } + private void CompilerLogsSection_OnSelectionChanged(object _, SelectionChangedEventArgs e) { var formatted = CompilerLogsSection.SelectionBoxItem?.ToString(); @@ -443,6 +457,22 @@ private void CompilerLogsSection_OnSelectionChanged(object _, SelectionChangedEv private void CompilerCountersGridFilter_OnTextChanged(object _, TextChangedEventArgs e) => UpdateCompilerCounters(); + private async void CopyCompilerCountersText_OnClick(object _, RoutedEventArgs e) + { + if (Clipboard == null) + { + SetStatus("Error: No Clipboard Detected."); + return; + } + + var lines = compilerData.GetLog("Counters"); + if (lines == null) + return; + + await Clipboard.SetTextAsync(CreateText(lines)); + SetStatus("Text Copied!"); + } + private void SetTransformationStep(int step) { if (step <= 0) @@ -529,7 +559,7 @@ private void PopulateTransformList() entry = new TransformEntry { - ID = Convert.ToInt32(parts[0].Trim()) + 1, + ID = Convert.ToInt32(parts[0].Trim()), Name = part1, Pass = pass }; @@ -542,7 +572,7 @@ private void PopulateTransformList() private void UpdateTransformLabels() { - var lines = GetCurrentTransformLines(); + var lines = GetCurrentTransformRecords(); TransformsBlock.Items.Clear(); TransformsBlock.Items.Add("All"); @@ -577,13 +607,7 @@ private List GetCurrentDebugLines() return stage == null ? null : currentMethodData.DebugLogs[stage]; } - private void UpdateGraphviz() - { - var graphviz = ShowGraphviz(); - - DebugPanel.IsVisible = graphviz; - Debug.IsVisible = !graphviz; - } + private void UpdateGraphviz() => DebugPanel.IsVisible = ShowGraphviz(); private bool ShowGraphviz() { @@ -595,11 +619,11 @@ private bool ShowGraphviz() if (DisplayGraphviz.IsChecked != null && !DisplayGraphviz.IsChecked.Value) return false; - if (string.IsNullOrEmpty(Debug.Text) || !Debug.Text.Contains("digraph blocks")) + if (string.IsNullOrEmpty(Debug.Text) || !Debug.Text.StartsWith("digraph blocks")) return false; var dot = Path.GetTempFileName(); - var bmp = Path.GetTempFileName(); + var img = Path.GetTempFileName(); try { @@ -608,29 +632,27 @@ private bool ShowGraphviz() var startInfo = new ProcessStartInfo { FileName = mosaSettings.GraphwizApp, - Arguments = $"dot -Tbmp -o \"{bmp}\" \"{dot}\"", + Arguments = $"-Tpng -o \"{img}\" \"{dot}\"", CreateNoWindow = true }; var process = Process.Start(startInfo); process?.WaitForExit(); - var file = File.ReadAllBytes(bmp); - - using var stream = new MemoryStream(file); + using var stream = File.OpenRead(img); var bitmap = new Bitmap(stream); - var picture = new Image + var image = new Image { Source = bitmap }; - DebugPanel.Children.Add(picture); + DebugPanel.Children.Add(image); } finally { File.Delete(dot); - File.Delete(bmp); + File.Delete(img); } return true; @@ -671,12 +693,24 @@ private void ExtendMethodCompilerPipeline(Pipeline pipe if (Dispatcher.UIThread.Invoke(() => DebugDiagnostic.IsChecked)) { for (var i = 1; i < pipeline.Count; i += 2) - pipeline.Insert(i, new GraphVizStage()); + pipeline.Insert(i, new ControlFlowGraphStage()); } else { - pipeline.InsertAfterLast(new GraphVizStage()); - pipeline.Add(new GraphVizStage()); + if (mosaSettings.InlineMethods || mosaSettings.InlineExplicit) + { + pipeline.InsertBefore(new ControlFlowGraphStage()); + pipeline.InsertAfterLast(new ControlFlowGraphStage()); + } + + if (mosaSettings.SSA) + { + pipeline.InsertBefore(new DominanceAnalysisStage()); + pipeline.InsertBefore(new ControlFlowGraphStage()); + } + + pipeline.InsertAfterLast(new ControlFlowGraphStage()); + pipeline.Add(new ControlFlowGraphStage()); } } @@ -780,19 +814,19 @@ private void UpdateInstructions() if (currentMethod == null) return; - var lines = GetCurrentInstructionLines(); + var records = GetCurrentInstructionLines(); var label = InstructionsBlock.SelectionBoxItem?.ToString(); SetStatus(currentMethod.FullName); - if (lines == null) + if (records == null) return; if (string.IsNullOrWhiteSpace(label) || label == "All") label = string.Empty; - Instructions.Text = methodStore.GetStageInstructions(lines, label, !ShowOperandTypes.IsChecked, - PadInstructions.IsChecked, RemoveIrNop.IsChecked); + Instructions.Text = FormatInstructions.Format(records, label, !ShowOperandTypes.IsChecked, + RemoveIrNop.IsChecked, LineBetweenBlocks.IsChecked); } private void UpdateTransforms() @@ -802,20 +836,20 @@ private void UpdateTransforms() if (currentMethod == null) return; - var lines = GetCurrentTransformLines(); + var records = GetCurrentTransformRecords(); var label = TransformsBlock.SelectionBoxItem?.ToString(); - if (lines == null) + if (records == null) return; if (string.IsNullOrWhiteSpace(label) || label == "All") label = string.Empty; - Transforms.Text = methodStore.GetStageInstructions(lines, label, !ShowOperandTypes.IsChecked, - PadInstructions.IsChecked, RemoveIrNop.IsChecked); + Transforms.Text = FormatInstructions.Format(records, label, !ShowOperandTypes.IsChecked, + RemoveIrNop.IsChecked, LineBetweenBlocks.IsChecked); } - private List GetCurrentTransformLines() + private List GetCurrentTransformRecords() { if (currentMethodData == null) return null; @@ -830,14 +864,13 @@ private List GetCurrentTransformLines() return log; } - private List GetCurrentInstructionLines() + private List GetCurrentInstructionLines() { if (currentMethodData == null) return null; var stage = InstructionsStage.SelectionBoxItem?.ToString(); return stage == null ? null : currentMethodData.InstructionLogs[stage]; - } private void UpdateInstructionStages() @@ -869,13 +902,9 @@ private void UpdateDebugStages() private void UpdateCounters() { - Counters.Clear(); - if (currentMethodData == null) return; - Counters.Text = CreateText(currentMethodData.Counters); - counterCollection.Clear(); var filter = CountersGridFilter.Text ?? string.Empty; @@ -1074,10 +1103,17 @@ private void LoadAssembly() UpdateSettings(); compiler = new MosaCompiler(mosaSettings, CreateCompilerHooks(), new ClrModuleLoader(), new ClrTypeResolver()); - compiler.Load(); - CreateTree(); - SetStatus("Assemblies Loaded!"); + ThreadPool.QueueUserWorkItem(_ => + { + Dispatcher.UIThread.Post(() => SetStatus("Loading Types...")); + compiler.Load(); + + Dispatcher.UIThread.Post(() => SetStatus("Building Type System Tree...")); + Dispatcher.UIThread.Post(CreateTree); + + Dispatcher.UIThread.Post(() => SetStatus("Assemblies Loaded!")); + }); } private void ClearAll() @@ -1176,10 +1212,8 @@ private static string CreateText(List list) var sb = new StringBuilder(); lock (list) - { foreach (var l in list) sb.AppendLine(l); - } return sb.ToString(); } @@ -1201,8 +1235,6 @@ private void UpdateCompilerCounters() var entry = ExtractCounterData(line); compilerCounterCollection.Add(entry); } - - CompilerCounters.Text = CreateText(lines); } private static CounterEntry ExtractCounterData(string line) diff --git a/Source/Mosa.Tool.Explorer.Avalonia/MethodData.cs b/Source/Mosa.Tool.Explorer.Avalonia/MethodData.cs index 4cbd5f0006..09a38d53a2 100755 --- a/Source/Mosa.Tool.Explorer.Avalonia/MethodData.cs +++ b/Source/Mosa.Tool.Explorer.Avalonia/MethodData.cs @@ -13,10 +13,10 @@ public class MethodData public readonly List OrderedTransformStageNames = new List(); - public readonly Dictionary> InstructionLogs = new Dictionary>(); + public readonly Dictionary> InstructionLogs = new Dictionary>(); + public readonly Dictionary>> TransformLogs = new Dictionary>>(); + public readonly Dictionary> DebugLogs = new Dictionary>(); public List Counters = new List(); - - public Dictionary>> TransformLogs = new Dictionary>>(); } diff --git a/Source/Mosa.Tool.Explorer.Avalonia/MethodStore.cs b/Source/Mosa.Tool.Explorer.Avalonia/MethodStore.cs index 8d8d79366f..a9a620d7e8 100755 --- a/Source/Mosa.Tool.Explorer.Avalonia/MethodStore.cs +++ b/Source/Mosa.Tool.Explorer.Avalonia/MethodStore.cs @@ -1,6 +1,5 @@ // Copyright (c) MOSA Project. Licensed under the New BSD License. -using System.Text; using Mosa.Compiler.Common; using Mosa.Compiler.MosaTypeSystem; @@ -13,9 +12,7 @@ public class MethodStore public void Clear() { lock (methodDataStore) - { methodDataStore.Clear(); - } } private static void ClearMethodDataOnNewVersion(int version, MethodData methodData) @@ -49,6 +46,10 @@ public MethodData GetMethodData(MosaMethod method, bool create) public void SetInstructionTraceInformation(MosaMethod method, string stage, List lines, int version) { var methodData = GetMethodData(method, true); + var records = new List(); + + foreach (var line in lines) + records.Add(new InstructionRecord(line)); lock (methodData) { @@ -56,13 +57,17 @@ public void SetInstructionTraceInformation(MosaMethod method, string stage, List methodData.OrderedStageNames.AddIfNew(stage); methodData.InstructionLogs.Remove(stage); - methodData.InstructionLogs.Add(stage, lines); + methodData.InstructionLogs.Add(stage, records); } } public void SetTransformTraceInformation(MosaMethod method, string stage, List lines, int version, int step) { var methodData = GetMethodData(method, true); + var records = new List(); + + foreach (var line in lines) + records.Add(new InstructionRecord(line)); lock (methodData) { @@ -70,13 +75,13 @@ public void SetTransformTraceInformation(MosaMethod method, string stage, List>(); - methodData.TransformLogs.Add(stage, directionary); + dictionary = new Dictionary>(); + methodData.TransformLogs.Add(stage, dictionary); } - directionary.Add(step, lines); + dictionary.Add(step, records); } } @@ -105,132 +110,4 @@ public void SetMethodCounterInformation(MosaMethod method, List lines, i methodData.Counters = lines; } } - - public string GetStageInstructions(List lines, string blockLabel, bool strip, bool pad, bool removeNop) - { - var result = new StringBuilder(); - - if (lines == null) - return string.Empty; - - if (string.IsNullOrWhiteSpace(blockLabel)) - { - foreach (var l in lines) - { - var line = l; - - if (line.Contains("IR.BlockStart") || line.Contains("IR.BlockEnd")) - continue; - - if (removeNop && line.Contains("IR.Nop")) - continue; - - if (strip) - line = StripBracketContents(line); - - if (pad) - line = PadInstruction(line); - - line = Simplify(line); - - result.Append(line); - result.Append('\n'); - } - - return result.ToString(); - } - - var inBlock = false; - - foreach (var l in lines) - { - var line = l; - - if ((!inBlock) && line.StartsWith("Block #") && line.EndsWith(blockLabel)) - inBlock = true; - - if (!inBlock) - continue; - - if (line.Contains("IR.BlockStart") || line.Contains("IR.BlockEnd")) - continue; - - if (strip) - line = StripBracketContents(line); - - if (pad) - line = PadInstruction(line); - - line = Simplify(line); - - result.Append(line); - result.Append('\n'); - - if (line.StartsWith(" Next:")) - return result.ToString(); - } - - return result.ToString(); - } - - private static string StripBracketContents(string s) - { - if (string.IsNullOrEmpty(s) || s.Length < 5) - return s; - - if (!char.IsDigit(s[0])) - return s; - - var at = 0; - while (true) - { - var open = s.IndexOf(" [", at, StringComparison.Ordinal); - if (open < 0) - return s; - - var close = s.IndexOf(']', open); - if (close < 0) - return s; - - var part = s.Substring(open + 2, close - open - 2); - if (part == "NULL" || char.IsSymbol(part[0]) || char.IsPunctuation(part[0])) - { - at = close; - continue; - } - - s = s.Remove(open, close - open + 1); - at = open; - } - } - - private static string PadInstruction(string s) - { - const int padding = 30; - - if (string.IsNullOrEmpty(s) || s.Length < 5) - return s; - - if (!char.IsDigit(s[0])) - return s; - - var first = s.IndexOf(':'); - if (first is < 0 or > 15) - return s; - - var second = s.IndexOf(' ', first + 2); - - switch (second) - { - case < 0: return s; - case > padding: return s; - default: - { - s = s.Insert(second, new string(' ', padding - second)); - return s; - } - } - } - - private static string Simplify(string s) => s.Replace("const=", string.Empty); } diff --git a/Source/Mosa.Tool.Explorer.Avalonia/Mosa.Tool.Explorer.Avalonia.csproj b/Source/Mosa.Tool.Explorer.Avalonia/Mosa.Tool.Explorer.Avalonia.csproj index b95bc0556d..0cf19b81e2 100755 --- a/Source/Mosa.Tool.Explorer.Avalonia/Mosa.Tool.Explorer.Avalonia.csproj +++ b/Source/Mosa.Tool.Explorer.Avalonia/Mosa.Tool.Explorer.Avalonia.csproj @@ -19,10 +19,10 @@ - - - - + + + + diff --git a/Source/Mosa.Tool.Explorer.Avalonia/Stages/DebugInfoStage.cs b/Source/Mosa.Tool.Explorer.Avalonia/Stages/DebugInfoStage.cs deleted file mode 100755 index 458e3135d4..0000000000 --- a/Source/Mosa.Tool.Explorer.Avalonia/Stages/DebugInfoStage.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) MOSA Project. Licensed under the New BSD License. - -using Mosa.Compiler.Framework; - -namespace Mosa.Tool.Explorer.Avalonia.Stages; - -public class DebugInfoStage : BaseMethodCompilerStage -{ - protected override void Run() - { - DumpByInstructions(); - DumpRegions(); - DumpSourceInfo(); - } - - protected void DumpByInstructions() - { - var trace = CreateTraceLog("Instructions"); - if (trace == null) - return; - - trace.Log("Label\tAddress\tLength\tStartLine\tEndLine\tStartColumn\tEndColumn\tInstruction\tDocument"); - - foreach (var block in BasicBlocks) - { - for (var node = block.First; !node.IsBlockEndInstruction; node = node.Next) - { - if (node.IsEmpty) - continue; - - if (node.Instruction.IgnoreDuringCodeGeneration) - continue; - - var label = node.Label; - var startLine = -1; - var endLine = 0; - var endColumn = 0; - var startColumn = 0; - var document = string.Empty; - - //var offset = node.Offset; - - var address = -1; - var length = 0; - - foreach (var instruction in Method.Code) - { - if (instruction.Offset != label) - continue; - - startLine = instruction.StartLine; - endLine = instruction.EndLine; - startColumn = instruction.StartColumn; - endColumn = instruction.EndColumn; - document = instruction.Document; - - break; - } - - if (startLine == -1) - continue; - - foreach (var region in MethodData.LabelRegions) - { - if (region.Label != label) - continue; - - address = region.Start; - length = region.Length; - break; - } - - if (address == -1) - continue; - - trace.Log($"{label:X5}\t{address}\t{length}\t{startLine}\t{endLine}\t{startColumn}\t{endColumn}\t{node}\t{document}"); - } - } - } - - protected void DumpRegions() - { - var trace = CreateTraceLog("Regions"); - - trace.Log("Label\tAddress\tLength"); - - foreach (var region in MethodData.LabelRegions) - { - trace.Log($"{region.Label:X5}\t{region.Start}\t{region.Length}"); - } - } - - protected void DumpSourceInfo() - { - var trace = CreateTraceLog("Source"); - - trace.Log("Label\tStartLine\tEndLine\tStartColumn\tEndColumn\tDocument"); - - foreach (var instruction in Method.Code) - { - trace.Log($"{instruction.Offset:X5}\t{instruction.StartLine}\t{instruction.EndLine}\t{instruction.StartColumn}\t{instruction.EndColumn}\t{instruction.Document}"); - } - } -} diff --git a/Source/Mosa.Tool.Explorer.Avalonia/Stages/DisassemblyStage.cs b/Source/Mosa.Tool.Explorer.Avalonia/Stages/DisassemblyStage.cs index d59150f209..da89e79ea6 100755 --- a/Source/Mosa.Tool.Explorer.Avalonia/Stages/DisassemblyStage.cs +++ b/Source/Mosa.Tool.Explorer.Avalonia/Stages/DisassemblyStage.cs @@ -16,7 +16,7 @@ protected override void Run() TracePatchRequests(); } - protected void TraceDisassembly() + private void TraceDisassembly() { var trace = CreateTraceLog(); if (trace == null) @@ -30,26 +30,26 @@ protected void TraceDisassembly() var memory = new byte[length]; stream.Position = 0; - stream.Read(memory, 0, length); + var read = stream.Read(memory, 0, length); stream.Position = oldPosition; - var disassembler = new Disassembler(Architecture.PlatformName); - disassembler.SetMemory(memory, 0); - - var list = disassembler.Decode(); - - if (list != null) + if (read != length) { - foreach (var instr in list) - trace.Log(instr.Full); + trace.Log("Error: Couldn't read enough bytes to disassemble."); + return; } - else + + var disassembler = new Disassembler(Architecture.PlatformName, memory, 0); + var instruction = disassembler.DecodeNext(); + + while (instruction != null) { - PostEvent(CompilerEvent.Error, $"Failed disassembly for method {MethodCompiler.Method}"); + trace.Log(instruction.Full); + instruction = disassembler.DecodeNext(); } } - protected void TracePatchRequests() + private void TracePatchRequests() { var trace = CreateTraceLog("Patch-Requests"); if (trace == null) diff --git a/Source/Mosa.Tool.Explorer.Avalonia/Stages/GraphVizStage.cs b/Source/Mosa.Tool.Explorer.Avalonia/Stages/GraphVizStage.cs deleted file mode 100755 index 2052ab2a57..0000000000 --- a/Source/Mosa.Tool.Explorer.Avalonia/Stages/GraphVizStage.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) MOSA Project. Licensed under the New BSD License. - -using Mosa.Compiler.Framework; - -namespace Mosa.Tool.Explorer.Avalonia.Stages; - -public class GraphVizStage : BaseMethodCompilerStage -{ - private const int TraceLevel = 6; - - protected override void Run() - { - if (!IsTraceable(TraceLevel)) - return; - - var trace = CreateTraceLog(); - trace.Log("digraph blocks {"); - - foreach (var block in BasicBlocks) - { - // trace.Log($"\t{block}"); - - foreach (var next in block.NextBlocks) - trace.Log($"\t{block} -> {next}"); - } - - trace.Log("}"); - } -} diff --git a/Source/Mosa.Tool.Explorer.Avalonia/TypeSystemTree.cs b/Source/Mosa.Tool.Explorer.Avalonia/TypeSystemTree.cs index b689c8a75a..7f19e95f02 100755 --- a/Source/Mosa.Tool.Explorer.Avalonia/TypeSystemTree.cs +++ b/Source/Mosa.Tool.Explorer.Avalonia/TypeSystemTree.cs @@ -296,7 +296,7 @@ private TreeViewItem GetOrCreateNode(MosaType type) GetOrCreateNode(method); } - // Method Table + // Method Table if (TypeLayout.GetMethodTable(type) != null) { var methodTableNode = new TreeViewItem { Header = "Method Table" }; @@ -306,11 +306,11 @@ private TreeViewItem GetOrCreateNode(MosaType type) foreach (var method in methodList) { - if (included == null || included.Contains(method)) - { - var methodNode = new TreeViewItem { Header = method.ShortName, Tag = method }; - methodTableNode.Items.Add(methodNode); - } + if (included != null && !included.Contains(method)) + continue; + + var methodNode = new TreeViewItem { Header = method.ShortName, Tag = method }; + methodTableNode.Items.Add(methodNode); } } diff --git a/Source/Mosa.Tool.Explorer.Avalonia/Utils.cs b/Source/Mosa.Tool.Explorer.Avalonia/Utils.cs index 1215ebfbf4..32082e2ea5 100755 --- a/Source/Mosa.Tool.Explorer.Avalonia/Utils.cs +++ b/Source/Mosa.Tool.Explorer.Avalonia/Utils.cs @@ -13,8 +13,12 @@ public static class Utils public static readonly FilePickerOpenOptions LibraryOpenOptions = new FilePickerOpenOptions { + Title = "Select a library to open in the explorer", FileTypeFilter = new List { LibraryFileType } }; - public static readonly FolderPickerOpenOptions FolderOpenOptions = new FolderPickerOpenOptions(); + public static readonly FolderPickerOpenOptions FolderOpenOptions = new FolderPickerOpenOptions + { + Title = "Select a folder where to dump all method stages" + }; } diff --git a/Source/Mosa.Tool.Explorer/Stages/DisassemblyStage.cs b/Source/Mosa.Tool.Explorer/Stages/DisassemblyStage.cs index a83e83f25a..4571ab33b4 100644 --- a/Source/Mosa.Tool.Explorer/Stages/DisassemblyStage.cs +++ b/Source/Mosa.Tool.Explorer/Stages/DisassemblyStage.cs @@ -34,21 +34,13 @@ protected void TraceDisassembly() stream.Read(memory, 0, length); stream.Position = oldPosition; - var disassembler = new Disassembler(Architecture.PlatformName); - disassembler.SetMemory(memory, 0); + var disassembler = new Disassembler(Architecture.PlatformName, memory, 0); + var instruction = disassembler.DecodeNext(); - var list = disassembler.Decode(); - - if (list != null) - { - foreach (var instr in list) - { - trace.Log(instr.Full); - } - } - else + while (instruction != null) { - PostEvent(CompilerEvent.Error, $"Failed disassembly for method {MethodCompiler.Method}"); + trace.Log(instruction.Full); + instruction = disassembler.DecodeNext(); } } diff --git a/Source/Mosa.Utility.Disassembler/DecodedInstruction.cs b/Source/Mosa.Utility.Disassembler/DecodedInstruction.cs index 0dc54452d0..ce1f0102c3 100644 --- a/Source/Mosa.Utility.Disassembler/DecodedInstruction.cs +++ b/Source/Mosa.Utility.Disassembler/DecodedInstruction.cs @@ -2,13 +2,13 @@ namespace Mosa.Utility.Disassembler; -public partial class DecodedInstruction +public class DecodedInstruction { - public ulong Address { get; set; } + public ulong Address { get; init; } - public int Length { get; set; } + public uint Length { get; init; } - public string Instruction { get; set; } + public string Instruction { get; init; } - public string Full { get; set; } + public string Full { get; init; } } diff --git a/Source/Mosa.Utility.Disassembler/Disassembler.cs b/Source/Mosa.Utility.Disassembler/Disassembler.cs index 78d6b562e1..4b3c7223b9 100644 --- a/Source/Mosa.Utility.Disassembler/Disassembler.cs +++ b/Source/Mosa.Utility.Disassembler/Disassembler.cs @@ -5,127 +5,88 @@ using Reko.Arch.Arm; using Reko.Arch.X86; using Reko.Core; +using Reko.Core.Machine; using Reko.Core.Memory; namespace Mosa.Utility.Disassembler; -public partial class Disassembler +public class Disassembler { - private byte[] memory; - public ulong Offset { get; set; } - private readonly ProcessorArchitecture arch; - private MemoryArea memoryArea; + private readonly byte[] memory; + private readonly IEnumerator instructions; + private readonly StringBuilder sb = new StringBuilder(100); - public Disassembler(string platform) + public Disassembler(string platform, byte[] bytes, ulong address) { var services = new ServiceContainer(); var options = new Dictionary(); + var memoryArea = new ByteMemoryArea(Address.Ptr32((uint)address), bytes); - arch = platform.ToLowerInvariant() switch + ProcessorArchitecture arch = platform.ToLowerInvariant() switch { "arm32" => new Arm32Architecture(services, "arm32", options), "arm64" => new Arm64Architecture(services, "arm64", options), "x86" => new X86ArchitectureFlat32(services, "x86-protected-32", options), "x64" => new X86ArchitectureFlat64(services, "x86-protected-64", options), - _ => arch + _ => throw new PlatformNotSupportedException(platform) }; - } - public void SetMemory(byte[] memory, ulong address) - { - this.memory = memory; - memoryArea = new ByteMemoryArea(Address.Ptr32((uint)address), memory); + memory = bytes; + instructions = arch.CreateDisassembler(memoryArea.CreateLeReader((long)Offset)).GetEnumerator(); } - public List Decode(int count = int.MaxValue) + public DecodedInstruction DecodeNext() { - var decoded = new List(); - - var sb = new StringBuilder(100); - - try - { - var dasm = arch.CreateDisassembler(memoryArea.CreateLeReader((long)Offset)); - - foreach (var instr in dasm) - { - var len = instr.Length; - var address = instr.Address.Offset; - var instruction = instr.ToString().Replace('\t', ' '); - - // preference - instruction = instruction.Replace(",", ", "); - - // fix up - //instruction = ChangeHex(instruction); - - sb.AppendFormat("{0:x8}", address); - sb.Append(' '); - var bytes = BytesToHex(memory, (uint)Offset, len); - sb.Append(bytes == null ? string.Empty : bytes.ToString()); - sb.Append(string.Empty.PadRight(41 - sb.Length, ' ')); - sb.Append(instruction); - - decoded.Add(new DecodedInstruction - { - Address = address, - Length = len, - Instruction = instruction, - Full = sb.ToString() - }); - - sb.Clear(); + if (!instructions.MoveNext()) + return null; - count--; + var machineInstruction = instructions.Current; + if (machineInstruction == null) + return null; - if (count == 0) - break; + var length = (uint)machineInstruction.Length; + var address = machineInstruction.Address.Offset; + var instruction = machineInstruction.ToString() + .Replace('\t', ' ') + .Replace(",", ", "); - Offset += (uint)len; - } + // FIXME + //instruction = ChangeHex(instruction); - return decoded; - } - catch + sb.Append(address.ToString("x8")); + sb.Append(' '); + for (var i = 0U; i < length; i++) { - return decoded; + var b = memory[i + Offset]; + sb.Append(b.ToString("x2")); + sb.Append(' '); } - } - - private static StringBuilder BytesToHex(byte[] memory, uint offset, int length) - { - if (length == 0) - return null; + for (var i = sb.Length; i < 41; i++) + sb.Append(' '); + sb.Append(instruction); - var sb = new StringBuilder(); - - for (uint i = 0; i < length; i++) + var decodedInstruction = new DecodedInstruction { - var b = memory[i + offset]; + Address = address, + Length = length, + Instruction = instruction, + Full = sb.ToString() + }; - sb.AppendFormat("{0:x2} ", b); - } + sb.Clear(); - sb.Length--; + Offset += length; - return sb; + return decodedInstruction; } - private static bool IsHex(char c) + private static bool IsHex(char c) => c switch { - if (c >= '0' && c <= '9') - return true; - - if (c >= 'a' && c <= 'f') - return true; - - if (c >= 'A' && c <= 'F') - return true; - - return false; - } + >= '0' and <= '9' or >= 'a' and <= 'f' or >= 'A' and <= 'F' => true, + _ => false + }; private static int IsNextWordHex(string s, int start) { @@ -150,7 +111,6 @@ private static string ChangeHex(string s) for (var i = 0; i < s.Length; i++) { var c = s[i]; - var l = IsNextWordHex(s, i); if (l == 0) @@ -158,17 +118,15 @@ private static string ChangeHex(string s) sb.Append(c); continue; } - else - { - var hex = s.Substring(i, l); - var value = long.Parse(hex, System.Globalization.NumberStyles.HexNumber); - var hex2 = Convert.ToString(value, 16).ToUpper(); - sb.Append("0x"); - sb.Append(hex2); + var hex = s.Substring(i, l); + var value = long.Parse(hex, System.Globalization.NumberStyles.HexNumber); + var hex2 = Convert.ToString(value, 16).ToUpper(); - i += l; - } + sb.Append("0x"); + sb.Append(hex2); + + i += l; } return sb.ToString(); diff --git a/Source/Mosa.Utility.Launcher/Builder.cs b/Source/Mosa.Utility.Launcher/Builder.cs index 6933287cb7..5857a10547 100644 --- a/Source/Mosa.Utility.Launcher/Builder.cs +++ b/Source/Mosa.Utility.Launcher/Builder.cs @@ -241,12 +241,12 @@ private void GenerateASMFile() for (ulong i = fileOffset; i < (ulong)code2.Length; i++) code[i - fileOffset] = code2[i]; - var disassembler = new Disassembler.Disassembler(MosaSettings.Platform); - disassembler.SetMemory(code, startingAddress); + var disassembler = new Disassembler.Disassembler(MosaSettings.Platform, code, startingAddress); using var dest = File.CreateText(MosaSettings.AsmFile); - foreach (var instruction in disassembler.Decode()) + var instruction = disassembler.DecodeNext(); + while (instruction != null) { if (map.TryGetValue(instruction.Address, out List list)) foreach (var entry in list) @@ -256,6 +256,8 @@ private void GenerateASMFile() if (instruction.Address > startingAddress + length) break; + + instruction = disassembler.DecodeNext(); } } diff --git a/Source/Mosa.sln b/Source/Mosa.sln index 96f56a44c5..8c5ee8e7c1 100644 --- a/Source/Mosa.sln +++ b/Source/Mosa.sln @@ -252,6 +252,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Template", "Template", "{A1 TemplateLibrary.txt = TemplateLibrary.txt EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mosa.Tool.Explorer.Avalonia", "Mosa.Tool.Explorer.Avalonia\Mosa.Tool.Explorer.Avalonia.csproj", "{763FDCF2-2501-4756-A7A1-62813D610B00}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1436,6 +1438,24 @@ Global {26667157-E909-4F7A-9130-F8B5C15A1E4E}.Release|Mixed Platforms.Build.0 = Release|Any CPU {26667157-E909-4F7A-9130-F8B5C15A1E4E}.Release|x86.ActiveCfg = Release|Any CPU {26667157-E909-4F7A-9130-F8B5C15A1E4E}.Release|x86.Build.0 = Release|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Debug|x86.ActiveCfg = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Debug|x86.Build.0 = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Description|Any CPU.ActiveCfg = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Description|Any CPU.Build.0 = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Description|Mixed Platforms.ActiveCfg = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Description|Mixed Platforms.Build.0 = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Description|x86.ActiveCfg = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Description|x86.Build.0 = Debug|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Release|Any CPU.Build.0 = Release|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Release|x86.ActiveCfg = Release|Any CPU + {763FDCF2-2501-4756-A7A1-62813D610B00}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1512,6 +1532,7 @@ Global {E94607AB-584E-4D15-B0FA-68E086FE9E70} = {75BB6B40-C122-422F-8B40-F50A70A08E0D} {26667157-E909-4F7A-9130-F8B5C15A1E4E} = {3A538FDC-0226-4971-A3C0-31570CDA340D} {A1660856-2153-477F-BAAC-39E8BEB75971} = {F0EFF742-92D5-4219-939A-8F6F8DAB24E5} + {763FDCF2-2501-4756-A7A1-62813D610B00} = {D032B24A-CE3A-4881-BACE-CC4FE0AFD69D} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C22A5C94-6B05-4B1B-845A-A2EA7615E093}