summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2014-03-01 18:13:10 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2014-03-01 18:13:10 +0900
commit675fd3dc801f17a4e81aa1bd15925500246fd5e5 (patch)
treec0c102c6a284d8d6640356b4d38c3d0196c04784 /src
parent8e170ce915626bb57ecad7e54d8fe207676d593e (diff)
downloadmruby-675fd3dc801f17a4e81aa1bd15925500246fd5e5.tar.gz
mruby-675fd3dc801f17a4e81aa1bd15925500246fd5e5.zip
allow send method not to call mrb_funcall if calling method is implemented in Ruby; fix #1680 ref #1765
Diffstat (limited to 'src')
-rw-r--r--src/backtrace.c1
-rw-r--r--src/kernel.c30
-rw-r--r--src/vm.c62
3 files changed, 63 insertions, 30 deletions
diff --git a/src/backtrace.c b/src/backtrace.c
index 6469fc069..c18a7cb95 100644
--- a/src/backtrace.c
+++ b/src/backtrace.c
@@ -72,6 +72,7 @@ output_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, output_stream_fun
filename = NULL;
lineno = -1;
+ if (!ci->proc) continue;
if (MRB_PROC_CFUNC_P(ci->proc)) {
continue;
}
diff --git a/src/kernel.c b/src/kernel.c
index e61a602be..45cc299d2 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -157,36 +157,6 @@ mrb_obj_id_m(mrb_state *mrb, mrb_value self)
return mrb_fixnum_value(mrb_obj_id(self));
}
-/* 15.3.1.3.4 */
-/* 15.3.1.3.44 */
-/*
- * call-seq:
- * obj.send(symbol [, args...]) -> obj
- * obj.__send__(symbol [, args...]) -> obj
- *
- * Invokes the method identified by _symbol_, passing it any
- * arguments specified. You can use <code>__send__</code> if the name
- * +send+ clashes with an existing method in _obj_.
- *
- * class Klass
- * def hello(*args)
- * "Hello " + args.join(' ')
- * end
- * end
- * k = Klass.new
- * k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
- */
-static mrb_value
-mrb_f_send(mrb_state *mrb, mrb_value self)
-{
- mrb_sym name;
- mrb_value block, *argv;
- int argc;
-
- mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block);
- return mrb_funcall_with_block(mrb,self, name, argc, argv, block);
-}
-
/* 15.3.1.2.2 */
/* 15.3.1.2.5 */
/* 15.3.1.3.6 */
diff --git a/src/vm.c b/src/vm.c
index 8bf34b170..62ac86c90 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -417,6 +417,68 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, int argc, mrb_valu
return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
}
+/* 15.3.1.3.4 */
+/* 15.3.1.3.44 */
+/*
+ * call-seq:
+ * obj.send(symbol [, args...]) -> obj
+ * obj.__send__(symbol [, args...]) -> obj
+ *
+ * Invokes the method identified by _symbol_, passing it any
+ * arguments specified. You can use <code>__send__</code> if the name
+ * +send+ clashes with an existing method in _obj_.
+ *
+ * class Klass
+ * def hello(*args)
+ * "Hello " + args.join(' ')
+ * end
+ * end
+ * k = Klass.new
+ * k.send :hello, "gentle", "readers" #=> "Hello gentle readers"
+ */
+mrb_value
+mrb_f_send(mrb_state *mrb, mrb_value self)
+{
+ mrb_sym name;
+ mrb_value block, *argv, *regs;
+ int argc, i, len;
+ struct RProc *p;
+ struct RClass *c;
+ mrb_callinfo *ci;
+
+ mrb_get_args(mrb, "n*&", &name, &argv, &argc, &block);
+
+ c = mrb_class(mrb, self);
+ p = mrb_method_search_vm(mrb, &c, name);
+ if (!p || MRB_PROC_CFUNC_P(p)) {
+ return mrb_funcall_with_block(mrb, self, name, argc, argv, block);
+ }
+
+ ci = mrb->c->ci;
+ ci->mid = name;
+ ci->target_class = c;
+ ci->proc = p;
+ regs = mrb->c->stack+1;
+ /* remove first symbol from arguments */
+ if (ci->argc >= 0) {
+ for (i=0,len=ci->argc; i<len; i++) {
+ regs[i] = regs[i+1];
+ }
+ ci->argc--;
+ }
+ else { /* variable length arguments */
+ mrb_ary_shift(mrb, regs[0]);
+ }
+ cipush(mrb);
+ ci = mrb->c->ci;
+ ci->target_class = 0;
+ ci->pc = p->body.irep->iseq;
+ ci->stackent = mrb->c->stack;
+ ci->acc = 0;
+
+ return self;
+}
+
mrb_value
mrb_yield_internal(mrb_state *mrb, mrb_value b, int argc, mrb_value *argv, mrb_value self, struct RClass *c)
{