diff options
author | Alan Wu <[email protected]> | 2021-05-11 12:05:06 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2021-05-11 12:05:06 -0400 |
commit | 39a2ba5cc559900c30c3143da32446c2f20a7484 (patch) | |
tree | 2069e0e787134fd79c46097e11198ded6a595a99 /vm_method.c | |
parent | 010bb0883e67f9f4c8e609266e22c0a12163549a (diff) |
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]
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/4386
Merged-By: XrXr
Diffstat (limited to 'vm_method.c')
-rw-r--r-- | vm_method.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/vm_method.c b/vm_method.c index be0c1ef719..34200dc5f8 100644 --- a/vm_method.c +++ b/vm_method.c @@ -8,6 +8,7 @@ static int vm_redefinition_check_flag(VALUE klass); static void rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass); +static inline rb_method_entry_t *lookup_method_table(VALUE klass, ID id); #define object_id idObject_id #define added idMethod_added @@ -187,9 +188,17 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid) // invalidate cc by invalidating cc->cme VALUE owner = cme->owner; VM_ASSERT(BUILTIN_TYPE(owner) == T_CLASS); + VALUE klass_housing_cme; + if (cme->def->type == VM_METHOD_TYPE_REFINED && !cme->def->body.refined.orig_me) { + klass_housing_cme = owner; + } + else { + klass_housing_cme = RCLASS_ORIGIN(owner); + } + // replace the cme that will be invalid + VM_ASSERT(lookup_method_table(klass_housing_cme, mid) == (const rb_method_entry_t *)cme); const rb_method_entry_t *new_cme = rb_method_entry_clone((const rb_method_entry_t *)cme); - VALUE origin = RCLASS_ORIGIN(owner); - rb_method_table_insert(origin, RCLASS_M_TBL(origin), mid, new_cme); + rb_method_table_insert(klass_housing_cme, RCLASS_M_TBL(klass_housing_cme), mid, new_cme); } vm_cme_invalidate((rb_callable_method_entry_t *)cme); |