summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
-rw-r--r--gc.c1279
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);