summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2017-02-04 16:19:31 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2017-02-04 16:19:31 +0900
commit48e0bbbfeea8268b09ad0a6bbc840834cc443fe0 (patch)
tree882a58b328d81b6ac23530f9f7a215365bf64ba6
parentbf4e79cc62af809138bc7db7e54ece67080b5fa8 (diff)
downloadmruby-48e0bbbfeea8268b09ad0a6bbc840834cc443fe0.tar.gz
mruby-48e0bbbfeea8268b09ad0a6bbc840834cc443fe0.zip
Make `eval` to use trampoline technique; fix #3415
Now `eval()` can call Fiber.yield etc.
-rw-r--r--mrbgems/mruby-eval/src/eval.c17
-rw-r--r--src/vm.c49
2 files changed, 35 insertions, 31 deletions
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c
index 26dd728ba..81bc80280 100644
--- a/mrbgems/mruby-eval/src/eval.c
+++ b/mrbgems/mruby-eval/src/eval.c
@@ -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);
diff --git a/src/vm.c b/src/vm.c
index 9684dabfd..0c0f5a4bb 100644
--- a/src/vm.c
+++ b/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