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,31 +190,33 @@ allocation_info_tracer_memsize(const void *ptr)
}
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;
if (allocated_object != rb_gc_location(allocated_object)) {
return ST_REPLACE;
st_table *table = (st_table *)data;
if (key != rb_gc_location(key)) {
DURING_GC_COULD_MALLOC_REGION_START();
{
st_insert(table, rb_gc_location(key), value);
}
DURING_GC_COULD_MALLOC_REGION_END();
return ST_DELETE;
}
return ST_CONTINUE;
}
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);
return ST_CONTINUE;
}
static void
allocation_info_tracer_compact(void *ptr)
{
struct traceobj_arg *trace_arg = (struct traceobj_arg *)ptr;
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");
}
}

View File

@ -287,6 +287,24 @@ class TestObjSpace < Test::Unit::TestCase
assert true # success
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
# Ensure that the fstring is promoted to old generation
4.times { GC.start }