summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c945
1 files changed, 62 insertions, 883 deletions
diff --git a/gc.c b/gc.c
index bbcdc4cedc..fdb6334a9d 100644
--- a/gc.c
+++ b/gc.c
@@ -1183,10 +1183,8 @@ total_freed_pages(rb_objspace_t *objspace)
#define is_lazy_sweeping(objspace) (GC_ENABLE_LAZY_SWEEP && has_sweeping_pages(objspace))
#if SIZEOF_LONG == SIZEOF_VOIDP
-# define nonspecial_obj_id(obj) (VALUE)((SIGNED_VALUE)(obj)|FIXNUM_FLAG)
# define obj_id_to_ref(objid) ((objid) ^ FIXNUM_FLAG) /* unset FIXNUM_FLAG */
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
-# define nonspecial_obj_id(obj) LL2NUM((SIGNED_VALUE)(obj) / 2)
# define obj_id_to_ref(objid) (FIXNUM_P(objid) ? \
((objid) ^ FIXNUM_FLAG) : (NUM2PTR(objid) << 1))
#else
@@ -1220,8 +1218,6 @@ void rb_vm_update_references(void *ptr);
void rb_gcdebug_print_obj_condition(VALUE obj);
-static VALUE define_final0(VALUE obj, VALUE block);
-
NORETURN(static void *gc_vraise(void *ptr));
NORETURN(static void gc_raise(VALUE exc, const char *fmt, ...));
NORETURN(static void negative_size_allocation_error(const char *));
@@ -4235,6 +4231,45 @@ should_be_finalizable(VALUE obj)
rb_check_frozen(obj);
}
+VALUE
+rb_define_finalizer_no_check(VALUE obj, VALUE block)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ VALUE table;
+ st_data_t data;
+
+ RBASIC(obj)->flags |= FL_FINALIZE;
+
+ if (st_lookup(finalizer_table, obj, &data)) {
+ table = (VALUE)data;
+
+ /* avoid duplicate block, table is usually small */
+ {
+ long len = RARRAY_LEN(table);
+ long i;
+
+ for (i = 0; i < len; i++) {
+ VALUE recv = RARRAY_AREF(table, i);
+ if (rb_equal(recv, block)) {
+ block = recv;
+ goto end;
+ }
+ }
+ }
+
+ rb_ary_push(table, block);
+ }
+ else {
+ table = rb_ary_new3(1, block);
+ RBASIC_CLEAR_CLASS(table);
+ st_add_direct(finalizer_table, obj, table);
+ }
+ end:
+ block = rb_ary_new3(2, INT2FIX(0), block);
+ OBJ_FREEZE(block);
+ return block;
+}
+
/*
* call-seq:
* ObjectSpace.define_finalizer(obj, aProc=proc())
@@ -4315,46 +4350,7 @@ define_final(int argc, VALUE *argv, VALUE os)
rb_warn("finalizer references object to be finalized");
}
- return define_final0(obj, block);
-}
-
-static VALUE
-define_final0(VALUE obj, VALUE block)
-{
- rb_objspace_t *objspace = &rb_objspace;
- VALUE table;
- st_data_t data;
-
- RBASIC(obj)->flags |= FL_FINALIZE;
-
- if (st_lookup(finalizer_table, obj, &data)) {
- table = (VALUE)data;
-
- /* avoid duplicate block, table is usually small */
- {
- long len = RARRAY_LEN(table);
- long i;
-
- for (i = 0; i < len; i++) {
- VALUE recv = RARRAY_AREF(table, i);
- if (rb_equal(recv, block)) {
- block = recv;
- goto end;
- }
- }
- }
-
- rb_ary_push(table, block);
- }
- else {
- table = rb_ary_new3(1, block);
- RBASIC_CLEAR_CLASS(table);
- st_add_direct(finalizer_table, obj, table);
- }
- end:
- block = rb_ary_new3(2, INT2FIX(0), block);
- OBJ_FREEZE(block);
- return block;
+ return rb_define_finalizer_no_check(obj, block);
}
VALUE
@@ -4362,7 +4358,7 @@ rb_define_finalizer(VALUE obj, VALUE block)
{
should_be_finalizable(obj);
should_be_callable(block);
- return define_final0(obj, block);
+ return rb_define_finalizer_no_check(obj, block);
}
void
@@ -4688,9 +4684,18 @@ rb_objspace_garbage_object_p(VALUE obj)
return is_garbage_object(objspace, obj);
}
-static VALUE
-id2ref_obj_tbl(rb_objspace_t *objspace, VALUE objid)
+bool
+rb_gc_is_ptr_to_obj(void *ptr)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+ return is_pointer_to_heap(objspace, ptr);
+}
+
+VALUE
+rb_gc_id2ref_obj_tbl(VALUE objid)
{
+ rb_objspace_t *objspace = &rb_objspace;
+
VALUE orig;
if (st_lookup(objspace->id_to_obj_tbl, objid, &orig)) {
return orig;
@@ -4747,7 +4752,7 @@ id2ref(VALUE objid)
}
}
- if (!UNDEF_P(orig = id2ref_obj_tbl(objspace, objid)) &&
+ if (!UNDEF_P(orig = rb_gc_id2ref_obj_tbl(objid)) &&
is_live_object(objspace, orig)) {
if (!rb_multi_ractor_p() || rb_ractor_shareable_p(orig)) {
@@ -4821,16 +4826,21 @@ cached_object_id(VALUE obj)
}
static VALUE
-nonspecial_obj_id_(VALUE obj)
+nonspecial_obj_id(VALUE obj)
{
- return nonspecial_obj_id(obj);
+#if SIZEOF_LONG == SIZEOF_VOIDP
+ return (VALUE)((SIGNED_VALUE)(obj)|FIXNUM_FLAG);
+#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
+ return LL2NUM((SIGNED_VALUE)(obj) / 2);
+#else
+# error not supported
+#endif
}
-
VALUE
rb_memory_id(VALUE obj)
{
- return rb_find_object_id(obj, nonspecial_obj_id_);
+ return rb_find_object_id(obj, nonspecial_obj_id);
}
/*
@@ -12869,787 +12879,6 @@ rb_gc_adjust_memory_usage(ssize_t diff)
}
/*
- ------------------------------ WeakMap ------------------------------
-*/
-
-struct weakmap {
- st_table *obj2wmap; /* obj -> [ref,...] */
- st_table *wmap2obj; /* ref -> obj */
- VALUE final;
-};
-
-#define WMAP_DELETE_DEAD_OBJECT_IN_MARK 0
-
-#if WMAP_DELETE_DEAD_OBJECT_IN_MARK
-static int
-wmap_mark_map(st_data_t key, st_data_t val, st_data_t arg)
-{
- rb_objspace_t *objspace = (rb_objspace_t *)arg;
- VALUE obj = (VALUE)val;
- if (!is_live_object(objspace, obj)) return ST_DELETE;
- return ST_CONTINUE;
-}
-#endif
-
-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);
- w->final = rb_gc_location(w->final);
-}
-
-static void
-wmap_mark(void *ptr)
-{
- struct weakmap *w = ptr;
-#if WMAP_DELETE_DEAD_OBJECT_IN_MARK
- if (w->obj2wmap) st_foreach(w->obj2wmap, wmap_mark_map, (st_data_t)&rb_objspace);
-#endif
- rb_gc_mark_movable(w->final);
-}
-
-static int
-wmap_free_map(st_data_t key, st_data_t val, st_data_t arg)
-{
- VALUE *ptr = (VALUE *)val;
- ruby_sized_xfree(ptr, (ptr[0] + 1) * sizeof(VALUE));
- return ST_CONTINUE;
-}
-
-static void
-wmap_free(void *ptr)
-{
- struct weakmap *w = ptr;
- st_foreach(w->obj2wmap, wmap_free_map, 0);
- st_free_table(w->obj2wmap);
- st_free_table(w->wmap2obj);
- xfree(w);
-}
-
-static int
-wmap_memsize_map(st_data_t key, st_data_t val, st_data_t arg)
-{
- VALUE *ptr = (VALUE *)val;
- *(size_t *)arg += (ptr[0] + 1) * sizeof(VALUE);
- return ST_CONTINUE;
-}
-
-static size_t
-wmap_memsize(const void *ptr)
-{
- size_t size;
- const struct weakmap *w = ptr;
- size = sizeof(*w);
- size += st_memsize(w->obj2wmap);
- size += st_memsize(w->wmap2obj);
- st_foreach(w->obj2wmap, wmap_memsize_map, (st_data_t)&size);
- return size;
-}
-
-static const rb_data_type_t weakmap_type = {
- "weakmap",
- {
- wmap_mark,
- wmap_free,
- wmap_memsize,
- wmap_compact,
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
-};
-
-static VALUE wmap_finalize(RB_BLOCK_CALL_FUNC_ARGLIST(objid, self));
-
-static VALUE
-wmap_allocate(VALUE klass)
-{
- struct weakmap *w;
- VALUE obj = TypedData_Make_Struct(klass, struct weakmap, &weakmap_type, w);
- w->obj2wmap = rb_init_identtable();
- w->wmap2obj = rb_init_identtable();
- w->final = rb_func_lambda_new(wmap_finalize, obj, 1, 1);
- return obj;
-}
-
-static int
-wmap_live_p(rb_objspace_t *objspace, VALUE obj)
-{
- if (SPECIAL_CONST_P(obj)) return TRUE;
- /* If is_pointer_to_heap returns false, the page could be in the tomb heap
- * or have already been freed. */
- if (!is_pointer_to_heap(objspace, (void *)obj)) return FALSE;
-
- void *poisoned = asan_unpoison_object_temporary(obj);
-
- enum ruby_value_type t = BUILTIN_TYPE(obj);
- int ret = (!(t == T_NONE || t >= T_FIXNUM || t == T_ICLASS) &&
- is_live_object(objspace, obj));
-
- if (poisoned) {
- asan_poison_object(obj);
- }
-
- return ret;
-}
-
-static int
-wmap_final_func(st_data_t *key, st_data_t *value, st_data_t arg, int existing)
-{
- VALUE wmap, *ptr, size, i, j;
- if (!existing) return ST_STOP;
- wmap = (VALUE)arg, ptr = (VALUE *)*value;
- for (i = j = 1, size = ptr[0]; i <= size; ++i) {
- if (ptr[i] != wmap) {
- ptr[j++] = ptr[i];
- }
- }
- if (j == 1) {
- ruby_sized_xfree(ptr, i * sizeof(VALUE));
- return ST_DELETE;
- }
- if (j < i) {
- SIZED_REALLOC_N(ptr, VALUE, j + 1, i);
- ptr[0] = j;
- *value = (st_data_t)ptr;
- }
- return ST_CONTINUE;
-}
-
-/* :nodoc: */
-static VALUE
-wmap_finalize(RB_BLOCK_CALL_FUNC_ARGLIST(objid, self))
-{
- st_data_t orig, wmap, data;
- VALUE obj, *rids, i, size;
- struct weakmap *w;
-
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
- /* Get reference from object id. */
- if (UNDEF_P(obj = id2ref_obj_tbl(&rb_objspace, objid))) {
- rb_bug("wmap_finalize: objid is not found.");
- }
-
- /* obj is original referenced object and/or weak reference. */
- orig = (st_data_t)obj;
- if (st_delete(w->obj2wmap, &orig, &data)) {
- rids = (VALUE *)data;
- size = *rids++;
- for (i = 0; i < size; ++i) {
- wmap = (st_data_t)rids[i];
- st_delete(w->wmap2obj, &wmap, NULL);
- }
- ruby_sized_xfree((VALUE *)data, (size + 1) * sizeof(VALUE));
- }
-
- wmap = (st_data_t)obj;
- if (st_delete(w->wmap2obj, &wmap, &orig)) {
- wmap = (st_data_t)obj;
- st_update(w->obj2wmap, orig, wmap_final_func, wmap);
- }
- return self;
-}
-
-struct wmap_iter_arg {
- rb_objspace_t *objspace;
- VALUE value;
-};
-
-static VALUE
-wmap_inspect_append(rb_objspace_t *objspace, VALUE str, VALUE obj)
-{
- if (SPECIAL_CONST_P(obj)) {
- return rb_str_append(str, rb_inspect(obj));
- }
- else if (wmap_live_p(objspace, obj)) {
- return rb_str_append(str, rb_any_to_s(obj));
- }
- else {
- return rb_str_catf(str, "#<collected:%p>", (void*)obj);
- }
-}
-
-static int
-wmap_inspect_i(st_data_t key, st_data_t val, st_data_t arg)
-{
- struct wmap_iter_arg *argp = (struct wmap_iter_arg *)arg;
- rb_objspace_t *objspace = argp->objspace;
- VALUE str = argp->value;
- VALUE k = (VALUE)key, v = (VALUE)val;
-
- if (RSTRING_PTR(str)[0] == '#') {
- rb_str_cat2(str, ", ");
- }
- else {
- rb_str_cat2(str, ": ");
- RSTRING_PTR(str)[0] = '#';
- }
- wmap_inspect_append(objspace, str, k);
- rb_str_cat2(str, " => ");
- wmap_inspect_append(objspace, str, v);
-
- return ST_CONTINUE;
-}
-
-static VALUE
-wmap_inspect(VALUE self)
-{
- VALUE str;
- VALUE c = rb_class_name(CLASS_OF(self));
- struct weakmap *w;
- struct wmap_iter_arg args;
-
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
- str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void *)self);
- if (w->wmap2obj) {
- args.objspace = &rb_objspace;
- args.value = str;
- st_foreach(w->wmap2obj, wmap_inspect_i, (st_data_t)&args);
- }
- RSTRING_PTR(str)[0] = '#';
- rb_str_cat2(str, ">");
- return str;
-}
-
-static inline bool
-wmap_live_entry_p(rb_objspace_t *objspace, st_data_t key, st_data_t val)
-{
- return wmap_live_p(objspace, (VALUE)key) && wmap_live_p(objspace, (VALUE)val);
-}
-
-static int
-wmap_each_i(st_data_t key, st_data_t val, st_data_t arg)
-{
- rb_objspace_t *objspace = (rb_objspace_t *)arg;
-
- if (wmap_live_entry_p(objspace, key, val)) {
- rb_yield_values(2, (VALUE)key, (VALUE)val);
- return ST_CONTINUE;
- }
- else {
- return ST_DELETE;
- }
-}
-
-/* Iterates over keys and objects in a weakly referenced object */
-static VALUE
-wmap_each(VALUE self)
-{
- struct weakmap *w;
- rb_objspace_t *objspace = &rb_objspace;
-
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
- st_foreach(w->wmap2obj, wmap_each_i, (st_data_t)objspace);
- return self;
-}
-
-static int
-wmap_each_key_i(st_data_t key, st_data_t val, st_data_t arg)
-{
- rb_objspace_t *objspace = (rb_objspace_t *)arg;
-
- if (wmap_live_entry_p(objspace, key, val)) {
- rb_yield((VALUE)key);
- return ST_CONTINUE;
- }
- else {
- return ST_DELETE;
- }
-}
-
-/* Iterates over keys and objects in a weakly referenced object */
-static VALUE
-wmap_each_key(VALUE self)
-{
- struct weakmap *w;
- rb_objspace_t *objspace = &rb_objspace;
-
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
- st_foreach(w->wmap2obj, wmap_each_key_i, (st_data_t)objspace);
- return self;
-}
-
-static int
-wmap_each_value_i(st_data_t key, st_data_t val, st_data_t arg)
-{
- rb_objspace_t *objspace = (rb_objspace_t *)arg;
-
- if (wmap_live_entry_p(objspace, key, val)) {
- rb_yield((VALUE)val);
- return ST_CONTINUE;
- }
- else {
- return ST_DELETE;
- }
-}
-
-/* Iterates over keys and objects in a weakly referenced object */
-static VALUE
-wmap_each_value(VALUE self)
-{
- struct weakmap *w;
- rb_objspace_t *objspace = &rb_objspace;
-
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
- st_foreach(w->wmap2obj, wmap_each_value_i, (st_data_t)objspace);
- return self;
-}
-
-static int
-wmap_keys_i(st_data_t key, st_data_t val, st_data_t arg)
-{
- struct wmap_iter_arg *argp = (struct wmap_iter_arg *)arg;
- rb_objspace_t *objspace = argp->objspace;
- VALUE ary = argp->value;
-
- if (wmap_live_entry_p(objspace, key, val)) {
- rb_ary_push(ary, (VALUE)key);
- return ST_CONTINUE;
- }
- else {
- return ST_DELETE;
- }
-}
-
-/* Iterates over keys and objects in a weakly referenced object */
-static VALUE
-wmap_keys(VALUE self)
-{
- struct weakmap *w;
- struct wmap_iter_arg args;
-
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
- args.objspace = &rb_objspace;
- args.value = rb_ary_new();
- st_foreach(w->wmap2obj, wmap_keys_i, (st_data_t)&args);
- return args.value;
-}
-
-static int
-wmap_values_i(st_data_t key, st_data_t val, st_data_t arg)
-{
- struct wmap_iter_arg *argp = (struct wmap_iter_arg *)arg;
- rb_objspace_t *objspace = argp->objspace;
- VALUE ary = argp->value;
-
- if (wmap_live_entry_p(objspace, key, val)) {
- rb_ary_push(ary, (VALUE)val);
- return ST_CONTINUE;
- }
- else {
- return ST_DELETE;
- }
-}
-
-/* Iterates over values and objects in a weakly referenced object */
-static VALUE
-wmap_values(VALUE self)
-{
- struct weakmap *w;
- struct wmap_iter_arg args;
-
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
- args.objspace = &rb_objspace;
- args.value = rb_ary_new();
- st_foreach(w->wmap2obj, wmap_values_i, (st_data_t)&args);
- return args.value;
-}
-
-static int
-wmap_aset_update(st_data_t *key, st_data_t *val, st_data_t arg, int existing)
-{
- VALUE size, *ptr, *optr;
- if (existing) {
- size = (ptr = optr = (VALUE *)*val)[0];
- ++size;
- SIZED_REALLOC_N(ptr, VALUE, size + 1, size);
- }
- else {
- optr = 0;
- size = 1;
- ptr = ruby_xmalloc0(2 * sizeof(VALUE));
- }
- ptr[0] = size;
- ptr[size] = (VALUE)arg;
- if (ptr == optr) return ST_STOP;
- *val = (st_data_t)ptr;
- return ST_CONTINUE;
-}
-
-/* Creates a weak reference from the given key to the given value */
-static VALUE
-wmap_aset(VALUE self, VALUE key, VALUE value)
-{
- struct weakmap *w;
-
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
- if (FL_ABLE(value)) {
- define_final0(value, w->final);
- }
- if (FL_ABLE(key)) {
- define_final0(key, w->final);
- }
-
- st_update(w->obj2wmap, (st_data_t)value, wmap_aset_update, key);
- st_insert(w->wmap2obj, (st_data_t)key, (st_data_t)value);
- return nonspecial_obj_id(value);
-}
-
-/* Retrieves a weakly referenced object with the given key */
-static VALUE
-wmap_lookup(VALUE self, VALUE key)
-{
- st_data_t data;
- VALUE obj;
- struct weakmap *w;
- rb_objspace_t *objspace = &rb_objspace;
- GC_ASSERT(wmap_live_p(objspace, key));
-
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
- if (!st_lookup(w->wmap2obj, (st_data_t)key, &data)) return Qundef;
- obj = (VALUE)data;
- if (!wmap_live_p(objspace, obj)) return Qundef;
- return obj;
-}
-
-/* Retrieves a weakly referenced object with the given key */
-static VALUE
-wmap_aref(VALUE self, VALUE key)
-{
- VALUE obj = wmap_lookup(self, key);
- return !UNDEF_P(obj) ? obj : Qnil;
-}
-
-/* Returns +true+ if +key+ is registered */
-static VALUE
-wmap_has_key(VALUE self, VALUE key)
-{
- return RBOOL(!UNDEF_P(wmap_lookup(self, key)));
-}
-
-/* Returns the number of referenced objects */
-static VALUE
-wmap_size(VALUE self)
-{
- struct weakmap *w;
- st_index_t n;
-
- TypedData_Get_Struct(self, struct weakmap, &weakmap_type, w);
- n = w->wmap2obj->num_entries;
-#if SIZEOF_ST_INDEX_T <= SIZEOF_LONG
- return ULONG2NUM(n);
-#else
- return ULL2NUM(n);
-#endif
-}
-
-
-/*
- ------------------------------ WeakKeyMap ------------------------------
-*/
-
-typedef struct weakkeymap_entry {
- VALUE obj;
- st_index_t hash;
-} weakkeymap_entry_t;
-
-struct weakkeymap {
- st_table *map;
- st_table *obj2hash;
- VALUE final;
-};
-
-static int
-weakkeymap_cmp_entry(st_data_t a, st_data_t b)
-{
- struct weakkeymap_entry *entry_a = (struct weakkeymap_entry *)a;
- struct weakkeymap_entry *entry_b = (struct weakkeymap_entry *)b;
- if (entry_a == entry_b) {
- return 0;
- }
- else {
- return rb_any_cmp(entry_a->obj, entry_b->obj);
- }
-}
-
-static st_index_t
-weakkeymap_hash_entry(st_data_t a)
-{
- struct weakkeymap_entry *entry_a = (struct weakkeymap_entry *)a;
- return entry_a->hash;
-}
-
-static const struct st_hash_type weakkeymap_hash = {
- weakkeymap_cmp_entry,
- weakkeymap_hash_entry,
-};
-
-static void
-wkmap_compact(void *ptr)
-{
- struct weakkeymap *w = ptr;
- if (w->map) rb_gc_update_tbl_refs(w->map);
- w->final = rb_gc_location(w->final);
-}
-
-static void
-wkmap_mark(void *ptr)
-{
- struct weakkeymap *w = ptr;
- rb_mark_tbl_no_pin(w->map);
- rb_gc_mark_movable(w->final);
-}
-
-static void
-wkmap_free(void *ptr)
-{
- struct weakkeymap *w = ptr;
- st_free_table(w->map);
- st_free_table(w->obj2hash);
- xfree(w);
-}
-
-static size_t
-wkmap_memsize(const void *ptr)
-{
- const struct weakkeymap *w = ptr;
- return sizeof(struct weakkeymap) + st_memsize(w->map) + st_memsize(w->obj2hash);
-}
-
-static const rb_data_type_t weakkeymap_type = {
- "weakkeymap",
- {
- wkmap_mark,
- wkmap_free,
- wkmap_memsize,
- wkmap_compact,
- },
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
-};
-
-static VALUE
-wkmap_finalize(RB_BLOCK_CALL_FUNC_ARGLIST(objid, self))
-{
- struct weakkeymap *w;
- VALUE key;
-
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
-
- /* Get reference from object id. */
- if ((key = id2ref_obj_tbl(&rb_objspace, objid)) == Qundef) {
- rb_bug("wkmap_finalize: objid is not found.");
- }
-
- st_index_t hash;
- if (st_delete(w->obj2hash, (st_data_t *)key, &hash)) {
- weakkeymap_entry_t lookup_entry = {key, hash};
- weakkeymap_entry_t *deleted_entry = NULL;
- if (st_get_key(w->map, (st_data_t)&lookup_entry, (st_data_t *)deleted_entry)) {
- st_data_t deleted_value;
- st_delete(w->map, (st_data_t *)deleted_entry, &deleted_value);
- xfree(deleted_entry);
- }
- }
-
- return self;
-}
-
-static VALUE
-wkmap_allocate(VALUE klass)
-{
- struct weakkeymap *w;
- VALUE obj = TypedData_Make_Struct(klass, struct weakkeymap, &weakkeymap_type, w);
- w->map = st_init_table(&weakkeymap_hash);
- w->obj2hash = rb_init_identtable();
- w->final = rb_func_lambda_new(wkmap_finalize, obj, 1, 1);
- return obj;
-}
-
-static st_index_t
-wkmap_lookup_hash(struct weakkeymap *w, VALUE key)
-{
- st_index_t hash;
- if (!st_lookup(w->obj2hash, (st_data_t)key, &hash)) {
- hash = rb_any_hash(key);
- }
- return hash;
-}
-
-static weakkeymap_entry_t*
-wkmap_lookup_entry(struct weakkeymap *w, VALUE key, st_index_t hash)
-{
- st_data_t data;
- weakkeymap_entry_t lookup_entry = {key, hash};
-
- if (st_get_key(w->map, (st_data_t)&lookup_entry, &data)) {
- return (weakkeymap_entry_t *)data;
- }
-
- return NULL;
-}
-
-static VALUE
-wkmap_lookup(VALUE self, VALUE key)
-{
- st_data_t data;
- struct weakkeymap *w;
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
-
- st_index_t hash = rb_any_hash(key);
- weakkeymap_entry_t lookup_entry = {key, hash};
-
- if (st_lookup(w->map, (st_data_t)&lookup_entry, &data)) {
- return (VALUE)data;
- }
- return Qundef;
-}
-
-/*
- * call-seq:
- * map[key] -> value
- *
- * Returns the value associated with the given +key+ if found.
- *
- * If +key+ is not found, returns +nil+.
- */
-static VALUE
-wkmap_aref(VALUE self, VALUE key)
-{
- VALUE obj = wkmap_lookup(self, key);
- return obj != Qundef ? obj : Qnil;
-}
-
-/*
- * call-seq:
- * map[key] = value -> value
- *
- * Associates the given +value+ with the given +key+; returns +value+.
- *
- * The reference to +key+ is weak, so when there is no other reference
- * to +key+ it may be garbage collected.
- *
- * If the given +key+ exists, replaces its value with the given +value+;
- * the ordering is not affected
- */
-static VALUE
-wkmap_aset(VALUE self, VALUE key, VALUE value)
-{
- struct weakkeymap *w;
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
-
- if (!(FL_ABLE(key) && !SYMBOL_P(key) && !RB_BIGNUM_TYPE_P(key))) {
- rb_raise(rb_eArgError, "WeakKeyMap must be garbage collectable");
- }
-
- st_index_t hash = wkmap_lookup_hash(w, key);
- weakkeymap_entry_t *key_entry = wkmap_lookup_entry(w, key, hash);
-
- if (!key_entry) {
- key_entry = ALLOC(weakkeymap_entry_t);
- key_entry->obj = key;
- key_entry->hash = hash;
- }
-
- if (!st_insert(w->map, (st_data_t)key_entry, (st_data_t)value)) {
- st_insert(w->obj2hash, (st_data_t)key, (st_data_t)hash);
- define_final0(key, w->final);
- }
-
- return value;
-}
-
-/*
- * call-seq:
- * map.getkey(key) -> existing_key or nil
- *
- * Returns the existing equal key if it exists, otherwise returns +nil+.
- */
-static VALUE
-wkmap_getkey(VALUE self, VALUE key)
-{
- struct weakkeymap *w;
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
-
- st_index_t hash = rb_any_hash(key);
- weakkeymap_entry_t lookup_entry = {key, hash};
-
- weakkeymap_entry_t *key_entry = NULL;
- if (st_get_key(w->map, (st_data_t)&lookup_entry, (st_data_t *)&key_entry)) {
- GC_ASSERT(key_entry != NULL);
-
- VALUE obj = key_entry->obj;
- if (wmap_live_p(&rb_objspace, obj)) {
- return obj;
- }
- }
- return Qnil;
-}
-
-/*
- * call-seq:
- * hash.key?(key) -> true or false
- *
- * Returns +true+ if +key+ is a key in +self+, otherwise +false+.
- */
-static VALUE
-wkmap_has_key(VALUE self, VALUE key)
-{
- return RBOOL(wkmap_lookup(self, key) != Qundef);
-}
-
-/*
- * call-seq:
- * map.clear -> self
- *
- * Removes all map entries; returns +self+.
- */
-static VALUE
-wkmap_clear(VALUE self)
-{
- struct weakkeymap *w;
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
- if (w->map) {
- st_clear(w->map);
- }
- if (w->obj2hash) {
- st_clear(w->obj2hash);
- }
- return self;
-}
-
-/*
- * call-seq:
- * map.inspect -> new_string
- *
- * Returns a new \String containing informations about the map:
-
- * m = ObjectSpace::WeakKeyMap.new
- * m[key] = value
- * m.inspect # => "#<ObjectSpace::WeakKeyMap:0x00000001028dcba8 size=1>"
- *
- */
-static VALUE
-wkmap_inspect(VALUE self)
-{
- struct weakkeymap *w;
- TypedData_Get_Struct(self, struct weakkeymap, &weakkeymap_type, w);
-
- st_index_t n = 0;
- if (w->map) {
- n = w->map->num_entries;
- }
-
-#if SIZEOF_ST_INDEX_T <= SIZEOF_LONG
- const char * format = "#<%"PRIsVALUE":%p size=%lu>";
-#else
- const char * format = "#<%"PRIsVALUE":%p size=%llu>";
-#endif
-
- VALUE str = rb_sprintf(format, rb_class_name(CLASS_OF(self)), (void *)self, n);
- return str;
-}
-
-/*
------------------------------ GC profiler ------------------------------
*/
@@ -14817,25 +14046,6 @@ rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
* Finalizer one on 537763480
*/
-/*
- * Document-class: ObjectSpace::WeakMap
- *
- * An ObjectSpace::WeakMap object holds references to
- * any objects, but those objects can get garbage collected.
- *
- * This class is mostly used internally by WeakRef, please use
- * +lib/weakref.rb+ for the public interface.
- */
-
-/*
- * Document-class: ObjectSpace::WeakKeyMap
- *
- * An ObjectSpace::WeakKeyMap object holds references to
- * any objects, but objects uses as keys can be garbage collected.
- *
- * Objects used as values can't be garbage collected until the key is.
- */
-
/* Document-class: GC::Profiler
*
* The GC profiler provides access to information on GC runs including time,
@@ -14925,37 +14135,6 @@ Init_GC(void)
rb_define_module_function(rb_mObjSpace, "count_objects", count_objects, -1);
- {
- VALUE rb_cWeakMap = rb_define_class_under(rb_mObjSpace, "WeakMap", rb_cObject);
- rb_define_alloc_func(rb_cWeakMap, wmap_allocate);
- rb_define_method(rb_cWeakMap, "[]=", wmap_aset, 2);
- rb_define_method(rb_cWeakMap, "[]", wmap_aref, 1);
- rb_define_method(rb_cWeakMap, "include?", wmap_has_key, 1);
- rb_define_method(rb_cWeakMap, "member?", wmap_has_key, 1);
- rb_define_method(rb_cWeakMap, "key?", wmap_has_key, 1);
- rb_define_method(rb_cWeakMap, "inspect", wmap_inspect, 0);
- rb_define_method(rb_cWeakMap, "each", wmap_each, 0);
- rb_define_method(rb_cWeakMap, "each_pair", wmap_each, 0);
- rb_define_method(rb_cWeakMap, "each_key", wmap_each_key, 0);
- rb_define_method(rb_cWeakMap, "each_value", wmap_each_value, 0);
- rb_define_method(rb_cWeakMap, "keys", wmap_keys, 0);
- rb_define_method(rb_cWeakMap, "values", wmap_values, 0);
- rb_define_method(rb_cWeakMap, "size", wmap_size, 0);
- rb_define_method(rb_cWeakMap, "length", wmap_size, 0);
- rb_include_module(rb_cWeakMap, rb_mEnumerable);
- }
-
- {
- VALUE rb_cWeakKeyMap = rb_define_class_under(rb_mObjSpace, "WeakKeyMap", rb_cObject);
- rb_define_alloc_func(rb_cWeakKeyMap, wkmap_allocate);
- rb_define_method(rb_cWeakKeyMap, "[]=", wkmap_aset, 2);
- rb_define_method(rb_cWeakKeyMap, "[]", wkmap_aref, 1);
- rb_define_method(rb_cWeakKeyMap, "getkey", wkmap_getkey, 1);
- rb_define_method(rb_cWeakKeyMap, "key?", wkmap_has_key, 1);
- rb_define_method(rb_cWeakKeyMap, "clear", wkmap_clear, 0);
- rb_define_method(rb_cWeakKeyMap, "inspect", wkmap_inspect, 0);
- }
-
/* internal methods */
rb_define_singleton_method(rb_mGC, "verify_internal_consistency", gc_verify_internal_consistency_m, 0);
rb_define_singleton_method(rb_mGC, "verify_transient_heap_internal_consistency", gc_verify_transient_heap_internal_consistency, 0);