diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs index ae307971acca..be5e6c7f3c9b 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs @@ -604,6 +604,7 @@ public static void wait_one () if_property_stepping(); fixed_size_array(); test_new_exception_filter(); + test_async_debug_generics(); return 3; } @@ -903,6 +904,17 @@ public static void ss7_3 () } } + [MethodImplAttribute (MethodImplOptions.NoInlining)] + public static void test_async_debug_generics () { + ExecuteAsync_Broken().Wait (); + } + + async static Task ExecuteAsync_Broken() + { + await Task.Delay(2); + return default; + } + [MethodImplAttribute (MethodImplOptions.NoInlining)] public static void inspect_enumerator_in_generic_struct() { TestEnumeratorInsideGenericStruct generic_struct = new TestEnumeratorInsideGenericStruct(new KeyValuePair("0", "f1")); diff --git a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs index c3893706fc51..52da50a45dbf 100644 --- a/mcs/class/Mono.Debugger.Soft/Test/dtest.cs +++ b/mcs/class/Mono.Debugger.Soft/Test/dtest.cs @@ -5152,6 +5152,16 @@ public void Bug59649 () vm = null; } + [Test] + public void TestAsyncDebugGenerics () { + Event e = run_until ("test_async_debug_generics"); + e = step_in_await ("test_async_debug_generics", e); + e = step_in_await ("MoveNext", e); + e = step_in_await ("MoveNext", e); + e = step_in_await ("MoveNext", e); + e = step_in_await ("MoveNext", e); + } + #endif } // class DebuggerTests } // namespace diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index d681e2536fea..3b0e3e2d7d19 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -4526,6 +4526,31 @@ get_object_id_for_debugger_method (MonoClass* async_builder_class) return method; } +static MonoClass * +get_class_to_get_builder_field(DbgEngineStackFrame *frame) +{ + ERROR_DECL (error); + gpointer this_addr = get_this_addr (frame); + MonoClass *original_class = frame->method->klass; + MonoClass *ret; + if (!m_class_is_valuetype (original_class) && mono_class_is_open_constructed_type (m_class_get_byval_arg (original_class))) { + MonoObject *this_obj = *(MonoObject**)this_addr; + MonoGenericContext context; + MonoType *inflated_type; + + g_assert (this_obj); + context = mono_get_generic_context_from_stack_frame (frame->ji, this_obj->vtable); + inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (original_class), &context, error); + mono_error_assert_ok (error); /* FIXME don't swallow the error */ + + ret = mono_class_from_mono_type_internal (inflated_type); + mono_metadata_free_type (inflated_type); + return ret; + } + return original_class; +} + + /* Return the address of the AsyncMethodBuilder struct belonging to the state machine method pointed to by FRAME */ static gpointer get_async_method_builder (DbgEngineStackFrame *frame) @@ -4534,15 +4559,17 @@ get_async_method_builder (DbgEngineStackFrame *frame) MonoClassField *builder_field; gpointer builder; gpointer this_addr; + MonoClass* klass = frame->method->klass; - builder_field = mono_class_get_field_from_name_full (frame->method->klass, "<>t__builder", NULL); + klass = get_class_to_get_builder_field(frame); + builder_field = mono_class_get_field_from_name_full (klass, "<>t__builder", NULL); g_assert (builder_field); this_addr = get_this_addr (frame); if (!this_addr) return NULL; - if (m_class_is_valuetype (frame->method->klass)) { + if (m_class_is_valuetype (klass)) { builder = mono_vtype_get_field_addr (*(guint8**)this_addr, builder_field); } else { this_obj = *(MonoObject**)this_addr; @@ -4574,7 +4601,7 @@ get_this_async_id (DbgEngineStackFrame *frame) if (!builder) return 0; - builder_field = mono_class_get_field_from_name_full (frame->method->klass, "<>t__builder", NULL); + builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL); g_assert (builder_field); tls = (DebuggerTlsData *)mono_native_tls_get_value (debugger_tls_id); @@ -4598,7 +4625,7 @@ get_this_async_id (DbgEngineStackFrame *frame) static gboolean set_set_notification_for_wait_completion_flag (DbgEngineStackFrame *frame) { - MonoClassField *builder_field = mono_class_get_field_from_name_full (frame->method->klass, "<>t__builder", NULL); + MonoClassField *builder_field = mono_class_get_field_from_name_full (get_class_to_get_builder_field(frame), "<>t__builder", NULL); g_assert (builder_field); gpointer builder = get_async_method_builder (frame); g_assert (builder); diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index b00db6f02ceb..ea52d7ec5898 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -72,6 +72,7 @@ #include "mini.h" #include "trace.h" #include "debugger-agent.h" +#include "debugger-engine.h" #include "seq-points.h" #include "llvm-runtime.h" #include "mini-llvm.h" @@ -842,8 +843,8 @@ get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx) /* * generic_info is either a MonoMethodRuntimeGenericContext or a MonoVTable. */ -static MonoGenericContext -get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info) +MonoGenericContext +mono_get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info) { MonoGenericContext context = { NULL, NULL }; MonoClass *klass, *method_container_class; @@ -888,6 +889,7 @@ get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info) return context; } + static MonoMethod* get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info) { @@ -897,7 +899,7 @@ get_method_from_stack_frame (MonoJitInfo *ji, gpointer generic_info) if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this) return jinfo_get_method (ji); - context = get_generic_context_from_stack_frame (ji, generic_info); + context = mono_get_generic_context_from_stack_frame (ji, generic_info); method = jinfo_get_method (ji); method = mono_method_get_declaring_generic_method (method); @@ -1948,7 +1950,7 @@ get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContex if (!ji->has_generic_jit_info || !mono_jit_info_get_generic_jit_info (ji)->has_this) return catch_class; - context = get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx)); + context = mono_get_generic_context_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, ctx)); /* FIXME: we shouldn't inflate but instead put the type in the rgctx and fetch it from there. It @@ -4019,7 +4021,7 @@ mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 reg MonoType *inflated_type; g_assert (rgctx || this_obj); - context = get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable); + context = mono_get_generic_context_from_stack_frame (jinfo, rgctx ? rgctx : this_obj->vtable); inflated_type = mono_class_inflate_generic_type_checked (m_class_get_byval_arg (catch_class), &context, error); mono_error_assert_ok (error); /* FIXME don't swallow the error */ diff --git a/mono/mini/mini.h b/mono/mini/mini.h index db89b70f6651..37d762f347e0 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -2907,4 +2907,7 @@ mini_safepoints_enabled (void) gpointer mono_arch_load_function (MonoJitICallId jit_icall_id); +MonoGenericContext +mono_get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info); + #endif /* __MONO_MINI_H__ */