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/