diff options
-rw-r--r-- | mono/mini/mini-wasm-debugger.c | 121 |
1 files changed, 80 insertions, 41 deletions
diff --git a/mono/mini/mini-wasm-debugger.c b/mono/mini/mini-wasm-debugger.c index 43e61020b1f..3c60fcdd6cd 100644 --- a/mono/mini/mini-wasm-debugger.c +++ b/mono/mini/mini-wasm-debugger.c @@ -30,6 +30,12 @@ enum { EXCEPTION_MODE_ALL }; +// Flags for get_*_properties +#define GPFLAG_NONE 0x0000 +#define GPFLAG_OWN_PROPERTIES 0x0001 +#define GPFLAG_ACCESSORS_ONLY 0x0002 +#define GPFLAG_EXPAND_VALUETYPES 0x0004 + //functions exported to be used by JS G_BEGIN_DECLS @@ -41,8 +47,8 @@ EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_local_vars (int scope, int* pos, int EMSCRIPTEN_KEEPALIVE void mono_wasm_clear_all_breakpoints (void); EMSCRIPTEN_KEEPALIVE int mono_wasm_setup_single_step (int kind); EMSCRIPTEN_KEEPALIVE int mono_wasm_pause_on_exceptions (int state); -EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_object_properties (int object_id, gboolean expand_value_types); -EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_array_values (int object_id, int start_idx, int count, gboolean expand_value_types); +EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_object_properties (int object_id, int gpflags); +EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_array_values (int object_id, int start_idx, int count, int gpflags); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_invoke_getter_on_object (int object_id, const char* name); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_invoke_getter_on_value (void *value, MonoClass *klass, const char *name); EMSCRIPTEN_KEEPALIVE gboolean mono_wasm_get_deref_ptr_value (void *value_addr, MonoClass *klass); @@ -61,7 +67,7 @@ extern void mono_wasm_add_typed_value (const char *type, const char *str_value, G_END_DECLS -static void describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAsyncLocalThis, gboolean expandValueType); +static void describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAsyncLocalThis, int gpflags); static void handle_exception (MonoException *exc, MonoContext *throw_ctx, MonoContext *catch_ctx, StackFrameInfo *catch_frame); //FIXME move all of those fields to the profiler object @@ -823,7 +829,8 @@ read_enum_value (const char *mem, int type) return 0; } -static gboolean describe_value(MonoType * type, gpointer addr, gboolean expandValueType) +static gboolean +describe_value(MonoType * type, gpointer addr, int gpflags) { ERROR_DECL (error); switch (type->type) { @@ -984,7 +991,7 @@ static gboolean describe_value(MonoType * type, gpointer addr, gboolean expandVa } else { char *to_string_val = get_to_string_description (class_name, klass, addr); - if (expandValueType) { + if (gpflags & GPFLAG_EXPAND_VALUETYPES) { int32_t size = mono_class_value_size (klass, NULL); void *value_buf = g_malloc0 (size); mono_value_copy_internal (value_buf, addr, klass); @@ -996,7 +1003,7 @@ static gboolean describe_value(MonoType * type, gpointer addr, gboolean expandVa g_free (value_buf); // FIXME: isAsyncLocalThis - describe_object_properties_for_klass (addr, klass, FALSE, expandValueType); + describe_object_properties_for_klass (addr, klass, FALSE, gpflags); mono_wasm_add_typed_value ("end_vt", NULL, 0); } else { EM_ASM ({ @@ -1043,35 +1050,45 @@ invoke_and_describe_getter_value (MonoObject *obj, MonoProperty *p) if (!is_ok (error) && exc == NULL) exc = (MonoObject*) mono_error_convert_to_exception (error); if (exc) - describe_value (mono_get_object_type (), &exc, TRUE); + describe_value (mono_get_object_type (), &exc, GPFLAG_EXPAND_VALUETYPES); else if (!res || !m_class_is_valuetype (mono_object_class (res))) - describe_value (sig->ret, &res, TRUE); + describe_value (sig->ret, &res, GPFLAG_EXPAND_VALUETYPES); else - describe_value (sig->ret, mono_object_unbox_internal (res), TRUE); + describe_value (sig->ret, mono_object_unbox_internal (res), GPFLAG_EXPAND_VALUETYPES); } static void -describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAsyncLocalThis, gboolean expandValueType) +describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAsyncLocalThis, int gpflags) { MonoClassField *f; MonoProperty *p; MonoMethodSignature *sig; - gpointer iter = NULL; gboolean is_valuetype; int pnum; char *klass_name; gboolean auto_invoke_getters; + gboolean is_own; + gboolean only_backing_fields; g_assert (klass); + MonoClass *start_klass = klass; + + only_backing_fields = gpflags & GPFLAG_ACCESSORS_ONLY; is_valuetype = m_class_is_valuetype(klass); + if (is_valuetype) + gpflags |= GPFLAG_EXPAND_VALUETYPES; +handle_parent: + is_own = (start_klass == klass); + klass_name = mono_class_full_name (klass); + gpointer iter = NULL; while (obj && (f = mono_class_get_fields_internal (klass, &iter))) { if (isAsyncLocalThis && f->name[0] == '<' && f->name[1] == '>') { if (g_str_has_suffix (f->name, "__this")) { mono_wasm_add_properties_var ("this", f->offset); gpointer field_value = (guint8*)obj + f->offset; - describe_value (f->type, field_value, is_valuetype | expandValueType); + describe_value (f->type, field_value, gpflags); } continue; @@ -1081,20 +1098,23 @@ describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAs if (mono_field_is_deleted (f)) continue; - mono_wasm_add_properties_var (f->name, f->offset); + if (only_backing_fields && !g_str_has_suffix(f->name, "k__BackingField")) + continue; + + EM_ASM ({ + MONO.mono_wasm_add_properties_var ($0, { field_offset: $1, is_own: $2, attr: $3, owner_class: $4 }); + }, f->name, f->offset, is_own, f->type->attrs, klass_name); gpointer field_addr; if (is_valuetype) field_addr = mono_vtype_get_field_addr (obj, f); else field_addr = (guint8*)obj + f->offset; - - describe_value (f->type, field_addr, is_valuetype | expandValueType); + + describe_value (f->type, field_addr, gpflags); } - klass_name = mono_class_full_name (klass); auto_invoke_getters = are_getters_allowed (klass_name); - iter = NULL; pnum = 0; while ((p = mono_class_get_properties (klass, &iter))) { @@ -1102,8 +1122,15 @@ describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAs if (isAsyncLocalThis && (p->name[0] != '<' || (p->name[0] == '<' && p->name[1] == '>'))) continue; - mono_wasm_add_properties_var (p->name, pnum); sig = mono_method_signature_internal (p->get); + if (sig->param_count != 0) { + // getters with params are not shown + continue; + } + + EM_ASM ({ + MONO.mono_wasm_add_properties_var ($0, { field_offset: $1, is_own: $2, attr: $3, owner_class: $4 }); + }, p->name, pnum, is_own, p->attrs, klass_name); gboolean vt_self_type_getter = is_valuetype && mono_class_from_mono_type_internal (sig->ret) == klass; if (auto_invoke_getters && !vt_self_type_getter) { @@ -1112,8 +1139,7 @@ describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAs // not allowed to call the getter here char *ret_class_name = mono_class_full_name (mono_class_from_mono_type_internal (sig->ret)); - gboolean invokable = sig->param_count == 0; - mono_wasm_add_typed_value ("getter", ret_class_name, invokable); + mono_wasm_add_typed_value ("getter", ret_class_name, -1); g_free (ret_class_name); continue; @@ -1123,6 +1149,14 @@ describe_object_properties_for_klass (void *obj, MonoClass *klass, gboolean isAs } g_free (klass_name); + + // ownProperties + // Note: ownProperties should mean that we return members of the klass itself, + // but we are going to ignore that here, because otherwise vscode/chrome don't + // seem to ask for inherited fields at all. + // if (!is_valuetype && !(gpflags & GPFLAG_OWN_PROPERTIES) && (klass = m_class_get_parent (klass))) + if (!is_valuetype && (klass = m_class_get_parent (klass))) + goto handle_parent; } /* @@ -1148,9 +1182,9 @@ describe_delegate_properties (MonoObject *obj) } static gboolean -describe_object_properties (guint64 objectId, gboolean isAsyncLocalThis, gboolean expandValueType) +describe_object_properties (guint64 objectId, gboolean isAsyncLocalThis, int gpflags) { - DEBUG_PRINTF (2, "describe_object_properties %llu\n", objectId); + DEBUG_PRINTF (2, "describe_object_properties %llu, gpflags: %d\n", objectId, gpflags); MonoObject *obj = get_object_from_id (objectId); if (!obj) @@ -1160,7 +1194,7 @@ describe_object_properties (guint64 objectId, gboolean isAsyncLocalThis, gboolea // delegates get the same id format as regular objects describe_delegate_properties (obj); } else { - describe_object_properties_for_klass (obj, obj->vtable->klass, isAsyncLocalThis, expandValueType); + describe_object_properties_for_klass (obj, obj->vtable->klass, isAsyncLocalThis, gpflags); } return TRUE; @@ -1174,7 +1208,9 @@ invoke_getter (void *obj_or_value, MonoClass *klass, const char *name) return FALSE; } - gpointer iter = NULL; + gpointer iter; +handle_parent: + iter = NULL; MonoProperty *p; while ((p = mono_class_get_properties (klass, &iter))) { //if get doesn't have name means that doesn't have a getter implemented and we don't want to show value, like VS debug @@ -1185,11 +1221,14 @@ invoke_getter (void *obj_or_value, MonoClass *klass, const char *name) return TRUE; } + if ((klass = m_class_get_parent(klass))) + goto handle_parent; + return FALSE; } -static gboolean -describe_array_values (guint64 objectId, int startIdx, int count, gboolean expandValueType) +static gboolean +describe_array_values (guint64 objectId, int startIdx, int count, int gpflags) { if (count == 0) return TRUE; @@ -1229,7 +1268,7 @@ describe_array_values (guint64 objectId, int startIdx, int count, gboolean expan for (int i = startIdx; i < endIdx; i ++) { mono_wasm_add_array_item(i); elem = (gpointer*)((char*)arr->vector + (i * esize)); - describe_value (m_class_get_byval_arg (m_class_get_element_class (klass)), elem, expandValueType); + describe_value (m_class_get_byval_arg (m_class_get_element_class (klass)), elem, gpflags); } return TRUE; } @@ -1237,14 +1276,14 @@ describe_array_values (guint64 objectId, int startIdx, int count, gboolean expan static void describe_async_method_locals (InterpFrame *frame, MonoMethod *method) { - //Async methods are special in the way that local variables can be lifted to generated class fields + //Async methods are special in the way that local variables can be lifted to generated class fields gpointer addr = NULL; if (mono_debug_lookup_method_async_debug_info (method)) { addr = mini_get_interp_callbacks ()->frame_get_this (frame); MonoObject *obj = *(MonoObject**)addr; int objId = get_object_id (obj); mono_wasm_set_is_async_method (objId); - describe_object_properties (objId, TRUE, FALSE); + describe_object_properties (objId, TRUE, GPFLAG_NONE); } } @@ -1264,17 +1303,17 @@ describe_non_async_this (InterpFrame *frame, MonoMethod *method) mono_wasm_add_properties_var ("this", -1); if (m_class_is_valuetype (klass)) { - describe_value (type, obj, TRUE); + describe_value (type, obj, GPFLAG_EXPAND_VALUETYPES); } else { // this is an object, and we can retrieve the valuetypes in it later // through the object id - describe_value (type, addr, FALSE); + describe_value (type, addr, GPFLAG_NONE); } } } static gboolean -describe_variable (InterpFrame *frame, MonoMethod *method, int pos, gboolean expandValueType) +describe_variable (InterpFrame *frame, MonoMethod *method, int pos, int gpflags) { ERROR_DECL (error); MonoMethodHeader *header = NULL; @@ -1295,7 +1334,7 @@ describe_variable (InterpFrame *frame, MonoMethod *method, int pos, gboolean exp DEBUG_PRINTF (2, "adding val %p type [%p] %s\n", addr, type, mono_type_full_name (type)); - describe_value(type, addr, expandValueType); + describe_value(type, addr, gpflags); if (header) mono_metadata_free_mh (header); @@ -1324,7 +1363,7 @@ describe_variables_on_frame (MonoStackFrameInfo *info, MonoContext *ctx, gpointe for (int i = 0; i < data->len; i++) { - describe_variable (frame, method, data->pos[i], TRUE); + describe_variable (frame, method, data->pos[i], GPFLAG_EXPAND_VALUETYPES); } describe_async_method_locals (frame, method); @@ -1343,7 +1382,7 @@ mono_wasm_get_deref_ptr_value (void *value_addr, MonoClass *klass) } mono_wasm_add_properties_var ("deref", -1); - describe_value (type->data.type, value_addr, TRUE); + describe_value (type->data.type, value_addr, GPFLAG_EXPAND_VALUETYPES); return TRUE; } @@ -1363,19 +1402,19 @@ mono_wasm_get_local_vars (int scope, int* pos, int len) } EMSCRIPTEN_KEEPALIVE gboolean -mono_wasm_get_object_properties (int object_id, gboolean expand_value_types) +mono_wasm_get_object_properties (int object_id, int gpflags) { - DEBUG_PRINTF (2, "getting properties of object %d\n", object_id); + DEBUG_PRINTF (2, "getting properties of object %d, gpflags: %d\n", object_id, gpflags); - return describe_object_properties (object_id, FALSE, expand_value_types); + return describe_object_properties (object_id, FALSE, gpflags); } EMSCRIPTEN_KEEPALIVE gboolean -mono_wasm_get_array_values (int object_id, int start_idx, int count, gboolean expand_value_types) +mono_wasm_get_array_values (int object_id, int start_idx, int count, int gpflags) { - DEBUG_PRINTF (2, "getting array values %d, startIdx: %d, count: %d, expandValueType: %d\n", object_id, start_idx, count, expand_value_types); + DEBUG_PRINTF (2, "getting array values %d, startIdx: %d, count: %d, gpflags: 0x%x\n", object_id, start_idx, count, gpflags); - return describe_array_values (object_id, start_idx, count, expand_value_types); + return describe_array_values (object_id, start_idx, count, gpflags); } EMSCRIPTEN_KEEPALIVE gboolean |