Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wasm][debugger] Tie sdb agent lifetime to the ExecutionContext and simplify the api #61392

Merged
merged 12 commits into from
Nov 18, 2021
18 changes: 9 additions & 9 deletions src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ public VarInfo(Parameter p, MetadataReader pdbReader)
public override string ToString() => $"(var-info [{Index}] '{Name}')";
}

internal class NewCliLocation
internal class IlLocation
{
public NewCliLocation(MethodInfo method, int offset)
public IlLocation(MethodInfo method, int offset)
{
Method = method;
Offset = offset;
Expand All @@ -174,7 +174,7 @@ internal class SourceLocation
private SourceId id;
private int line;
private int column;
private NewCliLocation cliLoc;
private IlLocation ilLocation;

public SourceLocation(SourceId id, int line, int column)
{
Expand All @@ -188,13 +188,13 @@ public SourceLocation(MethodInfo mi, SequencePoint sp)
this.id = mi.SourceId;
this.line = sp.StartLine - 1;
this.column = sp.StartColumn - 1;
this.cliLoc = new NewCliLocation(mi, sp.Offset);
this.ilLocation = new IlLocation(mi, sp.Offset);
}

public SourceId Id { get => id; }
public int Line { get => line; }
public int Column { get => column; }
public NewCliLocation CliLocation => this.cliLoc;
public IlLocation IlLocation => this.ilLocation;

public override string ToString() => $"{id}:{Line}:{Column}";

Expand Down Expand Up @@ -926,7 +926,7 @@ private class DebugItem
public Task<byte[][]> Data { get; set; }
}

public IEnumerable<MethodInfo> EnC(SessionId sessionId, AssemblyInfo asm, byte[] meta_data, byte[] pdb_data)
public IEnumerable<MethodInfo> EnC(AssemblyInfo asm, byte[] meta_data, byte[] pdb_data)
{
asm.EnC(meta_data, pdb_data);
foreach (var method in asm.Methods)
Expand All @@ -936,12 +936,12 @@ public IEnumerable<MethodInfo> EnC(SessionId sessionId, AssemblyInfo asm, byte[]
}
}

public IEnumerable<SourceFile> Add(SessionId sessionId, byte[] assembly_data, byte[] pdb_data)
public IEnumerable<SourceFile> Add(string name, byte[] assembly_data, byte[] pdb_data)
{
AssemblyInfo assembly = null;
try
{
assembly = new AssemblyInfo(sessionId.ToString(), assembly_data, pdb_data);
assembly = new AssemblyInfo(name, assembly_data, pdb_data);
}
catch (Exception e)
{
Expand All @@ -965,7 +965,7 @@ public IEnumerable<SourceFile> Add(SessionId sessionId, byte[] assembly_data, by
}
}

public async IAsyncEnumerable<SourceFile> Load(SessionId sessionId, string[] loaded_files, [EnumeratorCancellation] CancellationToken token)
public async IAsyncEnumerable<SourceFile> Load(string[] loaded_files, [EnumeratorCancellation] CancellationToken token)
{
var asm_files = new List<string>();
var pdb_files = new List<string>();
Expand Down
9 changes: 9 additions & 0 deletions src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,13 @@ internal enum PauseOnExceptionsKind

internal class ExecutionContext
{
public ExecutionContext(MonoSDBHelper sdbAgent, int id, object auxData)
{
Id = id;
AuxData = auxData;
SdbAgent = sdbAgent;
}

public string DebugId { get; set; }
public Dictionary<string, BreakpointRequest> BreakpointRequests { get; } = new Dictionary<string, BreakpointRequest>();

Expand All @@ -291,6 +298,7 @@ internal class ExecutionContext

public string[] LoadedFiles { get; set; }
internal DebugStore store;
internal MonoSDBHelper SdbAgent { get; init; }
public TaskCompletionSource<DebugStore> Source { get; } = new TaskCompletionSource<DebugStore>();

private Dictionary<int, PerScopeCache> perScopeCaches { get; } = new Dictionary<int, PerScopeCache>();
Expand Down Expand Up @@ -319,6 +327,7 @@ public PerScopeCache GetCacheForScope(int scopeId)
public void ClearState()
{
CallStack = null;
SdbAgent.ClearCache();
perScopeCaches.Clear();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,20 @@ internal class MemberReferenceResolver
private SessionId sessionId;
private int scopeId;
private MonoProxy proxy;
private ExecutionContext ctx;
private ExecutionContext context;
private PerScopeCache scopeCache;
private ILogger logger;
private bool localsFetched;
private int linqTypeId;
private MonoSDBHelper sdbHelper;

public MemberReferenceResolver(MonoProxy proxy, ExecutionContext ctx, SessionId sessionId, int scopeId, ILogger logger)
{
this.sessionId = sessionId;
this.scopeId = scopeId;
this.proxy = proxy;
this.ctx = ctx;
this.context = ctx;
this.logger = logger;
scopeCache = ctx.GetCacheForScope(scopeId);
sdbHelper = proxy.SdbHelper;
linqTypeId = -1;
}

Expand All @@ -42,11 +40,10 @@ public MemberReferenceResolver(MonoProxy proxy, ExecutionContext ctx, SessionId
this.sessionId = sessionId;
scopeId = -1;
this.proxy = proxy;
this.ctx = ctx;
this.context = ctx;
this.logger = logger;
scopeCache = new PerScopeCache(objectValues);
localsFetched = true;
sdbHelper = proxy.SdbHelper;
linqTypeId = -1;
}

Expand All @@ -56,7 +53,7 @@ public async Task<JObject> GetValueFromObject(JToken objRet, CancellationToken t
{
if (DotnetObjectId.TryParse(objRet?["value"]?["objectId"]?.Value<string>(), out DotnetObjectId objectId))
{
var exceptionObject = await sdbHelper.GetObjectValues(sessionId, int.Parse(objectId.Value), GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.OwnProperties, token);
var exceptionObject = await context.SdbAgent.GetObjectValues(int.Parse(objectId.Value), GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.OwnProperties, token);
var exceptionObjectMessage = exceptionObject.FirstOrDefault(attr => attr["name"].Value<string>().Equals("_message"));
exceptionObjectMessage["value"]["value"] = objRet["value"]?["className"]?.Value<string>() + ": " + exceptionObjectMessage["value"]?["value"]?.Value<string>();
return exceptionObjectMessage["value"]?.Value<JObject>();
Expand All @@ -70,10 +67,9 @@ public async Task<JObject> GetValueFromObject(JToken objRet, CancellationToken t
{
if (DotnetObjectId.TryParse(objRet?["get"]?["objectIdValue"]?.Value<string>(), out DotnetObjectId objectId))
{
var commandParams = new MemoryStream();
var commandParamsWriter = new MonoBinaryWriter(commandParams);
commandParamsWriter.WriteObj(objectId, sdbHelper);
var ret = await sdbHelper.InvokeMethod(sessionId, commandParams.ToArray(), objRet["get"]["methodId"].Value<int>(), objRet["name"].Value<string>(), token);
using var commandParamsWriter = new MonoBinaryWriter();
commandParamsWriter.WriteObj(objectId, context.SdbAgent);
var ret = await context.SdbAgent.InvokeMethod(commandParamsWriter.GetParameterBuffer(), objRet["get"]["methodId"].Value<int>(), objRet["name"].Value<string>(), token);
return await GetValueFromObject(ret, token);
}

Expand All @@ -93,27 +89,26 @@ public async Task<JObject> TryToRunOnLoadedClasses(string varName, CancellationT
classNameToFind += part.Trim();
if (typeId != -1)
{
var fields = await sdbHelper.GetTypeFields(sessionId, typeId, token);
var fields = await context.SdbAgent.GetTypeFields(typeId, token);
foreach (var field in fields)
{
if (field.Name == part.Trim())
{
var isInitialized = await sdbHelper.TypeIsInitialized(sessionId, typeId, token);
var isInitialized = await context.SdbAgent.TypeIsInitialized(typeId, token);
if (isInitialized == 0)
{
isInitialized = await sdbHelper.TypeInitialize(sessionId, typeId, token);
isInitialized = await context.SdbAgent.TypeInitialize(typeId, token);
}
var valueRet = await sdbHelper.GetFieldValue(sessionId, typeId, field.Id, token);
var valueRet = await context.SdbAgent.GetFieldValue(typeId, field.Id, token);
return await GetValueFromObject(valueRet, token);
}
}
var methodId = await sdbHelper.GetPropertyMethodIdByName(sessionId, typeId, part.Trim(), token);
var methodId = await context.SdbAgent.GetPropertyMethodIdByName(typeId, part.Trim(), token);
if (methodId != -1)
{
var commandParamsObj = new MemoryStream();
var commandParamsObjWriter = new MonoBinaryWriter(commandParamsObj);
using var commandParamsObjWriter = new MonoBinaryWriter();
commandParamsObjWriter.Write(0); //param count
var retMethod = await sdbHelper.InvokeMethod(sessionId, commandParamsObj.ToArray(), methodId, "methodRet", token);
var retMethod = await context.SdbAgent.InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, "methodRet", token);
return await GetValueFromObject(retMethod, token);
}
}
Expand Down Expand Up @@ -290,18 +285,17 @@ public async Task<JObject> Resolve(ElementAccessExpressionSyntax elementAccess,
switch (objectId.Scheme)
{
case "array":
rootObject["value"] = await sdbHelper.GetArrayValues(sessionId, int.Parse(objectId.Value), token);
rootObject["value"] = await context.SdbAgent.GetArrayValues(int.Parse(objectId.Value), token);
return (JObject)rootObject["value"][elementIdx]["value"];
case "object":
var typeIds = await sdbHelper.GetTypeIdFromObject(sessionId, int.Parse(objectId.Value), true, token);
int methodId = await sdbHelper.GetMethodIdByName(sessionId, typeIds[0], "ToArray", token);
var commandParamsObj = new MemoryStream();
var commandParamsObjWriter = new MonoBinaryWriter(commandParamsObj);
commandParamsObjWriter.WriteObj(objectId, sdbHelper);
var toArrayRetMethod = await sdbHelper.InvokeMethod(sessionId, commandParamsObj.ToArray(), methodId, elementAccess.Expression.ToString(), token);
var typeIds = await context.SdbAgent.GetTypeIdFromObject(int.Parse(objectId.Value), true, token);
int methodId = await context.SdbAgent.GetMethodIdByName(typeIds[0], "ToArray", token);
var commandParamsObjWriter = new MonoBinaryWriter();
commandParamsObjWriter.WriteObj(objectId, context.SdbAgent);
var toArrayRetMethod = await context.SdbAgent.InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, elementAccess.Expression.ToString(), token);
rootObject = await GetValueFromObject(toArrayRetMethod, token);
DotnetObjectId.TryParse(rootObject?["objectId"]?.Value<string>(), out DotnetObjectId arrayObjectId);
rootObject["value"] = await sdbHelper.GetArrayValues(sessionId, int.Parse(arrayObjectId.Value), token);
rootObject["value"] = await context.SdbAgent.GetArrayValues(int.Parse(arrayObjectId.Value), token);
return (JObject)rootObject["value"][elementIdx]["value"];
default:
throw new InvalidOperationException($"Cannot apply indexing with [] to an expression of type '{objectId.Scheme}'");
Expand Down Expand Up @@ -340,56 +334,55 @@ public async Task<JObject> Resolve(InvocationExpressionSyntax method, Dictionary
if (rootObject != null)
{
DotnetObjectId.TryParse(rootObject?["objectId"]?.Value<string>(), out DotnetObjectId objectId);
var typeIds = await sdbHelper.GetTypeIdFromObject(sessionId, int.Parse(objectId.Value), true, token);
int methodId = await sdbHelper.GetMethodIdByName(sessionId, typeIds[0], methodName, token);
var className = await sdbHelper.GetTypeNameOriginal(sessionId, typeIds[0], token);
var typeIds = await context.SdbAgent.GetTypeIdFromObject(int.Parse(objectId.Value), true, token);
int methodId = await context.SdbAgent.GetMethodIdByName(typeIds[0], methodName, token);
var className = await context.SdbAgent.GetTypeNameOriginal(typeIds[0], token);
if (methodId == 0) //try to search on System.Linq.Enumerable
{
if (linqTypeId == -1)
linqTypeId = await sdbHelper.GetTypeByName(sessionId, "System.Linq.Enumerable", token);
methodId = await sdbHelper.GetMethodIdByName(sessionId, linqTypeId, methodName, token);
linqTypeId = await context.SdbAgent.GetTypeByName("System.Linq.Enumerable", token);
methodId = await context.SdbAgent.GetMethodIdByName(linqTypeId, methodName, token);
if (methodId != 0)
{
foreach (var typeId in typeIds)
{
var genericTypeArgs = await sdbHelper.GetTypeParamsOrArgsForGenericType(sessionId, typeId, token);
var genericTypeArgs = await context.SdbAgent.GetTypeParamsOrArgsForGenericType(typeId, token);
if (genericTypeArgs.Count > 0)
{
isTryingLinq = 1;
methodId = await sdbHelper.MakeGenericMethod(sessionId, methodId, genericTypeArgs, token);
methodId = await context.SdbAgent.MakeGenericMethod(methodId, genericTypeArgs, token);
break;
}
}
}
}
if (methodId == 0) {
var typeName = await sdbHelper.GetTypeName(sessionId, typeIds[0], token);
var typeName = await context.SdbAgent.GetTypeName(typeIds[0], token);
throw new Exception($"Method '{methodName}' not found in type '{typeName}'");
}
var commandParamsObj = new MemoryStream();
var commandParamsObjWriter = new MonoBinaryWriter(commandParamsObj);
using var commandParamsObjWriter = new MonoBinaryWriter();
if (isTryingLinq == 0)
commandParamsObjWriter.WriteObj(objectId, sdbHelper);
commandParamsObjWriter.WriteObj(objectId, context.SdbAgent);
if (method.ArgumentList != null)
{
commandParamsObjWriter.Write((int)method.ArgumentList.Arguments.Count + isTryingLinq);
if (isTryingLinq == 1)
commandParamsObjWriter.WriteObj(objectId, sdbHelper);
commandParamsObjWriter.WriteObj(objectId, context.SdbAgent);
foreach (var arg in method.ArgumentList.Arguments)
{
if (arg.Expression is LiteralExpressionSyntax)
{
if (!await commandParamsObjWriter.WriteConst(sessionId, arg.Expression as LiteralExpressionSyntax, sdbHelper, token))
if (!await commandParamsObjWriter.WriteConst(arg.Expression as LiteralExpressionSyntax, context.SdbAgent, token))
return null;
}
if (arg.Expression is IdentifierNameSyntax)
{
var argParm = arg.Expression as IdentifierNameSyntax;
if (!await commandParamsObjWriter.WriteJsonValue(sessionId, memberAccessValues[argParm.Identifier.Text], sdbHelper, token))
if (!await commandParamsObjWriter.WriteJsonValue(memberAccessValues[argParm.Identifier.Text], context.SdbAgent, token))
return null;
}
}
var retMethod = await sdbHelper.InvokeMethod(sessionId, commandParamsObj.ToArray(), methodId, "methodRet", token);
var retMethod = await context.SdbAgent.InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, "methodRet", token);
return await GetValueFromObject(retMethod, token);
}
}
Expand Down
Loading