aboutsummaryrefslogtreecommitdiffstats
path: root/vm_insnhelper.c
diff options
context:
space:
mode:
authorJean Boussier <byroot@ruby-lang.org>2023-10-26 11:08:05 +0200
committerJean Boussier <jean.boussier@gmail.com>2023-11-03 12:47:43 +0100
commitb92b9e1e9e078d6bc1066a9335efb9e31f3bd4d9 (patch)
tree8b9d864ae3c370fc39ccae5319458564ad10a414 /vm_insnhelper.c
parent0ae6a2a1cf8ed63d7682a717edeb676221725cdb (diff)
downloadruby-b92b9e1e9e078d6bc1066a9335efb9e31f3bd4d9.tar.gz
vm_getivar: assume the cached shape_id like have a common ancestor
When an inline cache misses, it is very likely that the stale shape_id and the current instance shape_id have a close common ancestor. For example if the instance variable is sometimes frozen sometimes not, one of the two shape will be the direct parent of the other. Another pattern that commonly cause IC misses is "memoization", in such case the object will have a "base common shape" and then a number of close descendants. In addition, when we find a common ancestor, we store it in the inline cache instead of the current shape. This help prevent the cache from flip-flopping, ensuring the next lookup will be marginally faster and more generally avoid writing in memory too much. However, now that shapes have an ancestors index, we only check for a few ancestors before falling back to use the index. So overall this change speeds up what is assumed to be the more common case, but makes what is assumed to be the less common case a bit slower. ``` compare-ruby: ruby 3.3.0dev (2023-10-26T05:30:17Z master 701ca070b4) [arm64-darwin22] built-ruby: ruby 3.3.0dev (2023-10-26T09:25:09Z shapes_double_sear.. a723a85235) [arm64-darwin22] warming up...... | |compare-ruby|built-ruby| |:------------------------------------|-----------:|---------:| |vm_ivar_stable_shape | 11.672M| 11.679M| | | -| 1.00x| |vm_ivar_memoize_unstable_shape | 7.551M| 10.506M| | | -| 1.39x| |vm_ivar_memoize_unstable_shape_miss | 11.591M| 11.624M| | | -| 1.00x| |vm_ivar_unstable_undef | 9.037M| 7.981M| | | 1.13x| -| |vm_ivar_divergent_shape | 8.034M| 6.657M| | | 1.21x| -| |vm_ivar_divergent_shape_imbalanced | 10.471M| 9.231M| | | 1.13x| -| ``` Co-Authored-By: John Hawthorn <john@hawthorn.email>
Diffstat (limited to 'vm_insnhelper.c')
-rw-r--r--vm_insnhelper.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index e28323e588..785dbfedec 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1286,8 +1286,6 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
}
#endif
- rb_shape_t *shape = rb_shape_get_shape_by_id(shape_id);
-
if (shape_id == OBJ_TOO_COMPLEX_SHAPE_ID) {
st_table *table = NULL;
switch (BUILTIN_TYPE(obj)) {
@@ -1314,14 +1312,22 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call
}
}
else {
- if (rb_shape_get_iv_index(shape, id, &index)) {
+ shape_id_t previous_cached_id = cached_id;
+ if (rb_shape_get_iv_index_with_hint(shape_id, id, &index, &cached_id)) {
// This fills in the cache with the shared cache object.
// "ent" is the shared cache object
- fill_ivar_cache(iseq, ic, cc, is_attr, index, shape_id);
+ if (cached_id != previous_cached_id) {
+ fill_ivar_cache(iseq, ic, cc, is_attr, index, cached_id);
+ }
- // We fetched the ivar list above
- val = ivar_list[index];
- RUBY_ASSERT(!UNDEF_P(val));
+ if (index == ATTR_INDEX_NOT_SET) {
+ val = default_value;
+ }
+ else {
+ // We fetched the ivar list above
+ val = ivar_list[index];
+ RUBY_ASSERT(!UNDEF_P(val));
+ }
}
else {
if (is_attr) {