diff options
author | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-10-29 04:55:10 +0000 |
---|---|---|
committer | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2009-10-29 04:55:10 +0000 |
commit | 0580ba06110f7998fdaead724907a4c8d6540107 (patch) | |
tree | 4ceed7d1642d46a147114fc1a303ce5257af49bb | |
parent | 2bb26c118d9e52a52940f73c9cb1fc26e07003d6 (diff) |
* array.c (rb_ary_to_ary): do not use #respond_to? to detect
to_ary. Just call. [ruby-core:23738]
* eval.c (rb_check_funcall): new function with method existence
check. returns Qundef when the method does not exist.
* enumerator.c (enumerator_rewind): just call method, using
rb_check_funcall(). [ruby-core:23738]
* error.c (exc_equal): ditto.
* object.c (convert_type): ditto.
* error.c (rb_name_err_mesg_new): export function.
* eval.c (make_exception): ditto.
* io.c (pop_last_hash): return early when the last argument is nil.
* io.c (rb_io_puts): treat T_STRING specially for small
optimization.
* vm_eval.c (raise_method_missing): skip method call if possible
using rb_method_basic_definition_p().
* vm_eval.c (method_missing): ditto.
* test/ruby/test_rubyoptions.rb (TestRubyOptions#test_debug): test
suites changed to ignore exceptions caused by just-call policy.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25556 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 32 | ||||
-rw-r--r-- | array.c | 9 | ||||
-rw-r--r-- | enum.c | 7 | ||||
-rw-r--r-- | enumerator.c | 3 | ||||
-rw-r--r-- | error.c | 17 | ||||
-rw-r--r-- | eval.c | 60 | ||||
-rw-r--r-- | include/ruby/intern.h | 1 | ||||
-rw-r--r-- | io.c | 6 | ||||
-rw-r--r-- | object.c | 15 | ||||
-rw-r--r-- | test/ruby/test_rubyoptions.rb | 4 | ||||
-rw-r--r-- | vm_eval.c | 14 |
11 files changed, 129 insertions, 39 deletions
@@ -1,3 +1,35 @@ +Thu Oct 29 13:53:18 2009 Yukihiro Matsumoto <matz@ruby-lang.org> + + * array.c (rb_ary_to_ary): do not use #respond_to? to detect + to_ary. Just call. [ruby-core:23738] + + * eval.c (rb_check_funcall): new function with method existence + check. returns Qundef when the method does not exist. + + * enumerator.c (enumerator_rewind): just call method, using + rb_check_funcall(). [ruby-core:23738] + + * error.c (exc_equal): ditto. + + * object.c (convert_type): ditto. + + * error.c (rb_name_err_mesg_new): export function. + + * eval.c (make_exception): ditto. + + * io.c (pop_last_hash): return early when the last argument is nil. + + * io.c (rb_io_puts): treat T_STRING specially for small + optimization. + + * vm_eval.c (raise_method_missing): skip method call if possible + using rb_method_basic_definition_p(). + + * vm_eval.c (method_missing): ditto. + + * test/ruby/test_rubyoptions.rb (TestRubyOptions#test_debug): test + suites changed to ignore exceptions caused by just-call policy. + Thu Oct 29 04:41:44 2009 NARUSE, Yui <naruse@ruby-lang.org> * ruby.c (process_options): call rb_filesystem_encoding(). @@ -1223,12 +1223,9 @@ rb_ary_rindex(int argc, VALUE *argv, VALUE ary) VALUE rb_ary_to_ary(VALUE obj) { - if (TYPE(obj) == T_ARRAY) { - return obj; - } - if (rb_respond_to(obj, rb_intern("to_ary"))) { - return to_ary(obj); - } + VALUE tmp = rb_check_array_type(obj); + + if (!NIL_P(tmp)) return tmp; return rb_ary_new3(1, obj); } @@ -149,9 +149,10 @@ enum_count(int argc, VALUE *argv, VALUE obj) func = count_iter_i; } else { - if (rb_respond_to(obj, id_size)) { - return rb_funcall(obj, id_size, 0, 0); - } + VALUE tmp; + + tmp = rb_check_funcall(obj, id_size, 0, 0); + if (tmp != Qundef) return tmp; func = count_all_i; } } diff --git a/enumerator.c b/enumerator.c index 7b2ef3491e..0340338b50 100644 --- a/enumerator.c +++ b/enumerator.c @@ -856,8 +856,7 @@ enumerator_rewind(VALUE obj) { struct enumerator *e = enumerator_ptr(obj); - if (rb_respond_to(e->obj, id_rewind)) - rb_funcall(e->obj, id_rewind, 0); + rb_check_funcall(e->obj, id_rewind, 0, 0); e->fib = 0; e->dst = Qnil; @@ -608,13 +608,10 @@ exc_equal(VALUE exc, VALUE obj) CONST_ID(id_message, "message"); CONST_ID(id_backtrace, "backtrace"); - if (rb_respond_to(obj, id_message) && rb_respond_to(obj, id_backtrace)) { - mesg = rb_funcall(obj, id_message, 0, 0); - backtrace = rb_funcall(obj, id_backtrace, 0, 0); - } - else { - return Qfalse; - } + mesg = rb_check_funcall(obj, id_message, 0, 0); + if (mesg == Qundef) return Qfalse; + backtrace = rb_check_funcall(obj, id_backtrace, 0, 0); + if (backtrace == Qundef) return Qfalse; } else { mesg = rb_attr_get(obj, id_mesg); @@ -794,8 +791,8 @@ static const rb_data_type_t name_err_mesg_data_type = { }; /* :nodoc: */ -static VALUE -name_err_mesg_new(VALUE obj, VALUE mesg, VALUE recv, VALUE method) +VALUE +rb_name_err_mesg_new(VALUE obj, VALUE mesg, VALUE recv, VALUE method) { VALUE *ptr = ALLOC_N(VALUE, NAME_ERR_MESG_COUNT); @@ -1112,7 +1109,7 @@ Init_Exception(void) rb_define_method(rb_eNameError, "name", name_err_name, 0); rb_define_method(rb_eNameError, "to_s", name_err_to_s, 0); rb_cNameErrorMesg = rb_define_class_under(rb_eNameError, "message", rb_cData); - rb_define_singleton_method(rb_cNameErrorMesg, "!", name_err_mesg_new, NAME_ERR_MESG_COUNT); + rb_define_singleton_method(rb_cNameErrorMesg, "!", rb_name_err_mesg_new, NAME_ERR_MESG_COUNT); rb_define_method(rb_cNameErrorMesg, "==", name_err_mesg_equal, 1); rb_define_method(rb_cNameErrorMesg, "to_str", name_err_mesg_to_str, 0); rb_define_method(rb_cNameErrorMesg, "_dump", name_err_mesg_to_str, 1); @@ -425,11 +425,13 @@ rb_longjmp(int tag, volatile VALUE mesg) JUMP_TAG(tag); } +static VALUE make_exception(int argc, VALUE *argv, int isstr); + void rb_exc_raise(VALUE mesg) { if (!NIL_P(mesg)) { - mesg = rb_make_exception(1, &mesg); + mesg = make_exception(1, &mesg, Qfalse); } rb_longjmp(TAG_RAISE, mesg); } @@ -438,7 +440,7 @@ void rb_exc_fatal(VALUE mesg) { if (!NIL_P(mesg)) { - mesg = rb_make_exception(1, &mesg); + mesg = make_exception(1, &mesg, Qfalse); } rb_longjmp(TAG_FATAL, mesg); } @@ -490,8 +492,40 @@ rb_f_raise(int argc, VALUE *argv) return Qnil; /* not reached */ } +struct rescue_funcall_args { + VALUE obj; + ID id; + int argc; + VALUE *argv; +}; + +static VALUE +check_funcall(struct rescue_funcall_args *args) +{ + return rb_funcall2(args->obj, args->id, args->argc, args->argv); +} + +static VALUE +check_failed(VALUE data) +{ + return data; +} + VALUE -rb_make_exception(int argc, VALUE *argv) +rb_check_funcall(VALUE obj, ID id, int argc, VALUE *argv) +{ + struct rescue_funcall_args args; + + args.obj = obj; + args.id = id; + args.argc = argc; + args.argv = argv; + return rb_rescue2(check_funcall, (VALUE)&args, check_failed, Qundef, + rb_eNoMethodError, (VALUE)0); +} + +static VALUE +make_exception(int argc, VALUE *argv, int isstr) { VALUE mesg; ID exception; @@ -504,10 +538,12 @@ rb_make_exception(int argc, VALUE *argv) case 1: if (NIL_P(argv[0])) break; - mesg = rb_check_string_type(argv[0]); - if (!NIL_P(mesg)) { - mesg = rb_exc_new3(rb_eRuntimeError, mesg); - break; + if (isstr) { + mesg = rb_check_string_type(argv[0]); + if (!NIL_P(mesg)) { + mesg = rb_exc_new3(rb_eRuntimeError, mesg); + break; + } } n = 0; goto exception_call; @@ -517,10 +553,10 @@ rb_make_exception(int argc, VALUE *argv) n = 1; exception_call: CONST_ID(exception, "exception"); - if (!rb_respond_to(argv[0], exception)) { + mesg = rb_check_funcall(argv[0], exception, n, argv+1); + if (mesg == Qundef) { rb_raise(rb_eTypeError, "exception class/object expected"); } - mesg = rb_funcall(argv[0], exception, n, argv[1]); break; default: rb_raise(rb_eArgError, "wrong number of arguments"); @@ -536,6 +572,12 @@ rb_make_exception(int argc, VALUE *argv) return mesg; } +VALUE +rb_make_exception(int argc, VALUE *argv) +{ + return make_exception(argc, argv, Qtrue); +} + void rb_raise_jump(VALUE mesg) { diff --git a/include/ruby/intern.h b/include/ruby/intern.h index cece6424fe..fd37ecab2a 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -203,6 +203,7 @@ void rb_check_frozen(VALUE); /* eval.c */ int rb_sourceline(void); const char *rb_sourcefile(void); +VALUE rb_check_funcall(VALUE, ID, int, VALUE*); #if defined(NFDBITS) && defined(HAVE_RB_FD_INIT) typedef struct { @@ -5157,6 +5157,7 @@ pop_last_hash(int *argc_p, VALUE *argv) if (*argc_p == 0) return Qnil; last = argv[*argc_p-1]; + if (NIL_P(last)) return Qnil; tmp = rb_check_convert_type(last, T_HASH, "Hash", "to_hash"); if (NIL_P(tmp)) return Qnil; @@ -6066,12 +6067,17 @@ rb_io_puts(int argc, VALUE *argv, VALUE out) return Qnil; } for (i=0; i<argc; i++) { + if (TYPE(argv[i]) == T_STRING) { + line = argv[i]; + goto string; + } line = rb_check_array_type(argv[i]); if (!NIL_P(line)) { rb_exec_recursive(io_puts_ary, line, out); continue; } line = rb_obj_as_string(argv[i]); + string: rb_io_write(out, line); if (RSTRING_LEN(line) == 0 || RSTRING_PTR(line)[RSTRING_LEN(line)-1] != '\n') { @@ -2005,6 +2005,8 @@ convert_type(VALUE val, const char *tname, const char *method, int raise) { ID m = 0; int i; + VALUE args[4]; + VALUE r; for (i=0; conv_method_names[i].method; i++) { if (conv_method_names[i].method[0] == method[0] && @@ -2014,7 +2016,12 @@ convert_type(VALUE val, const char *tname, const char *method, int raise) } } if (!m) m = rb_intern(method); - if (!rb_respond_to(val, m)) { + args[0] = val; + args[1] = (VALUE)m; + args[2] = (VALUE)raise; + args[3] = (VALUE)tname; + r = rb_check_funcall(val, m, 0, 0); + if (r == Qundef) { if (raise) { rb_raise(rb_eTypeError, "can't convert %s into %s", NIL_P(val) ? "nil" : @@ -2023,11 +2030,9 @@ convert_type(VALUE val, const char *tname, const char *method, int raise) rb_obj_classname(val), tname); } - else { - return Qnil; - } + return Qnil; } - return rb_funcall(val, m, 0); + return r; } VALUE diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb index d4143cffb8..7e4ac8cfb4 100644 --- a/test/ruby/test_rubyoptions.rb +++ b/test/ruby/test_rubyoptions.rb @@ -53,9 +53,9 @@ class TestRubyOptions < Test::Unit::TestCase end def test_debug - assert_in_out_err(%w(-de) + ["p $DEBUG"], "", %w(true), []) + assert_in_out_err(%w(-de) + ["p $DEBUG"], "", %w(true), //) - assert_in_out_err(%w(--debug -e) + ["p $DEBUG"], "", %w(true), []) + assert_in_out_err(%w(--debug -e) + ["p $DEBUG"], "", %w(true), //) end def test_verbose @@ -390,9 +390,16 @@ raise_method_missing(rb_thread_t *th, int argc, const VALUE *argv, VALUE obj, { int n = 0; + VALUE mesg; VALUE args[3]; - args[n++] = rb_funcall(rb_const_get(exc, rb_intern("message")), '!', - 3, rb_str_new2(format), obj, argv[0]); + + mesg = rb_const_get(exc, rb_intern("message")); + if (rb_method_basic_definition_p(CLASS_OF(mesg), '!')) { + args[n++] = rb_name_err_mesg_new(mesg, rb_str_new2(format), obj, argv[0]); + } + else { + args[n++] = rb_funcall(mesg, '!', 3, rb_str_new2(format), obj, argv[0]); + } args[n++] = argv[0]; if (exc == rb_eNoMethodError) { args[n++] = rb_ary_new4(argc - 1, argv + 1); @@ -433,6 +440,9 @@ method_missing(VALUE obj, ID id, int argc, const VALUE *argv, int call_status) nargv[0] = ID2SYM(id); MEMCPY(nargv + 1, argv, VALUE, argc); + if (rb_method_basic_definition_p(CLASS_OF(obj) , idMethodMissing)) { + raise_method_missing(th, argc+1, nargv, obj, call_status | NOEX_MISSING); + } result = rb_funcall2(obj, idMethodMissing, argc + 1, nargv); if (argv_ary) rb_ary_clear(argv_ary); return result; |