summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-06-05 13:52:02 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-06-05 13:52:02 +0000
commit18d4c1f044a4422fde5dde381e0812296bf2b619 (patch)
tree3bcdc87f3c1a95d16715d2f4a4645726cbc6b102 /gc.c
parenteef10d71ddff0c5e6f7f5fe8f55d57a77075ebc9 (diff)
* gc.c (os_obj_of): heaps may be modified in yield.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@16845 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/gc.c b/gc.c
index d095c5e8c4..245b8ee2d9 100644
--- a/gc.c
+++ b/gc.c
@@ -1856,9 +1856,19 @@ os_obj_of(rb_objspace_t *objspace, VALUE of)
{
size_t i;
size_t n = 0;
-
- for (i = 0; i < heaps_used; i++) {
- RVALUE *p, *pend;
+ RVALUE *membase = 0;
+ RVALUE *p, *pend;
+ volatile VALUE v;
+
+ i = 0;
+ while (i < heaps_used) {
+ while (0 < i && (uintptr_t)membase < (uintptr_t)heaps[i-1].membase)
+ i--;
+ while (i < heaps_used && (uintptr_t)heaps[i].membase <= (uintptr_t)membase )
+ i++;
+ if (heaps_used <= i)
+ break;
+ membase = heaps[i].membase;
p = heaps[i].slot; pend = p + heaps[i].limit;
for (;p < pend; p++) {
@@ -1872,8 +1882,9 @@ os_obj_of(rb_objspace_t *objspace, VALUE of)
if (FL_TEST(p, FL_SINGLETON)) continue;
default:
if (!p->as.basic.klass) continue;
- if (!of || rb_obj_is_kind_of((VALUE)p, of)) {
- rb_yield((VALUE)p);
+ v = (VALUE)p;
+ if (!of || rb_obj_is_kind_of(v, of)) {
+ rb_yield(v);
n++;
}
}