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

ruby-changes:10973

From: yugui <ko1@a...>
Date: Sun, 22 Feb 2009 23:05:44 +0900 (JST)
Subject: [ruby-changes:10973] Ruby:r22551 (ruby_1_9_1): merges r22494 and r22495 from trunk into ruby_1_9_1.

yugui	2009-02-22 23:05:31 +0900 (Sun, 22 Feb 2009)

  New Revision: 22551

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

  Log:
    merges r22494 and r22495 from trunk into ruby_1_9_1.
    * 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:
    branches/ruby_1_9_1/ChangeLog
    branches/ruby_1_9_1/bootstraptest/test_method.rb
    branches/ruby_1_9_1/eval_intern.h
    branches/ruby_1_9_1/vm_eval.c
    branches/ruby_1_9_1/vm_insnhelper.c

Index: ruby_1_9_1/eval_intern.h
===================================================================
--- ruby_1_9_1/eval_intern.h	(revision 22550)
+++ ruby_1_9_1/eval_intern.h	(revision 22551)
@@ -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: ruby_1_9_1/ChangeLog
===================================================================
--- ruby_1_9_1/ChangeLog	(revision 22550)
+++ ruby_1_9_1/ChangeLog	(revision 22551)
@@ -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.
+
 Fri Feb 20 23:28:11 2009  NAKAMURA Usaku  <usa@r...>
 
 	* util.c (rv_alloc, freedtoa): use our normal xmalloc()/xfree() because
Index: ruby_1_9_1/bootstraptest/test_method.rb
===================================================================
--- ruby_1_9_1/bootstraptest/test_method.rb	(revision 22550)
+++ ruby_1_9_1/bootstraptest/test_method.rb	(revision 22551)
@@ -1140,3 +1140,14 @@
   end
   Foo.foo
 }, '[ruby-dev:37587]'
+
+assert_normal_exit %q{
+  class BasicObject
+    remove_method :method_missing
+  end
+  begin
+    "a".lalala!
+  rescue NoMethodError => e
+    e.message == "undefined method `lalala!' for \"a\":String" ? :ok : :ng
+  end
+}, '[ruby-core:22298]'
Index: ruby_1_9_1/vm_eval.c
===================================================================
--- ruby_1_9_1/vm_eval.c	(revision 22550)
+++ ruby_1_9_1/vm_eval.c	(revision 22551)
@@ -255,6 +255,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
@@ -291,11 +294,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");
     }
@@ -332,11 +345,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
@@ -349,7 +362,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",
@@ -371,6 +384,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: ruby_1_9_1/vm_insnhelper.c
===================================================================
--- ruby_1_9_1/vm_insnhelper.c	(revision 22550)
+++ ruby_1_9_1/vm_insnhelper.c	(revision 22551)
@@ -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/

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