diff --git a/src/gc-heap-snapshot.cpp b/src/gc-heap-snapshot.cpp index e436e6b12605b..d4a70785ead98 100644 --- a/src/gc-heap-snapshot.cpp +++ b/src/gc-heap-snapshot.cpp @@ -420,25 +420,22 @@ void _gc_heap_snapshot_record_module_edge(jl_module_t *from, jl_value_t *to, cha g_snapshot->names.find_or_create_string_id(name)); } -void _gc_heap_snapshot_record_object_edge(jl_value_t *from, jl_value_t *to, void* slot) JL_NOTSAFEPOINT { +void _gc_heap_snapshot_record_object_edge(jl_value_t *from, jl_value_t *to, size_t field_index) JL_NOTSAFEPOINT { jl_datatype_t *type = (jl_datatype_t*)jl_typeof(from); - auto field_paths = _fieldpath_for_slot(from, slot); - // Build the new field name by joining the strings, and/or use the struct + field names - // to create a bunch of edges + nodes - // (iterate the vector in reverse - the last element is the first path) - // TODO: Prefer to create intermediate edges and nodes instead of a combined string path. - string path; - for (auto it = field_paths.rbegin(); it != field_paths.rend(); ++it) { - // ... - path += it->second; - if ( it + 1 != field_paths.rend() ) { - path += "."; - } + if (field_index < 0 || jl_datatype_nfields(type) <= field_index) { + // TODO: We're getting -1 in some cases + //jl_printf(JL_STDERR, "WARNING - incorrect field index (%zu) for type\n", field_index); + //jl_(type); + _record_gc_edge("object", "element", from, to, field_index); + return; } + jl_svec_t *field_names = jl_field_names(type); + jl_sym_t *name = (jl_sym_t*)jl_svecref(field_names, field_index); + const char *field_name = jl_symbol_name(name); _record_gc_edge("object", "property", from, to, - g_snapshot->names.find_or_create_string_id(path)); + g_snapshot->names.find_or_create_string_id(field_name)); } void _gc_heap_snapshot_record_internal_edge(jl_value_t *from, jl_value_t *to) JL_NOTSAFEPOINT { diff --git a/src/gc-heap-snapshot.h b/src/gc-heap-snapshot.h index 05bb9d48f0c4d..28e566dab5cca 100644 --- a/src/gc-heap-snapshot.h +++ b/src/gc-heap-snapshot.h @@ -20,7 +20,7 @@ void _gc_heap_snapshot_record_task_to_frame_edge(jl_task_t *from, jl_gcframe_t * void _gc_heap_snapshot_record_frame_to_frame_edge(jl_gcframe_t *from, jl_gcframe_t *to) JL_NOTSAFEPOINT; void _gc_heap_snapshot_record_array_edge(jl_value_t *from, jl_value_t *to, size_t index) JL_NOTSAFEPOINT; void _gc_heap_snapshot_record_module_edge(jl_module_t *from, jl_value_t *to, char *name) JL_NOTSAFEPOINT; -void _gc_heap_snapshot_record_object_edge(jl_value_t *from, jl_value_t *to, void* slot) JL_NOTSAFEPOINT; +void _gc_heap_snapshot_record_object_edge(jl_value_t *from, jl_value_t *to, size_t field_index) JL_NOTSAFEPOINT; // Used for objects managed by GC, but which aren't exposed in the julia object, so have no // field or index. i.e. they're not reacahable from julia code, but we _will_ hit them in // the GC mark phase (so we can check their type tag to get the size). @@ -63,9 +63,9 @@ static inline void gc_heap_snapshot_record_module_edge(jl_module_t *from, jl_val _gc_heap_snapshot_record_module_edge(from, to, name); } } -static inline void gc_heap_snapshot_record_object_edge(jl_value_t *from, jl_value_t *to, void* slot) JL_NOTSAFEPOINT { +static inline void gc_heap_snapshot_record_object_edge(jl_value_t *from, jl_value_t *to, size_t field_index) JL_NOTSAFEPOINT { if (__unlikely(gc_heap_snapshot_enabled && prev_sweep_full)) { - _gc_heap_snapshot_record_object_edge(from, to, slot); + _gc_heap_snapshot_record_object_edge(from, to, field_index); } } static inline void gc_heap_snapshot_record_internal_edge(jl_value_t *from, jl_value_t *to) JL_NOTSAFEPOINT { diff --git a/src/gc.c b/src/gc.c index 48e0221a39d2d..09fd60f108d10 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1959,7 +1959,7 @@ STATIC_INLINE int gc_mark_scan_obj8(jl_ptls_t ptls, jl_gc_mark_sp_t *sp, gc_mark if (*pnew_obj) { verify_parent2("object", parent, slot, "field(%d)", gc_slot_to_fieldidx(parent, slot)); - gc_heap_snapshot_record_object_edge(parent, *slot, slot); + gc_heap_snapshot_record_object_edge(parent, *slot, gc_slot_to_fieldidx(parent, slot)); } if (!gc_try_setmark(*pnew_obj, &obj8->nptr, ptag, pbits)) continue; @@ -1995,7 +1995,7 @@ STATIC_INLINE int gc_mark_scan_obj16(jl_ptls_t ptls, jl_gc_mark_sp_t *sp, gc_mar verify_parent2("object", parent, slot, "field(%d)", gc_slot_to_fieldidx(parent, slot)); // TODO: Should this be *parent? Given the way it's used above? - gc_heap_snapshot_record_object_edge(parent, *slot, slot); + gc_heap_snapshot_record_object_edge(parent, *slot, gc_slot_to_fieldidx(parent, slot)); } if (!gc_try_setmark(*pnew_obj, &obj16->nptr, ptag, pbits)) continue; @@ -2030,7 +2030,7 @@ STATIC_INLINE int gc_mark_scan_obj32(jl_ptls_t ptls, jl_gc_mark_sp_t *sp, gc_mar if (*pnew_obj) { verify_parent2("object", parent, slot, "field(%d)", gc_slot_to_fieldidx(parent, slot)); - gc_heap_snapshot_record_object_edge(parent, *slot, slot); + gc_heap_snapshot_record_object_edge(parent, *slot, gc_slot_to_fieldidx(parent, slot)); } if (!gc_try_setmark(*pnew_obj, &obj32->nptr, ptag, pbits)) continue;