summaryrefslogtreecommitdiff
path: root/weakmap.c
diff options
context:
space:
mode:
authorJean Boussier <byroot@ruby-lang.org>2023-03-14 09:12:55 +0100
committerJean Boussier <jean.boussier@gmail.com>2023-03-14 16:49:23 +0100
commit548086b34e3dd125edabf5dc1e46b891fad3ea9c (patch)
tree6c147bc459e5c90e3c7efefc742d699f947c9a15 /weakmap.c
parentac65ce16e904695ba45888d3fba641d12caf733a (diff)
downloadruby-548086b34e3dd125edabf5dc1e46b891fad3ea9c.tar.gz
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.
Diffstat (limited to 'weakmap.c')
-rw-r--r--weakmap.c37
1 files changed, 36 insertions, 1 deletions
diff --git a/weakmap.c b/weakmap.c
index e6dbb325d7..2145e4d2f8 100644
--- a/weakmap.c
+++ b/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);
}