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
{
/* 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);
......
......@@ -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*
......
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