ささだです.
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