Skip to content

Commit 48e0bbb

Browse files
committed
Make eval to use trampoline technique; fix #3415
Now `eval()` can call Fiber.yield etc.
1 parent bf4e79c commit 48e0bbb

File tree

2 files changed

+35
-31
lines changed

2 files changed

+35
-31
lines changed

Diff for: mrbgems/mruby-eval/src/eval.c

+7-10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#include <mruby/proc.h>
66
#include <mruby/opcode.h>
77

8+
mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p);
9+
mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self);
10+
811
static struct mrb_irep *
912
get_closure_irep(mrb_state *mrb, int level)
1013
{
@@ -209,22 +212,15 @@ f_eval(mrb_state *mrb, mrb_value self)
209212
mrb_value binding = mrb_nil_value();
210213
char *file = NULL;
211214
mrb_int line = 1;
212-
mrb_value ret;
213215
struct RProc *proc;
214216

215217
mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line);
216218

217219
proc = create_proc_from_string(mrb, s, len, binding, file, line);
218-
ret = mrb_top_run(mrb, proc, mrb->c->stack[0], 0);
219-
if (mrb->exc) {
220-
mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
221-
}
222-
223-
return ret;
220+
mrb_assert(!MRB_PROC_CFUNC_P(proc));
221+
return mrb_exec_irep(mrb, self, proc);
224222
}
225223

226-
mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self);
227-
228224
#define CI_ACC_SKIP -1
229225

230226
static mrb_value
@@ -250,7 +246,8 @@ f_instance_eval(mrb_state *mrb, mrb_value self)
250246
c->ci->target_class = mrb_class_ptr(cv);
251247
proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line);
252248
mrb->c->ci->env = NULL;
253-
return mrb_vm_run(mrb, proc, mrb->c->stack[0], 0);
249+
mrb_assert(!MRB_PROC_CFUNC_P(proc));
250+
return mrb_exec_irep(mrb, self, proc);
254251
}
255252
else {
256253
mrb_get_args(mrb, "&", &b);

Diff for: src/vm.c

+28-21
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,33 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons
447447
return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value());
448448
}
449449

450+
mrb_value
451+
mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
452+
{
453+
mrb_callinfo *ci = mrb->c->ci;
454+
455+
ci->proc = p;
456+
if (MRB_PROC_CFUNC_P(p)) {
457+
return p->body.func(mrb, self);
458+
}
459+
if (ci->argc < 0) {
460+
stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3);
461+
}
462+
else {
463+
stack_extend(mrb, p->body.irep->nregs, ci->argc+2);
464+
}
465+
466+
ci->nregs = p->body.irep->nregs;
467+
ci = cipush(mrb);
468+
ci->nregs = 0;
469+
ci->target_class = 0;
470+
ci->pc = p->body.irep->iseq;
471+
ci->stackent = mrb->c->stack;
472+
ci->acc = 0;
473+
474+
return self;
475+
}
476+
450477
/* 15.3.1.3.4 */
451478
/* 15.3.1.3.44 */
452479
/*
@@ -488,7 +515,6 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
488515
ci = mrb->c->ci;
489516
ci->mid = name;
490517
ci->target_class = c;
491-
ci->proc = p;
492518
regs = mrb->c->stack+1;
493519
/* remove first symbol from arguments */
494520
if (ci->argc >= 0) {
@@ -501,26 +527,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
501527
mrb_ary_shift(mrb, regs[0]);
502528
}
503529

504-
if (MRB_PROC_CFUNC_P(p)) {
505-
return p->body.func(mrb, self);
506-
}
507-
508-
if (ci->argc < 0) {
509-
stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3);
510-
}
511-
else {
512-
stack_extend(mrb, p->body.irep->nregs, ci->argc+2);
513-
}
514-
515-
ci->nregs = p->body.irep->nregs;
516-
ci = cipush(mrb);
517-
ci->nregs = 0;
518-
ci->target_class = 0;
519-
ci->pc = p->body.irep->iseq;
520-
ci->stackent = mrb->c->stack;
521-
ci->acc = 0;
522-
523-
return self;
530+
return mrb_exec_irep(mrb, self, p);
524531
}
525532

526533
static mrb_value

0 commit comments

Comments
 (0)