From: SASADA Koichi Date: 2009-06-14T01:53:21+09:00 Subject: [ruby-dev:38602] [Feature: trunk] rb_objspace_each_objects  ささだです.  C レベルで ObjectSpace.each_object 相当の処理をするための C API を作る のはどうでしょうか.動機は,[ruby-dev:38584] で提案した機能を,gc.c に手 を入れずに作るためです.  インターフェス案です. void rb_objspace_each_objects( int (*func)(VALUE *start, VALUE *end, void *data), void *data)  ObjectSpace.each_object と違い,1つずつコールバック関数に渡すのではな く,あるまとまった単位ごとに何度かコールバック関数に渡されます.範囲は start から end まで.渡されるオブジェクトは,free された cell を含んでい る可能性があります.この場合,flags をチェックする必要があります. *まとめて渡すのは,性能上の理由です.  1つ1つ渡すと,結構性能低下が見られました.  実装を一応つけておきます.ついでに,os_obj_of() をこれで書き換えてみま した. *ST_CONTINUE みたいなのを使ってしまったんですが,  これは行儀が悪い気がする.どうするべき?  いかがでしょうか. Index: gc.c =================================================================== --- gc.c (リビジョン 23682) +++ gc.c (作業コピー) @@ -2383,13 +2523,13 @@ Init_heap(void) init_heap(&rb_objspace); } -static VALUE -os_obj_of(rb_objspace_t *objspace, VALUE of) +void +rb_objspace_each_objects(int (*func)(VALUE *start, VALUE *end, void *), void *data) { size_t i; - size_t n = 0; RVALUE *membase = 0; - RVALUE *p, *pend; + RVALUE *pstart, *pend; + rb_objspace_t *objspace = &rb_objspace; volatile VALUE v; i = 0; @@ -2402,30 +2542,70 @@ os_obj_of(rb_objspace_t *objspace, VALUE break; membase = heaps[i].membase; - p = heaps[i].slot; pend = p + heaps[i].limit; - for (;p < pend; p++) { + pstart = heaps[i].slot; + pend = pstart + heaps[i].limit; + + for (; pstart != pend; pstart++) { + if (pstart->as.basic.flags) { + v = (VALUE *)pstart; /* acquire to save this object */ + break; + } + } + if (pstart != pend) { + if ((*func)((VALUE *)pstart, (VALUE *)pend, data) != ST_CONTINUE) { + return; + } + } + } + + return; +} + +struct os_each_struct { + size_t num; + VALUE of; +}; + +static int +os_obj_of_i(VALUE *vstart, VALUE *vend, void *data) +{ + struct os_each_struct *oes = (struct os_each_struct *)data; + RVALUE *p, *pend; + VALUE v; + + for (p = (RVALUE *)vstart, pend = (RVALUE *)vend; p != pend; p++) { if (p->as.basic.flags) { switch (BUILTIN_TYPE(p)) { case T_NONE: case T_ICLASS: case T_NODE: case T_ZOMBIE: - continue; + break; case T_CLASS: - if (FL_TEST(p, FL_SINGLETON)) continue; + if (FL_TEST(p, FL_SINGLETON)) + break; default: - if (!p->as.basic.klass) continue; + if (!p->as.basic.klass) break; v = (VALUE)p; - if (!of || rb_obj_is_kind_of(v, of)) { + if (!oes->of || rb_obj_is_kind_of(v, oes->of)) { rb_yield(v); - n++; + oes->num++; } } } } + return ST_CONTINUE; } - return SIZET2NUM(n); +static VALUE +os_obj_of(VALUE of) +{ + struct os_each_struct oes; + + oes.num = 0; + oes.of = of; + rb_objspace_each_objects(os_obj_of_i, &oes); + return SIZET2NUM(oes.num); } /* @@ -2474,7 +2654,7 @@ os_each_obj(int argc, VALUE *argv, VALUE rb_scan_args(argc, argv, "01", &of); } RETURN_ENUMERATOR(os, 1, &of); - return os_obj_of(&rb_objspace, of); + return os_obj_of(of); } /* -- // SASADA Koichi at atdot dot net