summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/objspace/objspace_dump.c9
-rw-r--r--gc.h2
-rw-r--r--test/objspace/test_objspace.rb28
3 files changed, 39 insertions, 0 deletions
diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c
index cf7acb5c6f..e958a831c5 100644
--- a/ext/objspace/objspace_dump.c
+++ b/ext/objspace/objspace_dump.c
@@ -35,6 +35,7 @@ struct dump_config {
const char *root_category;
VALUE cur_obj;
VALUE cur_obj_klass;
+ size_t cur_page_slot_size;
size_t cur_obj_references;
unsigned int roots: 1;
unsigned int full_heap: 1;
@@ -360,6 +361,9 @@ dump_object(VALUE obj, struct dump_config *dc)
dump_append(dc, obj_type(obj));
dump_append(dc, "\"");
+ dump_append(dc, ", \"slot_size\":");
+ dump_append_sizet(dc, dc->cur_page_slot_size);
+
if (dc->cur_obj_klass) {
dump_append(dc, ", \"class\":");
dump_append_ref(dc, dc->cur_obj_klass);
@@ -539,6 +543,7 @@ heap_i(void *vstart, void *vend, size_t stride, void *data)
for (; v != (VALUE)vend; v += stride) {
void *ptr = asan_poisoned_object_p(v);
asan_unpoison_object(v, false);
+ dc->cur_page_slot_size = stride;
if (dc->full_heap || RBASIC(v)->flags)
dump_object(v, dc);
@@ -616,6 +621,10 @@ static VALUE
objspace_dump(VALUE os, VALUE obj, VALUE output)
{
struct dump_config dc = {0,};
+ if (!RB_SPECIAL_CONST_P(obj)) {
+ dc.cur_page_slot_size = rb_gc_obj_slot_size(obj);
+ }
+
dump_output(&dc, output, Qnil, Qnil);
dump_object(obj, &dc);
diff --git a/gc.h b/gc.h
index 91d6e5787d..84c8eade63 100644
--- a/gc.h
+++ b/gc.h
@@ -136,6 +136,8 @@ void rb_objspace_each_objects_without_setup(
int (*callback)(void *, void *, size_t, void *),
void *data);
+size_t rb_gc_obj_slot_size(VALUE obj);
+
RUBY_SYMBOL_EXPORT_END
#endif /* RUBY_GC_H */
diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb
index b7342e899b..34d9dd76ec 100644
--- a/test/objspace/test_objspace.rb
+++ b/test/objspace/test_objspace.rb
@@ -431,6 +431,27 @@ class TestObjSpace < Test::Unit::TestCase
end
end
+ def test_dump_objects_dumps_page_slot_sizes
+ assert_in_out_err(%w[-robjspace], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error|
+ begin;
+ def dump_my_heap_please
+ ObjectSpace.dump_all(output: $stdout)
+ end
+
+ p $stdout == dump_my_heap_please
+ end;
+ assert_equal 'true', output.pop
+ assert(output.count > 1)
+ output.each { |l|
+ obj = JSON.parse(l)
+ next if obj["type"] == "ROOT"
+
+ assert(obj["slot_size"] != nil)
+ assert(obj["slot_size"] % GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] == 0)
+ }
+ end
+ end
+
def test_dump_escapes_method_name
method_name = "foo\"bar"
klass = Class.new do
@@ -449,6 +470,13 @@ class TestObjSpace < Test::Unit::TestCase
ObjectSpace.trace_object_allocations_stop
end
+ def test_dump_includes_slot_size
+ str = "TEST"
+ dump = ObjectSpace.dump(str)
+
+ assert_includes dump, "\"slot_size\":#{GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]}"
+ end
+
def test_dump_reference_addresses_match_dump_all_addresses
assert_in_out_err(%w[-robjspace], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error|
begin;