Unverified Commit c2c37e14 authored by Yukihiro "Matz" Matsumoto's avatar Yukihiro "Matz" Matsumoto Committed by GitHub

Merge pull request #5401 from dearblue/mcall

Reorganize `mcall()` in `mruby-method`
parents 6d3c0227 4c196dcd
...@@ -131,15 +131,6 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc, mrb_func_t posthoo ...@@ -131,15 +131,6 @@ exec_irep(mrb_state *mrb, mrb_value self, struct RProc *proc, mrb_func_t posthoo
{ {
/* no argument passed from eval() */ /* no argument passed from eval() */
mrb->c->ci->argc = 0; 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 */ /* clear block */
mrb->c->ci->stack[1] = mrb_nil_value(); mrb->c->ci->stack[1] = mrb_nil_value();
return mrb_exec_irep(mrb, self, proc, posthook); return mrb_exec_irep(mrb, self, proc, posthook);
......
...@@ -6,12 +6,126 @@ ...@@ -6,12 +6,126 @@
#include "mruby/string.h" #include "mruby/string.h"
#include "mruby/presym.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 * static struct RObject *
method_object_alloc(mrb_state *mrb, struct RClass *mclass) method_object_alloc(mrb_state *mrb, struct RClass *mclass)
{ {
return (struct RObject*)mrb_obj_alloc(mrb, MRB_TT_OBJECT, 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 static void
bind_check(mrb_state *mrb, mrb_value recv, mrb_value owner) bind_check(mrb_state *mrb, mrb_value recv, mrb_value owner)
{ {
...@@ -109,61 +223,40 @@ method_eql(mrb_state *mrb, mrb_value self) ...@@ -109,61 +223,40 @@ method_eql(mrb_state *mrb, mrb_value self)
#undef IV_GET #undef IV_GET
static mrb_value static mrb_value
mcall(mrb_state *mrb, mrb_value recv, mrb_value proc, mrb_value name, struct RClass *owner, mcall(mrb_state *mrb, mrb_value self, mrb_value recv)
mrb_int argc, const mrb_value *argv, mrb_value block)
{ {
mrb_value ret; struct RProc *proc = method_extract_proc(mrb, self);
mrb_sym orig_mid = mrb->c->ci->mid; 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_undef_p(recv)) {
if (mrb_nil_p(proc)) { recv = method_extract_receiver(mrb, self);
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);
} }
else { 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 static mrb_value
method_call(mrb_state *mrb, mrb_value self) method_call(mrb_state *mrb, mrb_value self)
{ {
mrb_value proc = mrb_iv_get(mrb, self, MRB_SYM(_proc)); return mcall(mrb, self, mrb_undef_value());
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);
} }
static mrb_value static mrb_value
method_bcall(mrb_state *mrb, mrb_value self) method_bcall(mrb_state *mrb, mrb_value self)
{ {
mrb_value proc = mrb_iv_get(mrb, self, MRB_SYM(_proc)); mrb_value recv = args_shift(mrb);
mrb_value name = mrb_iv_get(mrb, self, MRB_SYM(_name)); mrb_gc_protect(mrb, recv);
mrb_value recv = mrb_iv_get(mrb, self, MRB_SYM(_recv)); return mcall(mrb, self, 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);
} }
static mrb_value static mrb_value
......
...@@ -543,8 +543,8 @@ mrb_exec_irep_prepare_posthook(mrb_state *mrb, mrb_callinfo *ci, int nregs, mrb_ ...@@ -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. * However, if `proc` is a C function, it will be ignored.
*/ */
mrb_value static mrb_value
mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook) mrb_exec_irep_vm(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t posthook)
{ {
mrb_callinfo *ci = mrb->c->ci; mrb_callinfo *ci = mrb->c->ci;
int keep, nregs; int keep, nregs;
...@@ -575,6 +575,31 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t postho ...@@ -575,6 +575,31 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p, mrb_func_t postho
return self; 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.4 */
/* 15.3.1.3.44 */ /* 15.3.1.3.44 */
/* /*
...@@ -638,7 +663,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self) ...@@ -638,7 +663,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self)
} }
return MRB_METHOD_CFUNC(m)(mrb, 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 static mrb_value
...@@ -826,7 +851,7 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const ...@@ -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[1] = mrb_ary_new_from_values(mrb, argc, argv);
mrb->c->ci->stack[2] = mrb_nil_value(); mrb->c->ci->stack[2] = mrb_nil_value();
ci->argc = -1; ci->argc = -1;
return mrb_exec_irep(mrb, self, p, NULL); return mrb_exec_irep_vm(mrb, self, p, NULL);
} }
static struct RBreak* static struct RBreak*
......
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