diff --git a/Tests/SimpleDebugClient/Program.cs b/Tests/SimpleDebugClient/Program.cs
index fbdc00a..d7eaa7a 100644
--- a/Tests/SimpleDebugClient/Program.cs
+++ b/Tests/SimpleDebugClient/Program.cs
@@ -2,6 +2,7 @@
using Microsoft.Iris.Debug.Data;
using Microsoft.Iris.Debug.SystemNet;
using System;
+using System.Threading;
namespace SimpleDebugClient;
@@ -14,22 +15,41 @@ internal class Program
var connectionString = args.Length >= 2
? new Uri(args[1]) : DebugRemoting.DEFAULT_TCP_URI;
- Console.CancelKeyPress += Console_CancelKeyPress;
-
Debugger = new NetDebuggerClient(connectionString);
- Debugger.DispatcherStep += Debugger_DispatcherStep;
+ //Debugger.DispatcherStep += Debugger_DispatcherStep;
Debugger.InterpreterStep += Debugger_InterpreterStep;
+ Debugger.InterpreterStateChanged += Debugger_InterpreterStateChanged;
- Console.WriteLine("Listening for debug messages. Press Ctrl-C to exit.");
- Console.ReadLine();
+ Console.WriteLine($"Listening for debug messages at '{Debugger.ConnectionUri}'. Press Ctrl-C or 'x' to exit.");
+
+ while (true)
+ {
+ var cmd = Console.ReadLine();
+ if (cmd[0] == 'x')
+ {
+ if (Debugger is IDisposable debugger)
+ debugger.Dispose();
+ break;
+ }
+
+ switch (cmd[0])
+ {
+ case 's':
+ Debugger.DebuggerCommand = InterpreterCommand.Step;
+ break;
+
+ case 'c':
+ Debugger.DebuggerCommand = InterpreterCommand.Continue;
+ break;
+ }
+ }
return 0;
}
- private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
+ private static void Debugger_InterpreterStateChanged(InterpreterCommand state)
{
- if (Debugger is IDisposable debugger)
- debugger.Dispose();
+ Console.WriteLine($"Interpreter is in {state} mode");
}
private static void Debugger_DispatcherStep(string obj)
@@ -39,6 +59,8 @@ internal class Program
private static void Debugger_InterpreterStep(object? sender, InterpreterEntry e)
{
+ if (e.LoadUri.EndsWith("TopToolbarSignIn.uix"))
+ return;
Console.WriteLine($"[Interpreter] {e}");
}
}
\ No newline at end of file
diff --git a/Tests/SimpleIrisApp/SimpleIrisApp.csproj b/Tests/SimpleIrisApp/SimpleIrisApp.csproj
index 388e4ed..3bc6aa9 100644
--- a/Tests/SimpleIrisApp/SimpleIrisApp.csproj
+++ b/Tests/SimpleIrisApp/SimpleIrisApp.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/UIX/Microsoft/Iris/Debug/Data/InterpreterCommand.cs b/UIX/Microsoft/Iris/Debug/Data/InterpreterCommand.cs
new file mode 100644
index 0000000..2dcbf0b
--- /dev/null
+++ b/UIX/Microsoft/Iris/Debug/Data/InterpreterCommand.cs
@@ -0,0 +1,8 @@
+namespace Microsoft.Iris.Debug.Data;
+
+public enum InterpreterCommand : byte
+{
+ Continue,
+ Break,
+ Step,
+}
diff --git a/UIX/Microsoft/Iris/Debug/DebuggerMessageType.cs b/UIX/Microsoft/Iris/Debug/DebuggerMessageType.cs
index 2401fa8..4ea8af4 100644
--- a/UIX/Microsoft/Iris/Debug/DebuggerMessageType.cs
+++ b/UIX/Microsoft/Iris/Debug/DebuggerMessageType.cs
@@ -6,4 +6,7 @@ public enum DebuggerMessageType : int
InterpreterOpCode,
DispatcherStep,
+
+ UpdateBreakpoint,
+ InterpreterCommand,
}
diff --git a/UIX/Microsoft/Iris/Debug/IDebuggerClient.cs b/UIX/Microsoft/Iris/Debug/IDebuggerClient.cs
index 0d5a2ca..4374f45 100644
--- a/UIX/Microsoft/Iris/Debug/IDebuggerClient.cs
+++ b/UIX/Microsoft/Iris/Debug/IDebuggerClient.cs
@@ -10,6 +10,10 @@ public interface IDebuggerClient
///
Uri ConnectionUri { get; }
+ InterpreterCommand DebuggerCommand { get; set; }
+
+ event Action InterpreterStateChanged;
+
///
/// Fired when the UIX interpreter steps forward.
///
@@ -19,4 +23,6 @@ public interface IDebuggerClient
/// Fired when the UIX dispatcher executes another call from the queue.
///
event Action DispatcherStep;
+
+ void UpdateBreakpoint(Breakpoint breakpoint);
}
diff --git a/UIX/Microsoft/Iris/Debug/IDebuggerServer.cs b/UIX/Microsoft/Iris/Debug/IDebuggerServer.cs
index f7cf3c8..265f376 100644
--- a/UIX/Microsoft/Iris/Debug/IDebuggerServer.cs
+++ b/UIX/Microsoft/Iris/Debug/IDebuggerServer.cs
@@ -4,15 +4,17 @@ namespace Microsoft.Iris.Debug;
internal interface IDebuggerServer
{
+ InterpreterCommand DebuggerCommand { get; set; }
+
///
/// Logs the context, opcode, and arguments of an instruction
/// executed by Microsoft.Iris.Markup.Interpreter.
///
- public void LogInterpreterOpCode(object context, InterpreterEntry entry);
+ void LogInterpreterOpCode(object context, InterpreterEntry entry);
///
/// Logs the string representation of a dispatcher step.
///
///
- public void LogDispatcher(string message);
+ void LogDispatcher(string message);
}
diff --git a/UIX/Microsoft/Iris/Debug/SystemNet/NetDebuggerClient.cs b/UIX/Microsoft/Iris/Debug/SystemNet/NetDebuggerClient.cs
index 4d4a442..1972064 100644
--- a/UIX/Microsoft/Iris/Debug/SystemNet/NetDebuggerClient.cs
+++ b/UIX/Microsoft/Iris/Debug/SystemNet/NetDebuggerClient.cs
@@ -1,24 +1,35 @@
using Microsoft.Iris.Debug.Data;
using System;
-using System.Collections.Generic;
-using System.IO;
+using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
-using System.Text;
namespace Microsoft.Iris.Debug.SystemNet;
public class NetDebuggerClient : IDebuggerClient, IDisposable
{
+ private readonly Socket _socket;
+ private readonly ConcurrentQueue _outQueue = new();
+ private readonly IFormatter _formatter;
+ private InterpreterCommand _uibCommand = InterpreterCommand.Continue;
+
public Uri ConnectionUri { get; }
- private readonly Socket _socket;
- private readonly Queue _queue;
- private readonly IFormatter _formatter;
+ public InterpreterCommand DebuggerCommand
+ {
+ get => _uibCommand;
+ set
+ {
+ var data = new[] { (byte)value };
+ QueueDebuggerMessage(new(0, DebuggerMessageType.InterpreterCommand, data));
+ _uibCommand = value;
+ }
+ }
public event EventHandler InterpreterStep;
public event Action DispatcherStep;
+ public event Action InterpreterStateChanged;
public NetDebuggerClient(string connectionUri) : this(new Uri(connectionUri))
{
@@ -30,18 +41,31 @@ public class NetDebuggerClient : IDebuggerClient, IDisposable
_socket = new(SocketType.Stream, ProtocolType.Tcp);
_formatter = DebugRemoting.CreateBsonFormatter();
- System.Threading.Thread connectThread = new(ConnectLoop);
+ System.Threading.Thread connectThread = new(ConnectLoop) { IsBackground = true };
connectThread.Start();
}
- public void Dispose() => _socket.Dispose();
+ public void Dispose()
+ {
+ if (_socket != null)
+ {
+ if (_socket.Connected)
+ _socket.Disconnect(false);
+ _socket.Close();
+ }
+ }
+
+ public void UpdateBreakpoint(Breakpoint breakpoint)
+ {
+ QueueDebuggerMessage(new(0, DebuggerMessageType.UpdateBreakpoint, breakpoint.Serialize(_formatter)));
+ }
private void QueueDebuggerMessage(DebuggerMessageFrame frame)
{
- _queue.Enqueue(frame.ToBytes());
+ _outQueue.Enqueue(frame.ToBytes());
}
- private void MessageRecieveLoop()
+ private void MessageReceiveLoop()
{
while (_socket.Connected)
{
@@ -52,11 +76,8 @@ public class NetDebuggerClient : IDebuggerClient, IDisposable
switch (frame.Type)
{
case DebuggerMessageType.InterpreterOpCode:
- {
- using MemoryStream stream = new(frame.Data);
- var entry = (InterpreterEntry)_formatter.Deserialize(stream);
- InterpreterStep?.Invoke(this, entry);
- }
+ var entry = frame.DeserializeData(_formatter);
+ InterpreterStep?.Invoke(this, entry);
break;
case DebuggerMessageType.DispatcherStep:
@@ -64,6 +85,11 @@ public class NetDebuggerClient : IDebuggerClient, IDisposable
DispatcherStep?.Invoke(message);
break;
+ case DebuggerMessageType.InterpreterCommand:
+ _uibCommand = (InterpreterCommand)frame.Data[0];
+ InterpreterStateChanged?.Invoke(_uibCommand);
+ break;
+
default:
Trace.WriteLine(TraceCategory.MarkupDebug, "Recieved unknown debugger message of type '{0}'.", frame.Type);
break;
@@ -71,6 +97,18 @@ public class NetDebuggerClient : IDebuggerClient, IDisposable
}
}
+ private void MessageSendLoop()
+ {
+ while (_socket.Connected)
+ {
+ byte[] frameBytes;
+ while (!_outQueue.TryDequeue(out frameBytes)) ;
+
+ _socket.Send(BitConverter.GetBytes(frameBytes.Length));
+ _socket.Send(frameBytes);
+ }
+ }
+
private void ConnectLoop()
{
while (!_socket.Connected)
@@ -83,7 +121,9 @@ public class NetDebuggerClient : IDebuggerClient, IDisposable
catch { }
}
- System.Threading.Thread receiveThread = new(MessageRecieveLoop);
+ System.Threading.Thread receiveThread = new(MessageReceiveLoop) { IsBackground = true };
+ System.Threading.Thread sendThread = new(MessageSendLoop) { IsBackground = true };
receiveThread.Start();
+ sendThread.Start();
}
}
\ No newline at end of file
diff --git a/UIX/Microsoft/Iris/Debug/SystemNet/NetDebuggerServer.cs b/UIX/Microsoft/Iris/Debug/SystemNet/NetDebuggerServer.cs
index 7f2e734..f0b36ad 100644
--- a/UIX/Microsoft/Iris/Debug/SystemNet/NetDebuggerServer.cs
+++ b/UIX/Microsoft/Iris/Debug/SystemNet/NetDebuggerServer.cs
@@ -1,7 +1,6 @@
using Microsoft.Iris.Debug.Data;
using System;
using System.Collections.Concurrent;
-using System.IO;
using System.Net.Sockets;
using System.Runtime.Serialization;
@@ -11,13 +10,25 @@ internal class NetDebuggerServer : IDebuggerServer, IDisposable
{
public static IDebuggerServer Current { get; private set; }
- public Uri ConnectionUri { get; }
-
private readonly ConcurrentQueue _outQueue = new();
private readonly TcpListener _listener;
private readonly IFormatter _formatter;
private Socket _socket;
private bool _disposed = false;
+ private InterpreterCommand _uibCommand = InterpreterCommand.Continue;
+
+ public Uri ConnectionUri { get; }
+
+ public InterpreterCommand DebuggerCommand
+ {
+ get => _uibCommand;
+ set
+ {
+ var data = new[] { (byte)value };
+ QueueDebuggerMessage(new(0, DebuggerMessageType.InterpreterCommand, data));
+ _uibCommand = value;
+ }
+ }
public NetDebuggerServer(string connectionUri) : this(new Uri(connectionUri))
{
@@ -32,7 +43,7 @@ internal class NetDebuggerServer : IDebuggerServer, IDisposable
_formatter = DebugRemoting.CreateBsonFormatter();
- System.Threading.Thread connectThread = new(ConnectLoop);
+ System.Threading.Thread connectThread = new(ConnectLoop) { IsBackground = true };
connectThread.Start();
Current = this;
@@ -40,10 +51,7 @@ internal class NetDebuggerServer : IDebuggerServer, IDisposable
public void LogInterpreterOpCode(object context, InterpreterEntry entry)
{
- using MemoryStream entryStream = new();
- _formatter.Serialize(entryStream, entry);
-
- QueueDebuggerMessage(new(0, DebuggerMessageType.InterpreterOpCode, entryStream.ToArray()));
+ QueueDebuggerMessage(new(0, DebuggerMessageType.InterpreterOpCode, entry.Serialize(_formatter)));
}
public void LogDispatcher(string message)
@@ -66,16 +74,28 @@ internal class NetDebuggerServer : IDebuggerServer, IDisposable
_outQueue.Enqueue(frame.ToBytes());
}
- private void MessageRecieveLoop()
+ private void MessageReceiveLoop()
{
while (_socket.Connected)
{
DebuggerMessageFrame frame;
while ((frame = DebugRemoting.ReceiveDebuggerMessage(_socket)) == null)
- ;
+ if (!_socket.Connected) return;
switch (frame.Type)
{
+ case DebuggerMessageType.UpdateBreakpoint:
+ var breakpoint = frame.DeserializeData(_formatter);
+ if (breakpoint.Enabled)
+ Application.DebugSettings.Breakpoints.Add(breakpoint);
+ else
+ Application.DebugSettings.Breakpoints.Remove(breakpoint);
+ break;
+
+ case DebuggerMessageType.InterpreterCommand:
+ _uibCommand = (InterpreterCommand)frame.Data[0];
+ break;
+
default:
Trace.WriteLine(TraceCategory.MarkupDebug, "Recieved unknown debugger message of type '{0}'.", frame.Type);
break;
@@ -90,8 +110,12 @@ internal class NetDebuggerServer : IDebuggerServer, IDisposable
byte[] frameBytes;
while (!_outQueue.TryDequeue(out frameBytes)) ;
- _socket.Send(BitConverter.GetBytes(frameBytes.Length));
- _socket.Send(frameBytes);
+ try
+ {
+ _socket.Send(BitConverter.GetBytes(frameBytes.Length));
+ _socket.Send(frameBytes);
+ }
+ catch (SocketException) { }
}
}
@@ -102,8 +126,8 @@ internal class NetDebuggerServer : IDebuggerServer, IDisposable
_socket = _listener.AcceptSocket();
- System.Threading.Thread receiveThread = new(MessageRecieveLoop);
- System.Threading.Thread sendThread = new(MessageSendLoop);
+ System.Threading.Thread receiveThread = new(MessageReceiveLoop) { IsBackground = true };
+ System.Threading.Thread sendThread = new(MessageSendLoop) { IsBackground = true };
receiveThread.Start();
sendThread.Start();
}
diff --git a/UIX/Microsoft/Iris/Markup/Interpreter.cs b/UIX/Microsoft/Iris/Markup/Interpreter.cs
index c2b94ae..0506d2e 100644
--- a/UIX/Microsoft/Iris/Markup/Interpreter.cs
+++ b/UIX/Microsoft/Iris/Markup/Interpreter.cs
@@ -78,18 +78,21 @@ namespace Microsoft.Iris.Markup
if (debugging && context.LoadResult.LineNumberTable.TryLookup(reader.CurrentOffset, out int line, out int column))
{
bool ShouldBreak(Breakpoint b)
- => b.Enabled
- && b.Uri.Equals(loadResult.Uri, StringComparison.OrdinalIgnoreCase)
- && (b.Offset == reader.CurrentOffset || (b.Line == line && b.Column == column));
+ => b.Enabled && b.Equals(loadResult.Uri, line, column, reader.CurrentOffset);
// Check if a breakpoint has been set at this location
bool shouldBreakHere = Application.DebugSettings.Breakpoints.Any(ShouldBreak);
if (shouldBreakHere)
{
- System.Diagnostics.Debugger.Break();
+ Application.Debugger.DebuggerCommand = InterpreterCommand.Break;
+ //System.Diagnostics.Debugger.Break();
}
}
+ while (Application.Debugger.DebuggerCommand == InterpreterCommand.Break) ;
+ if (Application.Debugger.DebuggerCommand == InterpreterCommand.Step)
+ Application.Debugger.DebuggerCommand = InterpreterCommand.Break;
+
switch (opCode)
{
case OpCode.ConstructObject: