diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-10-05 08:14:09 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-10-05 08:14:09 +0000 |
commit | e03d6d9eb84764cb854dc500ce8c19d85db53656 (patch) | |
tree | f0682f240c20512d7c888921ce72ecf4f697cc46 /gc.c | |
parent | 7cc6bfa32947dcc60dab6e47250409b7962b29e7 (diff) | |
download | ruby-e03d6d9eb84764cb854dc500ce8c19d85db53656.tar.gz |
* ext/objspace/objspace.c: add ObjectSpace#reachable_objects_from.
This method returns an array of objects referenced by given object.
If given object is special objects such as true/false/nil/Fixnum etc
then it returns nil. See rdoc for details.
[ruby-core:39772]
* test/objspace/test_objspace.rb: add a test for this method.
* gc.c: add rb_objspace_reachable_objects_from().
To make this function, add several member `mark_func_data'
to rb_objspace_t. If mark_func_data is not null, then
gc_mark() calls mark_func_data::mark_func.
* gc.h: export rb_objspace_reachable_objects_from().
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@37094 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'gc.c')
-rw-r--r-- | gc.c | 140 |
1 files changed, 111 insertions, 29 deletions
@@ -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 ------------------------ */ |