diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2021-04-09 21:46:09 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-04-09 21:46:09 +0900 |
| commit | c2c37e1451d258c13ff160e0fd5f48acfcb1c52f (patch) | |
| tree | 65b679e3f90e68fbba233088625af5b9d2b0e97c | |
| parent | 6d3c0227498050d551243417340e704023fcaf42 (diff) | |
| parent | 4c196dcdaaf4127e2ce988fb79f1912c78b9dca8 (diff) | |
| download | mruby-c2c37e1451d258c13ff160e0fd5f48acfcb1c52f.tar.gz mruby-c2c37e1451d258c13ff160e0fd5f48acfcb1c52f.zip | |
Merge pull request #5401 from dearblue/mcall
Reorganize `mcall()` in `mruby-method`
| -rw-r--r-- | mrbgems/mruby-eval/src/eval.c | 9 | ||||
| -rw-r--r-- | mrbgems/mruby-method/src/method.c | 173 | ||||
| -rw-r--r-- | src/vm.c | 33 |
3 files changed, 162 insertions, 53 deletions
diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 978d4fc30..508f5ffcb 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -131,15 +131,6 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc, mrb_func_t posthoo { /* no argument passed from eval() */ mrb->c->ci->argc = 0; - if (mrb->c->ci->acc < 0) { - ptrdiff_t cioff = mrb->c->ci - mrb->c->cibase; - mrb_value ret = mrb_top_run(mrb, proc, self, 0); - if (mrb->exc) { - mrb_exc_raise(mrb, mrb_obj_value(mrb->exc)); - } - mrb->c->ci = mrb->c->cibase + cioff; - return ret; - } /* clear block */ mrb->c->ci->stack[1] = mrb_nil_value(); return mrb_exec_irep(mrb, self, proc, posthook); diff --git a/mrbgems/mruby-method/src/method.c b/mrbgems/mruby-method/src/method.c index 8c8ebcd4f..02eddda9c 100644 --- a/mrbgems/mruby-method/src/method.c +++ b/mrbgems/mruby-method/src/method.c @@ -6,12 +6,126 @@ #include "mruby/string.h" #include "mruby/presym.h" +mrb_noreturn void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); +mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook); + +static mrb_value +args_shift(mrb_state *mrb) +{ + mrb_value *argv = mrb->c->ci->stack + 1; + + if (mrb->c->ci->argc > 0) { + mrb_value obj = argv[0]; + memmove(argv, argv + 1, (mrb->c->ci->argc + 1 /* block */ - 1 /* first value */) * sizeof(mrb_value)); + mrb->c->ci->argc--; + return obj; + } + else if (mrb->c->ci->argc < 0 && RARRAY_LEN(*argv) > 0) { + return mrb_ary_shift(mrb, *argv); + } + else { + mrb_argnum_error(mrb, 0, 1, -1); + return mrb_undef_value(); /* not reached */ + } +} + +static void +args_unshift(mrb_state *mrb, mrb_value obj) +{ + mrb_value *argv = mrb->c->ci->stack + 1; + + if (mrb->c->ci->argc >= 0) { + mrb_value block = argv[mrb->c->ci->argc]; + argv[0] = mrb_ary_new_from_values(mrb, mrb->c->ci->argc, argv); + argv[1] = block; + mrb->c->ci->argc = -1; + } + + mrb_ary_unshift(mrb, *argv, obj); +} + +static struct RProc* +method_missing_prepare(mrb_state *mrb, mrb_sym *mid, mrb_value recv, struct RClass **tc) +{ + const mrb_sym id_method_missing = MRB_SYM(method_missing); + + if (*mid == id_method_missing) { + method_missing: ; + int argc = mrb->c->ci->argc; + mrb_value *argv = mrb->c->ci->stack + 1; + mrb_value args = (argc < 0) ? argv[0] : mrb_ary_new_from_values(mrb, argc, argv); + mrb_method_missing(mrb, *mid, recv, args); + } + + *tc = mrb_class(mrb, recv); + mrb_method_t m = mrb_method_search_vm(mrb, tc, id_method_missing); + if (MRB_METHOD_UNDEF_P(m)) { + goto method_missing; + } + + struct RProc *proc; + if (MRB_METHOD_FUNC_P(m)) { + proc = mrb_proc_new_cfunc(mrb, MRB_METHOD_FUNC(m)); + MRB_PROC_SET_TARGET_CLASS(proc, *tc); + } + else { + proc = MRB_METHOD_PROC(m); + } + + args_unshift(mrb, mrb_symbol_value(*mid)); + *mid = id_method_missing; + + return proc; +} + static struct RObject * method_object_alloc(mrb_state *mrb, struct RClass *mclass) { return (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, mclass); } +static struct RProc* +method_extract_proc(mrb_state *mrb, mrb_value self) +{ + mrb_value obj = mrb_iv_get(mrb, self, MRB_SYM(_proc)); + if (mrb_nil_p(obj)) { + return NULL; + } + else { + mrb_check_type(mrb, obj, MRB_TT_PROC); + return mrb_proc_ptr(obj); + } +} + +static mrb_value +method_extract_receiver(mrb_state *mrb, mrb_value self) +{ + return mrb_iv_get(mrb, self, MRB_SYM(_recv)); +} + +static mrb_sym +method_extract_mid(mrb_state *mrb, mrb_value self) +{ + mrb_value obj = mrb_iv_get(mrb, self, MRB_SYM(_name)); + mrb_check_type(mrb, obj, MRB_TT_SYMBOL); + return mrb_symbol(obj); +} + +static struct RClass* +method_extract_owner(mrb_state *mrb, mrb_value self) +{ + mrb_value obj = mrb_iv_get(mrb, self, MRB_SYM(_owner)); + switch (mrb_type(obj)) { + case MRB_TT_CLASS: + case MRB_TT_MODULE: + case MRB_TT_SCLASS: + break; + default: + mrb_raise(mrb, E_TYPE_ERROR, "not class/module as owner of method object"); + } + return mrb_class_ptr(obj); +} + static void bind_check(mrb_state *mrb, mrb_value recv, mrb_value owner) { @@ -109,61 +223,40 @@ method_eql(mrb_state *mrb, mrb_value self) #undef IV_GET static mrb_value -mcall(mrb_state *mrb, mrb_value recv, mrb_value proc, mrb_value name, struct RClass *owner, - mrb_int argc, const mrb_value *argv, mrb_value block) +mcall(mrb_state *mrb, mrb_value self, mrb_value recv) { - mrb_value ret; - mrb_sym orig_mid = mrb->c->ci->mid; + struct RProc *proc = method_extract_proc(mrb, self); + mrb_sym mid = method_extract_mid(mrb, self); + struct RClass *tc = method_extract_owner(mrb, self); - mrb->c->ci->mid = mrb_symbol(name); - if (mrb_nil_p(proc)) { - mrb_value missing_argv = mrb_ary_new_from_values(mrb, argc, argv); - mrb_ary_unshift(mrb, missing_argv, name); - ret = mrb_funcall_argv(mrb, recv, MRB_SYM(method_missing), argc + 1, RARRAY_PTR(missing_argv)); - } - else if (!mrb_nil_p(block)) { - /* - workaround since `mrb_yield_with_class` does not support passing block as parameter - need new API that initializes `mrb->c->stack[argc+1]` with block passed by argument - */ - ret = mrb_funcall_with_block(mrb, recv, mrb_symbol(name), argc, argv, block); + if (mrb_undef_p(recv)) { + recv = method_extract_receiver(mrb, self); } else { - ret = mrb_yield_with_class(mrb, proc, argc, argv, recv, owner); + bind_check(mrb, recv, mrb_obj_value(tc)); } - mrb->c->ci->mid = orig_mid; - return ret; + + if (!proc) { + proc = method_missing_prepare(mrb, &mid, recv, &tc); + } + mrb->c->ci->mid = mid; + mrb->c->ci->u.target_class = tc; + + return mrb_exec_irep(mrb, recv, proc, NULL); } static mrb_value method_call(mrb_state *mrb, mrb_value self) { - mrb_value proc = mrb_iv_get(mrb, self, MRB_SYM(_proc)); - mrb_value name = mrb_iv_get(mrb, self, MRB_SYM(_name)); - mrb_value recv = mrb_iv_get(mrb, self, MRB_SYM(_recv)); - struct RClass *owner = mrb_class_ptr(mrb_iv_get(mrb, self, MRB_SYM(_owner))); - mrb_int argc; - const mrb_value *argv; - mrb_value block; - - mrb_get_args(mrb, "*&", &argv, &argc, &block); - return mcall(mrb, recv, proc, name, owner, argc, argv, block); + return mcall(mrb, self, mrb_undef_value()); } static mrb_value method_bcall(mrb_state *mrb, mrb_value self) { - mrb_value proc = mrb_iv_get(mrb, self, MRB_SYM(_proc)); - mrb_value name = mrb_iv_get(mrb, self, MRB_SYM(_name)); - mrb_value recv = mrb_iv_get(mrb, self, MRB_SYM(_recv)); - mrb_value owner = mrb_iv_get(mrb, self, MRB_SYM(_owner)); - mrb_int argc; - const mrb_value *argv; - mrb_value block; - - mrb_get_args(mrb, "o*&", &recv, &argv, &argc, &block); - bind_check(mrb, recv, owner); - return mcall(mrb, recv, proc, name, mrb_class_ptr(owner), argc, argv, block); + mrb_value recv = args_shift(mrb); + mrb_gc_protect(mrb, recv); + return mcall(mrb, self, recv); } static mrb_value @@ -543,8 +543,8 @@ mrb_exec_irep_prepare_posthook(mrb_state *mrb, mrb_callinfo *ci, int nregs, mrb_ * * However, if `proc` is a C function, it will be ignored. */ -mrb_value -mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook) +static mrb_value +mrb_exec_irep_vm(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook) { mrb_callinfo *ci = mrb->c->ci; int keep, nregs; @@ -575,6 +575,31 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t postho return self; } +mrb_value +mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook) +{ + mrb_callinfo *ci = mrb->c->ci; + if (ci->acc >= 0) { + return mrb_exec_irep_vm(mrb, self, p, posthook); + } + else { + mrb_value ret; + if (MRB_PROC_CFUNC_P(p)) { + cipush(mrb, 0, CI_ACC_DIRECT, mrb_vm_ci_target_class(ci), p, ci->mid, ci->argc); + ret = MRB_PROC_CFUNC(p)(mrb, self); + cipop(mrb); + } + else { + int keep = (ci->argc < 0 ? 1 : ci->argc) + 2 /* receiver + block */; + ret = mrb_top_run(mrb, p, self, keep); + } + if (mrb->exc && mrb->jmp) { + mrb_exc_raise(mrb, mrb_obj_value(mrb->exc)); + } + return ret; + } +} + /* 15.3.1.3.4 */ /* 15.3.1.3.44 */ /* @@ -638,7 +663,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self) } return MRB_METHOD_CFUNC(m)(mrb, self); } - return mrb_exec_irep(mrb, self, MRB_METHOD_PROC(m), NULL); + return mrb_exec_irep_vm(mrb, self, MRB_METHOD_PROC(m), NULL); } static mrb_value @@ -826,7 +851,7 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const mrb->c->ci->stack[1] = mrb_ary_new_from_values(mrb, argc, argv); mrb->c->ci->stack[2] = mrb_nil_value(); ci->argc = -1; - return mrb_exec_irep(mrb, self, p, NULL); + return mrb_exec_irep_vm(mrb, self, p, NULL); } static struct RBreak* |
