[wasm] [debugger] Adding test for #42227 PR (#42299)
authorThays Grazia <thaystg@gmail.com>
Fri, 18 Sep 2020 15:07:15 +0000 (12:07 -0300)
committerGitHub <noreply@github.com>
Fri, 18 Sep 2020 15:07:15 +0000 (12:07 -0300)
* Adding the test I realized that I need to move one more function.

* Adding line.

* Adding space.

src/mono/mono/mini/debugger-agent.c
src/mono/mono/mini/debugger-engine.c
src/mono/mono/mini/debugger-engine.h
src/mono/mono/mini/mini-wasm-debugger.c
src/mono/wasm/debugger/DebuggerTestSuite/Tests.cs
src/mono/wasm/debugger/tests/debugger-async-step.cs [new file with mode: 0644]

index dd84011..181b5d8 100644 (file)
@@ -4520,27 +4520,6 @@ breakpoint_matches_assembly (MonoBreakpoint *bp, MonoAssembly *assembly)
        return bp->method && m_class_get_image (bp->method->klass)->assembly == assembly;
 }
 
-static MonoMethod*
-get_object_id_for_debugger_method (MonoClass* async_builder_class)
-{
-       ERROR_DECL (error);
-       GPtrArray *array = mono_class_get_methods_by_name (async_builder_class, "get_ObjectIdForDebugger", 0x24, 1, FALSE, error);
-       mono_error_assert_ok (error);
-       if (array->len != 1) {
-               g_ptr_array_free (array, TRUE);
-               //if we don't find method get_ObjectIdForDebugger we try to find the property Task to continue async debug.
-               MonoProperty *prop = mono_class_get_property_from_name_internal (async_builder_class, "Task");
-               if (!prop) {
-                       DEBUG_PRINTF (1, "Impossible to debug async methods.\n");
-                       return NULL;
-               }
-               return prop->get;
-       }
-       MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, 0);
-       g_ptr_array_free (array, TRUE);
-       return method;
-}
-
 //This ID is used to figure out if breakpoint hit on resumeOffset belongs to us or not
 //since thread probably changed...
 static int
index 1df1d2f..c5964e0 100644 (file)
@@ -1657,6 +1657,27 @@ set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame)
        return TRUE;
 }
 
+MonoMethod*
+get_object_id_for_debugger_method (MonoClass* async_builder_class)
+{
+       ERROR_DECL (error);
+       GPtrArray *array = mono_class_get_methods_by_name (async_builder_class, "get_ObjectIdForDebugger", 0x24, 1, FALSE, error);
+       mono_error_assert_ok (error);
+       if (array->len != 1) {
+               g_ptr_array_free (array, TRUE);
+               //if we don't find method get_ObjectIdForDebugger we try to find the property Task to continue async debug.
+               MonoProperty *prop = mono_class_get_property_from_name_internal (async_builder_class, "Task");
+               if (!prop) {
+                       DEBUG_PRINTF (1, "Impossible to debug async methods.\n");
+                       return NULL;
+               }
+               return prop->get;
+       }
+       MonoMethod *method = (MonoMethod *)g_ptr_array_index (array, 0);
+       g_ptr_array_free (array, TRUE);
+       return method;
+}
+
 gpointer
 get_this_addr (DbgEngineStackFrame *the_frame)
 {
index 8c86ed5..ef332db 100644 (file)
@@ -323,4 +323,5 @@ gpointer get_this_addr (DbgEngineStackFrame *the_frame);
 gpointer get_async_method_builder (DbgEngineStackFrame *frame);
 MonoMethod* get_set_notification_method (MonoClass* async_builder_class);
 MonoMethod* get_notify_debugger_of_wait_completion_method (void);
+MonoMethod* get_object_id_for_debugger_method (MonoClass* async_builder_class);
 #endif
index 2278a74..a0eee7d 100644 (file)
@@ -148,13 +148,17 @@ collect_frames (MonoStackFrameInfo *info, MonoContext *ctx, gpointer data)
        if (!mono_find_prev_seq_point_for_native_offset (mono_get_root_domain (), method, info->native_offset, NULL, &sp))
                DEBUG_PRINTF (2, "collect_frames: Failed to lookup sequence point. method: %s, native_offset: %d \n", method->name, info->native_offset);
 
-       DbgEngineStackFrame *frame = g_new0 (DbgEngineStackFrame, 1);
-
-       frame->ji = info->ji;
-       frame->domain = info->domain;
-       frame->method = method;
-       frame->native_offset = info->native_offset;
-
+       StackFrame *frame = g_new0 (StackFrame, 1);
+       frame->de.ji = info->ji;
+       frame->de.domain = info->domain;
+       frame->de.method = method;
+       frame->de.native_offset = info->native_offset;
+
+       frame->il_offset = info->il_offset;
+       frame->interp_frame = info->interp_frame;
+       frame->frame_addr = info->frame_addr;
+       
        g_ptr_array_add (frames, frame);
 
        return FALSE;
@@ -235,11 +239,56 @@ ensure_runtime_is_suspended (void)
        return DE_ERR_NONE;
 }
 
+static int 
+get_object_id (MonoObject *obj) 
+{
+       ObjRef *ref;
+       if (!obj)
+               return 0;
+
+       ref = (ObjRef *)g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)));
+       if (ref)
+               return ref->id;
+       ref = g_new0 (ObjRef, 1);
+       ref->id = mono_atomic_inc_i32 (&objref_id);
+       ref->handle = mono_gchandle_new_weakref_internal (obj, FALSE);
+       g_hash_table_insert (objrefs, GINT_TO_POINTER (ref->id), ref);
+       g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)), ref);
+       return ref->id;
+}
+
+
 static int
-get_this_async_id (DbgEngineStackFrame *f)
+get_this_async_id (DbgEngineStackFrame *frame)
 {
-       g_error ("get_this_async_id");
-       return 0;
+       MonoClassField *builder_field;
+       gpointer builder;
+       MonoMethod *method;
+       MonoObject *ex;
+       ERROR_DECL (error);
+       MonoObject *obj;
+       
+       /*
+        * FRAME points to a method in a state machine class/struct.
+        * Call the ObjectIdForDebugger method of the associated method builder type.
+        */
+       builder = get_async_method_builder (frame);
+       if (!builder)
+               return 0;
+
+       builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL);
+       if (!builder_field)
+               return 0;
+
+       method = get_object_id_for_debugger_method (mono_class_from_mono_type_internal (builder_field->type));
+       if (!method) {
+               return 0;
+       }
+
+       obj = mono_runtime_try_invoke (method, builder, NULL, &ex, error);
+       mono_error_assert_ok (error);
+
+       return get_object_id (obj);
 }
 
 typedef struct {
@@ -438,24 +487,6 @@ mono_wasm_setup_single_step (int kind)
        return isBPOnNativeCode;
 }
 
-static int 
-get_object_id(MonoObject *obj) 
-{
-       ObjRef *ref;
-       if (!obj)
-               return 0;
-
-       ref = (ObjRef *)g_hash_table_lookup (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)));
-       if (ref)
-               return ref->id;
-       ref = g_new0 (ObjRef, 1);
-       ref->id = mono_atomic_inc_i32 (&objref_id);
-       ref->handle = mono_gchandle_new_weakref_internal (obj, FALSE);
-       g_hash_table_insert (objrefs, GINT_TO_POINTER (ref->id), ref);
-       g_hash_table_insert (obj_to_objref, GINT_TO_POINTER (~((gsize)obj)), ref);
-       return ref->id;
-}
-
 static void
 handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch_ctx, StackFrameInfo *catch_frame)
 {
index 16296b6..f5263fb 100644 (file)
@@ -1816,6 +1816,34 @@ namespace DebuggerTests
             });
 
         [Fact]
+        public async Task StepOverAsyncMethod()
+        {
+            var insp = new Inspector();
+            //Collect events
+            var scripts = SubscribeToScripts(insp);
+
+            await Ready();
+            await insp.Ready(async (cli, token) =>
+            {
+                ctx = new DebugTestContext(cli, insp, token, scripts);
+
+                var bp = await SetBreakpointInMethod("debugger-test.dll", "AsyncStepClass", "TestAsyncStepOut2", 2);
+                System.Console.WriteLine(bp);
+                await EvaluateAndCheck(
+                    "window.setTimeout(function() { invoke_static_method_async('[debugger-test] AsyncStepClass:TestAsyncStepOut'); }, 1);",
+                    "dotnet://debugger-test.dll/debugger-async-step.cs", 19, 8,
+                    "MoveNext");
+
+                await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-async-step.cs", 21, 8, "MoveNext");
+
+                await StepAndCheck(StepKind.Over, "dotnet://debugger-test.dll/debugger-async-step.cs", 22, 4, "MoveNext");
+
+                await StepAndCheck(StepKind.Over, null, 0, 0, "get_IsCompletedSuccessfully"); //not check the line number and the file name because this can be changed
+
+            });
+        }
+
+        [Fact]
         public async Task PreviousFrameForAReflectedCall() => await CheckInspectLocalsAtBreakpointSite(
              "DebuggerTests.GetPropertiesTests.CloneableStruct", "SimpleStaticMethod", 1, "SimpleStaticMethod",
              "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerTests.GetPropertiesTests.TestWithReflection:run'); })",
diff --git a/src/mono/wasm/debugger/tests/debugger-async-step.cs b/src/mono/wasm/debugger/tests/debugger-async-step.cs
new file mode 100644 (file)
index 0000000..18b519f
--- /dev/null
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Threading.Tasks; 
+using System.Net; 
+using System.Net.Http;
+
+public class AsyncStepClass
+{
+    static HttpClient client = new HttpClient();
+    public static async Task TestAsyncStepOut()
+    {
+        await TestAsyncStepOut2("foobar");
+    }
+
+    public static async Task<int> TestAsyncStepOut2(string some)
+    {
+        var resp = await client.GetAsync("http://localhost:9400/debugger-driver.html");
+        Console.WriteLine($"resp: {resp}"); /// BP at this line
+
+        return 10;
+    }
+}