Make `eval` to use trampoline technique; fix
Now `eval()` can call Fiber.yield etc.
MODIFY
mrbgems/mruby-eval/src/eval.c
mrbgems/mruby-eval/src/eval.c
#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);

MODIFY
src/vm.c
src/vm.c
@@ -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

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

Now `eval()` can call Fiber.yield etc.