diff --git a/debug_counter.h b/debug_counter.h index c151e535b0..1e7df10874 100644 --- a/debug_counter.h +++ b/debug_counter.h @@ -141,6 +141,7 @@ RB_DEBUG_COUNTER(gc_major_oldmalloc) * * [attr] * * _ptr: R?? is not embed. * * _embed: R?? is embed. + * * _transient: R?? uses transient heap. * * type specific attr. * * str_shared: str is shared. * * str_nofree: nofree @@ -162,8 +163,9 @@ RB_DEBUG_COUNTER(obj_free) RB_DEBUG_COUNTER(obj_promote) RB_DEBUG_COUNTER(obj_wb_unprotect) -RB_DEBUG_COUNTER(obj_obj_ptr) RB_DEBUG_COUNTER(obj_obj_embed) +RB_DEBUG_COUNTER(obj_obj_transient) +RB_DEBUG_COUNTER(obj_obj_ptr) RB_DEBUG_COUNTER(obj_str_ptr) RB_DEBUG_COUNTER(obj_str_embed) @@ -171,8 +173,9 @@ RB_DEBUG_COUNTER(obj_str_shared) RB_DEBUG_COUNTER(obj_str_nofree) RB_DEBUG_COUNTER(obj_str_fstr) -RB_DEBUG_COUNTER(obj_ary_ptr) RB_DEBUG_COUNTER(obj_ary_embed) +RB_DEBUG_COUNTER(obj_ary_transient) +RB_DEBUG_COUNTER(obj_ary_ptr) RB_DEBUG_COUNTER(obj_hash_empty) RB_DEBUG_COUNTER(obj_hash_under4) diff --git a/gc.c b/gc.c index 2504969303..22335586a6 100644 --- a/gc.c +++ b/gc.c @@ -2215,14 +2215,17 @@ obj_free(rb_objspace_t *objspace, VALUE obj) switch (BUILTIN_TYPE(obj)) { case T_OBJECT: - if (!(RANY(obj)->as.basic.flags & ROBJECT_EMBED) && - RANY(obj)->as.object.as.heap.ivptr) { - xfree(RANY(obj)->as.object.as.heap.ivptr); - RB_DEBUG_COUNTER_INC(obj_obj_ptr); - } - else { + if ((RANY(obj)->as.basic.flags & ROBJECT_EMBED) || + RANY(obj)->as.object.as.heap.ivptr == NULL) { RB_DEBUG_COUNTER_INC(obj_obj_embed); - } + } + else if (ROBJ_TRANSIENT_P(obj)) { + RB_DEBUG_COUNTER_INC(obj_obj_transient); + } + else { + xfree(RANY(obj)->as.object.as.heap.ivptr); + RB_DEBUG_COUNTER_INC(obj_obj_ptr); + } break; case T_MODULE: case T_CLASS: @@ -4717,10 +4720,18 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj) case T_OBJECT: { - uint32_t i, len = ROBJECT_NUMIV(obj); - VALUE *ptr = ROBJECT_IVPTR(obj); - for (i = 0; i < len; i++) { - gc_mark(objspace, *ptr++); + const VALUE * const ptr = ROBJECT_IVPTR(obj); + + if (ptr) { + uint32_t i, len = ROBJECT_NUMIV(obj); + for (i = 0; i < len; i++) { + gc_mark(objspace, ptr[i]); + } + + if (objspace->mark_func_data == NULL && + ROBJ_TRANSIENT_P(obj)) { + rb_transient_heap_mark(obj, ptr); + } } } break; @@ -9645,6 +9656,19 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj) } break; } + case T_OBJECT: + { + uint32_t len = ROBJECT_NUMIV(obj); + + if (RANY(obj)->as.basic.flags & ROBJECT_EMBED) { + snprintf(buff, buff_size, "%s (embed) len:%d", buff, len); + } + else { + VALUE *ptr = ROBJECT_IVPTR(obj); + snprintf(buff, buff_size, "%s len:%d ptr:%p", buff, len, ptr); + } + } + break; case T_DATA: { const struct rb_block *block; const rb_iseq_t *iseq; diff --git a/internal.h b/internal.h index ffe84528db..b680c8c79b 100644 --- a/internal.h +++ b/internal.h @@ -1922,6 +1922,9 @@ extern rb_encoding OnigEncodingUTF_8; #endif /* variable.c */ +#define ROBJECT_TRANSIENT_FLAG FL_USER13 +#define ROBJ_TRANSIENT_P(obj) FL_TEST_RAW((obj), ROBJECT_TRANSIENT_FLAG) + void rb_gc_mark_global_tbl(void); size_t rb_generic_ivar_memsize(VALUE); VALUE rb_search_class_path(VALUE); diff --git a/variable.c b/variable.c index 1c23173d6c..367fbcb6ef 100644 --- a/variable.c +++ b/variable.c @@ -22,6 +22,7 @@ #include "id_table.h" #include "debug_counter.h" #include "vm_core.h" +#include "transient_heap.h" static struct rb_id_table *rb_global_tbl; static ID autoload, classpath, tmp_classpath, classid; @@ -1333,53 +1334,124 @@ generic_ivar_set(VALUE obj, ID id, VALUE val) RB_OBJ_WRITTEN(obj, Qundef, val); } -VALUE -rb_ivar_set(VALUE obj, ID id, VALUE val) +static VALUE * +obj_ivar_heap_alloc(VALUE obj, size_t newsize) +{ + VALUE *newptr = rb_transient_heap_alloc(obj, sizeof(VALUE) * newsize); + + if (newptr != NULL) { + FL_SET_RAW(obj, ROBJECT_TRANSIENT_FLAG); + } + else { + FL_UNSET_RAW(obj, ROBJECT_TRANSIENT_FLAG); + newptr = ALLOC_N(VALUE, newsize); + } + return newptr; +} + +static VALUE * +obj_ivar_heap_realloc(VALUE obj, int32_t len, size_t newsize) +{ + VALUE *newptr; + int i; + + if (ROBJ_TRANSIENT_P(obj)) { + const VALUE *orig_ptr = ROBJECT(obj)->as.heap.ivptr; + if ((newptr = obj_ivar_heap_alloc(obj, newsize)) != NULL) { + /* ok */ + } + else { + newptr = ALLOC_N(VALUE, newsize); + FL_UNSET_RAW(obj, ROBJECT_TRANSIENT_FLAG); + } + ROBJECT(obj)->as.heap.ivptr = newptr; + for (i=0; i<(int)len; i++) { + newptr[i] = orig_ptr[i]; + } + } + else { + REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize); + newptr = ROBJECT(obj)->as.heap.ivptr; + } + + return newptr; +} + +void +rb_obj_transient_heap_evacuate(VALUE obj, int promote) +{ + if (ROBJ_TRANSIENT_P(obj)) { + uint32_t len = ROBJECT_NUMIV(obj); + const VALUE *old_ptr = ROBJECT_IVPTR(obj); + VALUE *new_ptr; + + if (promote) { + new_ptr = ALLOC_N(VALUE, len); + FL_UNSET_RAW(obj, ROBJECT_TRANSIENT_FLAG); + } + else { + new_ptr = obj_ivar_heap_alloc(obj, len); + } + MEMCPY(new_ptr, old_ptr, VALUE, len); + ROBJECT(obj)->as.heap.ivptr = new_ptr; + } +} + +static VALUE +obj_ivar_set(VALUE obj, ID id, VALUE val) { struct ivar_update ivup; uint32_t i, len; + ivup.iv_extended = 0; + ivup.u.iv_index_tbl = iv_index_tbl_make(obj); + iv_index_tbl_extend(&ivup, id); + len = ROBJECT_NUMIV(obj); + if (len <= ivup.index) { + VALUE *ptr = ROBJECT_IVPTR(obj); + if (ivup.index < ROBJECT_EMBED_LEN_MAX) { + RBASIC(obj)->flags |= ROBJECT_EMBED; + ptr = ROBJECT(obj)->as.ary; + for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) { + ptr[i] = Qundef; + } + } + else { + VALUE *newptr; + uint32_t newsize = iv_index_tbl_newsize(&ivup); + + if (RBASIC(obj)->flags & ROBJECT_EMBED) { + newptr = obj_ivar_heap_alloc(obj, newsize); + // newptr = ALLOC_N(VALUE, newsize); + MEMCPY(newptr, ptr, VALUE, len); + RBASIC(obj)->flags &= ~ROBJECT_EMBED; + ROBJECT(obj)->as.heap.ivptr = newptr; + } + else { + newptr = obj_ivar_heap_realloc(obj, len, newsize); + } + for (; len < newsize; len++) { + newptr[len] = Qundef; + } + ROBJECT(obj)->as.heap.numiv = newsize; + ROBJECT(obj)->as.heap.iv_index_tbl = ivup.u.iv_index_tbl; + } + } + RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[ivup.index], val); + + return val; +} + +VALUE +rb_ivar_set(VALUE obj, ID id, VALUE val) +{ RB_DEBUG_COUNTER_INC(ivar_set_base); rb_check_frozen(obj); switch (BUILTIN_TYPE(obj)) { case T_OBJECT: - ivup.iv_extended = 0; - ivup.u.iv_index_tbl = iv_index_tbl_make(obj); - iv_index_tbl_extend(&ivup, id); - len = ROBJECT_NUMIV(obj); - if (len <= ivup.index) { - VALUE *ptr = ROBJECT_IVPTR(obj); - if (ivup.index < ROBJECT_EMBED_LEN_MAX) { - RBASIC(obj)->flags |= ROBJECT_EMBED; - ptr = ROBJECT(obj)->as.ary; - for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) { - ptr[i] = Qundef; - } - } - else { - VALUE *newptr; - uint32_t newsize = iv_index_tbl_newsize(&ivup); - - if (RBASIC(obj)->flags & ROBJECT_EMBED) { - newptr = ALLOC_N(VALUE, newsize); - MEMCPY(newptr, ptr, VALUE, len); - RBASIC(obj)->flags &= ~ROBJECT_EMBED; - ROBJECT(obj)->as.heap.ivptr = newptr; - } - else { - REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize); - newptr = ROBJECT(obj)->as.heap.ivptr; - } - for (; len < newsize; len++) - newptr[len] = Qundef; - ROBJECT(obj)->as.heap.numiv = newsize; - ROBJECT(obj)->as.heap.iv_index_tbl = ivup.u.iv_index_tbl; - } - } - RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[ivup.index], val); - break; + return obj_ivar_set(obj, id, val); case T_CLASS: case T_MODULE: if (!RCLASS_IV_TBL(obj)) RCLASS_IV_TBL(obj) = st_init_numtable();