summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--benchmark/vm_ivar_init.yml14
-rw-r--r--internal/variable.h1
-rw-r--r--variable.c41
-rw-r--r--vm_insnhelper.c14
4 files changed, 50 insertions, 20 deletions
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);