From 6c6dece7f192664986c3973ed15c994cc6af1696 Mon Sep 17 00:00:00 2001 From: ko1 Date: Wed, 24 Oct 2012 00:04:56 +0000 Subject: [PATCH] * ext/objspace/objspace.c (ObjectSpace.reachable_objects_from): internal object support. If given object `obj' has references to internal objects (such as T_NODE objects), then this method returns instances of `ObjectSpace::InternalObjectWrapper' instead of that internal objects. This instance contains a refereance to an internal object and you can check the type of internal object using `ObjectSpace::InternalObjectWrapper#type' method. Rdoc of `InternalObjectWrapper' is not prepared yet. * gc.c (rb_objspace_reachable_objects_from), gc.h: change an interface of 'rb_objspace_reachable_objects_from()' * gc.c, gc.h: add two APIs - rb_objspace_markable_object_p(obj): check markable or not. - rb_objspace_internal_object_p(obj): check internal or not. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37307 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 19 +++++ ext/objspace/objspace.c | 170 +++++++++++++++++++++++++++++++--------- gc.c | 51 +++++------- gc.h | 4 +- 4 files changed, 174 insertions(+), 70 deletions(-) diff --git a/ChangeLog b/ChangeLog index f02b010249..5e4ccc2ac7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +Wed Oct 24 08:55:04 2012 Koichi Sasada + + * ext/objspace/objspace.c (ObjectSpace.reachable_objects_from): + internal object support. + If given object `obj' has references to internal objects + (such as T_NODE objects), then this method returns instances of + `ObjectSpace::InternalObjectWrapper' instead of that internal objects. + This instance contains a refereance to an internal object and you can + check the type of internal object using + `ObjectSpace::InternalObjectWrapper#type' method. + Rdoc of `InternalObjectWrapper' is not prepared yet. + + * gc.c (rb_objspace_reachable_objects_from), gc.h: change + an interface of 'rb_objspace_reachable_objects_from()' + + * gc.c, gc.h: add two APIs + - rb_objspace_markable_object_p(obj): check markable or not. + - rb_objspace_internal_object_p(obj): check internal or not. + Wed Oct 24 05:52:36 2012 Koichi Sasada * vm_insnhelper.c (vm_call_method): remove `default' and diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c index 1842209641..6e2da9aef1 100644 --- a/ext/objspace/objspace.c +++ b/ext/objspace/objspace.c @@ -37,7 +37,6 @@ size_t rb_ary_memsize(VALUE); size_t rb_io_memsize(const rb_io_t *); size_t rb_generic_ivar_memsize(VALUE); size_t rb_objspace_data_type_memsize(VALUE obj); -VALUE rb_objspace_reachable_objects_from(VALUE obj); static size_t memsize_of(VALUE obj) @@ -271,6 +270,43 @@ cos_i(void *vstart, void *vend, size_t stride, void *data) return 0; } +static VALUE +type2sym(int i) +{ + VALUE type; + switch (i) { +#define CASE_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break; + CASE_TYPE(T_NONE); + CASE_TYPE(T_OBJECT); + CASE_TYPE(T_CLASS); + CASE_TYPE(T_MODULE); + CASE_TYPE(T_FLOAT); + CASE_TYPE(T_STRING); + CASE_TYPE(T_REGEXP); + CASE_TYPE(T_ARRAY); + CASE_TYPE(T_HASH); + CASE_TYPE(T_STRUCT); + CASE_TYPE(T_BIGNUM); + CASE_TYPE(T_FILE); + CASE_TYPE(T_DATA); + CASE_TYPE(T_MATCH); + CASE_TYPE(T_COMPLEX); + CASE_TYPE(T_RATIONAL); + CASE_TYPE(T_NIL); + CASE_TYPE(T_TRUE); + CASE_TYPE(T_FALSE); + CASE_TYPE(T_SYMBOL); + CASE_TYPE(T_FIXNUM); + CASE_TYPE(T_UNDEF); + CASE_TYPE(T_NODE); + CASE_TYPE(T_ICLASS); + CASE_TYPE(T_ZOMBIE); +#undef CASE_TYPE + default: rb_bug("type2sym: unknown type (%d)", (int)type); + } + return type; +} + /* * call-seq: * ObjectSpace.count_objects_size([result_hash]) -> hash @@ -322,37 +358,7 @@ count_objects_size(int argc, VALUE *argv, VALUE os) for (i = 0; i <= T_MASK; i++) { if (counts[i]) { - VALUE type; - switch (i) { -#define COUNT_TYPE(t) case t: type = ID2SYM(rb_intern(#t)); break; - COUNT_TYPE(T_NONE); - COUNT_TYPE(T_OBJECT); - COUNT_TYPE(T_CLASS); - COUNT_TYPE(T_MODULE); - COUNT_TYPE(T_FLOAT); - COUNT_TYPE(T_STRING); - COUNT_TYPE(T_REGEXP); - COUNT_TYPE(T_ARRAY); - COUNT_TYPE(T_HASH); - COUNT_TYPE(T_STRUCT); - COUNT_TYPE(T_BIGNUM); - COUNT_TYPE(T_FILE); - COUNT_TYPE(T_DATA); - COUNT_TYPE(T_MATCH); - COUNT_TYPE(T_COMPLEX); - COUNT_TYPE(T_RATIONAL); - COUNT_TYPE(T_NIL); - COUNT_TYPE(T_TRUE); - COUNT_TYPE(T_FALSE); - COUNT_TYPE(T_SYMBOL); - COUNT_TYPE(T_FIXNUM); - COUNT_TYPE(T_UNDEF); - COUNT_TYPE(T_NODE); - COUNT_TYPE(T_ICLASS); - COUNT_TYPE(T_ZOMBIE); -#undef COUNT_TYPE - default: type = INT2NUM(i); break; - } + VALUE type = type2sym(i); total += counts[i]; rb_hash_aset(hash, type, SIZET2NUM(counts[i])); } @@ -627,6 +633,68 @@ count_tdata_objects(int argc, VALUE *argv, VALUE self) return hash; } +static void +iow_mark(void *ptr) +{ + rb_gc_mark((VALUE)ptr); +} + +static const rb_data_type_t iow_data_type = { + "ObjectSpace::InternalObjectWrapper", + {iow_mark, 0, 0,}, +}; + +static VALUE rb_mInternalObjectWrapper; + +static VALUE +iow_newobj(VALUE obj) +{ + return rb_data_typed_object_alloc(rb_mInternalObjectWrapper, (void *)obj, &iow_data_type); +} + +static VALUE +iow_type(VALUE self) +{ + VALUE obj = (VALUE)DATA_PTR(self); + return type2sym(BUILTIN_TYPE(obj)); +} + +static VALUE +iow_inspect(VALUE self) +{ + VALUE obj = (VALUE)DATA_PTR(self); + VALUE type = type2sym(BUILTIN_TYPE(obj)); + + return rb_sprintf("#", (void *)obj, rb_id2name(SYM2ID(type))); +} + +struct rof_data { + st_table *refs; + VALUE internals; +}; + +static void +reachable_object_from_i(VALUE obj, void *data_ptr) +{ + struct rof_data *data = (struct rof_data *)data_ptr; + + if (rb_objspace_markable_object_p(obj)) { + if (rb_objspace_internal_object_p(obj)) { + obj = iow_newobj(obj); + rb_ary_push(data->internals, obj); + } + st_insert(data->refs, obj, Qtrue); + } +} + +static int +collect_keys(st_data_t key, st_data_t value, st_data_t data) +{ + VALUE ary = (VALUE)data; + rb_ary_push(ary, (VALUE)key); + return ST_CONTINUE; +} + /* * call-seq: * ObjectSpace.reachable_objects_from(obj) -> array or nil @@ -640,6 +708,15 @@ count_tdata_objects(int argc, VALUE *argv, VALUE self) * true, false, nil, symbols and Fixnums (and Flonum) them it simply * returns nil. * + * If `obj' has references to 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. + * + * If `obj' is instance of `ObjectSpace::InternalObjectWrapper' + * class, then this method retuns all reachalbe object from + * an interna object, which is pointed by `obj'. + * * With this method, you can find memory leaks. * * This method is not expected to work except C Ruby. @@ -657,15 +734,30 @@ count_tdata_objects(int argc, VALUE *argv, VALUE self) * ObjectSpace.reachable_objects_from(1) * #=> nil # 1 is not markable (heap managed) object * - * Limitation: Current implementation can't acquire internal objects. - * This means that you can't acquire complete object graph - * (heap snapshot). This is future work. - * */ + static VALUE reachable_objects_from(VALUE self, VALUE obj) { - return rb_objspace_reachable_objects_from(obj); + if (rb_objspace_markable_object_p(obj)) { + VALUE ret = rb_ary_new(); + struct rof_data data; + + if (rb_typeddata_is_kind_of(obj, &iow_data_type)) { + obj = (VALUE)DATA_PTR(obj); + } + + data.refs = st_init_numtable(); + data.internals = rb_ary_new(); + + rb_objspace_reachable_objects_from(obj, reachable_object_from_i, &data); + + st_foreach(data.refs, collect_keys, (st_data_t)ret); + return ret; + } + else { + return Qnil; + } } /* objspace library extends ObjectSpace module and add several @@ -691,4 +783,8 @@ Init_objspace(void) rb_define_module_function(rb_mObjSpace, "count_tdata_objects", count_tdata_objects, -1); rb_define_module_function(rb_mObjSpace, "reachable_objects_from", reachable_objects_from, 1); + + rb_mInternalObjectWrapper = rb_define_class_under(rb_mObjSpace, "InternalObjectWrapper", rb_cObject); + rb_define_method(rb_mInternalObjectWrapper, "type", iow_type, 0); + rb_define_method(rb_mInternalObjectWrapper, "inspect", iow_inspect, 0); } diff --git a/gc.c b/gc.c index 2d21cada24..29b9cc7bde 100644 --- a/gc.c +++ b/gc.c @@ -275,8 +275,8 @@ typedef struct rb_objspace { int gc_stress; struct mark_func_data_struct { - VALUE data; - void (*mark_func)(struct rb_objspace *objspace, VALUE v); + void *data; + void (*mark_func)(VALUE v, void *data); } *mark_func_data; } rb_objspace_t; @@ -1182,6 +1182,12 @@ internal_object_p(VALUE obj) return 1; } +int +rb_objspace_internal_object_p(VALUE obj) +{ + return internal_object_p(obj); +} + static int os_obj_of_i(void *vstart, void *vend, size_t stride, void *data) { @@ -2568,6 +2574,12 @@ markable_object_p(rb_objspace_t *objspace, VALUE ptr) return 1; } +int +rb_objspace_markable_object_p(VALUE obj) +{ + return markable_object_p(/* now it doesn't use &rb_objspace */ 0, obj); +} + static void gc_mark(rb_objspace_t *objspace, VALUE ptr) { @@ -2580,7 +2592,7 @@ gc_mark(rb_objspace_t *objspace, VALUE ptr) push_mark_stack(&objspace->mark_stack, ptr); } else { - objspace->mark_func_data->mark_func(objspace, ptr); + objspace->mark_func_data->mark_func(ptr, objspace->mark_func_data->data); } } @@ -3303,43 +3315,18 @@ rb_gc_set_params(void) } } -static void -collect_refs(rb_objspace_t *objspace, VALUE obj) -{ - if (markable_object_p(objspace, obj) && !internal_object_p(obj)) { - st_insert((st_table *)objspace->mark_func_data->data, obj, Qtrue); - } -} - -static int -collect_keys(st_data_t key, st_data_t value, st_data_t data) -{ - VALUE ary = (VALUE)data; - rb_ary_push(ary, (VALUE)key); - return ST_CONTINUE; -} - -VALUE -rb_objspace_reachable_objects_from(VALUE obj) +void +rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data) { rb_objspace_t *objspace = &rb_objspace; if (markable_object_p(objspace, obj)) { - st_table *refs = st_init_numtable(); struct mark_func_data_struct mfd; - VALUE ret = rb_ary_new(); - mfd.mark_func = collect_refs; - mfd.data = (VALUE)refs; + mfd.mark_func = func; + mfd.data = data; objspace->mark_func_data = &mfd; - gc_mark_children(objspace, obj); - objspace->mark_func_data = 0; - st_foreach(refs, collect_keys, (st_data_t)ret); - return ret; - } - else { - return Qnil; } } diff --git a/gc.h b/gc.h index 741945349d..2a3dd92c01 100644 --- a/gc.h +++ b/gc.h @@ -89,7 +89,9 @@ int ruby_get_stack_grow_direction(volatile VALUE *addr); /* exports for objspace module */ size_t rb_objspace_data_type_memsize(VALUE obj); -VALUE rb_objspace_reachable_objects_from(VALUE obj); +void rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data); +int rb_objspace_markable_object_p(VALUE obj); +int rb_objspace_internal_object_p(VALUE obj); void rb_objspace_each_objects( int (*callback)(void *start, void *end, size_t stride, void *data),