summaryrefslogtreecommitdiff
path: root/vm_insnhelper.c
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2020-12-16 12:03:36 +0900
committerKoichi Sasada <ko1@atdot.net>2020-12-16 13:06:13 +0900
commit5499651ee75538a4d8a3bb4a7442f5f59f36acd8 (patch)
tree090e6ddbb6e82a551207aee066fdffd18238a8d4 /vm_insnhelper.c
parentad8e82f70828bf6a0a36648f8b4bdc3142b09968 (diff)
tuning ivar set
* make rb_init_iv_list() simple * introduce vm_setivar_slowpath() for cache miss cases ../clean/miniruby is 647ee6f091. Calculating ------------------------------------- ./miniruby ../clean/miniruby ../ruby_2_7/miniruby vm_ivar_init 7.388M 6.814M 5.771M i/s - 30.000M times in 4.060420s 4.402534s 5.198781s vm_ivar_init_subclass 2.158M 2.147M 1.974M i/s - 3.000M times in 1.390328s 1.397587s 1.519951s vm_ivar_set 128.607M 97.931M 140.668M i/s - 30.000M times in 0.233269s 0.306338s 0.213268s vm_ivar 144.315M 151.722M 117.734M i/s - 30.000M times in 0.207879s 0.197730s 0.254811s Comparison: vm_ivar_init ./miniruby: 7388398.8 i/s ../clean/miniruby: 6814257.1 i/s - 1.08x slower ../ruby_2_7/miniruby: 5770583.9 i/s - 1.28x slower vm_ivar_init_subclass ./miniruby: 2157763.6 i/s ../clean/miniruby: 2146557.0 i/s - 1.01x slower ../ruby_2_7/miniruby: 1973747.9 i/s - 1.09x slower vm_ivar_set ../ruby_2_7/miniruby: 140668063.8 i/s ./miniruby: 128606912.1 i/s - 1.09x slower ../clean/miniruby: 97931027.8 i/s - 1.44x slower vm_ivar ../clean/miniruby: 151722121.9 i/s ./miniruby: 144314526.5 i/s - 1.05x slower ../ruby_2_7/miniruby: 117734305.5 i/s - 1.29x slower
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/3912
Diffstat (limited to 'vm_insnhelper.c')
-rw-r--r--vm_insnhelper.c100
1 files changed, 56 insertions, 44 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index d565b79f92..f343f71bd6 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1190,70 +1190,82 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
}
}
+
+NOINLINE(static VALUE vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr));
+
+static VALUE
+vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr)
+{
+ rb_check_frozen_internal(obj);
+
+#if OPT_IC_FOR_IVAR
+ if (RB_TYPE_P(obj, T_OBJECT)) {
+ struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
+ struct rb_iv_index_tbl_entry *ent;
+
+ if (iv_index_tbl_lookup(iv_index_tbl, id, &ent)) {
+ if (!is_attr) {
+ ic->entry = ent;
+ RB_OBJ_WRITTEN(iseq, Qundef, ent->class_value);
+ }
+ else if (ent->index >= INT_MAX) {
+ rb_raise(rb_eArgError, "too many instance variables");
+ }
+ else {
+ vm_cc_attr_index_set(cc, (int)(ent->index + 1));
+ }
+
+ uint32_t index = ent->index;
+
+ if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) {
+ rb_init_iv_list(obj);
+ }
+ VALUE *ptr = ROBJECT_IVPTR(obj);
+ RB_OBJ_WRITE(obj, &ptr[index], val);
+ RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_iv_hit);
+
+ return val;
+ }
+ }
+#endif
+ RB_DEBUG_COUNTER_INC(ivar_set_ic_miss);
+ return rb_ivar_set(obj, id, val);
+}
+
static inline VALUE
vm_setivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr)
{
#if OPT_IC_FOR_IVAR
- rb_check_frozen_internal(obj);
-
- if (LIKELY(RB_TYPE_P(obj, T_OBJECT))) {
- VALUE klass = RBASIC(obj)->klass;
- uint32_t index;
+ if (LIKELY(RB_TYPE_P(obj, T_OBJECT)) &&
+ LIKELY(!RB_OBJ_FROZEN_RAW(obj))) {
VM_ASSERT(!rb_ractor_shareable_p(obj));
if (LIKELY(
- (!is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_serial, ic->entry && ic->entry->class_serial == RCLASS_SERIAL(klass))) ||
+ (!is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_serial, ic->entry && ic->entry->class_serial == RCLASS_SERIAL(RBASIC(obj)->klass))) ||
( is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_unset, vm_cc_attr_index(cc) > 0)))) {
- VALUE *ptr = ROBJECT_IVPTR(obj);
- index = !is_attr ? ic->entry->index : vm_cc_attr_index(cc)-1;
+ uint32_t index = !is_attr ? ic->entry->index : vm_cc_attr_index(cc)-1;
- if (index >= ROBJECT_NUMIV(obj)) {
- st_table * iv_idx_tbl = ROBJECT_IV_INDEX_TBL(obj);
- rb_init_iv_list(obj, ROBJECT_NUMIV(obj), (uint32_t)iv_idx_tbl->num_entries, iv_idx_tbl);
- ptr = ROBJECT_IVPTR(obj);
+ if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) {
+ rb_init_iv_list(obj);
}
+ VALUE *ptr = ROBJECT_IVPTR(obj);
RB_OBJ_WRITE(obj, &ptr[index], val);
RB_DEBUG_COUNTER_INC(ivar_set_ic_hit);
return val; /* inline cache hit */
}
- else {
- struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
- struct rb_iv_index_tbl_entry *ent;
-
- if (iv_index_tbl_lookup(iv_index_tbl, id, &ent)) {
- if (!is_attr) {
- ic->entry = ent;
- RB_OBJ_WRITTEN(iseq, Qundef, ent->class_value);
- }
- else if (ent->index >= INT_MAX) {
- rb_raise(rb_eArgError, "too many instance variables");
- }
- else {
- vm_cc_attr_index_set(cc, (int)(ent->index + 1));
- }
-
- index = ent->index;
-
- VALUE *ptr = ROBJECT_IVPTR(obj);
- if (index >= ROBJECT_NUMIV(obj)) {
- rb_init_iv_list(obj, ROBJECT_NUMIV(obj), (uint32_t)iv_index_tbl->num_entries, iv_index_tbl);
- ptr = ROBJECT_IVPTR(obj);
- }
- RB_OBJ_WRITE(obj, &ptr[index], val);
- RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_iv_hit);
-
- return val;
- }
- /* fall through */
- }
}
else {
RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_noobject);
}
#endif /* OPT_IC_FOR_IVAR */
- RB_DEBUG_COUNTER_INC(ivar_set_ic_miss);
- return rb_ivar_set(obj, id, val);
+ return vm_setivar_slowpath(obj, id, val, iseq, ic, cc, is_attr);
+}
+
+VALUE
+rb_vm_setivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic)
+{
+ return vm_setivar(obj, id, val, iseq, ic, NULL, false);
}
static inline VALUE