summaryrefslogtreecommitdiff
path: root/class.c
diff options
context:
space:
mode:
authornagachika <nagachika@ruby-lang.org>2021-05-29 14:35:12 +0900
committernagachika <nagachika@ruby-lang.org>2021-05-29 14:35:12 +0900
commitd47df50678b00bd622e6be474031204ed2e52b31 (patch)
tree5f69112b413dca78a9aa9165a79d688e912e55f0 /class.c
parent7b6a2ad04a3272a31323493133498dfc60d77d76 (diff)
merge revision(s) 39a2ba5cc559900c30c3143da32446c2f20a7484: [Backport #17806]
Method cache: fix refinement entry handling To invalidate some callable method entries, we replace the entry in the class. Most types of method entries are on the method table of the origin class, but refinement entries without an orig_me are housed in the method table of the class itself. They are there because refinements take priority over prepended methods. By unconditionally inserting a copy of the refinement entry into the origin class, clearing the method cache created situations where there are refinement entry duplicates in the lookup chain, leading to infinite loops and other problems. Update the replacement logic to use the right class that houses the method entry. Also, be more selective about cache invalidation when moving refinement entries for prepend. This avoids calling clear_method_cache_by_id_in_class() before refinement entries are in the place it expects. [Bug #17806] --- class.c | 4 +++- test/ruby/test_refinement.rb | 49 ++++++++++++++++++++++++++++++++++++++++++++ vm_method.c | 13 ++++++++++-- 3 files changed, 63 insertions(+), 3 deletions(-)
Diffstat (limited to 'class.c')
-rw-r--r--class.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/class.c b/class.c
index 47f35b1f90..b607135e2f 100644
--- a/class.c
+++ b/class.c
@@ -1134,10 +1134,12 @@ cache_clear_refined_method(ID key, VALUE value, void *data)
{
rb_method_entry_t *me = (rb_method_entry_t *) value;
- if (me->def->type == VM_METHOD_TYPE_REFINED) {
+ if (me->def->type == VM_METHOD_TYPE_REFINED && me->def->body.refined.orig_me) {
VALUE klass = (VALUE)data;
rb_clear_method_cache(klass, me->called_id);
}
+ // Refined method entries without an orig_me is going to stay in the method
+ // table of klass, like before the move, so no need to clear the cache.
return ID_TABLE_CONTINUE;
}