diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs index cb0a51ccd7804..7d2dd66ec0812 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoProxy.cs @@ -555,7 +555,7 @@ private async Task CallOnFunction(MessageId id, JObject args, Cancellation args["details"] = await SdbHelper.GetPointerContent(id, int.Parse(objectId.Value), token); break; case "array": - args["details"] = await SdbHelper.GetArrayValues(id, int.Parse(objectId.Value), token); + args["details"] = await SdbHelper.GetArrayValuesProxy(id, int.Parse(objectId.Value), token); break; case "cfo_res": { diff --git a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs index dee4b5ac0f5fd..a484cc4cbeefc 100644 --- a/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs +++ b/src/mono/wasm/debugger/BrowserDebugProxy/MonoSDBHelper.cs @@ -358,6 +358,52 @@ internal enum StepSize Line } + internal record ArrayDimensions + { + internal int Rank { get; } + internal int [] Bounds { get; } + internal int TotalLength { get; } + public ArrayDimensions(int [] rank) + { + Rank = rank.Length; + Bounds = rank; + TotalLength = 1; + for (int i = 0 ; i < Rank ; i++) + TotalLength *= Bounds[i]; + } + + public override string ToString() + { + return $"{string.Join(", ", Bounds)}"; + } + internal string GetArrayIndexString(int idx) + { + if (idx < 0 || idx >= TotalLength) + return "Invalid Index"; + int boundLimit = 1; + int lastBoundLimit = 1; + int[] arrayStr = new int[Rank]; + int rankStart = 0; + while (idx > 0) + { + boundLimit = 1; + for (int i = Rank - 1; i >= rankStart; i--) + { + lastBoundLimit = boundLimit; + boundLimit *= Bounds[i]; + if (idx < boundLimit) + { + arrayStr[i] = (int)(idx / lastBoundLimit); + idx -= arrayStr[i] * lastBoundLimit; + rankStart = i; + break; + } + } + } + return $"{string.Join(", ", arrayStr)}"; + } + } + internal record MethodInfoWithDebugInformation(MethodInfo Info, int DebugId, string Name); internal class TypeInfoWithDebugInformation @@ -1400,7 +1446,8 @@ public async Task GetTypeName(SessionId sessionId, int typeId, Cancellat string className = await GetTypeNameOriginal(sessionId, typeId, token); className = className.Replace("+", "."); className = Regex.Replace(className, @"`\d+", ""); - className = className.Replace("[]", "__SQUARED_BRACKETS__"); + className = Regex.Replace(className, @"[[, ]+]", "__SQUARED_BRACKETS__"); + //className = className.Replace("[]", "__SQUARED_BRACKETS__"); className = className.Replace("[", "<"); className = className.Replace("]", ">"); className = className.Replace("__SQUARED_BRACKETS__", "[]"); @@ -1451,15 +1498,20 @@ public async Task GetStringValue(SessionId sessionId, int string_id, Can } return null; } - public async Task GetArrayLength(SessionId sessionId, int object_id, CancellationToken token) + public async Task GetArrayDimensions(SessionId sessionId, int object_id, CancellationToken token) { var commandParams = new MemoryStream(); var commandParamsWriter = new MonoBinaryWriter(commandParams); commandParamsWriter.Write(object_id); var retDebuggerCmdReader = await SendDebuggerAgentCommand(sessionId, CmdArray.GetLength, commandParams, token); var length = retDebuggerCmdReader.ReadInt32(); - length = retDebuggerCmdReader.ReadInt32(); - return length; + var rank = new int[length]; + for (int i = 0 ; i < length; i++) + { + rank[i] = retDebuggerCmdReader.ReadInt32(); + retDebuggerCmdReader.ReadInt32(); //lower_bound + } + return new ArrayDimensions(rank); } public async Task> GetTypeIdFromObject(SessionId sessionId, int object_id, bool withParents, CancellationToken token) { @@ -1778,9 +1830,14 @@ public async Task CreateJObjectForString(SessionId sessionId, MonoBinar public async Task CreateJObjectForArray(SessionId sessionId, MonoBinaryReader retDebuggerCmdReader, CancellationToken token) { var objectId = retDebuggerCmdReader.ReadInt32(); - var value = await GetClassNameFromObject(sessionId, objectId, token); - var length = await GetArrayLength(sessionId, objectId, token); - return CreateJObject(null, "object", $"{value.ToString()}({length})", false, value.ToString(), "dotnet:array:" + objectId, null, "array"); + var className = await GetClassNameFromObject(sessionId, objectId, token); + var arrayType = className.ToString(); + var length = await GetArrayDimensions(sessionId, objectId, token); + if (arrayType.LastIndexOf('[') > 0) + arrayType = arrayType.Insert(arrayType.LastIndexOf('[')+1, length.ToString()); + if (className.LastIndexOf('[') > 0) + className = className.Insert(arrayType.LastIndexOf('[')+1, new string(',', length.Rank-1)); + return CreateJObject(null, "object", description : arrayType, writable : false, className.ToString(), "dotnet:array:" + objectId, null, subtype : length.Rank == 1 ? "array" : null); } public async Task CreateJObjectForObject(SessionId sessionId, MonoBinaryReader retDebuggerCmdReader, int typeIdFromAttribute, bool forDebuggerDisplayAttribute, CancellationToken token) @@ -2206,21 +2263,33 @@ public async Task GetValueTypeProxy(SessionId sessionId, int valueTypeId public async Task GetArrayValues(SessionId sessionId, int arrayId, CancellationToken token) { - var length = await GetArrayLength(sessionId, arrayId, token); + var dimensions = await GetArrayDimensions(sessionId, arrayId, token); var commandParams = new MemoryStream(); var commandParamsWriter = new MonoBinaryWriter(commandParams); commandParamsWriter.Write(arrayId); commandParamsWriter.Write(0); - commandParamsWriter.Write(length); + commandParamsWriter.Write(dimensions.TotalLength); var retDebuggerCmdReader = await SendDebuggerAgentCommand(sessionId, CmdArray.GetValues, commandParams, token); JArray array = new JArray(); - for (int i = 0 ; i < length ; i++) + for (int i = 0 ; i < dimensions.TotalLength; i++) { - var var_json = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, i.ToString(), false, -1, false, token); + var var_json = await CreateJObjectForVariableValue(sessionId, retDebuggerCmdReader, dimensions.GetArrayIndexString(i), isOwn : false, -1, forDebuggerDisplayAttribute : false, token); array.Add(var_json); } return array; } + + public async Task GetArrayValuesProxy(SessionId sessionId, int arrayId, CancellationToken token) + { + var length = await GetArrayDimensions(sessionId, arrayId, token); + var arrayProxy = JObject.FromObject(new + { + items = await GetArrayValues(sessionId, arrayId, token), + dimensionsDetails = length.Bounds + }); + return arrayProxy; + } + public async Task EnableExceptions(SessionId sessionId, PauseOnExceptionsKind state, CancellationToken token) { if (state == PauseOnExceptionsKind.Unset) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs index 7f685734cd9b9..3d7cdf93ae541 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/ArrayTests.cs @@ -198,6 +198,24 @@ public async Task InspectGenericValueTypeArrayLocals2(int line, int col, string frame_idx: frame_idx, use_cfo: use_cfo); + async Task GetObjectWithCFO(string objectId, JObject fn_args = null) + { + var fn_decl = "function () { return this; }"; + var cfo_args = JObject.FromObject(new + { + functionDeclaration = fn_decl, + objectId = objectId + }); + + if (fn_args != null) + cfo_args["arguments"] = fn_args; + + // callFunctionOn + var result = await cli.SendCommand("Runtime.callFunctionOn", cfo_args, token); + + return await GetProperties(result.Value["result"]["objectId"]?.Value(), fn_args); + } + async Task TestSimpleArrayLocals(int line, int col, string entry_method_name, string method_name, string etype_name, string local_var_name_prefix, object[] array, object[] array_elem_props, bool test_prev_frame = false, int frame_idx = 0, bool use_cfo = false) @@ -215,8 +233,8 @@ async Task TestSimpleArrayLocals(int line, int col, string entry_method_name, st var locals = await GetProperties(pause_location["callFrames"][frame_idx]["callFrameId"].Value()); Assert.Equal(4, locals.Count()); - CheckArray(locals, $"{local_var_name_prefix}_arr", $"{etype_name}[]", array?.Length ?? 0); - CheckArray(locals, $"{local_var_name_prefix}_arr_empty", $"{etype_name}[]", 0); + CheckArray(locals, $"{local_var_name_prefix}_arr", $"{etype_name}[]", $"{etype_name}[{array?.Length ?? 0}]"); + CheckArray(locals, $"{local_var_name_prefix}_arr_empty", $"{etype_name}[]", $"{etype_name}[0]"); CheckObject(locals, $"{local_var_name_prefix}_arr_null", $"{etype_name}[]", is_null: true); CheckBool(locals, "call_other", test_prev_frame); @@ -264,24 +282,6 @@ async Task TestSimpleArrayLocals(int line, int col, string entry_method_name, st var props = await GetObjectOnFrame(pause_location["callFrames"][frame_idx], $"{local_var_name_prefix}_arr_empty"); await CheckProps(props, new object[0], "${local_var_name_prefix}_arr_empty"); - - async Task GetObjectWithCFO(string objectId, JObject fn_args = null) - { - var fn_decl = "function () { return this; }"; - var cfo_args = JObject.FromObject(new - { - functionDeclaration = fn_decl, - objectId = objectId - }); - - if (fn_args != null) - cfo_args["arguments"] = fn_args; - - // callFunctionOn - var result = await cli.SendCommand("Runtime.callFunctionOn", cfo_args, token); - - return await GetProperties(result.Value["result"]["objectId"]?.Value(), fn_args); - } } [Theory] @@ -313,10 +313,10 @@ public async Task InspectObjectArrayMembers(bool use_cfo) await CheckProps(c_props, new { id = TString("c#id"), - ClassArrayProperty = TArray("DebuggerTests.SimpleClass[]", 3), - ClassArrayField = TArray("DebuggerTests.SimpleClass[]", 3), - PointsProperty = TArray("DebuggerTests.Point[]", 2), - PointsField = TArray("DebuggerTests.Point[]", 2) + ClassArrayProperty = TArray("DebuggerTests.SimpleClass[]", "DebuggerTests.SimpleClass[3]"), + ClassArrayField = TArray("DebuggerTests.SimpleClass[]", "DebuggerTests.SimpleClass[3]"), + PointsProperty = TArray("DebuggerTests.Point[]", "DebuggerTests.Point[2]"), + PointsField = TArray("DebuggerTests.Point[]", "DebuggerTests.Point[2]") }, "c" ); @@ -382,8 +382,8 @@ public async Task InspectValueTypeArrayLocalsStaticAsync(bool use_cfo) await CheckProps(frame_locals, new { call_other = TBool(false), - gvclass_arr = TArray("DebuggerTests.SimpleGenericStruct[]", 2), - gvclass_arr_empty = TArray("DebuggerTests.SimpleGenericStruct[]"), + gvclass_arr = TArray("DebuggerTests.SimpleGenericStruct[]", "DebuggerTests.SimpleGenericStruct[2]"), + gvclass_arr_empty = TArray("DebuggerTests.SimpleGenericStruct[]", "DebuggerTests.SimpleGenericStruct[0]"), gvclass_arr_null = TObject("DebuggerTests.SimpleGenericStruct[]", is_null: true), gvclass = TValueType("DebuggerTests.SimpleGenericStruct"), // BUG: this shouldn't be null! @@ -448,7 +448,7 @@ public async Task InspectValueTypeArrayLocalsInstanceAsync(bool use_cfo) { t1 = TObject("DebuggerTests.SimpleGenericStruct"), @this = TObject("DebuggerTests.ArrayTestsClass"), - point_arr = TArray("DebuggerTests.Point[]", 2), + point_arr = TArray("DebuggerTests.Point[]", "DebuggerTests.Point[2]"), point = TValueType("DebuggerTests.Point") }, "InspectValueTypeArrayLocalsInstanceAsync#locals"); @@ -642,6 +642,59 @@ public async Task InvalidAccessors() => await CheckInspectLocalsAtBreakpointSite AssertEqual("undefined", res.Value["result"]?["type"]?.ToString(), "Expected to get undefined result for non-existant accessor"); } }); + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task InspectPrimitiveTypeMultiArrayLocals(bool use_cfo) + { + var debugger_test_loc = "dotnet://debugger-test.dll/debugger-array-test.cs"; + + var eval_expr = "window.setTimeout(function() { invoke_static_method (" + + $"'[debugger-test] DebuggerTests.MultiDimensionalArray:run'" + + "); }, 1);"; + var pause_location = await EvaluateAndCheck(eval_expr, debugger_test_loc, 343, 12, "run"); + + var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + Assert.Equal(3, locals.Count()); + var int_arr_1 = !use_cfo ? + await GetProperties(locals[0]["value"]["objectId"].Value()) : + await GetObjectWithCFO((locals[0]["value"]["objectId"].Value())); + + CheckNumber(int_arr_1, "0", 0); + CheckNumber(int_arr_1, "1", 1); + var int_arr_2 = !use_cfo ? + await GetProperties(locals[1]["value"]["objectId"].Value()) : + await GetObjectWithCFO((locals[1]["value"]["objectId"].Value())); + CheckNumber(int_arr_2, "0, 0", 0); + CheckNumber(int_arr_2, "0, 1", 1); + CheckNumber(int_arr_2, "0, 2", 2); + CheckNumber(int_arr_2, "1, 0", 10); + CheckNumber(int_arr_2, "1, 1", 11); + CheckNumber(int_arr_2, "1, 2", 12); + + var int_arr_3 = !use_cfo ? + await GetProperties(locals[2]["value"]["objectId"].Value()) : + await GetObjectWithCFO((locals[2]["value"]["objectId"].Value())); + CheckNumber(int_arr_3, "0, 0, 0", 0); + CheckNumber(int_arr_3, "0, 0, 1", 1); + CheckNumber(int_arr_3, "0, 0, 2", 2); + CheckNumber(int_arr_3, "0, 1, 0", 10); + CheckNumber(int_arr_3, "0, 1, 1", 11); + CheckNumber(int_arr_3, "0, 1, 2", 12); + CheckNumber(int_arr_3, "0, 2, 0", 20); + CheckNumber(int_arr_3, "0, 2, 1", 21); + CheckNumber(int_arr_3, "0, 2, 2", 22); + CheckNumber(int_arr_3, "1, 0, 0", 100); + CheckNumber(int_arr_3, "1, 0, 1", 101); + CheckNumber(int_arr_3, "1, 0, 2", 102); + CheckNumber(int_arr_3, "1, 1, 0", 110); + CheckNumber(int_arr_3, "1, 1, 1", 111); + CheckNumber(int_arr_3, "1, 1, 2", 112); + CheckNumber(int_arr_3, "1, 2, 0", 120); + CheckNumber(int_arr_3, "1, 2, 1", 121); + CheckNumber(int_arr_3, "1, 2, 2", 122); + } } } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/AssignmentTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/AssignmentTests.cs index 1afa97939d5ef..0601552db6b60 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/AssignmentTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/AssignmentTests.cs @@ -19,7 +19,7 @@ public class AssignmentTests : DebuggerTestBase { "MONO_TYPE_CHAR", TSymbol("0 '\u0000'"), TSymbol("97 'a'") }, { "MONO_TYPE_STRING", TString(default), TString("hello") }, { "MONO_TYPE_ENUM", TEnum("DebuggerTests.RGB", "Red"), TEnum("DebuggerTests.RGB", "Blue") }, - { "MONO_TYPE_ARRAY", TObject("byte[]", is_null: true), TArray("byte[]", 2) }, + { "MONO_TYPE_ARRAY", TObject("byte[]", is_null: true), TArray("byte[]", "byte[2]") }, { "MONO_TYPE_VALUETYPE", TValueType("DebuggerTests.Point"), TValueType("DebuggerTests.Point") }, { "MONO_TYPE_VALUETYPE2", TValueType("System.Decimal","0"), TValueType("System.Decimal", "1.1") }, { "MONO_TYPE_GENERICINST", TObject("System.Func", is_null: true), TDelegate("System.Func", "int Prepare ()") }, diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/CallFunctionOnTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/CallFunctionOnTests.cs index d1e3a6511dd93..92e36a3bdca1e 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/CallFunctionOnTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/CallFunctionOnTests.cs @@ -361,7 +361,7 @@ public async Task RunOnJSObject(bool roundtrip) => await RunCallFunctionOn( await CheckProps(obj_own_val, new { a_obj = TObject("Object"), - b_arr = TArray("Array", 2) + b_arr = TArray("Array", "Array(2)") }, "obj_own"); }); @@ -641,7 +641,7 @@ public async Task PropertyGettersTest(string eval_fn, string method_name, int li // Check arrays through getters res = await InvokeGetter(obj, get_args_fn(new[] { "IntArray" }), cfo_fn); - await CheckValue(res.Value["result"], TArray("int[]", 2), $"{local_name}.IntArray"); + await CheckValue(res.Value["result"], TArray("int[]", "int[2]"), $"{local_name}.IntArray"); { var arr_elems = await GetProperties(res.Value["result"]?["objectId"]?.Value()); var exp_elems = new[] @@ -654,7 +654,7 @@ public async Task PropertyGettersTest(string eval_fn, string method_name, int li } res = await InvokeGetter(obj, get_args_fn(new[] { "DTArray" }), cfo_fn); - await CheckValue(res.Value["result"], TArray("System.DateTime[]", 2), $"{local_name}.DTArray"); + await CheckValue(res.Value["result"], TArray("System.DateTime[]", "System.DateTime[2]"), $"{local_name}.DTArray"); { var dt0 = new DateTime(6, 7, 8, 9, 10, 11); var dt1 = new DateTime(1, 2, 3, 4, 5, 6); @@ -944,7 +944,7 @@ async Task CheckCFOResult(Result result) if (res_array_len < 0) await CheckValue(result.Value["result"], TObject("Object"), $"cfo-res"); else - await CheckValue(result.Value["result"], TArray("Array", res_array_len), $"cfo-res"); + await CheckValue(result.Value["result"], TArray("Array", $"Array({res_array_len})"), $"cfo-res"); } } } diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs index 52087e598624f..06516155b7d39 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs @@ -51,7 +51,7 @@ public async Task UsingDebuggerTypeProxy() var props = await GetObjectOnFrame(frame, "myList"); Assert.Equal(1, props.Count()); - CheckArray(props, "Items", "int[]", 4); + CheckArray(props, "Items", "int[]", "int[4]"); CheckObject(locals, "b", "DebuggerTests.WithProxy", description:"DebuggerTests.WithProxy"); props = await GetObjectOnFrame(frame, "b"); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs index bd92af72637ad..c908343d9ef82 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DebuggerTestBase.cs @@ -357,10 +357,10 @@ internal JToken CheckEnum(JToken locals, string name, string class_name, string return l; } - internal void CheckArray(JToken locals, string name, string class_name, int length) + internal void CheckArray(JToken locals, string name, string class_name, string description) => CheckValue( GetAndAssertObjectWithName(locals, name)["value"], - TArray(class_name, length), name).Wait(); + TArray(class_name, description), name).Wait(); internal JToken GetAndAssertObjectWithName(JToken obj, string name, string label = "") { @@ -979,7 +979,7 @@ internal static JObject TObject(string className, string description = null, boo JObject.FromObject(new { type = "object", className = className, description = description ?? className, subtype = is_null ? "null" : null }) : JObject.FromObject(new { type = "object", className = className, description = description ?? className }); - internal static JObject TArray(string className, int length = 0) => JObject.FromObject(new { type = "object", className = className, description = $"{className}({length})", subtype = "array" }); + internal static JObject TArray(string className, string description) => JObject.FromObject(new { type = "object", className, description, subtype = "array" }); internal static JObject TBool(bool value) => JObject.FromObject(new { type = "boolean", value = @value, description = @value ? "true" : "false" }); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DelegateTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DelegateTests.cs index 2fc0fb52ce99f..cdbee2079e72a 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DelegateTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DelegateTests.cs @@ -32,19 +32,19 @@ await CheckInspectLocalsAtBreakpointSite( { fn_func = TDelegate("System.Func", "bool |(Math)"), fn_func_null = TObject("System.Func", is_null: true), - fn_func_arr = TArray("System.Func[]", 1), + fn_func_arr = TArray("System.Func[]", "System.Func[1]"), fn_del = TDelegate("Math.IsMathNull", "bool IsMathNullDelegateTarget (Math)"), fn_del_null = TObject("Math.IsMathNull", is_null: true), - fn_del_arr = TArray("Math.IsMathNull[]", 1), + fn_del_arr = TArray("Math.IsMathNull[]", "Math.IsMathNull[1]"), // Unused locals fn_func_unused = TDelegate("System.Func", "bool |(Math)"), fn_func_null_unused = TObject("System.Func", is_null: true), - fn_func_arr_unused = TArray("System.Func[]", 1), + fn_func_arr_unused = TArray("System.Func[]", "System.Func[1]"), fn_del_unused = TDelegate("Math.IsMathNull", "bool IsMathNullDelegateTarget (Math)"), fn_del_null_unused = TObject("Math.IsMathNull", is_null: true), - fn_del_arr_unused = TArray("Math.IsMathNull[]", 1), + fn_del_arr_unused = TArray("Math.IsMathNull[]", "Math.IsMathNull[1]"), res = TBool(false), m_obj = TObject("Math") @@ -105,7 +105,7 @@ public async Task InspectDelegateSignaturesWithFunc(int frame, int line, int col fn_func_null = TObject("System.Func>, Math.GenericStruct>", is_null: true), fn_func_only_ret = TDelegate("System.Func", "bool |()"), - fn_func_arr = TArray("System.Func>, Math.GenericStruct>[]", 1), + fn_func_arr = TArray("System.Func>, Math.GenericStruct>[]", "System.Func>, Math.GenericStruct>[1]"), fn_del = TDelegate("Math.DelegateForSignatureTest", "Math.GenericStruct DelegateTargetForSignatureTest (Math,Math.GenericStruct>)"), @@ -114,16 +114,16 @@ public async Task InspectDelegateSignaturesWithFunc(int frame, int line, int col "Math.GenericStruct |(Math,Math.GenericStruct>)"), fn_del_null = TObject("Math.DelegateForSignatureTest", is_null: true), - fn_del_arr = TArray("Math.DelegateForSignatureTest[]", 2), + fn_del_arr = TArray("Math.DelegateForSignatureTest[]", "Math.DelegateForSignatureTest[2]"), m_obj = TObject("Math"), gs_gs = TValueType("Math.GenericStruct>"), fn_void_del = TDelegate("Math.DelegateWithVoidReturn", "void DelegateTargetWithVoidReturn (Math.GenericStruct)"), - fn_void_del_arr = TArray("Math.DelegateWithVoidReturn[]", 1), + fn_void_del_arr = TArray("Math.DelegateWithVoidReturn[]", "Math.DelegateWithVoidReturn[1]"), fn_void_del_null = TObject("Math.DelegateWithVoidReturn", is_null: true), gs = TValueType("Math.GenericStruct"), - rets = TArray("Math.GenericStruct[]", 6) + rets = TArray("Math.GenericStruct[]", "Math.GenericStruct[6]") }, "locals"); await CompareObjectPropertiesFor(locals, "fn_func_arr", new[] @@ -176,7 +176,7 @@ public async Task ActionTSignatureTest(int frame, int line, int col, string bp_m fn_action_null = TObject("System.Action>", is_null: true), - fn_action_arr = TArray("System.Action>[]", 3), + fn_action_arr = TArray("System.Action>[]", "System.Action>[3]"), gs = TValueType("Math.GenericStruct"), }, "locals"); @@ -212,8 +212,8 @@ public async Task NestedDelegatesTest(int frame, int line, int col, string bp_me fn_func = TDelegate("System.Func, bool>", "bool |(Func)"), fn_func_null = TObject("System.Func, bool>", is_null: true), - fn_func_arr = TArray("System.Func, bool>[]", 1), - fn_del_arr = TArray("System.Func, bool>[]", 1), + fn_func_arr = TArray("System.Func, bool>[]", "System.Func, bool>[1]"), + fn_del_arr = TArray("System.Func, bool>[]", "System.Func, bool>[1]"), m_obj = TObject("Math"), fn_del_null = TObject("System.Func, bool>", is_null: true), @@ -253,7 +253,7 @@ public async Task DelegatesAsMethodArgsTest(int frame, int line, int col, string await CheckProps(locals, new { @this = TObject("Math"), - dst_arr = TArray("Math.DelegateForSignatureTest[]", 2), + dst_arr = TArray("Math.DelegateForSignatureTest[]", "Math.DelegateForSignatureTest[2]"), fn_func = TDelegate("System.Func", "bool |(char[])"), fn_action = TDelegate("System.Action[]>", @@ -284,7 +284,7 @@ public async Task MethodWithDelegatesAsyncTest(bool use_cfo) => await CheckInspe await CheckProps(locals, new { @this = TObject("Math"), - _dst_arr = TArray("Math.DelegateForSignatureTest[]", 2), + _dst_arr = TArray("Math.DelegateForSignatureTest[]", "Math.DelegateForSignatureTest[2]"), _fn_func = TDelegate("System.Func", "bool |(char[])"), _fn_action = TDelegate("System.Action[]>", diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/PointerTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/PointerTests.cs index ee703b29648bb..891eea7352c8a 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/PointerTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/PointerTests.cs @@ -81,7 +81,7 @@ public async Task InspectLocalPointerArrays(string eval_fn, string type, string var dt = new DateTime(5, 6, 7, 8, 9, 10); await CheckProps(locals, new { - ipa = TArray("int*[]", 3) + ipa = TArray("int*[]", "int*[3]") }, "locals", num_fields: 26); var ipa_elems = await CompareObjectPropertiesFor(locals, "ipa", new[] @@ -112,7 +112,7 @@ public async Task InspectLocalDoublePointerToPrimitiveTypeArrays(string eval_fn, var dt = new DateTime(5, 6, 7, 8, 9, 10); await CheckProps(locals, new { - ippa = TArray("int**[]", 5) + ippa = TArray("int**[]", "int**[5]") }, "locals", num_fields: 26); var ippa_elems = await CompareObjectPropertiesFor(locals, "ippa", new[] @@ -223,7 +223,7 @@ public async Task InspectLocalPointersToValueTypeArrays(string eval_fn, string t var dt = new DateTime(5, 6, 7, 8, 9, 10); await CheckProps(locals, new { - dtpa = TArray("System.DateTime*[]", 2) + dtpa = TArray("System.DateTime*[]", "System.DateTime*[2]") }, "locals", num_fields: 26); // dtpa @@ -256,7 +256,7 @@ public async Task InspectLocalPointersToGenericValueTypeArrays(string eval_fn, s var dt = new DateTime(5, 6, 7, 8, 9, 10); await CheckProps(locals, new { - gspa = TArray("DebuggerTests.GenericStructWithUnmanagedT*[]", 3), + gspa = TArray("DebuggerTests.GenericStructWithUnmanagedT*[]", "DebuggerTests.GenericStructWithUnmanagedT*[3]"), }, "locals", num_fields: 26); // dtpa @@ -323,7 +323,7 @@ public async Task InspectLocalDoublePointersToValueTypeArrays(string eval_fn, st var dt = new DateTime(5, 6, 7, 8, 9, 10); await CheckProps(locals, new { - dtppa = TArray("System.DateTime**[]", 3), + dtppa = TArray("System.DateTime**[]", "System.DateTime**[3]"), }, "locals", num_fields: 26); // DateTime**[] dtppa = new DateTime**[] { &dtp, &dtp_null, null }; @@ -395,8 +395,8 @@ public async Task InspectPrimitiveTypePointersAsMethodArgs(string eval_fn, strin { ip = TPointer("int*"), ipp = TPointer("int**"), - ipa = TArray("int*[]", 3), - ippa = TArray("int**[]", 5) + ipa = TArray("int*[]", "int*[3]"), + ippa = TArray("int**[]", "int**[5]") }, "locals", num_fields: 8); // ip @@ -468,8 +468,8 @@ public async Task InspectValueTypePointersAsMethodArgs(string eval_fn, string ty { dtp = TPointer("System.DateTime*"), dtpp = TPointer("System.DateTime**"), - dtpa = TArray("System.DateTime*[]", 2), - dtppa = TArray("System.DateTime**[]", 3) + dtpa = TArray("System.DateTime*[]", "System.DateTime*[2]"), + dtppa = TArray("System.DateTime**[]", "System.DateTime**[3]") }, "locals", num_fields: 8); // *dtp diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs index de1bd7a829b2a..e1a4a46fd83ea 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/SteppingTests.cs @@ -354,7 +354,7 @@ public async Task InspectLocalsInAsyncMethods(bool use_cfo) CheckObject(locals, "this", "Math.NestedInMath"); //FIXME: check fields CheckValueType(locals, "ss", "Math.SimpleStruct"); - CheckArray(locals, "ss_arr", "Math.SimpleStruct[]", 0); + CheckArray(locals, "ss_arr", "Math.SimpleStruct[]", "Math.SimpleStruct[0]"); // TODO: struct fields } ); @@ -584,7 +584,7 @@ async Task CheckArrayElements(JToken pause_location, DateTime dt) var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); await CheckProps(locals, new { - ssta = TArray("DebuggerTests.StructForToStringTests[]", 1) + ssta = TArray("DebuggerTests.StructForToStringTests[]", "DebuggerTests.StructForToStringTests[1]") }, "locals"); var ssta = await GetObjectOnLocals(locals, "ssta"); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs index d5e47384796d2..d6b260375c1f0 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs @@ -140,7 +140,7 @@ await CheckInspectLocalsAtBreakpointSite( str_spaces, str_esc, - strings = TArray("string[]", 4) + strings = TArray("string[]", "string[4]") }, "locals"); var strings_arr = await GetObjectOnLocals(locals, "strings"); @@ -204,14 +204,14 @@ await CheckInspectLocalsAtBreakpointSite( CheckObject(locals, "list", "System.Collections.Generic.Dictionary", description: "Count = 0"); CheckObject(locals, "list_null", "System.Collections.Generic.Dictionary", is_null: true); - CheckArray(locals, "list_arr", "System.Collections.Generic.Dictionary[]", 1); + CheckArray(locals, "list_arr", "System.Collections.Generic.Dictionary[]", "System.Collections.Generic.Dictionary[1]"); CheckObject(locals, "list_arr_null", "System.Collections.Generic.Dictionary[]", is_null: true); // Unused locals CheckObject(locals, "list_unused", "System.Collections.Generic.Dictionary", description: "Count = 0"); CheckObject(locals, "list_null_unused", "System.Collections.Generic.Dictionary", is_null: true); - CheckArray(locals, "list_arr_unused", "System.Collections.Generic.Dictionary[]", 1); + CheckArray(locals, "list_arr_unused", "System.Collections.Generic.Dictionary[]", "System.Collections.Generic.Dictionary[1]"); CheckObject(locals, "list_arr_null_unused", "System.Collections.Generic.Dictionary[]", is_null: true); } ); @@ -367,7 +367,7 @@ public async Task InspectBoxedLocals(string method_name, bool is_async) => await o_n_dt = TDateTime(dt), o_null = TObject("object", is_null: true), - o_ia = TArray("int[]", 2), + o_ia = TArray("int[]", "int[2]"), }, "locals"); foreach (var name in new[] { "n_gs", "o_gs", "o_n_gs" }) @@ -541,7 +541,7 @@ public async Task InspectLocalsForToStringDescriptions(int line, int col, string ts = TValueType("System.TimeSpan", ts.ToString()), dec = TValueType("System.Decimal", "123987123"), guid = TValueType("System.Guid", "3D36E07E-AC90-48C6-B7EC-A481E289D014"), - dts = TArray("System.DateTime[]", 2), + dts = TArray("System.DateTime[]", "System.DateTime[2]"), obj = TObject("DebuggerTests.ClassForToStringTests"), sst = TObject("DebuggerTests.StructForToStringTests") }, "locals#0"); @@ -712,7 +712,7 @@ public async Task PreviousFrameForAReflectedCall() => await CheckInspectLocalsAt mi = TObject("System.Reflection.RuntimeMethodInfo"), //this is what is returned when debugging desktop apps using VS dt = TDateTime(new DateTime(4210, 3, 4, 5, 6, 7)), i = TNumber(4), - strings = TArray("string[]", 1), + strings = TArray("string[]", "string[1]"), cs = TValueType("DebuggerTests.GetPropertiesTests.CloneableStruct"), num = TNumber(10), diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-array-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-array-test.cs index 26acccf68dc76..f1a2b41bd18a4 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-array-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-array-test.cs @@ -305,4 +305,44 @@ public static void run() new Point { X = 90, Y = -4, Id = "point#Id", Color = RGB.Green }.GenericInstanceMethod(sc); } } + public class MultiDimensionalArray + { + public static void run() + { + var int_arr_1 = new int[2]; + int_arr_1[0] = 0; + int_arr_1[1] = 1; + + var int_arr_2 = new int[2, 3]; + int_arr_2[0, 0] = 0; + int_arr_2[0, 1] = 1; + int_arr_2[0, 2] = 2; + int_arr_2[1, 0] = 10; + int_arr_2[1, 1] = 11; + int_arr_2[1, 2] = 12; + + var int_arr_3 = new int[2, 3, 3]; + int_arr_3[0, 0, 0] = 0; + int_arr_3[0, 0, 1] = 1; + int_arr_3[0, 0, 2] = 2; + int_arr_3[0, 1, 0] = 10; + int_arr_3[0, 1, 1] = 11; + int_arr_3[0, 1, 2] = 12; + int_arr_3[0, 2, 0] = 20; + int_arr_3[0, 2, 1] = 21; + int_arr_3[0, 2, 2] = 22; + int_arr_3[1, 0, 0] = 100; + int_arr_3[1, 0, 1] = 101; + int_arr_3[1, 0, 2] = 102; + int_arr_3[1, 1, 0] = 110; + int_arr_3[1, 1, 1] = 111; + int_arr_3[1, 1, 2] = 112; + int_arr_3[1, 2, 0] = 120; + int_arr_3[1, 2, 1] = 121; + int_arr_3[1, 2, 2] = 122; + + System.Diagnostics.Debugger.Break(); + Console.WriteLine($"int_arr: {int_arr_3.Length}"); + } + } } diff --git a/src/mono/wasm/runtime/debug.ts b/src/mono/wasm/runtime/debug.ts index b55aad2f017f6..a7932ebf728cc 100644 --- a/src/mono/wasm/runtime/debug.ts +++ b/src/mono/wasm/runtime/debug.ts @@ -118,8 +118,12 @@ export function mono_wasm_get_loaded_files(): string[] { function _create_proxy_from_object_id(objectId: string, details: any) { if (objectId.startsWith("dotnet:array:")) { - const ret = details.map((p: any) => p.value); - return ret; + let ret : Array; + if (details.dimensionsDetails == undefined || details.dimensionsDetails.length == 1) + { + ret = details.items.map((p: any) => p.value); + return ret; + } } const proxy: any = {};