[前][次][番号順一覧][スレッド一覧]

ruby-changes:25255

From: ko1 <ko1@a...>
Date: Wed, 24 Oct 2012 09:05:55 +0900 (JST)
Subject: [ruby-changes:25255] ko1:r37307 (trunk): * ext/objspace/objspace.c (ObjectSpace.reachable_objects_from):

ko1	2012-10-24 09:04:56 +0900 (Wed, 24 Oct 2012)

  New Revision: 37307

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=37307

  Log:
    * 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.

  Modified files:
    trunk/ChangeLog
    trunk/ext/objspace/objspace.c
    trunk/gc.c
    trunk/gc.h

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 37306)
+++ ChangeLog	(revision 37307)
@@ -1,3 +1,22 @@
+Wed Oct 24 08:55:04 2012  Koichi Sasada  <ko1@a...>
+
+	* 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@a...>
 
 	* vm_insnhelper.c (vm_call_method): remove `default' and
Index: gc.c
===================================================================
--- gc.c	(revision 37306)
+++ gc.c	(revision 37307)
@@ -275,8 +275,8 @@
     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 @@
     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 @@
     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 @@
 	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,44 +3315,19 @@
     }
 }
 
-static void
-collect_refs(rb_objspace_t *objspace, VALUE obj)
+void
+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;
 
     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;
-    }
 }
 
 /*
Index: gc.h
===================================================================
--- gc.h	(revision 37306)
+++ gc.h	(revision 37307)
@@ -89,7 +89,9 @@
 
 /* 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),
Index: ext/objspace/objspace.c
===================================================================
--- ext/objspace/objspace.c	(revision 37306)
+++ ext/objspace/objspace.c	(revision 37307)
@@ -37,7 +37,6 @@
 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 @@
     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 @@
 
     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 @@
     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:
  *     ObjectSpace.reachable_objects_from(obj) -> array or nil
@@ -640,6 +708,15 @@
  *  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 @@
  *    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 @@
     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);
 }

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]