summaryrefslogtreecommitdiffhomepage
path: root/src/vm.c
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-04-19 19:41:40 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2017-04-19 19:54:55 +0900
commit6a0b68f8b81adff8bc9fa58764eb014fa30de1c5 (patch)
tree05d0b17066208105a4565000c60bbb5272381793 /src/vm.c
parent77c2aa7b8aaf2c3611189e84c48ac3ee74d2f47d (diff)
downloadmruby-6a0b68f8b81adff8bc9fa58764eb014fa30de1c5.tar.gz
mruby-6a0b68f8b81adff8bc9fa58764eb014fa30de1c5.zip
Use trampoline technique for `instance_exec`; ref #3359
A new function `mrb_yield_cont()` is provided. You have to call it at the end of a C defined method, e.g. `return mrb_yield_cont()`.
Diffstat (limited to 'src/vm.c')
-rw-r--r--src/vm.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/src/vm.c b/src/vm.c
index 91aca3eb0..041a5238c 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -467,6 +467,7 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
{
mrb_callinfo *ci = mrb->c->ci;
+ mrb->c->stack[0] = self;
ci->proc = p;
ci->target_class = p->target_class;
if (MRB_PROC_CFUNC_P(p)) {
@@ -562,7 +563,8 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
}
ci = mrb->c->ci;
if (ci->acc == CI_ACC_DIRECT) {
- return mrb_yield_with_class(mrb, blk, 1, &self, self, c);
+ ci->target_class = c;
+ return mrb_yield_cont(mrb, blk, self, 1, &self);
}
ci->target_class = c;
p = mrb_proc_ptr(blk);
@@ -726,6 +728,29 @@ mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg)
return mrb_yield_with_class(mrb, b, 1, &arg, p->env->stack[0], p->target_class);
}
+mrb_value
+mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb_value *argv)
+{
+ struct RProc *p;
+ mrb_callinfo *ci;
+
+ if (mrb_nil_p(b)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+ if (mrb_type(b) != MRB_TT_PROC) {
+ mrb_raise(mrb, E_TYPE_ERROR, "not a block");
+ }
+
+ p = mrb_proc_ptr(b);
+ ci = mrb->c->ci;
+
+ stack_extend(mrb, 3);
+ mrb->c->stack[1] = mrb_ary_new_from_values(mrb, argc, argv);
+ mrb->c->stack[2] = mrb_nil_value();
+ ci->argc = -1;
+ return mrb_exec_irep(mrb, self, p);
+}
+
typedef enum {
LOCALJUMP_ERROR_RETURN = 0,
LOCALJUMP_ERROR_BREAK = 1,