diff options
author | tenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2019-04-17 03:17:25 +0000 |
---|---|---|
committer | tenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2019-04-17 03:17:25 +0000 |
commit | 3c55b643aec09bbe779dab25b2397947eded2b9b () | |
tree | d7705428a035cd7c4384a0e34d59415bf3de9ca4 /gc.c | |
parent | fcd679ed11e3e801431f2f931dbe925edb8df0bf (diff) |
Adding `GC.compact` and compacting GC support.
This commit adds the new method `GC.compact` and compacting GC support. Please see this issue for caveats: https://bugs.ruby-lang.org/issues/15626 [Feature #15626] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67576 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | gc.c | 1279 |
1 files changed, 1248 insertions, 31 deletions
@@ -29,6 +29,7 @@ #include "ruby_atomic.h" #include "probes.h" #include "id_table.h" #include <stdio.h> #include <stdarg.h> #include <setjmp.h> @@ -404,6 +405,7 @@ typedef struct RVALUE { VALUE flags; /* always 0 for freed obj */ struct RVALUE *next; } free; struct RBasic basic; struct RObject object; struct RClass klass; @@ -581,6 +583,7 @@ typedef struct rb_objspace { #if USE_RGENGC size_t minor_gc_count; size_t major_gc_count; #if RGENGC_PROFILE > 0 size_t total_generated_normal_object_count; size_t total_generated_shady_object_count; @@ -635,6 +638,12 @@ typedef struct rb_objspace { size_t error_count; #endif } rgengc; #if GC_ENABLE_INCREMENTAL_MARK struct { size_t pooled_slots; @@ -643,6 +652,9 @@ typedef struct rb_objspace { #endif #endif /* USE_RGENGC */ #if GC_DEBUG_STRESS_TO_CLASS VALUE stress_to_class; #endif @@ -682,6 +694,8 @@ struct heap_page { #if USE_RGENGC bits_t wb_unprotected_bits[HEAP_PAGE_BITMAP_LIMIT]; #endif /* the following three bitmaps are cleared at the beginning of full GC */ bits_t mark_bits[HEAP_PAGE_BITMAP_LIMIT]; #if USE_RGENGC @@ -706,6 +720,7 @@ struct heap_page { /* getting bitmap */ #define GET_HEAP_MARK_BITS(x) (&GET_HEAP_PAGE(x)->mark_bits[0]) #if USE_RGENGC #define GET_HEAP_UNCOLLECTIBLE_BITS(x) (&GET_HEAP_PAGE(x)->uncollectible_bits[0]) #define GET_HEAP_WB_UNPROTECTED_BITS(x) (&GET_HEAP_PAGE(x)->wb_unprotected_bits[0]) @@ -826,7 +841,9 @@ VALUE rb_mGC; int ruby_disable_gc = 0; void rb_iseq_mark(const rb_iseq_t *iseq); void rb_iseq_free(const rb_iseq_t *iseq); void rb_gcdebug_print_obj_condition(VALUE obj); @@ -861,8 +878,11 @@ static void gc_sweep_rest(rb_objspace_t *objspace); static void gc_sweep_continue(rb_objspace_t *objspace, rb_heap_t *heap); static inline void gc_mark(rb_objspace_t *objspace, VALUE ptr); static void gc_mark_ptr(rb_objspace_t *objspace, VALUE ptr); NO_SANITIZE("memory", static void gc_mark_maybe(rb_objspace_t *objspace, VALUE ptr)); static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr); static int gc_mark_stacked_objects_incremental(rb_objspace_t *, size_t count); @@ -895,6 +915,14 @@ static inline void gc_prof_sweep_timer_stop(rb_objspace_t *); static inline void gc_prof_set_malloc_info(rb_objspace_t *); static inline void gc_prof_set_heap_info(rb_objspace_t *); #define gc_prof_record(objspace) (objspace)->profile.current_record #define gc_prof_enabled(objspace) ((objspace)->profile.run && (objspace)->profile.current_record) @@ -1020,6 +1048,7 @@ tick(void) #define FL_UNSET2(x,f) FL_CHECK2("FL_UNSET2", x, RBASIC(x)->flags &= ~(f)) #define RVALUE_MARK_BITMAP(obj) MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), (obj)) #define RVALUE_PAGE_MARKED(page, obj) MARKED_IN_BITMAP((page)->mark_bits, (obj)) #if USE_RGENGC @@ -1114,12 +1143,39 @@ check_rvalue_consistency(const VALUE obj) #endif static inline int RVALUE_MARKED(VALUE obj) { check_rvalue_consistency(obj); return RVALUE_MARK_BITMAP(obj) != 0; } #if USE_RGENGC static inline int RVALUE_WB_UNPROTECTED(VALUE obj) @@ -1363,6 +1419,8 @@ rb_objspace_free(rb_objspace_t *objspace) objspace->eden_heap.total_pages = 0; objspace->eden_heap.total_slots = 0; } free_stack_chunks(&objspace->mark_stack); #if !(defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE) if (objspace == &rb_objspace) return; @@ -2207,6 +2265,19 @@ obj_free(rb_objspace_t *objspace, VALUE obj) FL_UNSET(obj, FL_EXIVAR); } #if USE_RGENGC if (RVALUE_WB_UNPROTECTED(obj)) CLEAR_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj); @@ -2374,6 +2445,7 @@ obj_free(rb_objspace_t *objspace, VALUE obj) break; case T_RATIONAL: case T_COMPLEX: break; case T_ICLASS: /* Basically , T_ICLASS shares table with the module */ @@ -2496,6 +2568,9 @@ Init_heap(void) { rb_objspace_t *objspace = &rb_objspace; gc_stress_set(objspace, ruby_initial_gc_stress); #if RGENGC_ESTIMATE_OLDMALLOC @@ -2639,6 +2714,7 @@ internal_object_p(VALUE obj) UNEXPECTED_NODE(internal_object_p); break; case T_NONE: case T_IMEMO: case T_ICLASS: case T_ZOMBIE: @@ -3214,6 +3290,7 @@ id2ref(VALUE obj, VALUE objid) #endif rb_objspace_t *objspace = &rb_objspace; VALUE ptr; void *p0; ptr = NUM2PTR(objid); @@ -3226,6 +3303,10 @@ id2ref(VALUE obj, VALUE objid) if (FLONUM_P(ptr)) return (VALUE)ptr; ptr = obj_id_to_ref(objid); if ((ptr % sizeof(RVALUE)) == (4 << 2)) { ID symid = ptr / sizeof(RVALUE); if (rb_id2str(symid) == 0) @@ -3245,6 +3326,70 @@ id2ref(VALUE obj, VALUE objid) return (VALUE)ptr; } /* * Document-method: __id__ * Document-method: object_id @@ -3301,20 +3446,8 @@ rb_obj_id(VALUE obj) * 24 if 32-bit, double is 8-byte aligned * 40 if 64-bit */ - if (STATIC_SYM_P(obj)) { - return (SYM2ID(obj) * sizeof(RVALUE) + (4 << 2)) | FIXNUM_FLAG; - } - else if (FLONUM_P(obj)) { -#if SIZEOF_LONG == SIZEOF_VOIDP - return LONG2NUM((SIGNED_VALUE)obj); -#else - return LL2NUM((SIGNED_VALUE)obj); -#endif - } - else if (SPECIAL_CONST_P(obj)) { - return LONG2NUM((SIGNED_VALUE)obj); - } - return nonspecial_obj_id(obj); } #include "regint.h" @@ -3437,6 +3570,7 @@ obj_memsize_of(VALUE obj, int use_all_types) break; case T_ZOMBIE: break; default: @@ -3493,6 +3627,7 @@ type_sym(size_t type) COUNT_TYPE(T_NODE); COUNT_TYPE(T_ICLASS); COUNT_TYPE(T_ZOMBIE); #undef COUNT_TYPE default: return INT2NUM(type); break; } @@ -4204,7 +4339,7 @@ mark_locations_array(rb_objspace_t *objspace, register const VALUE *x, register VALUE v; while (n--) { v = *x; - gc_mark_maybe(objspace, v); x++; } } @@ -4226,12 +4361,12 @@ rb_gc_mark_locations(const VALUE *start, const VALUE *end) } static void -gc_mark_values(rb_objspace_t *objspace, long n, const VALUE *values) { long i; for (i=0; i<n; i++) { - gc_mark(objspace, values[i]); } } @@ -4239,17 +4374,52 @@ void rb_gc_mark_values(long n, const VALUE *values) { rb_objspace_t *objspace = &rb_objspace; - gc_mark_values(objspace, n, values); } static int -mark_entry(st_data_t key, st_data_t value, st_data_t data) { rb_objspace_t *objspace = (rb_objspace_t *)data; gc_mark(objspace, (VALUE)value); return ST_CONTINUE; } static void mark_tbl(rb_objspace_t *objspace, st_table *tbl) { @@ -4283,7 +4453,12 @@ mark_keyvalue(st_data_t key, st_data_t value, st_data_t data) { rb_objspace_t *objspace = (rb_objspace_t *)data; - gc_mark(objspace, (VALUE)key); gc_mark(objspace, (VALUE)value); return ST_CONTINUE; } @@ -4463,8 +4638,14 @@ rb_mark_tbl(st_table *tbl) mark_tbl(&rb_objspace, tbl); } static void -gc_mark_maybe(rb_objspace_t *objspace, VALUE obj) { (void)VALGRIND_MAKE_MEM_DEFINED(&obj, sizeof(obj)); if (is_pointer_to_heap(objspace, (void *)obj)) { @@ -4473,19 +4654,35 @@ gc_mark_maybe(rb_objspace_t *objspace, VALUE obj) unpoison_object(obj, false); type = BUILTIN_TYPE(obj); - if (type != T_ZOMBIE && type != T_NONE) { gc_mark_ptr(objspace, obj); } if (ptr) { poison_object(obj); } } } void rb_gc_mark_maybe(VALUE obj) { - gc_mark_maybe(&rb_objspace, obj); } static inline int @@ -4621,6 +4818,21 @@ gc_mark_ptr(rb_objspace_t *objspace, VALUE obj) } static inline void gc_mark(rb_objspace_t *objspace, VALUE obj) { if (!is_markable_object(objspace, obj)) return; @@ -4628,11 +4840,17 @@ gc_mark(rb_objspace_t *objspace, VALUE obj) } void -rb_gc_mark(VALUE ptr) { gc_mark(&rb_objspace, ptr); } /* CAUTION: THIS FUNCTION ENABLE *ONLY BEFORE* SWEEPING. * This function is only for GC_END_MARK timing. */ @@ -4643,6 +4861,12 @@ rb_objspace_marked_object_p(VALUE obj) return RVALUE_MARKED(obj) ? TRUE : FALSE; } static inline void gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj) { @@ -4664,9 +4888,9 @@ gc_mark_imemo(rb_objspace_t *objspace, VALUE obj) { const rb_env_t *env = (const rb_env_t *)obj; GC_ASSERT(VM_ENV_ESCAPED_P(env->ep)); - gc_mark_values(objspace, (long)env->env_size, env->env); VM_ENV_FLAGS_SET(env->ep, VM_ENV_FLAG_WB_REQUIRED); - gc_mark(objspace, (VALUE)rb_vm_env_prev_env(env)); gc_mark(objspace, (VALUE)env->iseq); } return; @@ -4758,7 +4982,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj) case T_MODULE: mark_m_tbl(objspace, RCLASS_M_TBL(obj)); if (!RCLASS_EXT(obj)) break; - mark_tbl(objspace, RCLASS_IV_TBL(obj)); mark_const_tbl(objspace, RCLASS_CONST_TBL(obj)); gc_mark(objspace, RCLASS_SUPER((VALUE)obj)); break; @@ -4886,6 +5110,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj) #if GC_DEBUG rb_gcdebug_print_obj_condition((VALUE)obj); #endif if (BUILTIN_TYPE(obj) == T_NONE) rb_bug("rb_gc_mark(): %p is T_NONE", (void *)obj); if (BUILTIN_TYPE(obj) == T_ZOMBIE) rb_bug("rb_gc_mark(): %p is T_ZOMBIE", (void *)obj); rb_bug("rb_gc_mark(): unknown data type 0x%x(%p) %s", @@ -5365,7 +5590,12 @@ verify_internal_consistency_i(void *page_start, void *page_end, size_t stride, v /* count objects */ data->live_object_count++; - rb_objspace_reachable_objects_from(obj, check_children_i, (void *)data); #if USE_RGENGC /* check health of children */ @@ -6115,6 +6345,7 @@ rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace, rb_heap_t *heap) list_for_each(&heap->pages, page, page_node) { memset(&page->mark_bits[0], 0, HEAP_PAGE_BITMAP_SIZE); memset(&page->marking_bits[0], 0, HEAP_PAGE_BITMAP_SIZE); memset(&page->uncollectible_bits[0], 0, HEAP_PAGE_BITMAP_SIZE); page->flags.has_uncollectible_shady_objects = FALSE; @@ -6369,7 +6600,7 @@ rb_obj_gc_flags(VALUE obj, ID* flags, size_t max) size_t n = 0; static ID ID_marked; #if USE_RGENGC - static ID ID_wb_protected, ID_old, ID_marking, ID_uncollectible; #endif if (!ID_marked) { @@ -6380,6 +6611,7 @@ rb_obj_gc_flags(VALUE obj, ID* flags, size_t max) I(old); I(marking); I(uncollectible); #endif #undef I } @@ -6391,6 +6623,7 @@ rb_obj_gc_flags(VALUE obj, ID* flags, size_t max) if (MARKED_IN_BITMAP(GET_HEAP_MARKING_BITS(obj), obj) && n<max) flags[n++] = ID_marking; #endif if (MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj) && n<max) flags[n++] = ID_marked; return n; } @@ -6964,6 +7197,955 @@ gc_start_internal(int argc, VALUE *argv, VALUE self) return Qnil; } VALUE rb_gc_start(void) { @@ -7176,6 +8358,7 @@ enum gc_stat_sym { #if USE_RGENGC gc_stat_sym_minor_gc_count, gc_stat_sym_major_gc_count, gc_stat_sym_remembered_wb_unprotected_objects, gc_stat_sym_remembered_wb_unprotected_objects_limit, gc_stat_sym_old_objects, @@ -7251,6 +8434,7 @@ setup_gc_stat_symbols(void) S(malloc_increase_bytes_limit); #if USE_RGENGC S(minor_gc_count); S(major_gc_count); S(remembered_wb_unprotected_objects); S(remembered_wb_unprotected_objects_limit); @@ -7423,6 +8607,7 @@ gc_stat_internal(VALUE hash_or_sym) SET(malloc_increase_bytes_limit, malloc_limit); #if USE_RGENGC SET(minor_gc_count, objspace->profile.minor_gc_count); SET(major_gc_count, objspace->profile.major_gc_count); SET(remembered_wb_unprotected_objects, objspace->rgengc.uncollectible_wb_unprotected_objects); SET(remembered_wb_unprotected_objects_limit, objspace->rgengc.uncollectible_wb_unprotected_objects_limit); @@ -8628,10 +9813,25 @@ wmap_mark_map(st_data_t key, st_data_t val, st_data_t arg) } #endif 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 @@ -9631,6 +10831,7 @@ type_name(int type, VALUE obj) TYPE_NAME(T_UNDEF); TYPE_NAME(T_IMEMO); TYPE_NAME(T_ICLASS); TYPE_NAME(T_ZOMBIE); case T_DATA: if (obj && rb_objspace_data_type_name(obj)) { @@ -9679,7 +10880,7 @@ method_type_name(rb_method_type_t type) static void rb_raw_iseq_info(char *buff, const int buff_size, const rb_iseq_t *iseq) { - if (iseq->body && iseq->body->location.label) { VALUE path = rb_iseq_path(iseq); VALUE n = iseq->body->location.first_lineno; snprintf(buff, buff_size, "%s %s@%s:%d", buff, @@ -9710,10 +10911,11 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj) const int age = RVALUE_FLAGS_AGE(RBASIC(obj)->flags); if (is_pointer_to_heap(&rb_objspace, (void *)obj)) { - snprintf(buff, buff_size, "%p [%d%s%s%s%s] %s", (void *)obj, age, C(RVALUE_UNCOLLECTIBLE_BITMAP(obj), "L"), C(RVALUE_MARK_BITMAP(obj), "M"), C(RVALUE_MARKING_BITMAP(obj), "R"), C(RVALUE_WB_UNPROTECTED_BITMAP(obj), "U"), obj_type_name(obj)); @@ -9738,10 +10940,12 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj) snprintf(buff, buff_size, "%s (temporary internal)", buff); } else { VALUE class_path = rb_class_path_cached(RBASIC(obj)->klass); if (!NIL_P(class_path)) { snprintf(buff, buff_size, "%s (%s)", buff, RSTRING_PTR(class_path)); } } #if GC_DEBUG @@ -9777,6 +10981,10 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj) snprintf(buff, buff_size, "%s %s", buff, RSTRING_PTR(obj)); break; } case T_HASH: { snprintf(buff, buff_size, "%s [%c%c] %d", buff, RHASH_AR_TABLE_P(obj) ? 'A' : 'S', @@ -9938,6 +11146,12 @@ rb_gcdebug_print_obj_condition(VALUE obj) fprintf(stderr, "created at: %s:%d\n", RANY(obj)->file, RANY(obj)->line); if (is_pointer_to_heap(objspace, (void *)obj)) { fprintf(stderr, "pointer to heap?: true\n"); } @@ -9947,6 +11161,7 @@ rb_gcdebug_print_obj_condition(VALUE obj) } fprintf(stderr, "marked? : %s\n", MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj) ? "true" : "false"); #if USE_RGENGC fprintf(stderr, "age? : %d\n", RVALUE_AGE(obj)); fprintf(stderr, "old? : %s\n", RVALUE_OLD_P(obj) ? "true" : "false"); @@ -10105,6 +11320,7 @@ Init_GC(void) rb_define_singleton_method(rb_mGC, "count", gc_count, 0); rb_define_singleton_method(rb_mGC, "stat", gc_stat, -1); rb_define_singleton_method(rb_mGC, "latest_gc_info", gc_latest_gc_info, -1); rb_define_method(rb_mGC, "garbage_collect", gc_start_internal, -1); gc_constants = rb_hash_new(); @@ -10165,6 +11381,7 @@ Init_GC(void) /* internal methods */ rb_define_singleton_method(rb_mGC, "verify_internal_consistency", gc_verify_internal_consistency, 0); rb_define_singleton_method(rb_mGC, "verify_transient_heap_internal_consistency", gc_verify_transient_heap_internal_consistency, 0); #if MALLOC_ALLOCATED_SIZE rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0); |