From 8ae89b2c7473ba8f2397b9874264a6a4059e78d2 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Sat, 29 Aug 2020 18:26:23 -0400 Subject: [PATCH 1/6] [wasm][debugger] Add support for Nullable Return the value, or null. Fixes https://github.com/mono/mono/issues/20310 --- src/mono/mono/mini/mini-wasm-debugger.c | 53 +++++++++++++++++++ .../wasm/debugger/DebuggerTestSuite/Tests.cs | 37 +++++++++++++ .../debugger/tests/debugger-nullable-test.cs | 40 ++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 src/mono/wasm/debugger/tests/debugger-nullable-test.cs diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 3c60fcdd6cd8cb..08e2f505edf1b3 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -829,6 +829,42 @@ read_enum_value (const char *mem, int type) return 0; } +static MonoClassField* +nullable_class_get_value_field (MonoClass *klass) +{ + mono_class_setup_fields (klass); + g_assert (m_class_is_fields_inited (klass)); + + MonoClassField *klass_fields = m_class_get_fields (klass); + return &klass_fields [1]; +} + +static MonoClassField* +nullable_class_get_has_value_field (MonoClass *klass) +{ + mono_class_setup_fields (klass); + g_assert (m_class_is_fields_inited (klass)); + + MonoClassField *klass_fields = m_class_get_fields (klass); + return &klass_fields [0]; +} + +static gpointer +nullable_get_has_value_field_addr (guint8 *nullable, MonoClass *klass) +{ + MonoClassField *has_value_field = nullable_class_get_has_value_field (klass); + + return mono_vtype_get_field_addr (nullable, has_value_field); +} + +static gpointer +nullable_get_value_field_addr (guint8 *nullable, MonoClass *klass) +{ + MonoClassField *has_value_field = nullable_class_get_value_field (klass); + + return mono_vtype_get_field_addr (nullable, has_value_field); +} + static gboolean describe_value(MonoType * type, gpointer addr, int gpflags) { @@ -900,6 +936,23 @@ describe_value(MonoType * type, gpointer addr, int gpflags) break; } case MONO_TYPE_GENERICINST: { + MonoClass *klass = mono_class_from_mono_type_internal (type); + if (mono_class_is_nullable (klass)) { + MonoType *targ = type->data.generic_class->context.class_inst->type_argv [0]; + + gpointer has_value_addr = nullable_get_has_value_field_addr (addr, klass); + gboolean has_value = *(guint8*)has_value_addr; + if (!has_value) { + char* class_name = mono_type_full_name (type); + mono_wasm_add_obj_var (class_name, NULL, 0); + g_free (class_name); + break; + } else { + gpointer value_addr = nullable_get_value_field_addr(addr, klass); + return describe_value(targ, value_addr, gpflags); + } + } + if (mono_type_generic_inst_is_valuetype (type)) goto handle_vtype; /* diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs index 958b1761a56861..72a2ea48b06738 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs @@ -394,6 +394,43 @@ await CheckProps(strings_arr, new[] } ); + [Theory] + [InlineData("TestNullableLocal", false)] + [InlineData("TestNullableLocalAsync", true)] + public async Task InspectNullableLocals(string method_name, bool is_async) => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTests.NullableTests", + method_name, + 10, + is_async ? "MoveNext" : method_name, + $"window.setTimeout(function() {{ invoke_static_method_async('[debugger-test] DebuggerTests.NullableTests:{method_name}'); }}, 1);", + wait_for_event_fn: async (pause_location) => + { + var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + var dt = new DateTime(2310, 1, 2, 3, 4, 5); + await CheckProps(locals, new + { + n_int = TNumber(5), + n_int_null = TObject("System.Nullable", null), + + n_dt = TDateTime(dt), + n_dt_null = TObject("System.Nullable", null), + + n_gs = TValueType("DebuggerTests.ValueTypesTest.GenericStruct"), + n_gs_null = TObject("System.Nullable>", null), + }, "locals"); + + // check gs + + var n_gs = GetAndAssertObjectWithName(locals, "n_gs"); + var n_gs_props = await GetProperties(n_gs["value"]?["objectId"]?.Value ()); + await CheckProps(n_gs_props, new + { + List = TObject("System.Collections.Generic.List", is_null: true), + StringField = TString("n_gs#StringField"), + Options = TEnum ("DebuggerTests.Options", "None") + }, nameof(n_gs)); + }); + [Theory] [InlineData(false)] [InlineData(true)] diff --git a/src/mono/wasm/debugger/tests/debugger-nullable-test.cs b/src/mono/wasm/debugger/tests/debugger-nullable-test.cs new file mode 100644 index 00000000000000..435da2faed5271 --- /dev/null +++ b/src/mono/wasm/debugger/tests/debugger-nullable-test.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +#nullable enable + +namespace DebuggerTests +{ + public class NullableTests + { + public static void TestNullableLocal () + { + int? n_int = 5; + int? n_int_null = null; + + DateTime? n_dt = new DateTime(2310, 1, 2, 3, 4, 5); + DateTime? n_dt_null = null; + + ValueTypesTest.GenericStruct? n_gs = new ValueTypesTest.GenericStruct { StringField = "n_gs#StringField" }; + ValueTypesTest.GenericStruct? n_gs_null = null; + + Console.WriteLine ($"break here"); + } + + public static async Task TestNullableLocalAsync () + { + int? n_int = 5; + int? n_int_null = null; + + DateTime? n_dt = new DateTime(2310, 1, 2, 3, 4, 5); + DateTime? n_dt_null = null; + + ValueTypesTest.GenericStruct? n_gs = new ValueTypesTest.GenericStruct { StringField = "n_gs#StringField" }; + ValueTypesTest.GenericStruct? n_gs_null = null; + + Console.WriteLine ($"break here"); + await Task.CompletedTask; + } + } +} From b2e435d580e263d88ccc36423866417f54677957 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Fri, 4 Sep 2020 13:26:52 -0400 Subject: [PATCH 2/6] Address review feedback - merge functions --- src/mono/mono/mini/mini-wasm-debugger.c | 30 ++++++------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 08e2f505edf1b3..fd53ab1f1fea00 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -829,40 +829,24 @@ read_enum_value (const char *mem, int type) return 0; } -static MonoClassField* -nullable_class_get_value_field (MonoClass *klass) +static gpointer +nullable_get_has_value_field_addr (guint8 *nullable, MonoClass *klass) { mono_class_setup_fields (klass); g_assert (m_class_is_fields_inited (klass)); MonoClassField *klass_fields = m_class_get_fields (klass); - return &klass_fields [1]; + return mono_vtype_get_field_addr (nullable, &klass_fields[0]); } -static MonoClassField* -nullable_class_get_has_value_field (MonoClass *klass) +static gpointer +nullable_get_value_field_addr (guint8 *nullable, MonoClass *klass) { mono_class_setup_fields (klass); g_assert (m_class_is_fields_inited (klass)); MonoClassField *klass_fields = m_class_get_fields (klass); - return &klass_fields [0]; -} - -static gpointer -nullable_get_has_value_field_addr (guint8 *nullable, MonoClass *klass) -{ - MonoClassField *has_value_field = nullable_class_get_has_value_field (klass); - - return mono_vtype_get_field_addr (nullable, has_value_field); -} - -static gpointer -nullable_get_value_field_addr (guint8 *nullable, MonoClass *klass) -{ - MonoClassField *has_value_field = nullable_class_get_value_field (klass); - - return mono_vtype_get_field_addr (nullable, has_value_field); + return mono_vtype_get_field_addr (nullable, &klass_fields[1]); } static gboolean @@ -948,7 +932,7 @@ describe_value(MonoType * type, gpointer addr, int gpflags) g_free (class_name); break; } else { - gpointer value_addr = nullable_get_value_field_addr(addr, klass); + gpointer value_addr = nullable_get_value_field_addr (addr, klass); return describe_value(targ, value_addr, gpflags); } } From 254037b84ff02f109eaa2b96f75d284c7ba5e41a Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Fri, 4 Sep 2020 13:27:25 -0400 Subject: [PATCH 3/6] [wasm][debugger] run dotnet-format on the debugger test app --- .../tests/debugger-get-properties-test.cs | 24 +++++++++---------- .../debugger/tests/debugger-nullable-test.cs | 8 +++---- src/mono/wasm/debugger/tests/debugger-test.cs | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/mono/wasm/debugger/tests/debugger-get-properties-test.cs b/src/mono/wasm/debugger/tests/debugger-get-properties-test.cs index 60e2d485becd44..fd3e827ac5d59f 100644 --- a/src/mono/wasm/debugger/tests/debugger-get-properties-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-get-properties-test.cs @@ -17,7 +17,7 @@ public interface ILastName } public interface IName : IFirstName, ILastName - {} + { } public class BaseBaseClass { @@ -91,20 +91,20 @@ public DerivedClass() public static void run() { - new DerivedClass().InstanceMethod (); - new DerivedClass().InstanceMethodAsync ().Wait(); + new DerivedClass().InstanceMethod(); + new DerivedClass().InstanceMethodAsync().Wait(); } public string GetStringField() => _stringField; public void InstanceMethod() { - Console.WriteLine ($"break here"); + Console.WriteLine($"break here"); } public async Task InstanceMethodAsync() { - Console.WriteLine ($"break here"); + Console.WriteLine($"break here"); await Task.CompletedTask; } } @@ -138,20 +138,20 @@ public CloneableStruct(int bias) public static void run() { - new CloneableStruct(3).InstanceMethod (); - new CloneableStruct(3).InstanceMethodAsync ().Wait(); + new CloneableStruct(3).InstanceMethod(); + new CloneableStruct(3).InstanceMethodAsync().Wait(); } public string GetStringField() => _stringField; public void InstanceMethod() { - Console.WriteLine ($"break here"); + Console.WriteLine($"break here"); } public async Task InstanceMethodAsync() { - Console.WriteLine ($"break here"); + Console.WriteLine($"break here"); await Task.CompletedTask; } } @@ -174,13 +174,13 @@ public static void run() public static void TestNestedStructStatic() { var ns = new NestedStruct(3); - Console.WriteLine ($"break here"); + Console.WriteLine($"break here"); } public static async Task TestNestedStructStaticAsync() { var ns = new NestedStruct(3); - Console.WriteLine ($"break here"); + Console.WriteLine($"break here"); await Task.CompletedTask; } } @@ -200,7 +200,7 @@ class DerivedClassForJSTest : BaseClassForJSTest public static void run() { var obj = new DerivedClassForJSTest(); - Console.WriteLine ($"break here"); + Console.WriteLine($"break here"); } } } diff --git a/src/mono/wasm/debugger/tests/debugger-nullable-test.cs b/src/mono/wasm/debugger/tests/debugger-nullable-test.cs index 435da2faed5271..9ef65e0e903549 100644 --- a/src/mono/wasm/debugger/tests/debugger-nullable-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-nullable-test.cs @@ -8,7 +8,7 @@ namespace DebuggerTests { public class NullableTests { - public static void TestNullableLocal () + public static void TestNullableLocal() { int? n_int = 5; int? n_int_null = null; @@ -19,10 +19,10 @@ public static void TestNullableLocal () ValueTypesTest.GenericStruct? n_gs = new ValueTypesTest.GenericStruct { StringField = "n_gs#StringField" }; ValueTypesTest.GenericStruct? n_gs_null = null; - Console.WriteLine ($"break here"); + Console.WriteLine($"break here"); } - public static async Task TestNullableLocalAsync () + public static async Task TestNullableLocalAsync() { int? n_int = 5; int? n_int_null = null; @@ -33,7 +33,7 @@ public static async Task TestNullableLocalAsync () ValueTypesTest.GenericStruct? n_gs = new ValueTypesTest.GenericStruct { StringField = "n_gs#StringField" }; ValueTypesTest.GenericStruct? n_gs_null = null; - Console.WriteLine ($"break here"); + Console.WriteLine($"break here"); await Task.CompletedTask; } } diff --git a/src/mono/wasm/debugger/tests/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test.cs index 4fb58be0166330..598a37aceea274 100644 --- a/src/mono/wasm/debugger/tests/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test.cs @@ -316,7 +316,7 @@ public static void TestSimpleStrings() str_spaces, str_esc }; - Console.WriteLine ($"break here"); + Console.WriteLine($"break here"); } } From f026594f621a35d76706717f4b90172c3bec1a8a Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Fri, 4 Sep 2020 13:41:02 -0400 Subject: [PATCH 4/6] [wasm][debugger] simplify function sig, based on usage - addresses review feedback from @lewing --- src/mono/mono/mini/mini-wasm-debugger.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index fd53ab1f1fea00..9246732af2c476 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -829,14 +829,15 @@ read_enum_value (const char *mem, int type) return 0; } -static gpointer -nullable_get_has_value_field_addr (guint8 *nullable, MonoClass *klass) +static gboolean +nullable_get_has_value (guint8 *nullable, MonoClass *klass) { mono_class_setup_fields (klass); g_assert (m_class_is_fields_inited (klass)); MonoClassField *klass_fields = m_class_get_fields (klass); - return mono_vtype_get_field_addr (nullable, &klass_fields[0]); + gpointer addr = mono_vtype_get_field_addr (nullable, &klass_fields[0]); + return *(guint8*)addr != 0; } static gpointer @@ -924,9 +925,7 @@ describe_value(MonoType * type, gpointer addr, int gpflags) if (mono_class_is_nullable (klass)) { MonoType *targ = type->data.generic_class->context.class_inst->type_argv [0]; - gpointer has_value_addr = nullable_get_has_value_field_addr (addr, klass); - gboolean has_value = *(guint8*)has_value_addr; - if (!has_value) { + if (!nullable_get_has_value (addr, klass)) { char* class_name = mono_type_full_name (type); mono_wasm_add_obj_var (class_name, NULL, 0); g_free (class_name); From 10765d758dfe489d6a1f8e5ae0234c0792e07bea Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Fri, 4 Sep 2020 19:01:03 -0400 Subject: [PATCH 5/6] [wasm][debugger] Simplify the function further, based on @lewing's .. excellent suggestion! --- src/mono/mono/mini/mini-wasm-debugger.c | 27 ++++++++++--------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index 9246732af2c476..ac74dcdac349cc 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -830,24 +830,19 @@ read_enum_value (const char *mem, int type) } static gboolean -nullable_get_has_value (guint8 *nullable, MonoClass *klass) +nullable_try_get_value (guint8 *nullable, MonoClass *klass, gpointer* out_value) { mono_class_setup_fields (klass); g_assert (m_class_is_fields_inited (klass)); + *out_value = NULL; MonoClassField *klass_fields = m_class_get_fields (klass); - gpointer addr = mono_vtype_get_field_addr (nullable, &klass_fields[0]); - return *(guint8*)addr != 0; -} - -static gpointer -nullable_get_value_field_addr (guint8 *nullable, MonoClass *klass) -{ - mono_class_setup_fields (klass); - g_assert (m_class_is_fields_inited (klass)); + gpointer addr_for_has_value = mono_vtype_get_field_addr (nullable, &klass_fields[0]); + if (0 == *(guint8*)addr_for_has_value) + return FALSE; - MonoClassField *klass_fields = m_class_get_fields (klass); - return mono_vtype_get_field_addr (nullable, &klass_fields[1]); + *out_value = mono_vtype_get_field_addr (nullable, &klass_fields[1]); + return TRUE; } static gboolean @@ -925,14 +920,14 @@ describe_value(MonoType * type, gpointer addr, int gpflags) if (mono_class_is_nullable (klass)) { MonoType *targ = type->data.generic_class->context.class_inst->type_argv [0]; - if (!nullable_get_has_value (addr, klass)) { + gpointer nullable_value = NULL; + if (nullable_try_get_value (addr, klass, &nullable_value)) { + return describe_value (targ, nullable_value, gpflags); + } else { char* class_name = mono_type_full_name (type); mono_wasm_add_obj_var (class_name, NULL, 0); g_free (class_name); break; - } else { - gpointer value_addr = nullable_get_value_field_addr (addr, klass); - return describe_value(targ, value_addr, gpflags); } } From d91bbf2a4d8640677b61dba57d482e8375bfb3c7 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Sat, 29 Aug 2020 19:08:33 -0400 Subject: [PATCH 6/6] [wasm][debugger] Show actual data for boxed values Eg. `object o = "foobar"` This will show the string `"foobar"`, instead of an object, in the debugger. --- src/mono/mono/mini/mini-wasm-debugger.c | 20 +++++- .../wasm/debugger/DebuggerTestSuite/Tests.cs | 67 ++++++++++++++++--- src/mono/wasm/debugger/tests/debugger-test.cs | 47 ++++++++++++- 3 files changed, 121 insertions(+), 13 deletions(-) diff --git a/src/mono/mono/mini/mini-wasm-debugger.c b/src/mono/mono/mini/mini-wasm-debugger.c index ac74dcdac349cc..d352a9ba1354b0 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -915,6 +915,25 @@ describe_value(MonoType * type, gpointer addr, int gpflags) } break; } + + case MONO_TYPE_OBJECT: { + MonoObject *obj = *(MonoObject**)addr; + MonoClass *klass = obj->vtable->klass; + if (!klass) { + // boxed null + mono_wasm_add_obj_var ("object", NULL, 0); + break; + } + + type = m_class_get_byval_arg (klass); + + // Boxed valuetype + if (m_class_is_valuetype (klass)) + addr = mono_object_unbox_internal (obj); + + return describe_value (type, addr, gpflags); + } + case MONO_TYPE_GENERICINST: { MonoClass *klass = mono_class_from_mono_type_internal (type); if (mono_class_is_nullable (klass)) { @@ -940,7 +959,6 @@ describe_value(MonoType * type, gpointer addr, int gpflags) case MONO_TYPE_SZARRAY: case MONO_TYPE_ARRAY: - case MONO_TYPE_OBJECT: case MONO_TYPE_CLASS: { MonoObject *obj = *(MonoObject**)addr; MonoClass *klass = type->data.klass; diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs index 72a2ea48b06738..fde6296f42d856 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs @@ -456,12 +456,6 @@ await CheckInspectLocalsAtBreakpointSite( } ); - object TGenericStruct(string typearg, string stringField) => new - { - List = TObject($"System.Collections.Generic.List<{typearg}>"), - StringField = TString(stringField) - }; - [Fact] public async Task RuntimeGetPropertiesWithInvalidScopeIdTest() { @@ -631,7 +625,7 @@ await insp.Ready(async (cli, token) => Assert.Equal(3, props.Count()); CheckNumber(props, "A", 10); CheckString(props, "B", "xx"); - CheckObject(props, "c", "object"); + CheckString(props, "c", "20_xx"); // Check UseComplex frame var locals_m1 = await GetLocalsForFrame(pause_location["callFrames"][3], debugger_test_loc, 23, 8, "UseComplex"); @@ -649,7 +643,7 @@ await insp.Ready(async (cli, token) => Assert.Equal(3, props.Count()); CheckNumber(props, "A", 10); CheckString(props, "B", "xx"); - CheckObject(props, "c", "object"); + CheckString(props, "c", "20_xx"); pause_location = await StepAndCheck(StepKind.Over, dep_cs_loc, 23, 8, "DoStuff", times: 2); // Check UseComplex frame again @@ -668,7 +662,7 @@ await insp.Ready(async (cli, token) => Assert.Equal(3, props.Count()); CheckNumber(props, "A", 10); CheckString(props, "B", "xx"); - CheckObject(props, "c", "object"); + CheckString(props, "c", "20_xx"); }); } @@ -1016,6 +1010,59 @@ await CompareObjectPropertiesFor(vt_local_props, name, }); } + [Theory] + [InlineData("BoxingTest", false)] + [InlineData("BoxingTestAsync", true)] + public async Task InspectBoxedLocals(string method_name, bool is_async) => await CheckInspectLocalsAtBreakpointSite( + "DebuggerTest", + method_name, + 17, + is_async ? "MoveNext" : method_name, + $"window.setTimeout(function() {{ invoke_static_method_async('[debugger-test] DebuggerTest:{method_name}'); }}, 1);", + wait_for_event_fn: async (pause_location) => + { + var locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value()); + var dt = new DateTime(2310, 1, 2, 3, 4, 5); + await CheckProps(locals, new + { + n_i = TNumber(5), + o_i = TNumber(5), + o_n_i = TNumber(5), + o_s = TString("foobar"), + o_obj = TObject("Math"), + + n_gs = TValueType("DebuggerTests.ValueTypesTest.GenericStruct"), + o_gs = TValueType("DebuggerTests.ValueTypesTest.GenericStruct"), + o_n_gs = TValueType("DebuggerTests.ValueTypesTest.GenericStruct"), + + n_dt = TDateTime(dt), + o_dt = TDateTime(dt), + o_n_dt = TDateTime(dt), + + o_null = TObject("object", is_null: true), + o_ia = TArray("int[]", 2), + }, "locals"); + + foreach (var name in new[] { "n_gs", "o_gs", "o_n_gs" }) + { + var gs = GetAndAssertObjectWithName(locals, name); + var gs_props = await GetProperties(gs["value"]?["objectId"]?.Value ()); + await CheckProps(gs_props, new + { + List = TObject("System.Collections.Generic.List", is_null: true), + StringField = TString("n_gs#StringField"), + Options = TEnum ("DebuggerTests.Options", "None") + }, name); + } + + var o_ia_props = await GetObjectOnLocals(locals, "o_ia"); + await CheckProps(o_ia_props, new[] + { + TNumber(918), + TNumber(58971) + }, nameof(o_ia_props)); + }); + [Theory] [InlineData(false)] [InlineData(true)] @@ -1661,7 +1708,7 @@ await insp.Ready(async (cli, token) => await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://debugger-test.dll/debugger-test.cs", 12, 8, "IntAdd"); bp = await SetBreakpoint("dotnet://debugger-test.dll/debugger-test.cs", 10, 8); await SendCommandAndCheck(JObject.FromObject(new { }), "Debugger.resume", "dotnet://debugger-test.dll/debugger-test.cs", 10, 8, "IntAdd"); - + }); } //TODO add tests covering basic stepping behavior as step in/out/over diff --git a/src/mono/wasm/debugger/tests/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test.cs index 598a37aceea274..05b045b869ee55 100644 --- a/src/mono/wasm/debugger/tests/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; - +using System.Threading.Tasks; public partial class Math { //Only append content to this class as the test suite depends on line info public static int IntAdd(int a, int b) @@ -285,7 +285,7 @@ async System.Threading.Tasks.Task MethodWithDelegatesAsync() public delegate void DelegateWithVoidReturn(GenericStruct gs); public static void DelegateTargetWithVoidReturn(GenericStruct gs) { } - delegate GenericStruct DelegateForSignatureTest(Math m, GenericStruct> gs); + public delegate GenericStruct DelegateForSignatureTest(Math m, GenericStruct> gs); static bool DelegateTargetForNestedFunc(T arg) => true; public struct SimpleStruct @@ -339,4 +339,47 @@ public static int locals() } static void locals_inner() { } + + public static void BoxingTest() + { + int? n_i = 5; + object o_i = n_i.Value; + object o_n_i = n_i; + + object o_s = "foobar"; + object o_obj = new Math(); + DebuggerTests.ValueTypesTest.GenericStruct? n_gs = new DebuggerTests.ValueTypesTest.GenericStruct { StringField = "n_gs#StringField" }; + object o_gs = n_gs.Value; + object o_n_gs = n_gs; + + DateTime? n_dt = new DateTime(2310, 1, 2, 3, 4, 5); + object o_dt = n_dt.Value; + object o_n_dt = n_dt; + object o_null = null; + object o_ia = new int[] {918, 58971}; + + Console.WriteLine ($"break here"); + } + + public static async Task BoxingTestAsync() + { + int? n_i = 5; + object o_i = n_i.Value; + object o_n_i = n_i; + + object o_s = "foobar"; + object o_obj = new Math(); + DebuggerTests.ValueTypesTest.GenericStruct? n_gs = new DebuggerTests.ValueTypesTest.GenericStruct { StringField = "n_gs#StringField" }; + object o_gs = n_gs.Value; + object o_n_gs = n_gs; + + DateTime? n_dt = new DateTime(2310, 1, 2, 3, 4, 5); + object o_dt = n_dt.Value; + object o_n_dt = n_dt; + object o_null = null; + object o_ia = new int[] {918, 58971}; + + Console.WriteLine ($"break here"); + await Task.CompletedTask; + } }