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()`.
parent 77c2aa7b
......@@ -1121,6 +1121,11 @@ MRB_API mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg);
MRB_API mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv);
MRB_API mrb_value mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv, mrb_value self, struct RClass *c);
/* continue execution to the proc */
/* this function should always be called as the last function of a method */
/* e.g. return mrb_yield_cont(mrb, proc, self, argc, argv); */
mrb_value mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb_value *argv);
/* mrb_gc_protect() leaves the object in the arena */
MRB_API void mrb_gc_protect(mrb_state *mrb, mrb_value obj);
/* mrb_gc_register() keeps the object from GC. */
......
#include <mruby.h>
#include <mruby/array.h>
#include <mruby/class.h>
#include <mruby/proc.h>
/*
* call-seq:
......@@ -86,7 +87,8 @@ mrb_obj_instance_exec(mrb_state *mrb, mrb_value self)
}
args = mrb_ary_new_from_values(mrb, argc, argv);
argv = RARRAY_PTR(args);
return mrb_yield_with_class(mrb, blk, argc, argv, self, c);
mrb->c->ci->target_class = c;
return mrb_yield_cont(mrb, blk, self, argc, argv);
}
void
......
......@@ -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,
......
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