diff --git a/benchmark/vm_ivar_init.yml b/benchmark/vm_ivar_init.yml new file mode 100644 index 0000000000..c6f1633907 --- /dev/null +++ b/benchmark/vm_ivar_init.yml @@ -0,0 +1,14 @@ +prelude: | + class C + def initialize + @a = nil + @b = nil + @c = nil + @d = nil + @e = nil + end + end +benchmark: + vm_ivar_init: | + C.new +loop_count: 30000000 diff --git a/internal/variable.h b/internal/variable.h index d5d0cccbfb..34ad4e1199 100644 --- a/internal/variable.h +++ b/internal/variable.h @@ -52,6 +52,7 @@ VALUE rb_gvar_get(ID); VALUE rb_gvar_set(ID, VALUE); VALUE rb_gvar_defined(ID); void rb_const_warn_if_deprecated(const rb_const_entry_t *, VALUE, ID); +void rb_init_iv_list(VALUE obj, uint32_t len, uint32_t newsize, st_table * index_tbl); MJIT_SYMBOL_EXPORT_END static inline bool diff --git a/variable.c b/variable.c index 7ebbcf85b8..669d47e8d3 100644 --- a/variable.c +++ b/variable.c @@ -1402,6 +1402,28 @@ rb_obj_transient_heap_evacuate(VALUE obj, int promote) } #endif +void +rb_init_iv_list(VALUE obj, uint32_t len, uint32_t newsize, st_table * index_tbl) +{ + VALUE *ptr = ROBJECT_IVPTR(obj); + VALUE *newptr; + + if (RBASIC(obj)->flags & ROBJECT_EMBED) { + newptr = obj_ivar_heap_alloc(obj, 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 = index_tbl; +} + static VALUE obj_ivar_set(VALUE obj, ID id, VALUE val) { @@ -1419,25 +1441,8 @@ obj_ivar_set(VALUE obj, ID id, VALUE val) len = ROBJECT_NUMIV(obj); if (len <= ivup.index) { - VALUE *ptr = ROBJECT_IVPTR(obj); - VALUE *newptr; uint32_t newsize = iv_index_tbl_newsize(&ivup); - - if (RBASIC(obj)->flags & ROBJECT_EMBED) { - newptr = obj_ivar_heap_alloc(obj, 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_init_iv_list(obj, len, newsize, ivup.u.iv_index_tbl); } RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[ivup.index], val); diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 51b3c40010..f8b2f707ca 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1213,11 +1213,21 @@ vm_setivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const str VALUE *ptr = ROBJECT_IVPTR(obj); index = !is_attr ? ic->entry->index : vm_cc_attr_index(cc)-1; - if (RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_oorange, index < ROBJECT_NUMIV(obj))) { + if (index < ROBJECT_NUMIV(obj)) { RB_OBJ_WRITE(obj, &ptr[index], val); RB_DEBUG_COUNTER_INC(ivar_set_ic_hit); return val; /* inline cache hit */ - } + } else { + st_table * iv_idx_tbl = RCLASS_IV_INDEX_TBL(rb_class_real(klass)); + if (index < iv_idx_tbl->num_entries) { + rb_init_iv_list(obj, ROBJECT_NUMIV(obj), iv_idx_tbl->num_entries, iv_idx_tbl); + ptr = ROBJECT_IVPTR(obj); + RB_OBJ_WRITE(obj, &ptr[index], val); + RB_DEBUG_COUNTER_INC(ivar_set_ic_hit); + return val; /* inline cache hit */ + } + } + RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_oorange); } else { struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);