[wasm] [debugger] Cache debugger information on Proxy side to avoid going to debugger...
authorThays Grazia <thaystg@gmail.com>
Tue, 17 Aug 2021 15:22:09 +0000 (12:22 -0300)
committerGitHub <noreply@github.com>
Tue, 17 Aug 2021 15:22:09 +0000 (12:22 -0300)
* Caching some debugger information to avoid going to debugger-agent everytime.

* Apply suggestions from code review

Co-authored-by: Ankit Jain <radical@gmail.com>
* Addressing @radical comments.

* Adding cache for generic type.

* Fix merge.

* Fixing test behavior.

* Fixing debuggerproxy.

* Fixing merge
Fixing tests.

Co-authored-by: Ankit Jain <radical@gmail.com>
src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs
src/mono/wasm/debugger/BrowserDebugProxy/DevToolsHelper.cs
src/mono/wasm/debugger/BrowserDebugProxy/EvaluateExpression.cs
src/mono/wasm/debugger/BrowserDebugProxy/MemberReferenceResolver.cs
src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs
src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs
src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs

index c398ca8..be7d729 100644 (file)
@@ -317,21 +317,22 @@ namespace Microsoft.WebAssembly.Diagnostics
 
         public SourceId SourceId => source.SourceId;
 
-        public int DebuggerId { get; set; }
         public string Name { get; }
         public MethodDebugInformation DebugInformation;
         public MethodDefinitionHandle methodDefHandle;
         private MetadataReader pdbMetadataReader;
 
-        public SourceLocation StartLocation { get; set;}
-        public SourceLocation EndLocation { get; set;}
+        public SourceLocation StartLocation { get; set; }
+        public SourceLocation EndLocation { get; set; }
         public AssemblyInfo Assembly { get; }
         public int Token { get; }
         internal bool IsEnCMethod;
         internal LocalScopeHandleCollection localScopes;
         public bool IsStatic() => (methodDef.Attributes & MethodAttributes.Static) != 0;
+        public int IsAsync { get; set; }
         public MethodInfo(AssemblyInfo assembly, MethodDefinitionHandle methodDefHandle, int token, SourceFile source, TypeInfo type, MetadataReader asmMetadataReader, MetadataReader pdbMetadataReader)
         {
+            this.IsAsync = -1;
             this.Assembly = assembly;
             this.methodDef = asmMetadataReader.GetMethodDefinition(methodDefHandle);
             this.DebugInformation = pdbMetadataReader.GetMethodDebugInformation(methodDefHandle.ToDebugInformationHandle());
@@ -456,7 +457,7 @@ namespace Microsoft.WebAssembly.Diagnostics
         internal AssemblyInfo assembly;
         private TypeDefinition type;
         private List<MethodInfo> methods;
-        public int Token { get; }
+        internal int Token { get; }
 
         public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefinition type)
         {
@@ -483,6 +484,12 @@ namespace Microsoft.WebAssembly.Diagnostics
             FullName = namespaceName + Name;
         }
 
+        public TypeInfo(AssemblyInfo assembly, string name)
+        {
+            Name = name;
+            FullName = name;
+        }
+
         public string Name { get; }
         public string FullName { get; }
         public List<MethodInfo> Methods => methods;
@@ -498,7 +505,6 @@ namespace Microsoft.WebAssembly.Diagnostics
         private readonly ILogger logger;
         private Dictionary<int, MethodInfo> methods = new Dictionary<int, MethodInfo>();
         private Dictionary<string, string> sourceLinkMappings = new Dictionary<string, string>();
-        private Dictionary<string, TypeInfo> typesByName = new Dictionary<string, TypeInfo>();
         private readonly List<SourceFile> sources = new List<SourceFile>();
         internal string Url { get; }
         internal MetadataReader asmMetadataReader { get; }
@@ -508,6 +514,7 @@ namespace Microsoft.WebAssembly.Diagnostics
         internal PEReader peReader;
         internal MemoryStream asmStream;
         internal MemoryStream pdbStream;
+        public int DebugId { get; set; }
 
         public bool TriedToLoadSymbolsOnDemand { get; set; }
 
@@ -597,7 +604,8 @@ namespace Microsoft.WebAssembly.Diagnostics
                 var typeDefinition = asmMetadataReader.GetTypeDefinition(type);
 
                 var typeInfo = new TypeInfo(this, type, typeDefinition);
-                typesByName[typeInfo.FullName] = typeInfo;
+                TypesByName[typeInfo.FullName] = typeInfo;
+                TypesByToken[typeInfo.Token] = typeInfo;
                 if (pdbMetadataReader != null)
                 {
                     foreach (MethodDefinitionHandle method in typeDefinition.GetMethods())
@@ -675,7 +683,8 @@ namespace Microsoft.WebAssembly.Diagnostics
         public IEnumerable<SourceFile> Sources => this.sources;
         public Dictionary<int, MethodInfo> Methods => this.methods;
 
-        public Dictionary<string, TypeInfo> TypesByName => this.typesByName;
+        public Dictionary<string, TypeInfo> TypesByName { get; } = new();
+        public Dictionary<int, TypeInfo> TypesByToken { get; } = new();
         public int Id => id;
         public string Name { get; }
         public bool HasSymbols => pdbMetadataReader != null;
@@ -696,7 +705,7 @@ namespace Microsoft.WebAssembly.Diagnostics
 
         public TypeInfo GetTypeByName(string name)
         {
-            typesByName.TryGetValue(name, out TypeInfo res);
+            TypesByName.TryGetValue(name, out TypeInfo res);
             return res;
         }
 
index de40842..bc0f4fa 100644 (file)
@@ -214,14 +214,14 @@ namespace Microsoft.WebAssembly.Diagnostics
 
     internal class Frame
     {
-        public Frame(MethodInfo method, SourceLocation location, int id)
+        public Frame(MethodInfoWithDebugInformation method, SourceLocation location, int id)
         {
             this.Method = method;
             this.Location = location;
             this.Id = id;
         }
 
-        public MethodInfo Method { get; private set; }
+        public MethodInfoWithDebugInformation Method { get; private set; }
         public SourceLocation Location { get; private set; }
         public int Id { get; private set; }
     }
@@ -269,7 +269,7 @@ namespace Microsoft.WebAssembly.Diagnostics
 
     internal class ExecutionContext
     {
-        public string DebuggerId { get; set; }
+        public string DebugId { get; set; }
         public Dictionary<string, BreakpointRequest> BreakpointRequests { get; } = new Dictionary<string, BreakpointRequest>();
 
         public TaskCompletionSource<DebugStore> ready;
index 4a2abbc..f14aabb 100644 (file)
@@ -286,13 +286,17 @@ namespace Microsoft.WebAssembly.Diagnostics
         internal static async Task<JObject> CompileAndRunTheExpression(string expression, MemberReferenceResolver resolver, CancellationToken token)
         {
             expression = expression.Trim();
+            if (!expression.StartsWith('('))
+            {
+                expression = "(" + expression + ")";
+            }
             SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(@"
                 using System;
                 public class CompileAndRunTheExpression
                 {
                     public static object Evaluate()
                     {
-                        return (" + expression + @");
+                        return " + expression + @";
                     }
                 }", cancellationToken: token);
 
index e5823ea..5589667 100644 (file)
@@ -94,7 +94,7 @@ namespace Microsoft.WebAssembly.Diagnostics
                 classNameToFind += part.Trim();
                 if (typeId != -1)
                 {
-                    var fields = await sdbHelper.GetTypeFields(sessionId, typeId, onlyPublic: false, token);
+                    var fields = await sdbHelper.GetTypeFields(sessionId, typeId, token);
                     foreach (var field in fields)
                     {
                         if (field.Name == part.Trim())
@@ -124,8 +124,7 @@ namespace Microsoft.WebAssembly.Diagnostics
                     var type = asm.GetTypeByName(classNameToFind);
                     if (type != null)
                     {
-                        var assemblyId = await sdbHelper.GetAssemblyId(sessionId, type.assembly.Name, token);
-                        typeId = await sdbHelper.GetTypeIdFromToken(sessionId, assemblyId, type.Token, token);
+                        typeId = await sdbHelper.GetTypeIdFromToken(sessionId, asm.DebugId, type.Token, token);
                     }
                 }
             }
index f9710ef..95aa6de 100644 (file)
@@ -18,7 +18,7 @@ namespace Microsoft.WebAssembly.Diagnostics
 {
     internal class MonoProxy : DevToolsProxy
     {
-        internal MonoSDBHelper SdbHelper { get; }
+        internal MonoSDBHelper SdbHelper { get; set; }
         private IList<string> urlSymbolServerList;
         private static HttpClient client = new HttpClient();
         private HashSet<SessionId> sessions = new HashSet<SessionId>();
@@ -255,7 +255,7 @@ namespace Microsoft.WebAssembly.Diagnostics
                     {
                         Result resp = await SendCommand(id, method, args, token);
 
-                        context.DebuggerId = resp.Value["debuggerId"]?.ToString();
+                        context.DebugId = resp.Value["DebugId"]?.ToString();
 
                         if (await IsRuntimeAlreadyReadyAlready(id, token))
                             await RuntimeReady(id, token);
@@ -584,7 +584,7 @@ namespace Microsoft.WebAssembly.Diagnostics
                 var retDebuggerCmd = new MemoryStream(newBytes);
                 var retDebuggerCmdReader = new MonoBinaryReader(retDebuggerCmd);
                 retDebuggerCmdReader.ReadByte(); //number of objects returned.
-                var obj = await SdbHelper.CreateJObjectForVariableValue(id, retDebuggerCmdReader, "ret", false, -1, token);
+                var obj = await SdbHelper.CreateJObjectForVariableValue(id, retDebuggerCmdReader, "ret", false, -1, false, token);
                 /*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/
                 res = Result.OkFromObject(new { result = obj["value"]});
                 SendResponse(id, res, token);
@@ -601,7 +601,7 @@ namespace Microsoft.WebAssembly.Diagnostics
             Frame scope = ctx.CallStack.FirstOrDefault(s => s.Id == scopeId);
             if (scope == null)
                 return false;
-            var varIds = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset);
+            var varIds = scope.Method.Info.GetLiveVarsAt(scope.Location.CliLocation.Offset);
             if (varIds == null)
                 return false;
             var varToSetValue = varIds.FirstOrDefault(v => v.Name == varName);
@@ -714,30 +714,15 @@ namespace Microsoft.WebAssembly.Diagnostics
 
         private async Task<bool> SendBreakpointsOfMethodUpdated(SessionId sessionId, ExecutionContext context, MonoBinaryReader retDebuggerCmdReader, CancellationToken token)
         {
-            var method_id = retDebuggerCmdReader.ReadInt32();
-            var method_token = await SdbHelper.GetMethodToken(sessionId, method_id, token);
-            var assembly_id = await SdbHelper.GetAssemblyIdFromMethod(sessionId, method_id, token);
-            var assembly_name = await SdbHelper.GetAssemblyName(sessionId, assembly_id, token);
-            var method_name = await SdbHelper.GetMethodName(sessionId, method_id, token);
-            DebugStore store = await LoadStore(sessionId, token);
-            AssemblyInfo asm = store.GetAssemblyByName(assembly_name);
-            if (asm == null)
-            {
-                assembly_name = await SdbHelper.GetAssemblyFileNameFromId(sessionId, assembly_id, token);
-                asm = store.GetAssemblyByName(assembly_name);
-                if (asm == null)
-                {
-                    return true;
-                }
-            }
-            MethodInfo method = asm.GetMethodByToken(method_token);
+            var methodId = retDebuggerCmdReader.ReadInt32();
+            var method = await SdbHelper.GetMethodInfo(sessionId, methodId, token);
             if (method == null)
             {
                 return true;
             }
             foreach (var req in context.BreakpointRequests.Values)
             {
-                if (req.Method != null && req.Method.Assembly.Id == method.Assembly.Id && req.Method.Token == method.Token)
+                if (req.Method != null && req.Method.Assembly.Id == method.Info.Assembly.Id && req.Method.Token == method.Info.Token)
                 {
                     await SetBreakpoint(sessionId, context.store, req, true, token);
                 }
@@ -762,47 +747,10 @@ namespace Microsoft.WebAssembly.Diagnostics
                 var methodId = retDebuggerCmdReader.ReadInt32();
                 var il_pos = retDebuggerCmdReader.ReadInt32();
                 var flags = retDebuggerCmdReader.ReadByte();
-                var method_token = await SdbHelper.GetMethodToken(sessionId, methodId, token);
-                var assembly_id = await SdbHelper.GetAssemblyIdFromMethod(sessionId, methodId, token);
-                var assembly_name = await SdbHelper.GetAssemblyName(sessionId, assembly_id, token);
-                var method_name = await SdbHelper.GetMethodName(sessionId, methodId, token);
                 DebugStore store = await LoadStore(sessionId, token);
-                AssemblyInfo asm = store.GetAssemblyByName(assembly_name);
-                if (asm == null)
-                {
-                    assembly_name = await SdbHelper.GetAssemblyFileNameFromId(sessionId, assembly_id, token); //maybe is a lazy loaded assembly
-                    asm = store.GetAssemblyByName(assembly_name);
-                    if (asm == null)
-                    {
-                        Log("debug", $"Unable to find assembly: {assembly_name}");
-                        continue;
-                    }
-                }
-
-                MethodInfo method = asm.GetMethodByToken(method_token);
-
-                if (method == null && !asm.HasSymbols)
-                {
-                    try
-                    {
-                        method = await LoadSymbolsOnDemand(asm, method_token, sessionId, token);
-                    }
-                    catch (Exception e)
-                    {
-                        Log("info", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name} exception: {e}");
-                        continue;
-                    }
-                }
+                var method = await SdbHelper.GetMethodInfo(sessionId, methodId, token);
 
-                if (method == null)
-                {
-                    Log("debug", $"Unable to find il offset: {il_pos} in method token: {method_token} assembly name: {assembly_name}");
-                    continue;
-                }
-
-                method.DebuggerId = methodId;
-
-                SourceLocation location = method?.GetLocationByIl(il_pos);
+                SourceLocation location = method?.Info.GetLocationByIl(il_pos);
 
                 // When hitting a breakpoint on the "IncrementCount" method in the standard
                 // Blazor project template, one of the stack frames is inside mscorlib.dll
@@ -813,15 +761,15 @@ namespace Microsoft.WebAssembly.Diagnostics
                     continue;
                 }
 
-                Log("debug", $"frame il offset: {il_pos} method token: {method_token} assembly name: {assembly_name}");
-                Log("debug", $"\tmethod {method_name} location: {location}");
+                Log("debug", $"frame il offset: {il_pos} method token: {method.Info.Token} assembly name: {method.Info.Assembly.Name}");
+                Log("debug", $"\tmethod {method.Name} location: {location}");
                 frames.Add(new Frame(method, location, frame_id));
 
                 callFrames.Add(new
                 {
-                    functionName = method_name,
+                    functionName = method.Name,
                     callFrameId = $"dotnet:scope:{frame_id}",
-                    functionLocation = method.StartLocation.AsLocation(),
+                    functionLocation = method.Info.StartLocation.AsLocation(),
 
                     location = location.AsLocation(),
 
@@ -839,9 +787,9 @@ namespace Microsoft.WebAssembly.Diagnostics
                                             description = "Object",
                                             objectId = $"dotnet:scope:{frame_id}",
                                     },
-                                    name = method_name,
-                                    startLocation = method.StartLocation.AsLocation(),
-                                    endLocation = method.EndLocation.AsLocation(),
+                                    name = method.Name,
+                                    startLocation = method.Info.StartLocation.AsLocation(),
+                                    endLocation = method.Info.EndLocation.AsLocation(),
                             }
                         }
                 });
@@ -949,7 +897,7 @@ namespace Microsoft.WebAssembly.Diagnostics
             return false;
         }
 
-        private async Task<MethodInfo> LoadSymbolsOnDemand(AssemblyInfo asm, int method_token, SessionId sessionId, CancellationToken token)
+        internal async Task<MethodInfo> LoadSymbolsOnDemand(AssemblyInfo asm, int method_token, SessionId sessionId, CancellationToken token)
         {
             ExecutionContext context = GetContext(sessionId);
             if (urlSymbolServerList.Count == 0)
@@ -1166,7 +1114,7 @@ namespace Microsoft.WebAssembly.Diagnostics
                 if (scope == null)
                     return Result.Err(JObject.FromObject(new { message = $"Could not find scope with id #{scopeId}" }));
 
-                VarInfo[] varIds = scope.Method.GetLiveVarsAt(scope.Location.CliLocation.Offset);
+                VarInfo[] varIds = scope.Method.Info.GetLiveVarsAt(scope.Location.CliLocation.Offset);
 
                 var values = await SdbHelper.StackFrameGetValues(msg_id, scope.Method, ctx.ThreadId, scopeId, varIds, token);
                 if (values != null)
@@ -1282,9 +1230,9 @@ namespace Microsoft.WebAssembly.Diagnostics
             await SdbHelper.EnableReceiveRequests(sessionId, EventKind.MethodUpdate, token);
 
             DebugStore store = await LoadStore(sessionId, token);
-
             context.ready.SetResult(store);
             SendEvent(sessionId, "Mono.runtimeReady", new JObject(), token);
+            SdbHelper.SetStore(store);
             return store;
         }
 
index 1b31923..d804421 100644 (file)
@@ -357,6 +357,25 @@ namespace Microsoft.WebAssembly.Diagnostics
         Line
     }
 
+    internal record MethodInfoWithDebugInformation(MethodInfo Info, int DebugId, string Name);
+
+    internal class TypeInfoWithDebugInformation
+    {
+        public TypeInfo Info { get; }
+        public int DebugId { get; }
+        public string Name { get; }
+        public List<FieldTypeClass> FieldsList { get; set; }
+        public MonoBinaryReader PropertiesBinaryReader { get; set; }
+        public List<int> TypeParamsOrArgsForGenericType { get; set; }
+
+        public TypeInfoWithDebugInformation(TypeInfo typeInfo, int debugId, string name)
+        {
+            Info = typeInfo;
+            DebugId = debugId;
+            Name = name;
+        }
+    }
+
     internal class MonoBinaryReader : BinaryReader
     {
         public MonoBinaryReader(Stream stream) : base(stream) {}
@@ -583,11 +602,13 @@ namespace Microsoft.WebAssembly.Diagnostics
         public int Id { get; }
         public string Name { get; }
         public int TypeId { get; }
-        public FieldTypeClass(int id, string name, int typeId)
+        public bool IsPublic { get; }
+        public FieldTypeClass(int id, string name, int typeId, bool isPublic)
         {
             Id = id;
             Name = name;
             TypeId = typeId;
+            IsPublic = isPublic;
         }
     }
     internal class ValueTypeClass
@@ -627,14 +648,22 @@ namespace Microsoft.WebAssembly.Diagnostics
     }
     internal class MonoSDBHelper
     {
+        private static int debuggerObjectId;
+        private static int cmdId;
+        private static int GetId() {return cmdId++;}
+        private static int MINOR_VERSION = 61;
+        private static int MAJOR_VERSION = 2;
+
+        private Dictionary<int, MethodInfoWithDebugInformation> methods = new();
+        private Dictionary<int, AssemblyInfo> assemblies = new();
+        private Dictionary<int, TypeInfoWithDebugInformation> types = new();
+
         internal Dictionary<int, ValueTypeClass> valueTypes = new Dictionary<int, ValueTypeClass>();
         internal Dictionary<int, PointerValue> pointerValues = new Dictionary<int, PointerValue>();
-        private static int debugger_object_id;
-        private static int cmd_id;
-        private static int GetId() {return cmd_id++;}
+
         private MonoProxy proxy;
-        private static int MINOR_VERSION = 61;
-        private static int MAJOR_VERSION = 2;
+        private DebugStore store;
+
         private readonly ILogger logger;
         private Regex regexForAsyncLocals = new Regex(@"\<([^)]*)\>", RegexOptions.Singleline);
 
@@ -642,6 +671,115 @@ namespace Microsoft.WebAssembly.Diagnostics
         {
             this.proxy = proxy;
             this.logger = logger;
+            this.store = null;
+        }
+
+        public void SetStore(DebugStore store)
+        {
+            this.store = store;
+        }
+
+        public async Task<AssemblyInfo> GetAssemblyInfo(SessionId sessionId, int assemblyId, CancellationToken token)
+        {
+            AssemblyInfo asm = null;
+            if (assemblies.TryGetValue(assemblyId, out asm))
+            {
+                return asm;
+            }
+            var assemblyName = await GetAssemblyName(sessionId, assemblyId, token);
+
+            asm = store.GetAssemblyByName(assemblyName);
+
+            if (asm == null)
+            {
+                assemblyName = await GetAssemblyFileNameFromId(sessionId, assemblyId, token); //maybe is a lazy loaded assembly
+                asm = store.GetAssemblyByName(assemblyName);
+                if (asm == null)
+                {
+                    logger.LogDebug($"Unable to find assembly: {assemblyName}");
+                    return null;
+                }
+            }
+            asm.DebugId = assemblyId;
+            assemblies[assemblyId] = asm;
+            return asm;
+        }
+
+        public async Task<MethodInfoWithDebugInformation> GetMethodInfo(SessionId sessionId, int methodId, CancellationToken token)
+        {
+            MethodInfoWithDebugInformation methodDebugInfo = null;
+            if (methods.TryGetValue(methodId, out methodDebugInfo))
+            {
+                return methodDebugInfo;
+            }
+            var methodToken = await GetMethodToken(sessionId, methodId, token);
+            var assemblyId = await GetAssemblyIdFromMethod(sessionId, methodId, token);
+
+            var asm = await GetAssemblyInfo(sessionId, assemblyId, token);
+
+            if (asm == null)
+            {
+                logger.LogDebug($"Unable to find assembly: {assemblyId}");
+                return null;
+            }
+
+            var method = asm.GetMethodByToken(methodToken);
+
+            if (method == null && !asm.HasSymbols)
+            {
+                try
+                {
+                    method = await proxy.LoadSymbolsOnDemand(asm, methodToken, sessionId, token);
+                }
+                catch (Exception e)
+                {
+                    logger.LogDebug($"Unable to find method token: {methodToken} assembly name: {asm.Name} exception: {e}");
+                    return null;
+                }
+            }
+
+            if (method == null)
+            {
+                logger.LogDebug($"Unable to find method token: {methodToken} assembly name: {asm.Name}");
+                return null;
+            }
+
+            string methodName = await GetMethodName(sessionId, methodId, token);
+            methods[methodId] = new MethodInfoWithDebugInformation(method, methodId, methodName);
+            return methods[methodId];
+        }
+
+        public async Task<TypeInfoWithDebugInformation> GetTypeInfo(SessionId sessionId, int typeId, CancellationToken token)
+        {
+            TypeInfoWithDebugInformation typeDebugInfo = null;
+            if (types.TryGetValue(typeId, out typeDebugInfo))
+            {
+                return typeDebugInfo;
+            }
+
+            TypeInfo type = null;
+
+            var typeToken = await GetTypeToken(sessionId, typeId, token);
+            var typeName = await GetTypeName(sessionId, typeId, token);
+            var assemblyId = await GetAssemblyFromType(sessionId, typeId, token);
+            var asm = await GetAssemblyInfo(sessionId, assemblyId, token);
+
+            if (asm == null)
+            {
+                logger.LogDebug($"Unable to find assembly: {assemblyId}");
+                return null;
+            }
+
+            asm.TypesByToken.TryGetValue(typeToken, out type);
+
+            if (type == null)
+            {
+                logger.LogDebug($"Unable to find type token: {typeName} assembly name: {asm.Name}");
+                return null;
+            }
+
+            types[typeId] = new TypeInfoWithDebugInformation(type, typeId, typeName);
+            return types[typeId];
         }
 
         public void ClearCache()
@@ -782,12 +920,20 @@ namespace Microsoft.WebAssembly.Diagnostics
             return retDebuggerCmdReader.ReadInt32();
         }
 
-        public async Task<List<int>> GetTypeParamsOrArgsForGenericType(SessionId sessionId, int type_id, CancellationToken token)
+        public async Task<List<int>> GetTypeParamsOrArgsForGenericType(SessionId sessionId, int typeId, CancellationToken token)
         {
+            var typeInfo = await GetTypeInfo(sessionId, typeId, token);
+
+            if (typeInfo == null)
+                return null;
+
+            if (typeInfo.TypeParamsOrArgsForGenericType != null)
+                return typeInfo.TypeParamsOrArgsForGenericType;
+
             var ret = new List<int>();
             var commandParams = new MemoryStream();
             var commandParamsWriter = new MonoBinaryWriter(commandParams);
-            commandParamsWriter.Write(type_id);
+            commandParamsWriter.Write(typeId);
             commandParamsWriter.Write((int) MonoTypeNameFormat.FormatReflection);
             var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetInfo, commandParams, token);
 
@@ -813,6 +959,9 @@ namespace Microsoft.WebAssembly.Diagnostics
             {
                 ret.Add(retDebuggerCmdReader.ReadInt32()); //generic type
             }
+
+            typeInfo.TypeParamsOrArgsForGenericType = ret;
+
             return ret;
         }
 
@@ -892,6 +1041,10 @@ namespace Microsoft.WebAssembly.Diagnostics
 
         public async Task<bool> MethodIsStatic(SessionId sessionId, int methodId, CancellationToken token)
         {
+            var methodInfo = await GetMethodInfo(sessionId, methodId, token);
+            if (methodInfo != null)
+                return methodInfo.Info.IsStatic();
+
             var commandParams = new MemoryStream();
             var commandParamsWriter = new MonoBinaryWriter(commandParams);
             commandParamsWriter.Write(methodId);
@@ -1025,7 +1178,7 @@ namespace Microsoft.WebAssembly.Diagnostics
             commandParamsWriter.Write(fieldId);
 
             var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetValues, commandParams, token);
-            return await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, "", false, -1, token);
+            return await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, "", false, -1, false, token);
         }
 
         public async Task<int> TypeIsInitialized(SessionId sessionId, int typeId, CancellationToken token)
@@ -1050,25 +1203,53 @@ namespace Microsoft.WebAssembly.Diagnostics
             return retDebuggerCmdReader.ReadInt32();
         }
 
-        public async Task<List<FieldTypeClass>> GetTypeFields(SessionId sessionId, int type_id, bool onlyPublic, CancellationToken token)
+        public async Task<MonoBinaryReader> GetTypePropertiesReader(SessionId sessionId, int typeId, CancellationToken token)
         {
+            var typeInfo = await GetTypeInfo(sessionId, typeId, token);
+
+            if (typeInfo == null)
+                return null;
+
+            if (typeInfo.PropertiesBinaryReader != null)
+            {
+                typeInfo.PropertiesBinaryReader.BaseStream.Seek(0, SeekOrigin.Begin);
+                return typeInfo.PropertiesBinaryReader;
+            }
+
+            var commandParams = new MemoryStream();
+            var commandParamsWriter = new MonoBinaryWriter(commandParams);
+            commandParamsWriter.Write(typeId);
+
+            typeInfo.PropertiesBinaryReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetProperties, commandParams, token);
+            return typeInfo.PropertiesBinaryReader;
+        }
+
+        public async Task<List<FieldTypeClass>> GetTypeFields(SessionId sessionId, int typeId, CancellationToken token)
+        {
+            var typeInfo = await GetTypeInfo(sessionId, typeId, token);
+
+            if (typeInfo.FieldsList != null) {
+                return typeInfo.FieldsList;
+            }
+
             var ret = new List<FieldTypeClass>();
             var commandParams = new MemoryStream();
             var commandParamsWriter = new MonoBinaryWriter(commandParams);
-            commandParamsWriter.Write(type_id);
+            commandParamsWriter.Write(typeId);
 
             var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetFields, commandParams, token);
             var nFields = retDebuggerCmdReader.ReadInt32();
 
             for (int i = 0 ; i < nFields; i++)
             {
+                bool isPublic = false;
                 int fieldId = retDebuggerCmdReader.ReadInt32(); //fieldId
                 string fieldNameStr = retDebuggerCmdReader.ReadString();
-                int typeId = retDebuggerCmdReader.ReadInt32(); //typeId
+                int fieldTypeId = retDebuggerCmdReader.ReadInt32(); //typeId
                 int attrs = retDebuggerCmdReader.ReadInt32(); //attrs
                 int isSpecialStatic = retDebuggerCmdReader.ReadInt32(); //is_special_static
-                if (onlyPublic && ((attrs & (int)MethodAttributes.Public) == 0))
-                    continue;
+                if (((attrs & (int)MethodAttributes.Public) != 0))
+                    isPublic = true;
                 if (isSpecialStatic == 1)
                     continue;
                 if (fieldNameStr.Contains("k__BackingField"))
@@ -1077,8 +1258,9 @@ namespace Microsoft.WebAssembly.Diagnostics
                     fieldNameStr = fieldNameStr.Replace("<", "");
                     fieldNameStr = fieldNameStr.Replace(">", "");
                 }
-                ret.Add(new FieldTypeClass(fieldId, fieldNameStr, typeId));
+                ret.Add(new FieldTypeClass(fieldId, fieldNameStr, fieldTypeId, isPublic));
             }
+            typeInfo.FieldsList = ret;
             return ret;
         }
 
@@ -1093,6 +1275,7 @@ namespace Microsoft.WebAssembly.Diagnostics
             className = className.Replace("System.Byte", "byte");
             return className;
         }
+
         internal async Task<MonoBinaryReader> GetCAttrsFromType(SessionId sessionId, int objectId, int typeId, string attrName, CancellationToken token)
         {
             var invokeParams = new MemoryStream();
@@ -1124,13 +1307,28 @@ namespace Microsoft.WebAssembly.Diagnostics
                     for (int j = 0; j < parmCount; j++)
                     {
                         //to typed_args
-                        await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, "varName", false, -1, token);
+                        await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, "varName", false, -1, false, token);
                     }
                 }
             }
             return null;
         }
 
+        public async Task<int> GetAssemblyFromType(SessionId sessionId, int type_id, CancellationToken token)
+        {
+            var commandParams = new MemoryStream();
+            var commandParamsWriter = new MonoBinaryWriter(commandParams);
+            commandParamsWriter.Write(type_id);
+            commandParamsWriter.Write((int) MonoTypeNameFormat.FormatReflection);
+            var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetInfo, commandParams, token);
+
+            retDebuggerCmdReader.ReadString();
+            retDebuggerCmdReader.ReadString();
+            retDebuggerCmdReader.ReadString();
+
+            return retDebuggerCmdReader.ReadInt32();
+        }
+
         public async Task<string> GetValueFromDebuggerDisplayAttribute(SessionId sessionId, int objectId, int typeId, CancellationToken token)
         {
             string expr = "";
@@ -1166,10 +1364,15 @@ namespace Microsoft.WebAssembly.Diagnostics
                 {
                     dispAttrStr = dispAttrStr.Replace(", nq", "");
                 }
+                if (dispAttrStr.Contains(",nq"))
+                {
+                    dispAttrStr = dispAttrStr.Replace(",nq", "");
+                }
                 expr = "$\"" + dispAttrStr + "\"";
                 JObject retValue = await resolver.Resolve(expr, token);
                 if (retValue == null)
                     retValue = await EvaluateExpression.CompileAndRunTheExpression(expr, resolver, token);
+
                 return retValue?["value"]?.Value<string>();
             }
             catch (Exception)
@@ -1205,6 +1408,23 @@ namespace Microsoft.WebAssembly.Diagnostics
             return retDebuggerCmdReader.ReadString(); //class name formatted
         }
 
+        public async Task<int> GetTypeToken(SessionId sessionId, int typeId, CancellationToken token)
+        {
+            var commandParams = new MemoryStream();
+            var commandParamsWriter = new MonoBinaryWriter(commandParams);
+            commandParamsWriter.Write(typeId);
+            commandParamsWriter.Write((int) MonoTypeNameFormat.FormatReflection);
+            var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetInfo, commandParams, token);
+            retDebuggerCmdReader.ReadString(); //namespace
+            retDebuggerCmdReader.ReadString(); //class name
+            retDebuggerCmdReader.ReadString(); //class name formatted
+            retDebuggerCmdReader.ReadInt32(); //assemblyid
+            retDebuggerCmdReader.ReadInt32(); //moduleId
+            retDebuggerCmdReader.ReadInt32(); //parent typeId
+            retDebuggerCmdReader.ReadInt32(); //array typeId
+            return retDebuggerCmdReader.ReadInt32(); //token
+        }
+
         public async Task<string> GetStringValue(SessionId sessionId, int string_id, CancellationToken token)
         {
             var commandParams = new MemoryStream();
@@ -1331,16 +1551,15 @@ namespace Microsoft.WebAssembly.Diagnostics
             commandParamsWriter.Write(0);
             var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdVM>(sessionId, CmdVM.InvokeMethod, parms, token);
             retDebuggerCmdReader.ReadByte(); //number of objects returned.
-            return await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, varName, false, -1, token);
+            return await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, varName, false, -1, false, token);
         }
 
         public async Task<int> GetPropertyMethodIdByName(SessionId sessionId, int typeId, string propertyName, CancellationToken token)
         {
-            var commandParams = new MemoryStream();
-            var commandParamsWriter = new MonoBinaryWriter(commandParams);
-            commandParamsWriter.Write(typeId);
+            var retDebuggerCmdReader =  await GetTypePropertiesReader(sessionId, typeId, token);
+            if (retDebuggerCmdReader == null)
+                return -1;
 
-            var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetProperties, commandParams, token);
             var nProperties = retDebuggerCmdReader.ReadInt32();
             for (int i = 0 ; i < nProperties; i++)
             {
@@ -1360,11 +1579,10 @@ namespace Microsoft.WebAssembly.Diagnostics
         public async Task<JArray> CreateJArrayForProperties(SessionId sessionId, int typeId, byte[] object_buffer, JArray attributes, bool isAutoExpandable, string objectId, bool isOwn, CancellationToken token)
         {
             JArray ret = new JArray();
-            var commandParams = new MemoryStream();
-            var commandParamsWriter = new MonoBinaryWriter(commandParams);
-            commandParamsWriter.Write(typeId);
+            var retDebuggerCmdReader =  await GetTypePropertiesReader(sessionId, typeId, token);
+            if (retDebuggerCmdReader == null)
+                return null;
 
-            var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetProperties, commandParams, token);
             var nProperties = retDebuggerCmdReader.ReadInt32();
             for (int i = 0 ; i < nProperties; i++)
             {
@@ -1420,8 +1638,9 @@ namespace Microsoft.WebAssembly.Diagnostics
             var varName = pointerValues[pointerId].varName;
             if (int.TryParse(varName, out _))
                 varName = $"[{varName}]";
-            return await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, "*" + varName, false, -1, token);
+            return await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, "*" + varName, false, -1, false, token);
         }
+
         public async Task<JArray> GetPropertiesValuesOfValueType(SessionId sessionId, int valueTypeId, CancellationToken token)
         {
             JArray ret = new JArray();
@@ -1523,7 +1742,7 @@ namespace Microsoft.WebAssembly.Diagnostics
             int pointerId = 0;
             if (valueAddress != 0 && className != "(void*)")
             {
-                pointerId = Interlocked.Increment(ref debugger_object_id);
+                pointerId = Interlocked.Increment(ref debuggerObjectId);
                 type = "object";
                 value =  className;
                 pointerValues[pointerId] = new PointerValue(valueAddress, typeId, name);
@@ -1551,13 +1770,15 @@ namespace Microsoft.WebAssembly.Diagnostics
             return CreateJObject<string>(null, "object", $"{value.ToString()}({length})", false, value.ToString(), "dotnet:array:" + objectId, null, "array");
         }
 
-        public async Task<JObject> CreateJObjectForObject(SessionId sessionId, MonoBinaryReader retDebuggerCmdReader, int typeIdFromAttribute, CancellationToken token)
+        public async Task<JObject> CreateJObjectForObject(SessionId sessionId, MonoBinaryReader retDebuggerCmdReader, int typeIdFromAttribute, bool forDebuggerDisplayAttribute, CancellationToken token)
         {
             var objectId = retDebuggerCmdReader.ReadInt32();
             var className = "";
             var type_id = await GetTypeIdFromObject(sessionId, objectId, false, token);
             className = await GetTypeName(sessionId, type_id[0], token);
-            var debuggerDisplayAttribute = await GetValueFromDebuggerDisplayAttribute(sessionId, objectId, type_id[0], token);
+            string debuggerDisplayAttribute = null;
+            if (!forDebuggerDisplayAttribute)
+                debuggerDisplayAttribute = await GetValueFromDebuggerDisplayAttribute(sessionId, objectId, type_id[0], token);
             var description = className.ToString();
 
             if (debuggerDisplayAttribute != null)
@@ -1588,13 +1809,13 @@ namespace Microsoft.WebAssembly.Diagnostics
             var className = await GetTypeName(sessionId, typeId, token);
             var description = className;
             var numFields = retDebuggerCmdReader.ReadInt32();
-            var fields = await GetTypeFields(sessionId, typeId, onlyPublic: false, token);
+            var fields = await GetTypeFields(sessionId, typeId, token);
             JArray valueTypeFields = new JArray();
             if (className.IndexOf("System.Nullable<") == 0) //should we call something on debugger-agent to check???
             {
                 retDebuggerCmdReader.ReadByte(); //ignoring the boolean type
                 var isNull = retDebuggerCmdReader.ReadInt32();
-                var value = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, name, false, -1, token);
+                var value = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, name, false, -1, false, token);
                 if (isNull != 0)
                     return value;
                 else
@@ -1602,12 +1823,12 @@ namespace Microsoft.WebAssembly.Diagnostics
             }
             for (int i = 0; i < numFields ; i++)
             {
-                fieldValueType = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, fields.ElementAt(i).Name, true, fields.ElementAt(i).TypeId, token);
+                fieldValueType = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, fields.ElementAt(i).Name, true, fields.ElementAt(i).TypeId, false, token);
                 valueTypeFields.Add(fieldValueType);
             }
 
             long endPos = retDebuggerCmdReader.BaseStream.Position;
-            var valueTypeId = Interlocked.Increment(ref debugger_object_id);
+            var valueTypeId = Interlocked.Increment(ref debuggerObjectId);
 
             retDebuggerCmdReader.BaseStream.Position = initialPos;
             byte[] valueTypeBuffer = new byte[endPos - initialPos];
@@ -1663,7 +1884,7 @@ namespace Microsoft.WebAssembly.Diagnostics
             return CreateJObject<string>(null, "object", className, false, className, null, null, "null");
         }
 
-        public async Task<JObject> CreateJObjectForVariableValue(SessionId sessionId, MonoBinaryReader retDebuggerCmdReader, string name, bool isOwn, int typeIdFromAttribute, CancellationToken token)
+        public async Task<JObject> CreateJObjectForVariableValue(SessionId sessionId, MonoBinaryReader retDebuggerCmdReader, string name, bool isOwn, int typeIdFromAttribute, bool forDebuggerDisplayAttribute, CancellationToken token)
         {
             long initialPos = retDebuggerCmdReader == null ? 0 : retDebuggerCmdReader.BaseStream.Position;
             ElementType etype = (ElementType)retDebuggerCmdReader.ReadByte();
@@ -1771,7 +1992,7 @@ namespace Microsoft.WebAssembly.Diagnostics
                 case ElementType.Class:
                 case ElementType.Object:
                 {
-                    ret = await CreateJObjectForObject(sessionId, retDebuggerCmdReader, typeIdFromAttribute, token);
+                    ret = await CreateJObjectForObject(sessionId, retDebuggerCmdReader, typeIdFromAttribute, forDebuggerDisplayAttribute, token);
                     break;
                 }
                 case ElementType.ValueType:
@@ -1806,12 +2027,19 @@ namespace Microsoft.WebAssembly.Diagnostics
 
         public async Task<bool> IsAsyncMethod(SessionId sessionId, int methodId, CancellationToken token)
         {
+            var methodInfo = await GetMethodInfo(sessionId, methodId, token);
+            if (methodInfo != null && methodInfo.Info.IsAsync != -1)
+            {
+                return methodInfo.Info.IsAsync == 1;
+            }
+
             var commandParams = new MemoryStream();
             var commandParamsWriter = new MonoBinaryWriter(commandParams);
             commandParamsWriter.Write(methodId);
 
             var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdMethod>(sessionId, CmdMethod.AsyncDebugInfo, commandParams, token);
-            return retDebuggerCmdReader.ReadByte() == 1 ; //token
+            methodInfo.Info.IsAsync = retDebuggerCmdReader.ReadByte();
+            return methodInfo.Info.IsAsync == 1;
         }
 
         private bool IsClosureReferenceField (string fieldName)
@@ -1870,7 +2098,7 @@ namespace Microsoft.WebAssembly.Diagnostics
             return asyncLocalsFull;
         }
 
-        public async Task<JArray> StackFrameGetValues(SessionId sessionId, MethodInfo method, int thread_id, int frame_id, VarInfo[] varIds, CancellationToken token)
+        public async Task<JArray> StackFrameGetValues(SessionId sessionId, MethodInfoWithDebugInformation method, int thread_id, int frame_id, VarInfo[] varIds, CancellationToken token)
         {
             var commandParams = new MemoryStream();
             var commandParamsWriter = new MonoBinaryWriter(commandParams);
@@ -1883,20 +2111,13 @@ namespace Microsoft.WebAssembly.Diagnostics
                 commandParamsWriter.Write(var.Index);
             }
 
-            if (await IsAsyncMethod(sessionId, method.DebuggerId, token))
+            if (await IsAsyncMethod(sessionId, method.DebugId, token))
             {
                 retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdFrame>(sessionId, CmdFrame.GetThis, commandParams, token);
                 retDebuggerCmdReader.ReadByte(); //ignore type
                 var objectId = retDebuggerCmdReader.ReadInt32();
                 var asyncLocals = await GetObjectValues(sessionId, objectId, GetObjectCommandOptions.WithProperties, token);
-                asyncLocals = new JArray(asyncLocals.Where( asyncLocal => !asyncLocal["name"].Value<string>().Contains("<>") || asyncLocal["name"].Value<string>().EndsWith("__this")));
-                foreach (var asyncLocal in asyncLocals)
-                {
-                    if (asyncLocal["name"].Value<string>().EndsWith("__this", StringComparison.Ordinal))
-                        asyncLocal["name"] = "this";
-                    else if (asyncLocal["name"].Value<string>().Contains('<'))
-                        asyncLocal["name"] = Regex.Match(asyncLocal["name"].Value<string>(), @"\<([^)]*)\>").Groups[1].Value;
-                }
+                asyncLocals = await GetHoistedLocalVariables(sessionId, objectId, asyncLocals, token);
                 return asyncLocals;
             }
 
@@ -1904,13 +2125,13 @@ namespace Microsoft.WebAssembly.Diagnostics
             retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdFrame>(sessionId, CmdFrame.GetValues, commandParams, token);
             foreach (var var in varIds)
             {
-                var var_json = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, var.Name, false, -1, token);
+                var var_json = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, var.Name, false, -1, false, token);
                 locals.Add(var_json);
             }
-            if (!method.IsStatic())
+            if (!method.Info.IsStatic())
             {
                 retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdFrame>(sessionId, CmdFrame.GetThis, commandParams, token);
-                var var_json = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, "this", false, -1, token);
+                var var_json = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, "this", false, -1, false, token);
                 var_json.Add("fieldOffset", -1);
                 locals.Add(var_json);
             }
@@ -1936,11 +2157,10 @@ namespace Microsoft.WebAssembly.Diagnostics
                 return valueTypes[valueTypeId].valueTypeProxy;
             valueTypes[valueTypeId].valueTypeProxy = new JArray(valueTypes[valueTypeId].valueTypeJson);
 
-            var commandParams = new MemoryStream();
-            var commandParamsWriter = new MonoBinaryWriter(commandParams);
-            commandParamsWriter.Write(valueTypes[valueTypeId].typeId);
+            var retDebuggerCmdReader =  await GetTypePropertiesReader(sessionId, valueTypes[valueTypeId].typeId, token);
+            if (retDebuggerCmdReader == null)
+                return null;
 
-            var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetProperties, commandParams, token);
             var nProperties = retDebuggerCmdReader.ReadInt32();
 
             for (int i = 0 ; i < nProperties; i++)
@@ -1983,7 +2203,7 @@ namespace Microsoft.WebAssembly.Diagnostics
             JArray array = new JArray();
             for (int i = 0 ; i < length ; i++)
             {
-                var var_json = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, i.ToString(), false, -1, token);
+                var var_json = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, i.ToString(), false, -1, false, token);
                 array.Add(var_json);
             }
             return array;
@@ -2115,7 +2335,10 @@ namespace Microsoft.WebAssembly.Diagnostics
             {
                 if (!getCommandType.HasFlag(GetObjectCommandOptions.AccessorPropertiesOnly))
                 {
-                    var fields = await GetTypeFields(sessionId, typeId[i], onlyPublic: getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerProxyAttribute), token);
+                    className = await GetTypeName(sessionId, typeId[i], token);
+                    var fields = await GetTypeFields(sessionId, typeId[i], token);
+                    if (getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerProxyAttribute))
+                        fields = fields.Where(field => field.IsPublic).ToList();
                     JArray objectFields = new JArray();
 
                     var commandParams = new MemoryStream();
@@ -2124,7 +2347,7 @@ namespace Microsoft.WebAssembly.Diagnostics
                     commandParamsWriter.Write(fields.Count);
                     foreach (var field in fields)
                     {
-                            commandParamsWriter.Write(field.Id);
+                        commandParamsWriter.Write(field.Id);
                     }
 
                     var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdObject>(sessionId, CmdObject.RefGetValues, commandParams, token);
@@ -2134,8 +2357,7 @@ namespace Microsoft.WebAssembly.Diagnostics
                         long initialPos = retDebuggerCmdReader.BaseStream.Position;
                         int valtype = retDebuggerCmdReader.ReadByte();
                         retDebuggerCmdReader.BaseStream.Position = initialPos;
-                        var fieldValue = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, field.Name, i == 0, field.TypeId, token);
-
+                        var fieldValue = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, field.Name, i == 0, field.TypeId, getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerDisplayAttribute), token);
                         if (ret.Where(attribute => attribute["name"].Value<string>().Equals(fieldValue["name"].Value<string>())).Any()) {
                             continue;
                         }
@@ -2182,7 +2404,7 @@ namespace Microsoft.WebAssembly.Diagnostics
                 List<List<FieldTypeClass>> allFields = new List<List<FieldTypeClass>>();
                 for (int i = 0; i < typeId.Count; i++)
                 {
-                    var fields = await GetTypeFields(sessionId, typeId[i], onlyPublic: false, token);
+                    var fields = await GetTypeFields(sessionId, typeId[i], token);
                     allFields.Add(fields);
                 }
                 foreach (var item in ret)
@@ -2216,11 +2438,10 @@ namespace Microsoft.WebAssembly.Diagnostics
             var typeIds = await GetTypeIdFromObject(sessionId, objectId, true, token);
             foreach (var typeId in typeIds)
             {
-                var commandParams = new MemoryStream();
-                var commandParamsWriter = new MonoBinaryWriter(commandParams);
-                commandParamsWriter.Write(typeId);
+                var retDebuggerCmdReader =  await GetTypePropertiesReader(sessionId, typeId, token);
+                if (retDebuggerCmdReader == null)
+                    return null;
 
-                var retDebuggerCmdReader = await SendDebuggerAgentCommand<CmdType>(sessionId, CmdType.GetProperties, commandParams, token);
                 var nProperties = retDebuggerCmdReader.ReadInt32();
                 for (int i = 0 ; i < nProperties; i++)
                 {
index 91f42ab..548b012 100644 (file)
@@ -841,7 +841,6 @@ namespace DebuggerTests
                 var t_props = await GetObjectOnLocals(locals, "t");
                 await CheckProps(t_props, new
                     {
-                        s_taskIdCounter = TNumber(0),
                         Status = TGetter("Status")
                     }, "t_props", num_fields: 53);
             });