summaryrefslogtreecommitdiff
path: root/ext/objspace/objspace.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/objspace/objspace.c')
-rw-r--r--ext/objspace/objspace.c326
1 files changed, 67 insertions, 259 deletions
diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c
index 31099b8849..457ffc2789 100644
--- a/ext/objspace/objspace.c
+++ b/ext/objspace/objspace.c
@@ -12,14 +12,13 @@
**********************************************************************/
-#include "gc.h"
#include "internal.h"
#include "internal/class.h"
#include "internal/compilers.h"
+#include "internal/gc.h"
#include "internal/hash.h"
#include "internal/imemo.h"
#include "internal/sanitizers.h"
-#include "node.h"
#include "ruby/io.h"
#include "ruby/re.h"
#include "ruby/st.h"
@@ -39,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
@@ -82,15 +82,15 @@ heap_iter(void *vstart, void *vend, size_t stride, void *ptr)
VALUE v;
for (v = (VALUE)vstart; v != (VALUE)vend; v += stride) {
- void *poisoned = asan_poisoned_object_p(v);
- asan_unpoison_object(v, false);
+ void *poisoned = rb_asan_poisoned_object_p(v);
+ rb_asan_unpoison_object(v, false);
if (RBASIC(v)->flags) {
(*ctx->cb)(v, ctx->data);
}
if (poisoned) {
- asan_poison_object(v);
+ rb_asan_poison_object(v);
}
}
@@ -108,28 +108,24 @@ each_object_with_flags(each_obj_with_flags cb, void *ctx)
/*
* call-seq:
- * ObjectSpace.memsize_of_all([klass]) -> Integer
- *
- * Return consuming memory size of all living objects in bytes.
+ * ObjectSpace.memsize_of_all(klass = nil) -> integer
*
- * If +klass+ (should be Class object) is given, return the total memory size
- * of instances of the given class.
+ * Returns the total memory size of all living objects in bytes.
*
- * 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.
+ * ObjectSpace.memsize_of_all # => 12502001
*
- * Note that this method does *NOT* return total malloc'ed memory size.
+ * 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+.
*
- * This method can be defined by the following Ruby code:
+ * class MyClass; end
+ * ObjectSpace.memsize_of_all(MyClass) # => 0
+ * o = MyClass.new
+ * ObjectSpace.memsize_of_all(MyClass) # => 40
*
- * 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.
*/
@@ -170,8 +166,7 @@ setup_hash(int argc, VALUE *argv)
hash = rb_hash_new();
}
else if (!RHASH_EMPTY_P(hash)) {
- /* WB: no new reference */
- st_foreach(RHASH_TBL_RAW(hash), set_zero_i, hash);
+ rb_hash_foreach(hash, set_zero_i, (st_data_t)hash);
}
return hash;
@@ -296,28 +291,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
@@ -338,174 +332,6 @@ count_symbols(int argc, VALUE *argv, VALUE os)
}
static void
-cn_i(VALUE v, void *n)
-{
- size_t *nodes = (size_t *)n;
-
- if (BUILTIN_TYPE(v) == T_NODE) {
- size_t s = nd_type((NODE *)v);
- nodes[s]++;
- }
-}
-
-/*
- * 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)
-{
- size_t nodes[NODE_LAST+1];
- enum node_type i;
- VALUE hash = setup_hash(argc, argv);
-
- for (i = 0; i <= NODE_LAST; i++) {
- nodes[i] = 0;
- }
-
- each_object_with_flags(cn_i, &nodes[0]);
-
- for (i=0; i<NODE_LAST; i++) {
- if (nodes[i] != 0) {
- VALUE node;
- switch (i) {
-#define COUNT_NODE(n) case n: node = ID2SYM(rb_intern(#n)); goto set
- COUNT_NODE(NODE_SCOPE);
- COUNT_NODE(NODE_BLOCK);
- COUNT_NODE(NODE_IF);
- COUNT_NODE(NODE_UNLESS);
- COUNT_NODE(NODE_CASE);
- COUNT_NODE(NODE_CASE2);
- COUNT_NODE(NODE_CASE3);
- COUNT_NODE(NODE_WHEN);
- COUNT_NODE(NODE_IN);
- COUNT_NODE(NODE_WHILE);
- COUNT_NODE(NODE_UNTIL);
- COUNT_NODE(NODE_ITER);
- COUNT_NODE(NODE_FOR);
- COUNT_NODE(NODE_FOR_MASGN);
- COUNT_NODE(NODE_BREAK);
- COUNT_NODE(NODE_NEXT);
- COUNT_NODE(NODE_REDO);
- COUNT_NODE(NODE_RETRY);
- COUNT_NODE(NODE_BEGIN);
- COUNT_NODE(NODE_RESCUE);
- COUNT_NODE(NODE_RESBODY);
- COUNT_NODE(NODE_ENSURE);
- COUNT_NODE(NODE_AND);
- COUNT_NODE(NODE_OR);
- COUNT_NODE(NODE_MASGN);
- COUNT_NODE(NODE_LASGN);
- COUNT_NODE(NODE_DASGN);
- COUNT_NODE(NODE_GASGN);
- COUNT_NODE(NODE_IASGN);
- COUNT_NODE(NODE_CDECL);
- COUNT_NODE(NODE_CVASGN);
- COUNT_NODE(NODE_OP_ASGN1);
- COUNT_NODE(NODE_OP_ASGN2);
- COUNT_NODE(NODE_OP_ASGN_AND);
- COUNT_NODE(NODE_OP_ASGN_OR);
- COUNT_NODE(NODE_OP_CDECL);
- COUNT_NODE(NODE_CALL);
- COUNT_NODE(NODE_OPCALL);
- COUNT_NODE(NODE_FCALL);
- COUNT_NODE(NODE_VCALL);
- COUNT_NODE(NODE_QCALL);
- COUNT_NODE(NODE_SUPER);
- COUNT_NODE(NODE_ZSUPER);
- COUNT_NODE(NODE_LIST);
- COUNT_NODE(NODE_ZLIST);
- COUNT_NODE(NODE_VALUES);
- COUNT_NODE(NODE_HASH);
- COUNT_NODE(NODE_RETURN);
- COUNT_NODE(NODE_YIELD);
- COUNT_NODE(NODE_LVAR);
- COUNT_NODE(NODE_DVAR);
- COUNT_NODE(NODE_GVAR);
- COUNT_NODE(NODE_IVAR);
- COUNT_NODE(NODE_CONST);
- COUNT_NODE(NODE_CVAR);
- COUNT_NODE(NODE_NTH_REF);
- COUNT_NODE(NODE_BACK_REF);
- COUNT_NODE(NODE_MATCH);
- COUNT_NODE(NODE_MATCH2);
- COUNT_NODE(NODE_MATCH3);
- COUNT_NODE(NODE_LIT);
- COUNT_NODE(NODE_STR);
- COUNT_NODE(NODE_DSTR);
- COUNT_NODE(NODE_XSTR);
- COUNT_NODE(NODE_DXSTR);
- COUNT_NODE(NODE_EVSTR);
- COUNT_NODE(NODE_DREGX);
- COUNT_NODE(NODE_ONCE);
- COUNT_NODE(NODE_ARGS);
- COUNT_NODE(NODE_ARGS_AUX);
- COUNT_NODE(NODE_OPT_ARG);
- COUNT_NODE(NODE_KW_ARG);
- COUNT_NODE(NODE_POSTARG);
- COUNT_NODE(NODE_ARGSCAT);
- COUNT_NODE(NODE_ARGSPUSH);
- COUNT_NODE(NODE_SPLAT);
- COUNT_NODE(NODE_BLOCK_PASS);
- COUNT_NODE(NODE_DEFN);
- COUNT_NODE(NODE_DEFS);
- COUNT_NODE(NODE_ALIAS);
- COUNT_NODE(NODE_VALIAS);
- COUNT_NODE(NODE_UNDEF);
- COUNT_NODE(NODE_CLASS);
- COUNT_NODE(NODE_MODULE);
- COUNT_NODE(NODE_SCLASS);
- COUNT_NODE(NODE_COLON2);
- COUNT_NODE(NODE_COLON3);
- COUNT_NODE(NODE_DOT2);
- COUNT_NODE(NODE_DOT3);
- COUNT_NODE(NODE_FLIP2);
- COUNT_NODE(NODE_FLIP3);
- COUNT_NODE(NODE_SELF);
- COUNT_NODE(NODE_NIL);
- COUNT_NODE(NODE_TRUE);
- COUNT_NODE(NODE_FALSE);
- COUNT_NODE(NODE_ERRINFO);
- COUNT_NODE(NODE_DEFINED);
- COUNT_NODE(NODE_POSTEXE);
- COUNT_NODE(NODE_DSYM);
- COUNT_NODE(NODE_ATTRASGN);
- COUNT_NODE(NODE_LAMBDA);
- COUNT_NODE(NODE_ARYPTN);
- COUNT_NODE(NODE_FNDPTN);
- COUNT_NODE(NODE_HSHPTN);
- COUNT_NODE(NODE_ERROR);
-#undef COUNT_NODE
- case NODE_LAST: break;
- }
- UNREACHABLE;
- set:
- rb_hash_aset(hash, node, SIZET2NUM(nodes[i]));
- }
- }
- return hash;
-}
-
-static void
cto_i(VALUE v, void *data)
{
VALUE hash = (VALUE)data;
@@ -534,32 +360,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.
*/
@@ -598,28 +414,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:
- *
- * {:imemo_ifunc=>8,
- * :imemo_svar=>7,
- * :imemo_cref=>509,
- * :imemo_memo=>1,
- * :imemo_throw_data=>1}
+ * 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.
*
- * If the optional argument, result_hash, is given, it is overwritten and
- * returned. This is intended to avoid probe effect.
+ * ObjectSpace.count_imemo_objects
+ * # => {imemo_callcache: 5482, imemo_constcache: 1258, imemo_ment: 13906, ... }
*
- * 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 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.
*/
@@ -640,11 +450,10 @@ 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_callinfo);
INIT_IMEMO_TYPE_ID(imemo_callcache);
INIT_IMEMO_TYPE_ID(imemo_constcache);
+ INIT_IMEMO_TYPE_ID(imemo_fields);
#undef INIT_IMEMO_TYPE_ID
}
@@ -718,7 +527,7 @@ reachable_object_from_i(VALUE obj, void *data_ptr)
VALUE key = obj;
VALUE val = obj;
- if (rb_objspace_markable_object_p(obj)) {
+ if (!rb_objspace_garbage_object_p(obj)) {
if (NIL_P(rb_hash_lookup(data->refs, key))) {
rb_hash_aset(data->refs, key, Qtrue);
@@ -764,7 +573,7 @@ collect_values(st_data_t key, st_data_t value, st_data_t data)
*
* With this method, you can find memory leaks.
*
- * This method is only expected to work except with C Ruby.
+ * This method is only expected to work with C Ruby.
*
* Example:
* ObjectSpace.reachable_objects_from(['a', 'b', 'c'])
@@ -784,7 +593,7 @@ collect_values(st_data_t key, st_data_t value, st_data_t data)
static VALUE
reachable_objects_from(VALUE self, VALUE obj)
{
- if (rb_objspace_markable_object_p(obj)) {
+ if (!RB_SPECIAL_CONST_P(obj)) {
struct rof_data data;
if (rb_typeddata_is_kind_of(obj, &iow_data_type)) {
@@ -831,7 +640,7 @@ reachable_object_from_root_i(const char *category, VALUE obj, void *ptr)
rb_hash_aset(data->categories, category_str, category_objects);
}
- if (rb_objspace_markable_object_p(obj) &&
+ if (!rb_objspace_garbage_object_p(obj) &&
obj != data->categories &&
obj != data->last_category_objects) {
if (rb_objspace_internal_object_p(obj)) {
@@ -933,7 +742,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");
@@ -975,7 +784,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);