зеркало из https://github.com/github/ruby.git
ObjectSpace::WeakMap: fix compaction support
[Bug #19529] `rb_gc_update_tbl_refs` can't be used on `w->obj2wmap` because it's not a `VALUE -> VALUE` table, but a `VALUE -> VALUE *` table, so we need some dedicated iterator.
This commit is contained in:
Родитель
ac65ce16e9
Коммит
548086b34e
|
@ -176,4 +176,12 @@ class TestWeakMap < Test::Unit::TestCase
|
|||
end
|
||||
end;
|
||||
end
|
||||
|
||||
def test_compaction_bug_19529
|
||||
obj = Object.new
|
||||
100.times do |i|
|
||||
GC.compact
|
||||
@wm[i] = obj
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
37
weakmap.c
37
weakmap.c
|
@ -12,12 +12,47 @@ struct weakmap {
|
|||
VALUE final;
|
||||
};
|
||||
|
||||
static int
|
||||
wmap_replace_ref(st_data_t *key, st_data_t *value, st_data_t _argp, int existing)
|
||||
{
|
||||
*key = rb_gc_location((VALUE)*key);
|
||||
|
||||
VALUE *values = (VALUE *)value;
|
||||
VALUE size = values[0];
|
||||
|
||||
for (VALUE index = 1; index <= size; index++) {
|
||||
values[index] = rb_gc_location(values[index]);
|
||||
}
|
||||
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
wmap_foreach_replace(st_data_t key, st_data_t value, st_data_t _argp, int error)
|
||||
{
|
||||
if (rb_gc_location((VALUE)key) != (VALUE)key) {
|
||||
return ST_REPLACE;
|
||||
}
|
||||
|
||||
VALUE *values = (VALUE *)value;
|
||||
VALUE size = values[0];
|
||||
|
||||
for (VALUE index = 1; index <= size; index++) {
|
||||
VALUE val = values[index];
|
||||
if (rb_gc_location(val) != val) {
|
||||
return ST_REPLACE;
|
||||
}
|
||||
}
|
||||
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
wmap_compact(void *ptr)
|
||||
{
|
||||
struct weakmap *w = ptr;
|
||||
if (w->wmap2obj) rb_gc_update_tbl_refs(w->wmap2obj);
|
||||
if (w->obj2wmap) rb_gc_update_tbl_refs(w->obj2wmap);
|
||||
if (w->obj2wmap) st_foreach_with_replace(w->obj2wmap, wmap_foreach_replace, wmap_replace_ref, (st_data_t)NULL);
|
||||
w->final = rb_gc_location(w->final);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче