[前][次][番号順一覧][スレッド一覧]

ruby-changes:73799

From: Benoit <ko1@a...>
Date: Thu, 29 Sep 2022 22:49:00 +0900 (JST)
Subject: [ruby-changes:73799] 6b7d32a5e5 (master): Resolve zsuper method during lookup but preserve owner separately

https://git.ruby-lang.org/ruby.git/commit/?id=6b7d32a5e5

From 6b7d32a5e54088b6b4014529bbf2b4b8c1a96029 Mon Sep 17 00:00:00 2001
From: Benoit Daloze <eregontp@g...>
Date: Wed, 28 Sep 2022 19:49:13 +0200
Subject: Resolve zsuper method during lookup but preserve owner separately

* See https://bugs.ruby-lang.org/issues/18729#note-34
* See [Bug #18729]
---
 proc.c                   | 109 +++++++++++++++++++++++++----------------------
 test/ruby/test_method.rb |  66 +++++++++++++++++++++++-----
 2 files changed, 114 insertions(+), 61 deletions(-)

diff --git a/proc.c b/proc.c
index 8e79007d5c..6362efc28e 100644
--- a/proc.c
+++ b/proc.c
@@ -37,7 +37,11 @@ const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase); https://github.com/ruby/ruby/blob/trunk/proc.c#L37
 struct METHOD {
     const VALUE recv;
     const VALUE klass;
+    /* needed for #super_method */
     const VALUE iclass;
+    /* Different than me->owner only for ZSUPER methods.
+       This is error-prone but unavoidable unless ZSUPER methods are removed. */
+    const VALUE owner;
     const rb_method_entry_t * const me;
     /* for bound methods, `me' should be rb_callable_method_entry_t * */
 };
@@ -1655,6 +1659,7 @@ mnew_missing(VALUE klass, VALUE obj, ID id, VALUE mclass) https://github.com/ruby/ruby/blob/trunk/proc.c#L1659
 
     RB_OBJ_WRITE(method, &data->recv, obj);
     RB_OBJ_WRITE(method, &data->klass, klass);
+    RB_OBJ_WRITE(method, &data->owner, klass);
 
     def = ZALLOC(rb_method_definition_t);
     def->type = VM_METHOD_TYPE_MISSING;
@@ -1676,12 +1681,40 @@ mnew_missing_by_name(VALUE klass, VALUE obj, VALUE *name, int scope, VALUE mclas https://github.com/ruby/ruby/blob/trunk/proc.c#L1681
     return mnew_missing(klass, obj, SYM2ID(vid), mclass);
 }
 
+static inline VALUE
+method_entry_defined_class(const rb_method_entry_t *me)
+{
+    VALUE defined_class = me->defined_class;
+    return defined_class ? defined_class : me->owner;
+}
+
+static const rb_method_entry_t*
+zsuper_resolve(const rb_method_entry_t *me, VALUE *iclass_ptr)
+{
+    const rb_method_entry_t *super_me;
+    while (me->def->type == VM_METHOD_TYPE_ZSUPER) {
+        VALUE defined_class = method_entry_defined_class(me);
+        VALUE super_class = RCLASS_SUPER(RCLASS_ORIGIN(defined_class));
+        if (!super_class) {
+            break;
+        }
+        ID id = me->def->original_id;
+        super_me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(super_class, id, iclass_ptr);
+        if (!super_me) {
+            break;
+        }
+        me = super_me;
+    }
+    return me;
+}
+
 static VALUE
 mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass,
               VALUE obj, ID id, VALUE mclass, int scope, int error)
 {
     struct METHOD *data;
     VALUE method;
+    const rb_method_entry_t *zsuper_resolved_me;
     rb_method_visibility_t visi = METHOD_VISI_UNDEF;
 
     if (UNDEFINED_METHOD_ENTRY_P(me)) {
@@ -1699,13 +1732,15 @@ mnew_internal(const rb_method_entry_t *me, VALUE klass, VALUE iclass, https://github.com/ruby/ruby/blob/trunk/proc.c#L1732
             rb_print_inaccessible(klass, id, visi);
         }
     }
+    zsuper_resolved_me = zsuper_resolve(me, &iclass);
 
     method = TypedData_Make_Struct(mclass, struct METHOD, &method_data_type, data);
 
     RB_OBJ_WRITE(method, &data->recv, obj);
     RB_OBJ_WRITE(method, &data->klass, klass);
     RB_OBJ_WRITE(method, &data->iclass, iclass);
-    RB_OBJ_WRITE(method, &data->me, me);
+    RB_OBJ_WRITE(method, &data->owner, me->owner);
+    RB_OBJ_WRITE(method, &data->me, zsuper_resolved_me);
 
     return method;
 }
@@ -1738,34 +1773,6 @@ mnew_unbound(VALUE klass, ID id, VALUE mclass, int scope) https://github.com/ruby/ruby/blob/trunk/proc.c#L1773
     return mnew_from_me(me, klass, iclass, Qundef, id, mclass, scope);
 }
 
-static const rb_method_entry_t*
-zsuper_resolve(const rb_method_entry_t *me)
-{
-    const rb_method_entry_t *super_me;
-    while (me->def->type == VM_METHOD_TYPE_ZSUPER) {
-        VALUE defined_class = me->defined_class ? me->defined_class : me->owner;
-        VALUE super_class = RCLASS_SUPER(RCLASS_ORIGIN(defined_class));
-        if (!super_class) {
-            break;
-        }
-        ID id = me->def->original_id;
-        VALUE iclass;
-        super_me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(super_class, id, &iclass);
-        if (!super_me) {
-            break;
-        }
-        me = super_me;
-    }
-    return me;
-}
-
-static inline VALUE
-method_entry_defined_class(const rb_method_entry_t *me)
-{
-    VALUE defined_class = me->defined_class;
-    return defined_class ? defined_class : me->owner;
-}
-
 /**********************************************************************
  *
  * Document-class: Method
@@ -1819,8 +1826,8 @@ method_eq(VALUE method, VALUE other) https://github.com/ruby/ruby/blob/trunk/proc.c#L1826
     m1 = (struct METHOD *)DATA_PTR(method);
     m2 = (struct METHOD *)DATA_PTR(other);
 
-    const rb_method_entry_t *m1_me = zsuper_resolve(m1->me);
-    const rb_method_entry_t *m2_me = zsuper_resolve(m2->me);
+    const rb_method_entry_t *m1_me = m1->me;
+    const rb_method_entry_t *m2_me = m2->me;
 
     klass1 = method_entry_defined_class(m1_me);
     klass2 = method_entry_defined_class(m2_me);
@@ -1879,6 +1886,7 @@ method_unbind(VALUE obj) https://github.com/ruby/ruby/blob/trunk/proc.c#L1886
     RB_OBJ_WRITE(method, &data->recv, Qundef);
     RB_OBJ_WRITE(method, &data->klass, orig->klass);
     RB_OBJ_WRITE(method, &data->iclass, orig->iclass);
+    RB_OBJ_WRITE(method, &data->owner, orig->owner);
     RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me));
 
     return method;
@@ -1963,7 +1971,7 @@ method_owner(VALUE obj) https://github.com/ruby/ruby/blob/trunk/proc.c#L1971
 {
     struct METHOD *data;
     TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
-    return data->me->owner;
+    return data->owner;
 }
 
 void
@@ -2402,6 +2410,7 @@ method_clone(VALUE self) https://github.com/ruby/ruby/blob/trunk/proc.c#L2410
     RB_OBJ_WRITE(clone, &data->recv, orig->recv);
     RB_OBJ_WRITE(clone, &data->klass, orig->klass);
     RB_OBJ_WRITE(clone, &data->iclass, orig->iclass);
+    RB_OBJ_WRITE(clone, &data->owner, orig->owner);
     RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me));
     return clone;
 }
@@ -2562,7 +2571,7 @@ rb_method_call_with_block(int argc, const VALUE *argv, VALUE method, VALUE passe https://github.com/ruby/ruby/blob/trunk/proc.c#L2571
 static void
 convert_umethod_to_method_components(const struct METHOD *data, VALUE recv, VALUE *methclass_out, VALUE *klass_out, VALUE *iclass_out, const rb_method_entry_t **me_out, const bool clone)
 {
-    VALUE methclass = data->me->owner;
+    VALUE methclass = data->owner;
     VALUE iclass = data->me->defined_class;
     VALUE klass = CLASS_OF(recv);
 
@@ -2593,7 +2602,7 @@ convert_umethod_to_method_components(const struct METHOD *data, VALUE recv, VALU https://github.com/ruby/ruby/blob/trunk/proc.c#L2602
     if (RB_TYPE_P(me->owner, T_MODULE)) {
         if (!clone) {
             // if we didn't previously clone the method entry, then we need to clone it now
-            // because this branch manipualtes it in rb_method_entry_complement_defined_class
+            // because this branch manipulates it in rb_method_entry_complement_defined_class
             me = rb_method_entry_clone(me);
         }
         VALUE ic = rb_class_search_ancestor(klass, me->owner);
@@ -2662,6 +2671,7 @@ umethod_bind(VALUE method, VALUE recv) https://github.com/ruby/ruby/blob/trunk/proc.c#L2671
     RB_OBJ_WRITE(method, &bound->recv, recv);
     RB_OBJ_WRITE(method, &bound->klass, klass);
     RB_OBJ_WRITE(method, &bound->iclass, iclass);
+    RB_OBJ_WRITE(method, &bound->owner, methclass);
     RB_OBJ_WRITE(method, &bound->me, me);
 
     return method;
@@ -2698,7 +2708,7 @@ umethod_bind_call(int argc, VALUE *argv, VALUE method) https://github.com/ruby/ruby/blob/trunk/proc.c#L2708
         VALUE methclass, klass, iclass;
         const rb_method_entry_t *me;
         convert_umethod_to_method_components(data, recv, &methclass, &klass, &iclass, &me, false);
-        struct METHOD bound = { recv, klass, 0, me };
+        struct METHOD bound = { recv, klass, 0, methclass, me };
 
         return call_method_data(ec, &bound, argc, argv, passed_procval, RB_PASS_CALLED_KEYWORDS);
     }
@@ -2974,7 +2984,7 @@ zsuper_ref_method_def(VALUE method) https://github.com/ruby/ruby/blob/trunk/proc.c#L2984
 {
     const struct METHOD *data;
     TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
-    return zsuper_resolve(data->me)->def;
+    return data->me->def;
 }
 
 /*
@@ -3139,7 +3149,7 @@ method_inspect(VALUE method) https://github.com/ruby/ruby/blob/trunk/proc.c#L3149
         defined_class = data->me->def->body.alias.original_me->owner;
     }
     else {
-        defined_class = method_entry_defined_class(zsuper_resolve(data->me));
+        defined_class = method_entry_defined_class(data->me);
     }
 
     if (RB_TYPE_P(defined_class, T_ICLASS)) {
@@ -3363,25 +3373,24 @@ method_super_method(VALUE method) https://github.com/ruby/ruby/blob/trunk/proc.c#L3373
     const struct METHOD *data;
     VALUE super_class, iclass;
     ID mid;
-    const rb_method_entry_t *super_me, *me;
+    const rb_method_entry_t *me;
 
     TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
-    me = zsuper_resolve(data->me);
-    VALUE defined_class = me->defined_class ? me->defined_class : me->owner;
-    if (!defined_class) return Qnil;
-    if (me->def->type == VM_METHOD_TYPE_ALIAS && me->defined_class) {
-        super_class = RCLASS_SUPER(rb_find_defined_class_by_owner(me->defined_class,
-            me->def->body.alias.original_me->owner));
-        mid = me->def->body.alias.original_me->def->original_id;
+    iclass = data->iclass;
+    if (!iclass) return Qnil;
+    if (data->me->def->type == VM_METHOD_TYPE_ALIAS && data->me (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]