summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c140
1 files changed, 111 insertions, 29 deletions
diff --git a/gc.c b/gc.c
index e87e0295966..d34e70940b3 100644
--- a/gc.c
+++ b/gc.c
@@ -273,6 +273,11 @@ typedef struct rb_objspace {
struct gc_list *global_list;
size_t count;
int gc_stress;
+
+ struct mark_func_data_struct {
+ VALUE data;
+ void (*mark_func)(struct rb_objspace *objspace, VALUE v);
+ } *mark_func_data;
} rb_objspace_t;
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
@@ -1138,30 +1143,40 @@ struct os_each_struct {
};
static int
+internal_object_p(VALUE obj)
+{
+ RVALUE *p = (RVALUE *)obj;
+
+ if (p->as.basic.flags) {
+ switch (BUILTIN_TYPE(p)) {
+ case T_NONE:
+ case T_ICLASS:
+ case T_NODE:
+ case T_ZOMBIE:
+ break;
+ case T_CLASS:
+ if (FL_TEST(p, FL_SINGLETON))
+ break;
+ default:
+ if (!p->as.basic.klass) break;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
os_obj_of_i(void *vstart, void *vend, size_t stride, void *data)
{
struct os_each_struct *oes = (struct os_each_struct *)data;
RVALUE *p = (RVALUE *)vstart, *pend = (RVALUE *)vend;
- volatile VALUE v;
for (; 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;
- case T_CLASS:
- if (FL_TEST(p, FL_SINGLETON))
- continue;
- default:
- if (!p->as.basic.klass) continue;
- v = (VALUE)p;
- if (!oes->of || rb_obj_is_kind_of(v, oes->of)) {
- rb_yield(v);
- oes->num++;
- }
+ volatile VALUE v = (VALUE)p;
+ if (!internal_object_p(v)) {
+ if (!oes->of || rb_obj_is_kind_of(v, oes->of)) {
+ rb_yield(v);
+ oes->num++;
}
}
}
@@ -2521,17 +2536,31 @@ gc_mark_ptr(rb_objspace_t *objspace, VALUE ptr)
return 1;
}
+static int
+markable_object_p(rb_objspace_t *objspace, VALUE ptr)
+{
+ register RVALUE *obj = RANY(ptr);
+
+ if (rb_special_const_p(ptr)) return 0; /* special const not marked */
+ if (obj->as.basic.flags == 0) return 0 ; /* free cell */
+
+ return 1;
+}
+
static void
gc_mark(rb_objspace_t *objspace, VALUE ptr)
{
- register RVALUE *obj;
-
- obj = RANY(ptr);
- if (rb_special_const_p(ptr)) return; /* special const not marked */
- if (obj->as.basic.flags == 0) return; /* free cell */
- if (!gc_mark_ptr(objspace, ptr)) return; /* already marked */
+ if (!markable_object_p(objspace, ptr)) {
+ return;
+ }
- push_mark_stack(&objspace->mark_stack, ptr);
+ if (LIKELY(objspace->mark_func_data == 0)) {
+ if (!gc_mark_ptr(objspace, ptr)) return; /* already marked */
+ push_mark_stack(&objspace->mark_stack, ptr);
+ }
+ else {
+ objspace->mark_func_data->mark_func(objspace, ptr);
+ }
}
void
@@ -2548,10 +2577,16 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr)
goto marking; /* skip */
again:
- obj = RANY(ptr);
- if (rb_special_const_p(ptr)) return; /* special const not marked */
- if (obj->as.basic.flags == 0) return; /* free cell */
- if (!gc_mark_ptr(objspace, ptr)) return; /* already marked */
+ if (LIKELY(objspace->mark_func_data == 0)) {
+ obj = RANY(ptr);
+ if (rb_special_const_p(ptr)) return; /* special const not marked */
+ if (obj->as.basic.flags == 0) return; /* free cell */
+ if (!gc_mark_ptr(objspace, ptr)) return; /* already marked */
+ }
+ else {
+ gc_mark(objspace, ptr);
+ return;
+ }
marking:
if (FL_TEST(obj, FL_EXIVAR)) {
@@ -2953,6 +2988,8 @@ rb_gc_unregister_address(VALUE *addr)
static int
garbage_collect(rb_objspace_t *objspace)
{
+ struct mark_func_data_struct *prev_mark_func_data;
+
if (GC_NOTIFY) printf("start garbage_collect()\n");
if (!heaps) {
@@ -2964,6 +3001,9 @@ garbage_collect(rb_objspace_t *objspace)
gc_prof_timer_start(objspace);
+ prev_mark_func_data = objspace->mark_func_data;
+ objspace->mark_func_data = 0;
+
rest_sweep(objspace);
during_gc++;
@@ -2973,6 +3013,8 @@ garbage_collect(rb_objspace_t *objspace)
gc_sweep(objspace);
gc_prof_sweep_timer_stop(objspace);
+ objspace->mark_func_data = prev_mark_func_data;
+
gc_prof_timer_stop(objspace, Qtrue);
if (GC_NOTIFY) printf("end garbage_collect()\n");
return TRUE;
@@ -3241,6 +3283,46 @@ rb_gc_set_params(void)
}
}
+static void
+collect_refs(rb_objspace_t *objspace, VALUE obj)
+{
+ if (markable_object_p(objspace, obj) && !internal_object_p(obj)) {
+ st_insert((st_table *)objspace->mark_func_data->data, obj, Qtrue);
+ }
+}
+
+static int
+collect_keys(st_data_t key, st_data_t value, st_data_t data)
+{
+ VALUE ary = (VALUE)data;
+ rb_ary_push(ary, (VALUE)key);
+ return ST_CONTINUE;
+}
+
+VALUE
+rb_objspace_reachable_objects_from(VALUE obj)
+{
+ rb_objspace_t *objspace = &rb_objspace;
+
+ if (markable_object_p(objspace, obj)) {
+ st_table *refs = st_init_numtable();
+ struct mark_func_data_struct mfd;
+ VALUE ret = rb_ary_new();
+ mfd.mark_func = collect_refs;
+ mfd.data = (VALUE)refs;
+ objspace->mark_func_data = &mfd;
+
+ gc_mark_children(objspace, obj);
+
+ objspace->mark_func_data = 0;
+ st_foreach(refs, collect_keys, (st_data_t)ret);
+ return ret;
+ }
+ else {
+ return Qnil;
+ }
+}
+
/*
------------------------ Extended allocator ------------------------
*/