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

ruby-changes:26179

From: shugo <ko1@a...>
Date: Thu, 6 Dec 2012 22:08:55 +0900 (JST)
Subject: [ruby-changes:26179] shugo:r38236 (trunk): * revised r37993 to avoid SEGV/ILL in tests. In r37993, a method

shugo	2012-12-06 22:08:41 +0900 (Thu, 06 Dec 2012)

  New Revision: 38236

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38236

  Log:
    * revised r37993 to avoid SEGV/ILL in tests.  In r37993, a method
      entry with VM_METHOD_TYPE_REFINED holds only the original method
      definition, so ci->me is set to a method entry allocated in the
      stack, and it causes SEGV/ILL.  In this commit, a method entry
      with VM_METHOD_TYPE_REFINED holds the whole original method entry.
      Furthermore, rb_thread_mark() is changed to mark cfp->klass to
      avoid GC for iclasses created by copy_refinement_iclass().
    
    * vm_method.c (rb_method_entry_make): add a method entry with
      VM_METHOD_TYPE_REFINED to the class refined by the refinement if
      the target module is a refinement.  When a method entry with
      VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
      the same name is searched in refinements.  If such a method is
      found, the method is invoked.  Otherwise, the original method in
      the refined class (rb_method_definition_t::body.orig_me) is
      invoked.  This change is made to simplify the normal method lookup
      and to improve the performance of normal method calls.
    
    * vm_method.c (EXPR1, search_method, rb_method_entry),
      vm_eval.c (rb_call0, rb_search_method_entry): do not use
      refinements for method lookup.
    
    * vm_insnhelper.c (vm_call_method): search methods in refinements if
      ci->me is VM_METHOD_TYPE_REFINED.  If the method is called by
      super (i.e., ci->call == vm_call_super_method), skip the same
      method entry as the current method to avoid infinite call of the
      same method.
    
    * class.c (include_modules_at): add a refined method entry for each
      method defined in a module included in a refinement.
    
    * class.c (rb_prepend_module): set an empty table to
      RCLASS_M_TBL(klass) to add refined method entries, because
      refinements should have priority over prepended modules.
    
    * proc.c (mnew): use rb_method_entry_with_refinements() to get
      a refined method.
    
    * vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
      copy_refinement_iclass().
    
    * vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
    
    * test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
      the test because it should pass successfully.
    
    * test/ruby/test_refinement.rb (test_redefine_refined_method): new
      test for the case a refined method is redefined.

  Modified files:
    trunk/ChangeLog
    trunk/class.c
    trunk/cont.c
    trunk/eval.c
    trunk/gc.c
    trunk/internal.h
    trunk/method.h
    trunk/object.c
    trunk/proc.c
    trunk/test/ruby/test_refinement.rb
    trunk/vm.c
    trunk/vm_eval.c
    trunk/vm_insnhelper.c
    trunk/vm_method.c

Index: method.h
===================================================================
--- method.h	(revision 38235)
+++ method.h	(revision 38236)
@@ -42,7 +42,8 @@
     VM_METHOD_TYPE_NOTIMPLEMENTED,
     VM_METHOD_TYPE_OPTIMIZED, /* Kernel#send, Proc#call, etc */
     VM_METHOD_TYPE_MISSING,   /* wrapper for method_missing(id) */
-    VM_METHOD_TYPE_CFUNC_FRAMELESS
+    VM_METHOD_TYPE_CFUNC_FRAMELESS,
+    VM_METHOD_TYPE_REFINED,
 } rb_method_type_t;
 
 struct rb_call_info_struct;
@@ -72,6 +73,7 @@
 	    OPTIMIZED_METHOD_TYPE_SEND,
 	    OPTIMIZED_METHOD_TYPE_CALL
 	} optimize_type;
+	struct rb_method_entry_struct *orig_me;
     } body;
     int alias_count;
 } rb_method_definition_t;
@@ -94,9 +96,14 @@
 void rb_add_method_cfunc(VALUE klass, ID mid, VALUE (*func)(ANYARGS), int argc, rb_method_flag_t noex);
 rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex);
 rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr);
+void rb_add_refined_method_entry(VALUE refined_class, ID mid);
+rb_method_entry_t *rb_resolve_refined_method(VALUE refinements,
+					     rb_method_entry_t *me,
+					     VALUE *defined_class_ptr);
+rb_method_entry_t *rb_method_entry_with_refinements(VALUE klass, ID id,
+						    VALUE *defined_class_ptr);
 
-rb_method_entry_t *rb_method_entry_get_with_refinements(VALUE refinements, VALUE klass, ID id, VALUE *define_class_ptr);
-rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, VALUE refinements, ID id, VALUE *define_class_ptr);
+rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *define_class_ptr);
 rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_flag_t noex);
 
 int rb_method_entry_arity(const rb_method_entry_t *me);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 38235)
+++ ChangeLog	(revision 38236)
@@ -1,3 +1,54 @@
+Thu Dec  6 18:23:05 2012  Shugo Maeda  <shugo@r...>
+
+	* revised r37993 to avoid SEGV/ILL in tests.  In r37993, a method
+	  entry with VM_METHOD_TYPE_REFINED holds only the original method
+	  definition, so ci->me is set to a method entry allocated in the
+	  stack, and it causes SEGV/ILL.  In this commit, a method entry
+	  with VM_METHOD_TYPE_REFINED holds the whole original method entry.
+	  Furthermore, rb_thread_mark() is changed to mark cfp->klass to
+	  avoid GC for iclasses created by copy_refinement_iclass().
+
+	* vm_method.c (rb_method_entry_make): add a method entry with
+	  VM_METHOD_TYPE_REFINED to the class refined by the refinement if
+	  the target module is a refinement.  When a method entry with
+	  VM_METHOD_TYPE_UNDEF is invoked by vm_call_method(), a method with
+	  the same name is searched in refinements.  If such a method is
+	  found, the method is invoked.  Otherwise, the original method in
+	  the refined class (rb_method_definition_t::body.orig_me) is
+	  invoked.  This change is made to simplify the normal method lookup
+	  and to improve the performance of normal method calls.
+
+	* vm_method.c (EXPR1, search_method, rb_method_entry),
+	  vm_eval.c (rb_call0, rb_search_method_entry): do not use
+	  refinements for method lookup.
+
+	* vm_insnhelper.c (vm_call_method): search methods in refinements if
+	  ci->me is VM_METHOD_TYPE_REFINED.  If the method is called by
+	  super (i.e., ci->call == vm_call_super_method), skip the same
+	  method entry as the current method to avoid infinite call of the
+	  same method.
+
+	* class.c (include_modules_at): add a refined method entry for each
+	  method defined in a module included in a refinement.
+
+	* class.c (rb_prepend_module): set an empty table to
+	  RCLASS_M_TBL(klass) to add refined method entries, because
+	  refinements should have priority over prepended modules.
+
+	* proc.c (mnew): use rb_method_entry_with_refinements() to get
+	  a refined method.
+
+	* vm.c (rb_thread_mark): mark cfp->klass for iclasses created by
+	  copy_refinement_iclass().
+
+	* vm.c (Init_VM), cont.c (fiber_init): initialize th->cfp->klass.
+
+	* test/ruby/test_refinement.rb (test_inline_method_cache): do not skip
+	  the test because it should pass successfully.
+
+	* test/ruby/test_refinement.rb (test_redefine_refined_method): new
+	  test for the case a refined method is redefined.
+
 Thu Dec  6 17:29:03 2012  Nobuyoshi Nakada  <nobu@r...>
 
 	* parse.y (parser_here_document): flush string content between new
Index: object.c
===================================================================
--- object.c	(revision 38235)
+++ object.c	(revision 38236)
@@ -1338,7 +1338,7 @@
 static VALUE
 rb_mod_to_s(VALUE klass)
 {
-    ID id_refined_class, id_defined_at;
+    ID id_defined_at;
     VALUE refined_class, defined_at;
 
     if (FL_TEST(klass, FL_SINGLETON)) {
@@ -1358,8 +1358,7 @@
 
 	return s;
     }
-    CONST_ID(id_refined_class, "__refined_class__");
-    refined_class = rb_attr_get(klass, id_refined_class);
+    refined_class = rb_refinement_module_get_refined_class(klass);
     if (!NIL_P(refined_class)) {
 	VALUE s = rb_usascii_str_new2("#<refinement:");
 
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 38235)
+++ vm_eval.c	(revision 38236)
@@ -179,7 +179,14 @@
       case VM_METHOD_TYPE_BMETHOD:
 	return vm_call_bmethod_body(th, ci, argv);
       case VM_METHOD_TYPE_ZSUPER:
+      case VM_METHOD_TYPE_REFINED:
 	{
+	    if (ci->me->def->type == VM_METHOD_TYPE_REFINED &&
+		ci->me->def->body.orig_me) {
+		ci->me = ci->me->def->body.orig_me;
+		goto again;
+	    }
+
 	    ci->defined_class = RCLASS_SUPER(ci->defined_class);
 
 	    if (!ci->defined_class || !(ci->me = rb_method_entry(ci->defined_class, ci->mid, &ci->defined_class))) {
@@ -274,8 +281,7 @@
 }
 
 static inline rb_method_entry_t *
-    rb_search_method_entry(VALUE refinements, VALUE recv, ID mid,
-			   VALUE *defined_class_ptr);
+    rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr);
 static inline int rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type scope, VALUE self);
 #define NOEX_OK NOEX_NOSUPER
 
@@ -296,11 +302,11 @@
  */
 static inline VALUE
 rb_call0(VALUE recv, ID mid, int argc, const VALUE *argv,
-	 call_type scope, VALUE self, VALUE refinements)
+	 call_type scope, VALUE self)
 {
     VALUE defined_class;
     rb_method_entry_t *me =
-	rb_search_method_entry(refinements, recv, mid, &defined_class);
+	rb_search_method_entry(recv, mid, &defined_class);
     rb_thread_t *th = GET_THREAD();
     int call_status = rb_method_call_status(th, me, scope, self);
 
@@ -364,7 +370,7 @@
 	}
     }
 
-    me = rb_search_method_entry(Qnil, recv, mid, &defined_class);
+    me = rb_search_method_entry(recv, mid, &defined_class);
     call_status = rb_method_call_status(th, me, CALL_FCALL, th->cfp->self);
     if (call_status != NOEX_OK) {
 	if (rb_method_basic_definition_p(klass, idMethodMissing)) {
@@ -429,8 +435,7 @@
 }
 
 static inline rb_method_entry_t *
-rb_search_method_entry(VALUE refinements, VALUE recv, ID mid,
-		       VALUE *defined_class_ptr)
+rb_search_method_entry(VALUE recv, ID mid, VALUE *defined_class_ptr)
 {
     VALUE klass = CLASS_OF(recv);
 
@@ -469,8 +474,7 @@
                          rb_id2name(mid), type, (void *)recv, flags, klass);
         }
     }
-    return rb_method_entry_get_with_refinements(refinements, klass, mid,
-						defined_class_ptr);
+    return rb_method_entry(klass, mid, defined_class_ptr);
 }
 
 static inline int
@@ -532,7 +536,7 @@
 rb_call(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope)
 {
     rb_thread_t *th = GET_THREAD();
-    return rb_call0(recv, mid, argc, argv, scope, th->cfp->self, Qnil);
+    return rb_call0(recv, mid, argc, argv, scope, th->cfp->self);
 }
 
 NORETURN(static void raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv,
@@ -785,11 +789,23 @@
 					  const VALUE *argv,
 					  VALUE refinements)
 {
-    rb_thread_t *th = GET_THREAD();
+    VALUE defined_class;
+    rb_method_entry_t *me =
+	rb_search_method_entry(recv, mid, &defined_class);
+    rb_thread_t *th;
+    int call_status;
 
-    PASS_PASSED_BLOCK_TH(th);
-    return rb_call0(recv, mid, argc, argv, CALL_PUBLIC, th->cfp->self,
-		    refinements);
+    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
+	me = rb_resolve_refined_method(refinements, me, &defined_class);
+    }
+    PASS_PASSED_BLOCK_TH(GET_THREAD());
+    th = GET_THREAD();
+    call_status = rb_method_call_status(th, me, CALL_PUBLIC, th->cfp->self);
+    if (call_status != NOEX_OK) {
+	return method_missing(recv, mid, argc, argv, call_status);
+    }
+    stack_check();
+    return vm_call0(th, recv, mid, argc, argv, me, defined_class);
 }
 
 static VALUE
@@ -823,7 +839,7 @@
 	id = rb_to_id(vid);
     }
     PASS_PASSED_BLOCK_TH(th);
-    return rb_call0(recv, id, argc, argv, scope, self, Qnil);
+    return rb_call0(recv, id, argc, argv, scope, self);
 }
 
 /*
Index: proc.c
===================================================================
--- proc.c	(revision 38235)
+++ proc.c	(revision 38236)
@@ -917,7 +917,7 @@
     rb_method_flag_t flag = NOEX_UNDEF;
 
   again:
-    me = rb_method_entry(klass, id, &defined_class);
+    me = rb_method_entry_with_refinements(klass, id, &defined_class);
     if (UNDEFINED_METHOD_ENTRY_P(me)) {
 	ID rmiss = rb_intern("respond_to_missing?");
 	VALUE sym = ID2SYM(id);
@@ -1683,6 +1683,8 @@
 	  default:
 	    break;
 	}
+      case VM_METHOD_TYPE_REFINED:
+	return -1;
       }
     }
     rb_bug("rb_method_entry_arity: invalid method entry type (%d)", def->type);
Index: vm_method.c
===================================================================
--- vm_method.c	(revision 38235)
+++ vm_method.c	(revision 38236)
@@ -4,7 +4,7 @@
 
 #define CACHE_SIZE 0x800
 #define CACHE_MASK 0x7ff
-#define EXPR1(c,o,m) ((((c)>>3)^((o)>>3)^(m))&CACHE_MASK)
+#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
 
 #define NOEX_NOREDEF 0
 #ifndef NOEX_NOREDEF
@@ -21,7 +21,6 @@
     VALUE filled_version;        /* filled state version */
     ID mid;			/* method's id */
     VALUE klass;		/* receiver's class */
-    VALUE refinements;		/* refinements */
     rb_method_entry_t *me;
     VALUE defined_class;
 };
@@ -148,27 +147,79 @@
     }
 }
 
+static void
+release_method_definition(rb_method_definition_t *def)
+{
+    if (def == 0)
+	return;
+    if (def->alias_count == 0) {
+	if (def->type == VM_METHOD_TYPE_REFINED &&
+	    def->body.orig_me) {
+	    release_method_definition(def->body.orig_me->def);
+	    xfree(def->body.orig_me);
+	}
+	xfree(def);
+    }
+    else if (def->alias_count > 0) {
+	def->alias_count--;
+    }
+}
+
 void
 rb_free_method_entry(rb_method_entry_t *me)
 {
-    rb_method_definition_t *def = me->def;
-
-    if (def) {
-	if (def->alias_count == 0) {
-	    xfree(def);
-	}
-	else if (def->alias_count > 0) {
-	    def->alias_count--;
-	}
-	me->def = 0;
-    }
+    release_method_definition(me->def);
     xfree(me);
 }
 
 static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
 
-void rb_redefine_opt_method(VALUE, ID);
+static inline rb_method_entry_t *
+lookup_method_table(VALUE klass, ID id)
+{
+    st_data_t body;
+    st_table *m_tbl = RCLASS_M_TBL(klass);
+    if (st_lookup(m_tbl, id, &body)) {
+	return (rb_method_entry_t *) body;
+    }
+    else {
+	return 0;
+    }
+}
 
+static void
+make_method_entry_refined(rb_method_entry_t *me)
+{
+    rb_method_definition_t *new_def;
+
+    if (me->def && me->def->type == VM_METHOD_TYPE_REFINED)
+	return;
+
+    new_def = ALLOC(rb_method_definition_t);
+    new_def->type = VM_METHOD_TYPE_REFINED;
+    new_def->original_id = me->called_id;
+    new_def->alias_count = 0;
+    new_def->body.orig_me = ALLOC(rb_method_entry_t);
+    *new_def->body.orig_me = *me;
+    rb_vm_check_redefinition_opt_method(me, me->klass);
+    if (me->def) me->def->alias_count++;
+    me->def = new_def;
+}
+
+void
+rb_add_refined_method_entry(VALUE refined_class, ID mid)
+{
+    rb_method_entry_t *me = lookup_method_table(refined_class, mid);
+
+    if (me) {
+	make_method_entry_refined(me);
+    }
+    else {
+	rb_add_method(refined_class, mid, VM_METHOD_TYPE_REFINED, 0,
+		      NOEX_PUBLIC);
+    }
+}
+
 static rb_method_entry_t *
 rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type,
 		     rb_method_definition_t *def, rb_method_flag_t noex)
@@ -179,6 +230,7 @@
 #endif
     st_table *mtbl;
     st_data_t data;
+    int make_refined = 0;
 
     if (NIL_P(klass)) {
 	klass = rb_cObject;
@@ -201,14 +253,19 @@
     rklass = klass;
 #endif
     if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
-	ID id_refined_class;
-	VALUE refined_class;
+	VALUE refined_class =
+	    rb_refinement_module_get_refined_class(klass);
 
-	CONST_ID(id_refined_class, "__refined_class__");
-	refined_class = rb_ivar_get(klass, id_refined_class);
-	rb_redefine_opt_method(refined_class, mid);
+	rb_add_refined_method_entry(refined_class, mid);
     }
-    klass = RCLASS_ORIGIN(klass);
+    if (type == VM_METHOD_TYPE_REFINED) {
+	rb_method_entry_t *old_me =
+	    lookup_method_table(RCLASS_ORIGIN(klass), mid);
+	if (old_me) rb_vm_check_redefinition_opt_method(old_me, klass);
+    }
+    else {
+	klass = RCLASS_ORIGIN(klass);
+    }
     mtbl = RCLASS_M_TBL(klass);
 
     /* check re-definition */
@@ -224,6 +281,8 @@
 	}
 #endif
 	rb_vm_check_redefinition_opt_method(old_me, klass);
+	if (old_def->type == VM_METHOD_TYPE_REFINED)
+	    make_refined = 1;
 
 	if (RTEST(ruby_verbose) &&
 	    type != VM_METHOD_TYPE_UNDEF &&
@@ -276,6 +335,10 @@
 	}
     }
 
+    if (make_refined) {
+	make_method_entry_refined(me);
+    }
+
     st_insert(mtbl, mid, (st_data_t) me);
 
     return me;
@@ -343,7 +406,12 @@
     int line;
     rb_method_entry_t *me = rb_method_entry_make(klass, mid, type, 0, noex);
     rb_method_definition_t *def = ALLOC(rb_method_definition_t);
-    me->def = def;
+    if (me->def && me->def->type == VM_METHOD_TYPE_REFINED) {
+	me->def->body.orig_me->def = def;
+    }
+    else {
+	me->def = def;
+    }
     def->type = type;
     def->original_id = mid;
     def->alias_count = 0;
@@ -381,10 +449,13 @@
       case VM_METHOD_TYPE_ZSUPER:
       case VM_METHOD_TYPE_UNDEF:
 	break;
+      case VM_METHOD_TYPE_REFINED:
+	def->body.orig_me = (rb_method_entry_t *) opts;
+	break;
       default:
 	rb_bug("rb_add_method: unsupported method type (%d)\n", type);
     }
-    if (type != VM_METHOD_TYPE_UNDEF) {
+    if (type != VM_METHOD_TYPE_UNDEF && type != VM_METHOD_TYPE_REFINED) {
 	method_added(klass, mid);
     }
     return me;
@@ -427,88 +498,20 @@
     return 0;
 }
 
-static VALUE
-copy_refinement_iclass(VALUE iclass, VALUE superclass)
-{
-    VALUE result, c;
-
-    Check_Type(iclass, T_ICLASS);
-    c = result = rb_include_class_new(RBASIC(iclass)->klass, superclass);
-    RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
-    iclass = RCLASS_SUPER(iclass);
-    while (iclass && BUILTIN_TYPE(iclass) == T_ICLASS) {
-	c = RCLASS_SUPER(c) = rb_include_class_new(RBASIC(iclass)->klass,
-						   RCLASS_SUPER(c));
-	RCLASS_REFINED_CLASS(c) = RCLASS_REFINED_CLASS(iclass);
-	iclass = RCLASS_SUPER(iclass);
-    }
-    return result;
-}
-
-static inline int
-lookup_method_table(VALUE klass, ID id, st_data_t *body)
-{
-    st_table *m_tbl = RCLASS_M_TBL(klass);
-    if (!m_tbl) {
-	m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(RBASIC(klass)->klass));
-    }
-    return st_lookup(m_tbl, id, body);
-}
-
 static inline rb_method_entry_t*
-search_method_with_refinements(VALUE klass, ID id, VALUE refinements,
-			       VALUE *defined_class_ptr)
+search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
 {
-    st_data_t body;
-    VALUE iclass, skipped_class = Qnil;
+    rb_method_entry_t *me;
 
-    for (body = 0; klass; klass = RCLASS_SUPER(klass)) {
-	if (klass != skipped_class) {
-	    iclass = rb_hash_lookup(refinements, klass);
-	    if (NIL_P(iclass) && BUILTIN_TYPE(klass) == T_ICLASS) {
-		iclass = rb_hash_lookup(refinements, RBASIC(klass)->klass);
-		if (!NIL_P(iclass))
-		    iclass = copy_refinement_iclass(iclass, klass);
-	    }
-	    if (!NIL_P(iclass)) {
-		skipped_class = klass;
-		klass = iclass;
-	    }
-	}
-	if (lookup_method_table(klass, id, &body)) break;
+    for (me = 0; klass; klass = RCLASS_SUPER(klass)) {
+	if ((me = lookup_method_table(klass, id)) != 0) break;
     }
 
     if (defined_class_ptr)
 	*defined_class_ptr = klass;
-    return (rb_method_entry_t *)body;
+    return me;
 }
 
-static inline rb_method_entry_t*
-search_method_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
-{
-    st_data_t body;
-
-    for (body = 0; klass; klass = RCLASS_SUPER(klass)) {
-	if (lookup_method_table(klass, id, &body)) break;
-    }
-
-    if (defined_class_ptr)
-	*defined_class_ptr = klass;
-    return (rb_method_entry_t *)body;
-}
-
-static rb_method_entry_t*
-search_method(VALUE klass, ID id, VALUE refinements, VALUE *defined_class_ptr)
-{
-    if (NIL_P(refinements)) {
-	return search_method_without_refinements(klass, id, defined_class_ptr);
-    }
-    else {
-	return search_method_with_refinements(klass, id, refinements,
-					      defined_class_ptr);
-    }
-}
-
 /*
  * search method entry without the method cache.
  *
@@ -516,19 +519,17 @@
  * rb_method_entry() simply.
  */
 rb_method_entry_t *
-rb_method_entry_get_without_cache(VALUE klass, VALUE refinements, ID id,
+rb_method_entry_get_without_cache(VALUE klass, ID id,
 				  VALUE *defined_class_ptr)
 {
     VALUE defined_class;
-    rb_method_entry_t *me = search_method(klass, id, refinements,
-					  &defined_class);
+    rb_method_entry_t *me = search_method(klass, id, &defined_class);
 
     if (ruby_running) {
 	struct cache_entry *ent;
-	ent = cache + EXPR1(klass, refinements, id);
+	ent = cache + EXPR1(klass, id);
 	ent->filled_version = GET_VM_STATE_VERSION();
 	ent->klass = klass;
-	ent->refinements = refinements;
 	ent->defined_class = defined_class;
 
 	if (UNDEFINED_METHOD_ENTRY_P(me)) {
@@ -548,37 +549,84 @@
 }
 
 rb_method_entry_t *
-rb_method_entry_get_with_refinements(VALUE refinements, VALUE klass, ID id,
-				     VALUE *defined_class_ptr)
+rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
 {
 #if OPT_GLOBAL_METHOD_CACHE
     struct cache_entry *ent;
 
-    ent = cache + EXPR1(klass, refinements, id);
+    ent = cache + EXPR1(klass, id);
     if (ent->filled_version == GET_VM_STATE_VERSION() &&
-	ent->mid == id && ent->klass == klass &&
-       	ent->refinements == refinements) {
+	ent->mid == id && ent->klass == klass) {
 	if (defined_class_ptr)
 	    *defined_class_ptr = ent->defined_class;
 	return ent->me;
     }
 #endif
 
-    return rb_method_entry_get_without_cache(klass, refinements, id,
+    return rb_method_entry_get_without_cache(klass, id, defined_class_ptr);
+}
+
+static rb_method_entry_t *
+get_original_method_entry(VALUE refinements,
+			  rb_method_entry_t *me,
+			  VALUE *defined_class_ptr)
+{
+    if (me->def->body.orig_me) {
+	return me->def->body.orig_me;
+    }
+    else {
+	rb_method_entry_t *tmp_me;
+	tmp_me = rb_method_entry(RCLASS_SUPER(me->klass), me->called_id,
+				 defined_class_ptr);
+	return rb_resolve_refined_method(refinements, tmp_me,
+					 defined_class_ptr);
+    }
+}
+
+rb_method_entry_t *
+rb_resolve_refined_method(VALUE refinements, rb_method_entry_t *me,
+			  VALUE *defined_class_ptr)
+{
+    if (me && me->def->type == VM_METHOD_TYPE_REFINED) {
+	VALUE refinement;
+	rb_method_entry_t *tmp_me;
+
+	refinement = find_refinement(refinements, me->klass);
+	if (NIL_P(refinement)) {
+	    return get_original_method_entry(refinements, me,
 					     defined_class_ptr);
+	}
+	tmp_me = rb_method_entry(refinement, me->called_id,
+				 defined_class_ptr);
+	if (tmp_me && tmp_me->def->type != VM_METHOD_TYPE_REFINED) {
+	    return tmp_me;
+	}
+	else {
+	     (... truncated)

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

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