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

ruby-changes:13760

From: matz <ko1@a...>
Date: Thu, 29 Oct 2009 13:55:29 +0900 (JST)
Subject: [ruby-changes:13760] Ruby:r25556 (trunk): * array.c (rb_ary_to_ary): do not use #respond_to? to detect

matz	2009-10-29 13:55:10 +0900 (Thu, 29 Oct 2009)

  New Revision: 25556

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

  Log:
    * 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.

  Modified files:
    trunk/ChangeLog
    trunk/array.c
    trunk/enum.c
    trunk/enumerator.c
    trunk/error.c
    trunk/eval.c
    trunk/include/ruby/intern.h
    trunk/io.c
    trunk/object.c
    trunk/test/ruby/test_rubyoptions.rb
    trunk/vm_eval.c

Index: array.c
===================================================================
--- array.c	(revision 25555)
+++ array.c	(revision 25556)
@@ -1223,12 +1223,9 @@
 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);
 }
 
Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 25555)
+++ include/ruby/intern.h	(revision 25556)
@@ -203,6 +203,7 @@
 /* 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 {
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 25555)
+++ ChangeLog	(revision 25556)
@@ -1,3 +1,35 @@
+Thu Oct 29 13:53:18 2009  Yukihiro Matsumoto  <matz@r...>
+
+	* 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@r...>
 
 	* ruby.c (process_options): call rb_filesystem_encoding().
Index: enumerator.c
===================================================================
--- enumerator.c	(revision 25555)
+++ enumerator.c	(revision 25556)
@@ -856,8 +856,7 @@
 {
     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;
Index: enum.c
===================================================================
--- enum.c	(revision 25555)
+++ enum.c	(revision 25556)
@@ -149,9 +149,10 @@
 	    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;
 	}
     }
Index: object.c
===================================================================
--- object.c	(revision 25555)
+++ object.c	(revision 25556)
@@ -2005,6 +2005,8 @@
 {
     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 @@
 	}
     }
     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 @@
 		     rb_obj_classname(val),
 		     tname);
 	}
-	else {
-	    return Qnil;
-	}
+	return Qnil;
     }
-    return rb_funcall(val, m, 0);
+    return r;
 }
 
 VALUE
Index: io.c
===================================================================
--- io.c	(revision 25555)
+++ io.c	(revision 25556)
@@ -5157,6 +5157,7 @@
     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 @@
 	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') {
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 25555)
+++ vm_eval.c	(revision 25556)
@@ -390,9 +390,16 @@
 
     {
 	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 @@
     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;
Index: eval.c
===================================================================
--- eval.c	(revision 25555)
+++ eval.c	(revision 25556)
@@ -425,11 +425,13 @@
     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 @@
 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,9 +492,41 @@
     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;
     int n;
@@ -504,10 +538,12 @@
       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 @@
 	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 @@
     return mesg;
 }
 
+VALUE
+rb_make_exception(int argc, VALUE *argv)
+{
+    return make_exception(argc, argv, Qtrue);
+}
+
 void
 rb_raise_jump(VALUE mesg)
 {
Index: error.c
===================================================================
--- error.c	(revision 25555)
+++ error.c	(revision 25556)
@@ -608,13 +608,10 @@
 	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 @@
 };
 
 /* :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 @@
     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);
Index: test/ruby/test_rubyoptions.rb
===================================================================
--- test/ruby/test_rubyoptions.rb	(revision 25555)
+++ test/ruby/test_rubyoptions.rb	(revision 25556)
@@ -53,9 +53,9 @@
   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

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

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