From 66f4b4b70412da19f1785f57d7ae349febb0cd99 Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Fri, 4 Sep 2020 22:08:55 -0400 Subject: [PATCH] [wasm][debugger] Add support for Nullable (#41559) * [wasm][debugger] Add support for Nullable Return the value, or null. Fixes https://github.com/mono/mono/issues/20310 * Address review feedback - merge functions * [wasm][debugger] run dotnet-format on the debugger test app * [wasm][debugger] simplify function sig, based on usage - addresses review feedback from @lewing * [wasm][debugger] Simplify the function further, based on @lewing's .. excellent suggestion! --- src/mono/mono/mini/mini-wasm-debugger.c | 31 +++++++++++++++++ src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs | 37 ++++++++++++++++++++ .../debugger/tests/debugger-get-properties-test.cs | 24 ++++++------- .../wasm/debugger/tests/debugger-nullable-test.cs | 40 ++++++++++++++++++++++ src/mono/wasm/debugger/tests/debugger-test.cs | 2 +- 5 files changed, 121 insertions(+), 13 deletions(-) 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 3c60fcd..ac74dcd 100644 --- a/src/mono/mono/mini/mini-wasm-debugger.c +++ b/src/mono/mono/mini/mini-wasm-debugger.c @@ -830,6 +830,22 @@ read_enum_value (const char *mem, int type) } static gboolean +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_for_has_value = mono_vtype_get_field_addr (nullable, &klass_fields[0]); + if (0 == *(guint8*)addr_for_has_value) + return FALSE; + + *out_value = mono_vtype_get_field_addr (nullable, &klass_fields[1]); + return TRUE; +} + +static gboolean describe_value(MonoType * type, gpointer addr, int gpflags) { ERROR_DECL (error); @@ -900,6 +916,21 @@ 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 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; + } + } + 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 958b176..72a2ea4 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs @@ -395,6 +395,43 @@ namespace DebuggerTests ); [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)] public async Task InspectLocalsWithGenericTypesAtBreakpointSite(bool use_cfo) => 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 60e2d48..fd3e827 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 @@ namespace DebuggerTests.GetPropertiesTests } public interface IName : IFirstName, ILastName - {} + { } public class BaseBaseClass { @@ -91,20 +91,20 @@ namespace DebuggerTests.GetPropertiesTests 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 @@ namespace DebuggerTests.GetPropertiesTests 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 @@ namespace DebuggerTests.GetPropertiesTests 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 @@ namespace DebuggerTests.GetPropertiesTests 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 new file mode 100644 index 0000000..9ef65e0 --- /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; + } + } +} diff --git a/src/mono/wasm/debugger/tests/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test.cs index 4fb58be..598a37a 100644 --- a/src/mono/wasm/debugger/tests/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test.cs @@ -316,7 +316,7 @@ public partial class Math str_spaces, str_esc }; - Console.WriteLine ($"break here"); + Console.WriteLine($"break here"); } } -- 2.7.4