diff options
Diffstat (limited to 'ext/objspace')
| -rw-r--r-- | ext/objspace/depend | 13 | ||||
| -rw-r--r-- | ext/objspace/object_tracing.c | 11 | ||||
| -rw-r--r-- | ext/objspace/objspace.c | 245 | ||||
| -rw-r--r-- | ext/objspace/objspace_dump.c | 150 |
4 files changed, 215 insertions, 204 deletions
diff --git a/ext/objspace/depend b/ext/objspace/depend index a02168b06a..d9dfc0c42b 100644 --- a/ext/objspace/depend +++ b/ext/objspace/depend @@ -140,6 +140,7 @@ object_tracing.o: $(hdrdir)/ruby/internal/intern/re.h object_tracing.o: $(hdrdir)/ruby/internal/intern/ruby.h object_tracing.o: $(hdrdir)/ruby/internal/intern/select.h object_tracing.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +object_tracing.o: $(hdrdir)/ruby/internal/intern/set.h object_tracing.o: $(hdrdir)/ruby/internal/intern/signal.h object_tracing.o: $(hdrdir)/ruby/internal/intern/sprintf.h object_tracing.o: $(hdrdir)/ruby/internal/intern/string.h @@ -177,14 +178,17 @@ object_tracing.o: $(top_srcdir)/ccan/check_type/check_type.h object_tracing.o: $(top_srcdir)/ccan/container_of/container_of.h object_tracing.o: $(top_srcdir)/ccan/list/list.h object_tracing.o: $(top_srcdir)/ccan/str/str.h +object_tracing.o: $(top_srcdir)/id_table.h object_tracing.o: $(top_srcdir)/internal.h object_tracing.o: $(top_srcdir)/internal/array.h object_tracing.o: $(top_srcdir)/internal/basic_operators.h +object_tracing.o: $(top_srcdir)/internal/box.h object_tracing.o: $(top_srcdir)/internal/compilers.h object_tracing.o: $(top_srcdir)/internal/gc.h object_tracing.o: $(top_srcdir)/internal/imemo.h object_tracing.o: $(top_srcdir)/internal/sanitizers.h object_tracing.o: $(top_srcdir)/internal/serial.h +object_tracing.o: $(top_srcdir)/internal/set_table.h object_tracing.o: $(top_srcdir)/internal/static_assert.h object_tracing.o: $(top_srcdir)/internal/vm.h object_tracing.o: $(top_srcdir)/internal/warnings.h @@ -340,6 +344,7 @@ objspace.o: $(hdrdir)/ruby/internal/intern/re.h objspace.o: $(hdrdir)/ruby/internal/intern/ruby.h objspace.o: $(hdrdir)/ruby/internal/intern/select.h objspace.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +objspace.o: $(hdrdir)/ruby/internal/intern/set.h objspace.o: $(hdrdir)/ruby/internal/intern/signal.h objspace.o: $(hdrdir)/ruby/internal/intern/sprintf.h objspace.o: $(hdrdir)/ruby/internal/intern/string.h @@ -386,6 +391,7 @@ objspace.o: $(top_srcdir)/id_table.h objspace.o: $(top_srcdir)/internal.h objspace.o: $(top_srcdir)/internal/array.h objspace.o: $(top_srcdir)/internal/basic_operators.h +objspace.o: $(top_srcdir)/internal/box.h objspace.o: $(top_srcdir)/internal/class.h objspace.o: $(top_srcdir)/internal/compilers.h objspace.o: $(top_srcdir)/internal/gc.h @@ -393,7 +399,9 @@ objspace.o: $(top_srcdir)/internal/hash.h objspace.o: $(top_srcdir)/internal/imemo.h objspace.o: $(top_srcdir)/internal/sanitizers.h objspace.o: $(top_srcdir)/internal/serial.h +objspace.o: $(top_srcdir)/internal/set_table.h objspace.o: $(top_srcdir)/internal/static_assert.h +objspace.o: $(top_srcdir)/internal/struct.h objspace.o: $(top_srcdir)/internal/variable.h objspace.o: $(top_srcdir)/internal/vm.h objspace.o: $(top_srcdir)/internal/warnings.h @@ -552,6 +560,7 @@ objspace_dump.o: $(hdrdir)/ruby/internal/intern/re.h objspace_dump.o: $(hdrdir)/ruby/internal/intern/ruby.h objspace_dump.o: $(hdrdir)/ruby/internal/intern/select.h objspace_dump.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +objspace_dump.o: $(hdrdir)/ruby/internal/intern/set.h objspace_dump.o: $(hdrdir)/ruby/internal/intern/signal.h objspace_dump.o: $(hdrdir)/ruby/internal/intern/sprintf.h objspace_dump.o: $(hdrdir)/ruby/internal/intern/string.h @@ -593,10 +602,12 @@ objspace_dump.o: $(top_srcdir)/ccan/list/list.h objspace_dump.o: $(top_srcdir)/ccan/str/str.h objspace_dump.o: $(top_srcdir)/constant.h objspace_dump.o: $(top_srcdir)/debug_counter.h +objspace_dump.o: $(top_srcdir)/encindex.h objspace_dump.o: $(top_srcdir)/id_table.h objspace_dump.o: $(top_srcdir)/internal.h objspace_dump.o: $(top_srcdir)/internal/array.h objspace_dump.o: $(top_srcdir)/internal/basic_operators.h +objspace_dump.o: $(top_srcdir)/internal/box.h objspace_dump.o: $(top_srcdir)/internal/class.h objspace_dump.o: $(top_srcdir)/internal/compilers.h objspace_dump.o: $(top_srcdir)/internal/gc.h @@ -605,8 +616,10 @@ objspace_dump.o: $(top_srcdir)/internal/imemo.h objspace_dump.o: $(top_srcdir)/internal/io.h objspace_dump.o: $(top_srcdir)/internal/sanitizers.h objspace_dump.o: $(top_srcdir)/internal/serial.h +objspace_dump.o: $(top_srcdir)/internal/set_table.h objspace_dump.o: $(top_srcdir)/internal/static_assert.h objspace_dump.o: $(top_srcdir)/internal/string.h +objspace_dump.o: $(top_srcdir)/internal/struct.h objspace_dump.o: $(top_srcdir)/internal/variable.h objspace_dump.o: $(top_srcdir)/internal/vm.h objspace_dump.o: $(top_srcdir)/internal/warnings.h diff --git a/ext/objspace/object_tracing.c b/ext/objspace/object_tracing.c index 0156642ef2..1c18bf02ee 100644 --- a/ext/objspace/object_tracing.c +++ b/ext/objspace/object_tracing.c @@ -91,7 +91,7 @@ newobj_i(VALUE tpval, void *data) VALUE klass = rb_tracearg_defined_class(tparg); struct allocation_info *info; const char *path_cstr = RTEST(path) ? make_unique_str(arg->str_table, RSTRING_PTR(path), RSTRING_LEN(path)) : 0; - VALUE class_path = (RTEST(klass) && !OBJ_FROZEN(klass)) ? rb_class_path_cached(klass) : Qnil; + VALUE class_path = (RTEST(klass) && !OBJ_FROZEN(klass)) ? rb_mod_name(klass) : Qnil; const char *class_path_cstr = RTEST(class_path) ? make_unique_str(arg->str_table, RSTRING_PTR(class_path), RSTRING_LEN(class_path)) : 0; st_data_t v; @@ -203,6 +203,8 @@ allocation_info_tracer_compact_update_object_table_i(st_data_t key, st_data_t va st_table *table = (st_table *)data; if (!rb_gc_pointer_to_heap_p(key)) { + struct allocation_info *info = (struct allocation_info *)value; + xfree(info); return ST_DELETE; } @@ -411,6 +413,13 @@ object_allocations_reporter(FILE *out, void *ptr) fprintf(out, "== object_allocations_reporter: END\n"); } +/* + * call-seq: trace_object_allocations_debug_start + * + * Starts tracing object allocations for GC debugging. + * If you encounter the BUG "... is T_NONE" (and so on) on your + * application, please try this method at the beginning of your app. + */ static VALUE trace_object_allocations_debug_start(VALUE self) { diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c index 0ead94713a..38bffb07f7 100644 --- a/ext/objspace/objspace.c +++ b/ext/objspace/objspace.c @@ -38,10 +38,11 @@ * information as only a *HINT*. Especially, the size of +T_DATA+ may not be * correct. * - * This method is only expected to work with C Ruby. + * This method is only expected to work with CRuby. * - * From Ruby 2.2, memsize_of(obj) returns a memory size includes - * sizeof(RVALUE). + * From Ruby 3.2 with Variable Width Allocation, it returns the actual slot + * size used plus any additional memory allocated outside the slot (such + * as external strings, arrays, or hash tables). */ static VALUE @@ -107,28 +108,24 @@ each_object_with_flags(each_obj_with_flags cb, void *ctx) /* * call-seq: - * ObjectSpace.memsize_of_all([klass]) -> Integer + * ObjectSpace.memsize_of_all(klass = nil) -> integer * - * Return consuming memory size of all living objects in bytes. + * Returns the total memory size of all living objects in bytes. * - * If +klass+ (should be Class object) is given, return the total memory size - * of instances of the given class. + * ObjectSpace.memsize_of_all # => 12502001 * - * Note that the returned size is incomplete. You need to deal with this - * information as only a *HINT*. Especially, the size of +T_DATA+ may not be - * correct. + * If +klass+ is given (which must be a Class or Module), returns the total + * memory size of objects whose class is, or is a subclass, of +klass+. * - * Note that this method does *NOT* return total malloc'ed memory size. + * class MyClass; end + * ObjectSpace.memsize_of_all(MyClass) # => 0 + * o = MyClass.new + * ObjectSpace.memsize_of_all(MyClass) # => 40 * - * This method can be defined by the following Ruby code: - * - * def memsize_of_all klass = false - * total = 0 - * ObjectSpace.each_object{|e| - * total += ObjectSpace.memsize_of(e) if klass == false || e.kind_of?(klass) - * } - * total - * end + * Note that the value returned may be an underestimate of the actual amount + * of memory used. Therefore, the value returned should only be used as a hint, + * rather than a source of truth. In particular, the size of +T_DATA+ objects may + * not be correct. * * This method is only expected to work with C Ruby. */ @@ -140,6 +137,7 @@ memsize_of_all_m(int argc, VALUE *argv, VALUE self) if (argc > 0) { rb_scan_args(argc, argv, "01", &data.klass); + if (!NIL_P(data.klass)) rb_obj_is_kind_of(Qnil, data.klass); } each_object_with_flags(total_i, &data); @@ -223,23 +221,26 @@ type2sym(enum ruby_value_type i) /* * call-seq: - * ObjectSpace.count_objects_size([result_hash]) -> hash + * ObjectSpace.count_objects_size(result_hash = {}) -> result_hash * * Counts objects size (in bytes) for each type. * - * Note that this information is incomplete. You need to deal with - * this information as only a *HINT*. Especially, total size of - * T_DATA may be wrong. + * Note that the returned size may not be accurate, so it should only + * be used as a hint. Specifically, the size for +T_DATA+ may be + * inaccurate because these are custom objects defined in Ruby and + * native extensions and so they may not accurately report their + * memory size. * - * It returns a hash as: - * {:TOTAL=>1461154, :T_CLASS=>158280, :T_MODULE=>20672, :T_STRING=>527249, ...} + * It returns a hash that looks like: * - * If the optional argument, result_hash, is given, - * it is overwritten and returned. - * This is intended to avoid probe effect. + * {TOTAL: 1461154, T_CLASS: 158280, T_MODULE: 20672, T_STRING: 527249, ...} * - * The contents of the returned hash is implementation defined. - * It may be changed in future. + * The contents of the returned hash are implementation specific and + * may be changed in future versions without notice. + * + * If the optional argument, +result_hash+, is given, + * it is overwritten and returned. + * This is intended to avoid the probe effect. * * This method is only expected to work with C Ruby. */ @@ -294,28 +295,27 @@ size_t rb_sym_immortal_count(void); /* * call-seq: - * ObjectSpace.count_symbols([result_hash]) -> hash + * ObjectSpace.count_symbols(result_hash = nil) -> hash * - * Counts symbols for each Symbol type. + * Returns a hash containing the number of objects for each Symbol type. * - * This method is only for MRI developers interested in performance and memory - * usage of Ruby programs. + * The types of Symbols are the following: * - * If the optional argument, result_hash, is given, it is overwritten and - * returned. This is intended to avoid probe effect. + * - +mortal_dynamic_symbol+: Symbols that are garbage collectable. + * - +immortal_dynamic_symbol+: Symbols that are objects allocated from the + * garbage collector, but are not garbage collectable. + * - +immortal_static_symbol+: Symbols that are not allocated from the + * garbage collector, and are thus not garbage collectable. + * - +immortal_symbol+: the sum of +immortal_dynamic_symbol+ and +immortal_static_symbol+. * - * Note: - * The contents of the returned hash is implementation defined. - * It may be changed in future. + * If the optional argument +result_hash+ is given, it is overwritten and + * returned. This is intended to avoid the probe effect. * - * This method is only expected to work with C Ruby. + * This method is intended for developers interested in performance and memory + * usage of Ruby programs. The contents of the returned hash is implementation + * specific and may change in the future. * - * On this version of MRI, they have 3 types of Symbols (and 1 total counts). - * - * * mortal_dynamic_symbol: GC target symbols (collected by GC) - * * immortal_dynamic_symbol: Immortal symbols promoted from dynamic symbols (do not collected by GC) - * * immortal_static_symbol: Immortal symbols (do not collected by GC) - * * immortal_symbol: total immortal symbols (immortal_dynamic_symbol+immortal_static_symbol) + * This method is only expected to work with C Ruby. */ static VALUE @@ -335,35 +335,6 @@ count_symbols(int argc, VALUE *argv, VALUE os) return hash; } -/* - * call-seq: - * ObjectSpace.count_nodes([result_hash]) -> hash - * - * Counts nodes for each node type. - * - * This method is only for MRI developers interested in performance and memory - * usage of Ruby programs. - * - * It returns a hash as: - * - * {:NODE_METHOD=>2027, :NODE_FBODY=>1927, :NODE_CFUNC=>1798, ...} - * - * If the optional argument, result_hash, is given, it is overwritten and - * returned. This is intended to avoid probe effect. - * - * Note: - * The contents of the returned hash is implementation defined. - * It may be changed in future. - * - * This method is only expected to work with C Ruby. - */ - -static VALUE -count_nodes(int argc, VALUE *argv, VALUE os) -{ - return setup_hash(argc, argv); -} - static void cto_i(VALUE v, void *data) { @@ -393,32 +364,22 @@ cto_i(VALUE v, void *data) /* * call-seq: - * ObjectSpace.count_tdata_objects([result_hash]) -> hash - * - * Counts objects for each +T_DATA+ type. - * - * This method is only for MRI developers interested in performance and memory - * usage of Ruby programs. - * - * It returns a hash as: + * ObjectSpace.count_tdata_objects(result_hash = nil) -> hash * - * {RubyVM::InstructionSequence=>504, :parser=>5, :barrier=>6, - * :mutex=>6, Proc=>60, RubyVM::Env=>57, Mutex=>1, Encoding=>99, - * ThreadGroup=>1, Binding=>1, Thread=>1, RubyVM=>1, :iseq=>1, - * Random=>1, ARGF.class=>1, Data=>1, :autoload=>3, Time=>2} - * # T_DATA objects existing at startup on r32276. + * Returns a hash containing the number of objects for each +T_DATA+ type. + * The keys are Class objects when the +T_DATA+ object has an associated class, + * or Symbol objects of the name defined in the +rb_data_type_struct+ for internal + * +T_DATA+ objects. * - * If the optional argument, result_hash, is given, it is overwritten and - * returned. This is intended to avoid probe effect. + * ObjectSpace.count_tdata_objects + * # => {RBS::Location => 39255, marshal_compat_table: 1, Encoding => 103, mutex: 1, ... } * - * The contents of the returned hash is implementation specific and may change - * in the future. + * If the optional argument +result_hash+ is given, it is overwritten and + * returned. This is intended to avoid the probe effect. * - * In this version, keys are Class object or Symbol object. - * - * If object is kind of normal (accessible) object, the key is Class object. - * If object is not a kind of normal (internal) object, the key is symbol - * name, registered by rb_data_type_struct. + * This method is intended for developers interested in performance and memory + * usage of Ruby programs. The contents of the returned hash is implementation + * specific and may change in the future. * * This method is only expected to work with C Ruby. */ @@ -457,28 +418,22 @@ count_imemo_objects_i(VALUE v, void *data) /* * call-seq: - * ObjectSpace.count_imemo_objects([result_hash]) -> hash - * - * Counts objects for each +T_IMEMO+ type. - * - * This method is only for MRI developers interested in performance and memory - * usage of Ruby programs. + * ObjectSpace.count_imemo_objects(result_hash = nil) -> hash * - * It returns a hash as: + * Returns a hash containing the number of objects for each +T_IMEMO+ type. + * The keys are Symbol objects of the +T_IMEMO+ type name. + * +T_IMEMO+ objects are Ruby internal objects that are not visible to Ruby + * programs. * - * {:imemo_ifunc=>8, - * :imemo_svar=>7, - * :imemo_cref=>509, - * :imemo_memo=>1, - * :imemo_throw_data=>1} + * ObjectSpace.count_imemo_objects + * # => {imemo_callcache: 5482, imemo_constcache: 1258, imemo_ment: 13906, ... } * - * If the optional argument, result_hash, is given, it is overwritten and - * returned. This is intended to avoid probe effect. + * If the optional argument +result_hash+ is given, it is overwritten and + * returned. This is intended to avoid the probe effect. * - * The contents of the returned hash is implementation specific and may change - * in the future. - * - * In this version, keys are symbol objects. + * This method is intended for developers interested in performance and memory + * usage of Ruby programs. The contents of the returned hash is implementation + * specific and may change in the future. * * This method is only expected to work with C Ruby. */ @@ -499,11 +454,13 @@ count_imemo_objects(int argc, VALUE *argv, VALUE self) INIT_IMEMO_TYPE_ID(imemo_ment); INIT_IMEMO_TYPE_ID(imemo_iseq); INIT_IMEMO_TYPE_ID(imemo_tmpbuf); - INIT_IMEMO_TYPE_ID(imemo_ast); - INIT_IMEMO_TYPE_ID(imemo_parser_strterm); + INIT_IMEMO_TYPE_ID(imemo_cvar_entry); INIT_IMEMO_TYPE_ID(imemo_callinfo); INIT_IMEMO_TYPE_ID(imemo_callcache); INIT_IMEMO_TYPE_ID(imemo_constcache); + INIT_IMEMO_TYPE_ID(imemo_fields); + INIT_IMEMO_TYPE_ID(imemo_subclasses); + INIT_IMEMO_TYPE_ID(imemo_cdhash); #undef INIT_IMEMO_TYPE_ID } @@ -602,42 +559,37 @@ collect_values(st_data_t key, st_data_t value, st_data_t data) * call-seq: * ObjectSpace.reachable_objects_from(obj) -> array or nil * - * [MRI specific feature] Return all reachable objects from `obj'. + * Returns all reachable objects from +obj+ as an array: * - * This method returns all reachable objects from `obj'. + * ObjectSpace.reachable_objects_from(['a', 'b', 'c']) + * #=> [Array, 'a', 'b', 'c'] * - * If `obj' has two or more references to the same object `x', then returned - * array only includes one `x' object. + * The returned array is deduplicated, meaning that if +obj+ refers + * to another object more than once, it will only be added to the array + * once: * - * If `obj' is a non-markable (non-heap management) object such as true, - * false, nil, symbols and Fixnums (and Flonum) then it simply returns nil. + * ObjectSpace.reachable_objects_from([v = 'a', v, v]) + * #=> [Array, 'a'] * - * If `obj' has references to an internal object, then it returns instances of - * ObjectSpace::InternalObjectWrapper class. This object contains a reference - * to an internal object and you can check the type of internal object with - * `type' method. + * Returns +nil+ if +obj+ is not a markable object (i.e. non-heap + * managed) object. Non-markable objects include +true+, +false+, + * +nil+, certain symbols, small integers, and floats: * - * If `obj' is instance of ObjectSpace::InternalObjectWrapper class, then this - * method returns all reachable object from an internal object, which is - * pointed by `obj'. + * ObjectSpace.reachable_objects_from(1) + * #=> nil * - * With this method, you can find memory leaks. + * All references to internal objects in the returned array are wrapped + * using ObjectSpace::InternalObjectWrapper objects. This object contains + * a reference to the internal object and the type of the object can + * be accessed using the ObjectSpace::InternalObjectWrapper#type method. * - * This method is only expected to work with C Ruby. + * If +obj+ is instance of ObjectSpace::InternalObjectWrapper, then this + * method returns all reachable object from the internal object. * - * Example: - * ObjectSpace.reachable_objects_from(['a', 'b', 'c']) - * #=> [Array, 'a', 'b', 'c'] - * - * ObjectSpace.reachable_objects_from(['a', 'a', 'a']) - * #=> [Array, 'a', 'a', 'a'] # all 'a' strings have different object id - * - * ObjectSpace.reachable_objects_from([v = 'a', v, v]) - * #=> [Array, 'a'] - * - * ObjectSpace.reachable_objects_from(1) - * #=> nil # 1 is not markable (heap managed) object + * This method is useful for debugging purposes, such as finding + * memory leaks. * + * This method is only expected to work with C Ruby. */ static VALUE @@ -792,7 +744,7 @@ objspace_internal_super_of(VALUE self, VALUE obj) case T_MODULE: case T_CLASS: case T_ICLASS: - super = RCLASS_SUPER(obj); + super = rb_class_super_of(obj); break; default: rb_raise(rb_eArgError, "class or module is expected"); @@ -834,7 +786,6 @@ Init_objspace(void) rb_define_module_function(rb_mObjSpace, "count_objects_size", count_objects_size, -1); rb_define_module_function(rb_mObjSpace, "count_symbols", count_symbols, -1); - rb_define_module_function(rb_mObjSpace, "count_nodes", count_nodes, -1); rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1); rb_define_module_function(rb_mObjSpace, "count_imemo_objects", count_imemo_objects, -1); diff --git a/ext/objspace/objspace_dump.c b/ext/objspace/objspace_dump.c index 139612526f..68ada01af3 100644 --- a/ext/objspace/objspace_dump.c +++ b/ext/objspace/objspace_dump.c @@ -29,7 +29,7 @@ #include "ruby/util.h" #include "ruby/io.h" #include "vm_callinfo.h" -#include "vm_core.h" +#include "vm_sync.h" RUBY_EXTERN const char ruby_hexdigits[]; @@ -394,9 +394,10 @@ dump_object(VALUE obj, struct dump_config *dc) dc->cur_obj = obj; dc->cur_obj_references = 0; - if (BUILTIN_TYPE(obj) == T_NODE || BUILTIN_TYPE(obj) == T_IMEMO) { + if (BUILTIN_TYPE(obj) == T_NODE || (BUILTIN_TYPE(obj) == T_IMEMO && !IMEMO_TYPE_P(obj, imemo_fields))) { dc->cur_obj_klass = 0; - } else { + } + else { dc->cur_obj_klass = RBASIC_CLASS(obj); } @@ -414,9 +415,11 @@ dump_object(VALUE obj, struct dump_config *dc) dump_append(dc, obj_type(obj)); dump_append(dc, "\""); - size_t shape_id = rb_shape_get_shape_id(obj); - dump_append(dc, ", \"shape_id\":"); - dump_append_sizet(dc, shape_id); + if (BUILTIN_TYPE(obj) != T_IMEMO || IMEMO_TYPE_P(obj, imemo_fields)) { + size_t shape_id = rb_obj_shape_id(obj) & SHAPE_ID_OFFSET_MASK; + dump_append(dc, ", \"shape_id\":"); + dump_append_sizet(dc, shape_id); + } dump_append(dc, ", \"slot_size\":"); dump_append_sizet(dc, dc->cur_page_slot_size); @@ -448,13 +451,16 @@ dump_object(VALUE obj, struct dump_config *dc) break; case imemo_callcache: - mid = vm_cc_cme((const struct rb_callcache *)obj)->called_id; - if (mid != 0) { - dump_append(dc, ", \"called_id\":"); - dump_append_id(dc, mid); - + { VALUE klass = ((const struct rb_callcache *)obj)->klass; - if (klass != 0) { + if (klass != Qundef) { + mid = vm_cc_cme((const struct rb_callcache *)obj)->called_id; + if (mid != 0) { + dump_append(dc, ", \"called_id\":"); + dump_append_id(dc, mid); + + } + dump_append(dc, ", \"receiver_class\":"); dump_append_ref(dc, klass); } @@ -537,7 +543,7 @@ dump_object(VALUE obj, struct dump_config *dc) case T_CLASS: dump_append(dc, ", \"variation_count\":"); - dump_append_d(dc, RCLASS_EXT(obj)->variation_count); + dump_append_d(dc, rb_class_variation_count(obj)); case T_MODULE: if (rb_class_get_superclass(obj)) { @@ -560,17 +566,22 @@ dump_object(VALUE obj, struct dump_config *dc) } } - if (RCLASS_SINGLETON_P(obj)) { + if (rb_class_singleton_p(obj)) { dump_append(dc, ", \"singleton\":true"); } } break; case T_DATA: - if (RTYPEDDATA_P(obj)) { + { + const rb_data_type_t *type = RTYPEDDATA_TYPE(obj); dump_append(dc, ", \"struct\":\""); - dump_append(dc, RTYPEDDATA_TYPE(obj)->wrap_struct_name); + dump_append(dc, type->wrap_struct_name); dump_append(dc, "\""); + if (!(type->flags & RUBY_TYPED_FREE_IMMEDIATELY) && + type->function.dfree != RUBY_DEFAULT_FREE) { + dump_append(dc, ", \"free_immediately\":false"); + } } break; @@ -581,14 +592,14 @@ dump_object(VALUE obj, struct dump_config *dc) break; case T_OBJECT: - if (FL_TEST(obj, ROBJECT_EMBED)) { + if (!FL_TEST_RAW(obj, ROBJECT_HEAP)) { dump_append(dc, ", \"embedded\":true"); } dump_append(dc, ", \"ivars\":"); - dump_append_lu(dc, ROBJECT_IV_COUNT(obj)); - if (rb_shape_obj_too_complex(obj)) { - dump_append(dc, ", \"too_complex_shape\":true"); + dump_append_lu(dc, ROBJECT_FIELDS_COUNT(obj)); + if (rb_obj_shape_complex_p(obj)) { + dump_append(dc, ", \"complex_shape\":true"); } break; @@ -636,11 +647,6 @@ dump_object(VALUE obj, struct dump_config *dc) dump_append_sizet(dc, memsize); } - if (FL_TEST(obj, FL_SEEN_OBJ_ID)) { - dump_append(dc, ", \"object_id\":"); - dump_append_lu(dc, RB_NUM2ULONG(rb_obj_id(obj))); - } - struct rb_gc_object_metadata_entry *gc_metadata = rb_gc_object_metadata(obj); for (int i = 0; gc_metadata[i].name != 0; i++) { if (i == 0) { @@ -770,15 +776,16 @@ dump_result(struct dump_config *dc) return dc->given_output; } -/* :nodoc: */ static VALUE -objspace_dump(VALUE os, VALUE obj, VALUE output) +dump_locked(void *args_p) { struct dump_config dc = {0,}; + VALUE obj = ((VALUE*)args_p)[0]; + VALUE output = ((VALUE*)args_p)[1]; + if (!RB_SPECIAL_CONST_P(obj)) { dc.cur_page_slot_size = rb_gc_obj_slot_size(obj); } - dump_output(&dc, output, Qnil, Qnil, Qnil); dump_object(obj, &dc); @@ -786,69 +793,73 @@ objspace_dump(VALUE os, VALUE obj, VALUE output) return dump_result(&dc); } +/* :nodoc: */ +static VALUE +objspace_dump(VALUE os, VALUE obj, VALUE output) +{ + VALUE args[2]; + args[0] = obj; + args[1] = output; + return rb_vm_lock_with_barrier(dump_locked, (void*)args); +} + static void -shape_i(rb_shape_t *shape, void *data) +shape_id_i(shape_id_t shape_id, void *data) { struct dump_config *dc = (struct dump_config *)data; - size_t shape_id = rb_shape_id(shape); if (shape_id < dc->shapes_since) { return; } dump_append(dc, "{\"address\":"); - dump_append_ref(dc, (VALUE)shape); + dump_append_ref(dc, (VALUE)RSHAPE(shape_id)); dump_append(dc, ", \"type\":\"SHAPE\", \"id\":"); dump_append_sizet(dc, shape_id); - if (shape->type != SHAPE_ROOT) { + if (RSHAPE_TYPE(shape_id) != SHAPE_ROOT) { dump_append(dc, ", \"parent_id\":"); - dump_append_lu(dc, shape->parent_id); + dump_append_lu(dc, RSHAPE_PARENT_OFFSET(shape_id)); } dump_append(dc, ", \"depth\":"); - dump_append_sizet(dc, rb_shape_depth(shape)); + dump_append_sizet(dc, rb_shape_depth(shape_id)); - dump_append(dc, ", \"shape_type\":"); - switch((enum shape_type)shape->type) { + switch (RSHAPE_TYPE(shape_id)) { case SHAPE_ROOT: - dump_append(dc, "\"ROOT\""); + dump_append(dc, ", \"shape_type\":\"ROOT\""); break; case SHAPE_IVAR: - dump_append(dc, "\"IVAR\""); + dump_append(dc, ", \"shape_type\":\"IVAR\""); dump_append(dc, ",\"edge_name\":"); - dump_append_id(dc, shape->edge_name); + dump_append_id(dc, RSHAPE_EDGE_NAME(shape_id)); break; - case SHAPE_FROZEN: - dump_append(dc, "\"FROZEN\""); - break; - case SHAPE_T_OBJECT: - dump_append(dc, "\"T_OBJECT\""); - break; - case SHAPE_OBJ_TOO_COMPLEX: - dump_append(dc, "\"OBJ_TOO_COMPLEX\""); + case SHAPE_OBJ_ID: + dump_append(dc, ", \"shape_type\":\"OBJ_ID\""); break; - default: - rb_bug("[objspace] unexpected shape type"); } dump_append(dc, ", \"edges\":"); - dump_append_sizet(dc, rb_shape_edges_count(shape)); + dump_append_sizet(dc, rb_shape_edges_count(shape_id)); dump_append(dc, ", \"memsize\":"); - dump_append_sizet(dc, rb_shape_memsize(shape)); + dump_append_sizet(dc, rb_shape_memsize(shape_id)); dump_append(dc, "}\n"); } -/* :nodoc: */ static VALUE -objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes) +dump_all_locked(void *args_p) { struct dump_config dc = {0,}; + VALUE output = ((VALUE*)args_p)[0]; + VALUE full = ((VALUE*)args_p)[1]; + VALUE since = ((VALUE*)args_p)[2]; + VALUE shapes = ((VALUE*)args_p)[3]; + dump_output(&dc, output, full, since, shapes); if (!dc.partial_dump || dc.since == 0) { @@ -858,7 +869,7 @@ objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes) } if (RTEST(shapes)) { - rb_shape_each_shape(shape_i, &dc); + rb_shape_each_shape_id(shape_id_i, &dc); } /* dump all objects */ @@ -869,17 +880,41 @@ objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes) /* :nodoc: */ static VALUE -objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes) +objspace_dump_all(VALUE os, VALUE output, VALUE full, VALUE since, VALUE shapes) +{ + VALUE args[4]; + args[0] = output; + args[1] = full; + args[2] = since; + args[3] = shapes; + return rb_vm_lock_with_barrier(dump_all_locked, (void*)args); +} + +static VALUE +dump_shapes_locked(void *args_p) { struct dump_config dc = {0,}; + VALUE output = ((VALUE*)args_p)[0]; + VALUE shapes = ((VALUE*)args_p)[1]; + dump_output(&dc, output, Qfalse, Qnil, shapes); if (RTEST(shapes)) { - rb_shape_each_shape(shape_i, &dc); + rb_shape_each_shape_id(shape_id_i, &dc); } return dump_result(&dc); } +/* :nodoc: */ +static VALUE +objspace_dump_shapes(VALUE os, VALUE output, VALUE shapes) +{ + VALUE args[2]; + args[0] = output; + args[1] = shapes; + return rb_vm_lock_with_barrier(dump_shapes_locked, (void*)args); +} + void Init_objspace_dump(VALUE rb_mObjSpace) { @@ -887,6 +922,9 @@ Init_objspace_dump(VALUE rb_mObjSpace) #if 0 rb_mObjSpace = rb_define_module("ObjectSpace"); /* let rdoc know */ #endif +#ifdef HAVE_RB_EXT_RACTOR_SAFE + RB_EXT_RACTOR_SAFE(true); +#endif rb_define_module_function(rb_mObjSpace, "_dump", objspace_dump, 2); rb_define_module_function(rb_mObjSpace, "_dump_all", objspace_dump_all, 4); |
