Make `eval` to use trampoline technique; fix #3415

Now `eval()` can call Fiber.yield etc.
parent bf4e79cc
......@@ -5,6 +5,9 @@
#include <mruby/proc.h>
#include <mruby/opcode.h>
mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p);
mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self);
static struct mrb_irep *
get_closure_irep(mrb_state *mrb, int level)
{
......@@ -209,22 +212,15 @@ f_eval(mrb_state *mrb, mrb_value self)
mrb_value binding = mrb_nil_value();
char *file = NULL;
mrb_int line = 1;
mrb_value ret;
struct RProc *proc;
mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line);
proc = create_proc_from_string(mrb, s, len, binding, file, line);
ret = mrb_top_run(mrb, proc, mrb->c->stack[0], 0);
if (mrb->exc) {
mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
}
return ret;
mrb_assert(!MRB_PROC_CFUNC_P(proc));
return mrb_exec_irep(mrb, self, proc);
}
mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self);
#define CI_ACC_SKIP -1
static mrb_value
......@@ -250,7 +246,8 @@ f_instance_eval(mrb_state *mrb, mrb_value self)
c->ci->target_class = mrb_class_ptr(cv);
proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line);
mrb->c->ci->env = NULL;
return mrb_vm_run(mrb, proc, mrb->c->stack[0], 0);
mrb_assert(!MRB_PROC_CFUNC_P(proc));
return mrb_exec_irep(mrb, self, proc);
}
else {
mrb_get_args(mrb, "&", &b);
......
......@@ -447,6 +447,33 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons
return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
}
mrb_value
mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
{
mrb_callinfo *ci = mrb->c->ci;
ci->proc = p;
if (MRB_PROC_CFUNC_P(p)) {
return p->body.func(mrb, self);
}
if (ci->argc < 0) {
stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3);
}
else {
stack_extend(mrb, p->body.irep->nregs, ci->argc+2);
}
ci->nregs = p->body.irep->nregs;
ci = cipush(mrb);
ci->nregs = 0;
ci->target_class = 0;
ci->pc = p->body.irep->iseq;
ci->stackent = mrb->c->stack;
ci->acc = 0;
return self;
}
/* 15.3.1.3.4 */
/* 15.3.1.3.44 */
/*
......@@ -488,7 +515,6 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
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) {
......@@ -501,26 +527,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
mrb_ary_shift(mrb, regs[0]);
}
if (MRB_PROC_CFUNC_P(p)) {
return p->body.func(mrb, self);
}
if (ci->argc < 0) {
stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3);
}
else {
stack_extend(mrb, p->body.irep->nregs, ci->argc+2);
}
ci->nregs = p->body.irep->nregs;
ci = cipush(mrb);
ci->nregs = 0;
ci->target_class = 0;
ci->pc = p->body.irep->iseq;
ci->stackent = mrb->c->stack;
ci->acc = 0;
return self;
return mrb_exec_irep(mrb, self, p);
}
static mrb_value
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment