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

ruby-changes:10918

From: nobu <ko1@a...>
Date: Sun, 22 Feb 2009 10:44:10 +0900 (JST)
Subject: [ruby-changes:10918] Ruby:r22494 (trunk): * vm_eval.c (method_missing): should not pop cfp if missing method

nobu	2009-02-22 10:43:59 +0900 (Sun, 22 Feb 2009)

  New Revision: 22494

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

  Log:
    * vm_eval.c (method_missing): should not pop cfp if missing method
      is method_missing.  [ruby-core:22298]
    * vm_eval.c (rb_raise_method_missing): new function to directly
      raise NoMethodError.
    
    * vm_insnhelper.c (vm_call_method): fixed the case method_missing
      is missing.

  Modified files:
    trunk/ChangeLog
    trunk/eval_intern.h
    trunk/vm_eval.c
    trunk/vm_insnhelper.c

Index: eval_intern.h
===================================================================
--- eval_intern.h	(revision 22493)
+++ eval_intern.h	(revision 22494)
@@ -195,6 +195,8 @@
 NORETURN(void rb_print_undef(VALUE, ID, int));
 NORETURN(void rb_vm_localjump_error(const char *,VALUE, int));
 NORETURN(void rb_vm_jump_tag_but_local_jump(int, VALUE));
+NORETURN(void rb_raise_method_missing(rb_thread_t *th, int argc, VALUE *argv,
+				      VALUE obj, int call_status));
 
 VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val);
 NODE *rb_vm_cref(void);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 22493)
+++ ChangeLog	(revision 22494)
@@ -1,3 +1,14 @@
+Sun Feb 22 10:43:57 2009  Nobuyoshi Nakada  <nobu@r...>
+
+	* vm_eval.c (method_missing): should not pop cfp if missing method
+	  is method_missing.  [ruby-core:22298]
+
+	* vm_eval.c (rb_raise_method_missing): new function to directly
+	  raise NoMethodError.
+
+	* vm_insnhelper.c (vm_call_method): fixed the case method_missing
+	  is missing.
+
 Sun Feb 22 02:15:40 2009  Tanaka Akira  <akr@f...>
 
 	* ext/socket/ancdata.c (bsock_recvmsg_internal): handle EMSGSIZE as
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 22493)
+++ vm_eval.c	(revision 22494)
@@ -256,6 +256,9 @@
     return rb_call0(klass, recv, mid, argc, argv, scope, Qundef);
 }
 
+NORETURN(static void raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv,
+					  VALUE obj, int call_status));
+
 /*
  *  call-seq:
  *     obj.method_missing(symbol [, *args] )   => result
@@ -292,11 +295,21 @@
 static VALUE
 rb_method_missing(int argc, const VALUE *argv, VALUE obj)
 {
+    rb_thread_t *th = GET_THREAD();
+    raise_method_missing(th, argc, argv, obj, th->method_missing_reason);
+    return Qnil;		/* not reached */
+}
+
+#define NOEX_MISSING   0x80
+
+static void
+raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv, VALUE obj,
+		     int last_call_status)
+{
     ID id;
     VALUE exc = rb_eNoMethodError;
     const char *format = 0;
-    rb_thread_t *th = GET_THREAD();
-    int last_call_status = th->method_missing_reason;
+
     if (argc == 0 || !SYMBOL_P(argv[0])) {
 	rb_raise(rb_eArgError, "no id given");
     }
@@ -333,11 +346,11 @@
 	}
 	exc = rb_class_new_instance(n, args, exc);
 
-	th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
+	if (!(last_call_status & NOEX_MISSING)) {
+	    th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
+	}
 	rb_exc_raise(exc);
     }
-
-    return Qnil;		/* not reached */
 }
 
 static inline VALUE
@@ -350,7 +363,7 @@
     th->passed_block = 0;
 
     if (id == idMethodMissing) {
-	rb_method_missing(argc, argv, obj);
+	raise_method_missing(th, argc, argv, obj, call_status | NOEX_MISSING);
     }
     else if (id == ID_ALLOCATOR) {
 	rb_raise(rb_eTypeError, "allocator undefined for %s",
@@ -372,6 +385,14 @@
     return result;
 }
 
+void
+rb_raise_method_missing(rb_thread_t *th, int argc, VALUE *argv,
+			VALUE obj, int call_status)
+{
+    th->passed_block = 0;
+    raise_method_missing(th, argc, argv, obj, call_status | NOEX_MISSING);
+}
+
 VALUE
 rb_apply(VALUE recv, ID mid, VALUE args)
 {
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 22493)
+++ vm_insnhelper.c	(revision 22494)
@@ -403,22 +403,27 @@
     return val;
 }
 
-static inline VALUE
-vm_method_missing(rb_thread_t *th, ID id, VALUE recv,
+static inline void
+vm_method_missing_args(rb_thread_t *th, VALUE *argv,
 		  int num, rb_block_t *blockptr, int opt)
 {
-    VALUE val;
     rb_control_frame_t * const reg_cfp = th->cfp;
-    VALUE *argv = ALLOCA_N(VALUE, num + 1);
     MEMCPY(argv, STACK_ADDR_FROM_TOP(num + 1), VALUE, num + 1);
-    argv[0] = ID2SYM(id);
     th->method_missing_reason = opt;
     th->passed_block = blockptr;
     POPN(num + 1);
-    val = rb_funcall2(recv, idMethodMissing, num + 1, argv);
-    return val;
 }
 
+static inline VALUE
+vm_method_missing(rb_thread_t *th, ID id, VALUE recv,
+		  int num, rb_block_t *blockptr, int opt)
+{
+    VALUE *argv = ALLOCA_N(VALUE, num + 1);
+    vm_method_missing_args(th, argv, num, blockptr, opt);
+    argv[0] = ID2SYM(id);
+    return rb_funcall2(recv, idMethodMissing, num + 1, argv);
+}
+
 static inline void
 vm_setup_method(rb_thread_t *th, rb_control_frame_t *cfp,
 		const int argc, const rb_block_t *blockptr, const VALUE flag,
@@ -581,17 +586,19 @@
     }
     else {
 	/* method missing */
+	int stat = 0;
+	if (flag & VM_CALL_VCALL_BIT) {
+	    stat |= NOEX_VCALL;
+	}
+	if (flag & VM_CALL_SUPER_BIT) {
+	    stat |= NOEX_SUPER;
+	}
 	if (id == idMethodMissing) {
-	    rb_bug("method missing");
+	    VALUE *argv = ALLOCA_N(VALUE, num);
+	    vm_method_missing_args(th, argv, num - 1, 0, stat);
+	    rb_raise_method_missing(th, num, argv, recv, stat);
 	}
 	else {
-	    int stat = 0;
-	    if (flag & VM_CALL_VCALL_BIT) {
-		stat |= NOEX_VCALL;
-	    }
-	    if (flag & VM_CALL_SUPER_BIT) {
-		stat |= NOEX_SUPER;
-	    }
 	    val = vm_method_missing(th, id, recv, num, blockptr, stat);
 	}
     }

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

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