зеркало из https://github.com/github/ruby.git
* 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
This commit is contained in:
Родитель
e1d772c801
Коммит
6c6dece7f1
19
ChangeLog
19
ChangeLog
|
@ -1,3 +1,22 @@
|
||||||
|
Wed Oct 24 08:55:04 2012 Koichi Sasada <ko1@atdot.net>
|
||||||
|
|
||||||
|
* 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 <ko1@atdot.net>
|
Wed Oct 24 05:52:36 2012 Koichi Sasada <ko1@atdot.net>
|
||||||
|
|
||||||
* vm_insnhelper.c (vm_call_method): remove `default' and
|
* vm_insnhelper.c (vm_call_method): remove `default' and
|
||||||
|
|
|
@ -37,7 +37,6 @@ size_t rb_ary_memsize(VALUE);
|
||||||
size_t rb_io_memsize(const rb_io_t *);
|
size_t rb_io_memsize(const rb_io_t *);
|
||||||
size_t rb_generic_ivar_memsize(VALUE);
|
size_t rb_generic_ivar_memsize(VALUE);
|
||||||
size_t rb_objspace_data_type_memsize(VALUE obj);
|
size_t rb_objspace_data_type_memsize(VALUE obj);
|
||||||
VALUE rb_objspace_reachable_objects_from(VALUE obj);
|
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
memsize_of(VALUE obj)
|
memsize_of(VALUE obj)
|
||||||
|
@ -271,6 +270,43 @@ cos_i(void *vstart, void *vend, size_t stride, void *data)
|
||||||
return 0;
|
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:
|
* call-seq:
|
||||||
* ObjectSpace.count_objects_size([result_hash]) -> hash
|
* 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++) {
|
for (i = 0; i <= T_MASK; i++) {
|
||||||
if (counts[i]) {
|
if (counts[i]) {
|
||||||
VALUE type;
|
VALUE type = type2sym(i);
|
||||||
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;
|
|
||||||
}
|
|
||||||
total += counts[i];
|
total += counts[i];
|
||||||
rb_hash_aset(hash, type, SIZET2NUM(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;
|
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("#<InternalObject:%p %s>", (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:
|
* call-seq:
|
||||||
* ObjectSpace.reachable_objects_from(obj) -> array or nil
|
* 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
|
* true, false, nil, symbols and Fixnums (and Flonum) them it simply
|
||||||
* returns nil.
|
* 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.
|
* With this method, you can find memory leaks.
|
||||||
*
|
*
|
||||||
* This method is not expected to work except C Ruby.
|
* 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)
|
* ObjectSpace.reachable_objects_from(1)
|
||||||
* #=> nil # 1 is not markable (heap managed) object
|
* #=> 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
|
static VALUE
|
||||||
reachable_objects_from(VALUE self, VALUE obj)
|
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
|
/* 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, "count_tdata_objects", count_tdata_objects, -1);
|
||||||
|
|
||||||
rb_define_module_function(rb_mObjSpace, "reachable_objects_from", reachable_objects_from, 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);
|
||||||
}
|
}
|
||||||
|
|
51
gc.c
51
gc.c
|
@ -275,8 +275,8 @@ typedef struct rb_objspace {
|
||||||
int gc_stress;
|
int gc_stress;
|
||||||
|
|
||||||
struct mark_func_data_struct {
|
struct mark_func_data_struct {
|
||||||
VALUE data;
|
void *data;
|
||||||
void (*mark_func)(struct rb_objspace *objspace, VALUE v);
|
void (*mark_func)(VALUE v, void *data);
|
||||||
} *mark_func_data;
|
} *mark_func_data;
|
||||||
} rb_objspace_t;
|
} rb_objspace_t;
|
||||||
|
|
||||||
|
@ -1182,6 +1182,12 @@ internal_object_p(VALUE obj)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rb_objspace_internal_object_p(VALUE obj)
|
||||||
|
{
|
||||||
|
return internal_object_p(obj);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
os_obj_of_i(void *vstart, void *vend, size_t stride, void *data)
|
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;
|
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
|
static void
|
||||||
gc_mark(rb_objspace_t *objspace, VALUE ptr)
|
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);
|
push_mark_stack(&objspace->mark_stack, ptr);
|
||||||
}
|
}
|
||||||
else {
|
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
|
void
|
||||||
collect_refs(rb_objspace_t *objspace, VALUE obj)
|
rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), void *data)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
rb_objspace_t *objspace = &rb_objspace;
|
rb_objspace_t *objspace = &rb_objspace;
|
||||||
|
|
||||||
if (markable_object_p(objspace, obj)) {
|
if (markable_object_p(objspace, obj)) {
|
||||||
st_table *refs = st_init_numtable();
|
|
||||||
struct mark_func_data_struct mfd;
|
struct mark_func_data_struct mfd;
|
||||||
VALUE ret = rb_ary_new();
|
mfd.mark_func = func;
|
||||||
mfd.mark_func = collect_refs;
|
mfd.data = data;
|
||||||
mfd.data = (VALUE)refs;
|
|
||||||
objspace->mark_func_data = &mfd;
|
objspace->mark_func_data = &mfd;
|
||||||
|
|
||||||
gc_mark_children(objspace, obj);
|
gc_mark_children(objspace, obj);
|
||||||
|
|
||||||
objspace->mark_func_data = 0;
|
objspace->mark_func_data = 0;
|
||||||
st_foreach(refs, collect_keys, (st_data_t)ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Qnil;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
gc.h
4
gc.h
|
@ -89,7 +89,9 @@ int ruby_get_stack_grow_direction(volatile VALUE *addr);
|
||||||
|
|
||||||
/* exports for objspace module */
|
/* exports for objspace module */
|
||||||
size_t rb_objspace_data_type_memsize(VALUE obj);
|
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(
|
void rb_objspace_each_objects(
|
||||||
int (*callback)(void *start, void *end, size_t stride, void *data),
|
int (*callback)(void *start, void *end, size_t stride, void *data),
|
||||||
|
|
Загрузка…
Ссылка в новой задаче