Fix ObjectSpace.trace_object_allocations for compaction

We need to reinsert into the ST table when an object moves because it is
a numtable that hashes on the object address, so when an object moves we
need to reinsert it rather than just updating the key.
This commit is contained in:
Peter Zhu 2024-12-13 12:20:30 -05:00
parent b038530506
commit 15765eac0a
Notes: git 2024-12-16 15:13:13 +00:00
2 changed files with 33 additions and 13 deletions

View File

@ -190,20 +190,19 @@ allocation_info_tracer_memsize(const void *ptr)
} }
static int static int
hash_foreach_should_replace_key(st_data_t key, st_data_t value, st_data_t argp, int error) allocation_info_tracer_compact_update_object_table_i(st_data_t key, st_data_t value, st_data_t data)
{ {
VALUE allocated_object = (VALUE)key; st_table *table = (st_table *)data;
if (allocated_object != rb_gc_location(allocated_object)) {
return ST_REPLACE;
}
return ST_CONTINUE; if (key != rb_gc_location(key)) {
} DURING_GC_COULD_MALLOC_REGION_START();
static int
hash_replace_key(st_data_t *key, st_data_t *value, st_data_t argp, int existing)
{ {
*key = rb_gc_location((VALUE)*key); st_insert(table, rb_gc_location(key), value);
}
DURING_GC_COULD_MALLOC_REGION_END();
return ST_DELETE;
}
return ST_CONTINUE; return ST_CONTINUE;
} }
@ -214,7 +213,10 @@ allocation_info_tracer_compact(void *ptr)
struct traceobj_arg *trace_arg = (struct traceobj_arg *)ptr; struct traceobj_arg *trace_arg = (struct traceobj_arg *)ptr;
if (trace_arg->object_table && if (trace_arg->object_table &&
st_foreach_with_replace(trace_arg->object_table, hash_foreach_should_replace_key, hash_replace_key, 0)) { st_foreach(
trace_arg->object_table,
allocation_info_tracer_compact_update_object_table_i,
(st_data_t)trace_arg->object_table)) {
rb_raise(rb_eRuntimeError, "hash modified during iteration"); rb_raise(rb_eRuntimeError, "hash modified during iteration");
} }
} }

View File

@ -287,6 +287,24 @@ class TestObjSpace < Test::Unit::TestCase
assert true # success assert true # success
end end
def test_trace_object_allocations_compaction
omit "compaction is not supported on this platform" unless GC.respond_to?(:compact)
assert_separately(%w(-robjspace), <<~RUBY)
ObjectSpace.trace_object_allocations do
objs = 100.times.map do
Object.new
end
assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(objs[0]))
GC.verify_compaction_references(expand_heap: true, toward: :empty)
assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(objs[0]))
end
RUBY
end
def test_dump_flags def test_dump_flags
# Ensure that the fstring is promoted to old generation # Ensure that the fstring is promoted to old generation
4.times { GC.start } 4.times { GC.start }