diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-04-19 19:41:40 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-04-19 19:54:55 +0900 |
| commit | 6a0b68f8b81adff8bc9fa58764eb014fa30de1c5 (patch) | |
| tree | 05d0b17066208105a4565000c60bbb5272381793 | |
| parent | 77c2aa7b8aaf2c3611189e84c48ac3ee74d2f47d (diff) | |
| download | mruby-6a0b68f8b81adff8bc9fa58764eb014fa30de1c5.tar.gz mruby-6a0b68f8b81adff8bc9fa58764eb014fa30de1c5.zip | |
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()`.
| -rw-r--r-- | include/mruby.h | 5 | ||||
| -rw-r--r-- | mrbgems/mruby-object-ext/src/object.c | 4 | ||||
| -rw-r--r-- | src/vm.c | 27 |
3 files changed, 34 insertions, 2 deletions
diff --git a/include/mruby.h b/include/mruby.h index 8adce289b..7a3def3fa 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -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. */ diff --git a/mrbgems/mruby-object-ext/src/object.c b/mrbgems/mruby-object-ext/src/object.c index 8a2325ef9..c6caf935f 100644 --- a/mrbgems/mruby-object-ext/src/object.c +++ b/mrbgems/mruby-object-ext/src/object.c @@ -1,6 +1,7 @@ #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, |
