summaryrefslogtreecommitdiffhomepage
path: root/src/vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm.c')
-rw-r--r--src/vm.c97
1 files changed, 57 insertions, 40 deletions
diff --git a/src/vm.c b/src/vm.c
index d47b4c7fc..91c617a83 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -356,7 +356,6 @@ ecall(mrb_state *mrb)
ci->acc = CI_ACC_SKIP;
ci->argc = 0;
ci->proc = p;
- ci->nregs = p->body.irep->nregs;
ci->target_class = MRB_PROC_TARGET_CLASS(p);
env = MRB_PROC_ENV(p);
mrb_assert(env);
@@ -396,6 +395,30 @@ mrb_funcall(mrb_state *mrb, mrb_value self, const char *name, mrb_int argc, ...)
return mrb_funcall_argv(mrb, self, mid, argc, argv);
}
+static int
+ci_nregs(mrb_callinfo *ci)
+{
+ struct RProc *p;
+ int n = 0;
+
+ if (!ci) return 3;
+ p = ci->proc;
+ if (!p) {
+ if (ci->argc < 0) return 3;
+ return ci->argc+2;
+ }
+ if (!MRB_PROC_CFUNC_P(p) && p->body.irep) {
+ n = p->body.irep->nregs;
+ }
+ if (ci->argc < 0) {
+ if (n < 3) n = 3; /* self + args + blk */
+ }
+ if (ci->argc > n) {
+ n = ci->argc + 2; /* self + blk */
+ }
+ return n;
+}
+
MRB_API mrb_value
mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, const mrb_value *argv, mrb_value blk)
{
@@ -426,13 +449,12 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
mrb_method_t m;
struct RClass *c;
mrb_callinfo *ci;
- int n;
+ int n = ci_nregs(mrb->c->ci);
ptrdiff_t voff = -1;
if (!mrb->c->stack) {
stack_init(mrb);
}
- n = mrb->c->ci->nregs;
if (argc < 0) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative argc for funcall (%S)", mrb_fixnum_value(argc));
}
@@ -463,22 +485,22 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
voff = argv - mrb->c->stbase;
}
if (MRB_METHOD_CFUNC_P(m)) {
- ci->nregs = (int)(argc + 2);
- mrb_stack_extend(mrb, ci->nregs);
+ mrb_stack_extend(mrb, argc + 2);
}
else if (argc >= CALL_MAXARGS) {
mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
- mrb_stack_extend(mrb, ci->nregs+2);
+
+ mrb_stack_extend(mrb, 3);
mrb->c->stack[1] = args;
ci->argc = -1;
argc = 1;
}
else {
struct RProc *p = MRB_METHOD_PROC(m);
+
ci->proc = p;
if (argc < 0) argc = 1;
- ci->nregs = (int)(p->body.irep->nregs + argc);
- mrb_stack_extend(mrb, ci->nregs);
+ mrb_stack_extend(mrb, p->body.irep->nregs + argc);
}
if (voff >= 0) {
argv = mrb->c->stbase + voff;
@@ -520,26 +542,25 @@ mrb_value
mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
{
mrb_callinfo *ci = mrb->c->ci;
- int keep;
+ int keep, nregs;
mrb->c->stack[0] = self;
ci->proc = p;
if (MRB_PROC_CFUNC_P(p)) {
return MRB_PROC_CFUNC(p)(mrb, self);
}
- ci->nregs = p->body.irep->nregs;
+ nregs = p->body.irep->nregs;
if (ci->argc < 0) keep = 3;
else keep = ci->argc + 2;
- if (ci->nregs < keep) {
+ if (nregs < keep) {
mrb_stack_extend(mrb, keep);
}
else {
- mrb_stack_extend(mrb, ci->nregs);
- stack_clear(mrb->c->stack+keep, ci->nregs-keep);
+ mrb_stack_extend(mrb, nregs);
+ stack_clear(mrb->c->stack+keep, nregs-keep);
}
ci = cipush(mrb);
- ci->nregs = 0;
ci->target_class = 0;
ci->pc = p->body.irep->iseq;
ci->stackent = mrb->c->stack;
@@ -618,6 +639,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
{
struct RProc *p;
mrb_callinfo *ci;
+ int nregs;
if (mrb_nil_p(blk)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
@@ -639,13 +661,12 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c)
mrb->c->stack[2] = mrb_nil_value();
return MRB_PROC_CFUNC(p)(mrb, self);
}
- ci->nregs = p->body.irep->nregs;
- mrb_stack_extend(mrb, (ci->nregs < 3) ? 3 : ci->nregs);
+ nregs = p->body.irep->nregs;
+ mrb_stack_extend(mrb, (nregs < 3) ? 3 : nregs);
mrb->c->stack[0] = self;
mrb->c->stack[1] = self;
mrb->c->stack[2] = mrb_nil_value();
ci = cipush(mrb);
- ci->nregs = 0;
ci->target_class = 0;
ci->pc = p->body.irep->iseq;
ci->stackent = mrb->c->stack;
@@ -728,13 +749,15 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value
struct RProc *p;
mrb_sym mid = mrb->c->ci->mid;
mrb_callinfo *ci;
- int n = mrb->c->ci->nregs;
mrb_value val;
+ int n;
if (mrb_nil_p(b)) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
}
- if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
+ ci = mrb->c->ci;
+ n = ci_nregs(ci);
+ if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) {
mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err));
}
p = mrb_proc_ptr(b);
@@ -745,9 +768,9 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value
ci->argc = (int)argc;
ci->target_class = c;
ci->acc = CI_ACC_SKIP;
+ n = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs;
mrb->c->stack = mrb->c->stack + n;
- ci->nregs = MRB_PROC_CFUNC_P(p) ? (int)(argc+2) : p->body.irep->nregs;
- mrb_stack_extend(mrb, ci->nregs);
+ mrb_stack_extend(mrb, n);
mrb->c->stack[0] = self;
if (argc > 0) {
@@ -1008,7 +1031,6 @@ RETRY_TRY_BLOCK:
}
mrb->jmp = &c_jmp;
mrb->c->ci->proc = proc;
- mrb->c->ci->nregs = irep->nregs;
#define regs (mrb->c->stack)
INIT_DISPATCH {
@@ -1296,6 +1318,8 @@ RETRY_TRY_BLOCK:
if (a > (int)mrb->c->eidx - epos)
a = mrb->c->eidx - epos;
for (n=0; n<a; n++) {
+ int nregs = irep->nregs;
+
proc = mrb->c->ensure[epos+n];
mrb->c->ensure[epos+n] = NULL;
if (proc == NULL) continue;
@@ -1305,12 +1329,11 @@ RETRY_TRY_BLOCK:
ci->argc = 0;
ci->proc = proc;
ci->stackent = mrb->c->stack;
- ci->nregs = irep->nregs;
ci->target_class = target_class;
ci->pc = pc;
- ci->acc = ci[-1].nregs;
+ ci->acc = nregs;
mrb->c->stack += ci->acc;
- mrb_stack_extend(mrb, ci->nregs);
+ mrb_stack_extend(mrb, irep->nregs);
regs[0] = self;
pc = irep->iseq;
}
@@ -1350,7 +1373,7 @@ RETRY_TRY_BLOCK:
mrb_value recv, blk;
mrb_sym mid = syms[b];
- mrb_assert(bidx < ci->nregs);
+ mrb_assert(bidx < irep->nregs);
recv = regs[a];
blk = regs[bidx];
@@ -1396,7 +1419,6 @@ RETRY_TRY_BLOCK:
mrb->c->stack += a;
if (MRB_METHOD_CFUNC_P(m)) {
- ci->nregs = (argc < 0) ? 3 : c+2;
if (MRB_METHOD_PROC_P(m)) {
struct RProc *p = MRB_METHOD_PROC(m);
@@ -1442,8 +1464,7 @@ RETRY_TRY_BLOCK:
irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
- ci->nregs = irep->nregs;
- mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs);
+ mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs);
pc = irep->iseq;
JUMP;
}
@@ -1498,8 +1519,7 @@ RETRY_TRY_BLOCK:
}
pool = irep->pool;
syms = irep->syms;
- ci->nregs = irep->nregs;
- mrb_stack_extend(mrb, ci->nregs);
+ mrb_stack_extend(mrb, irep->nregs);
if (ci->argc < 0) {
if (irep->nregs > 3) {
stack_clear(regs+3, irep->nregs-3);
@@ -1526,7 +1546,7 @@ RETRY_TRY_BLOCK:
mrb_sym mid = ci->mid;
struct RClass* target_class = MRB_PROC_TARGET_CLASS(ci->proc);
- mrb_assert(bidx < ci->nregs);
+ mrb_assert(bidx < irep->nregs);
if (mid == 0 || !target_class) {
mrb_value exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method");
@@ -1572,7 +1592,7 @@ RETRY_TRY_BLOCK:
}
mid = missing;
if (argc >= 0) {
- if (a+2 >= ci->nregs) {
+ if (a+2 >= irep->nregs) {
mrb_stack_extend(mrb, a+3);
}
regs[a+1] = mrb_ary_new_from_values(mrb, b, regs+a+1);
@@ -1596,7 +1616,7 @@ RETRY_TRY_BLOCK:
if (MRB_METHOD_CFUNC_P(m)) {
mrb_value v;
- ci->nregs = (argc < 0) ? 3 : b+2;
+
if (MRB_METHOD_PROC_P(m)) {
ci->proc = MRB_METHOD_PROC(m);
}
@@ -1633,8 +1653,7 @@ RETRY_TRY_BLOCK:
irep = proc->body.irep;
pool = irep->pool;
syms = irep->syms;
- ci->nregs = irep->nregs;
- mrb_stack_extend(mrb, (argc < 0 && ci->nregs < 3) ? 3 : ci->nregs);
+ mrb_stack_extend(mrb, (argc < 0 && irep->nregs < 3) ? 3 : irep->nregs);
pc = irep->iseq;
JUMP;
}
@@ -2795,9 +2814,8 @@ RETRY_TRY_BLOCK:
irep = p->body.irep;
pool = irep->pool;
syms = irep->syms;
- ci->nregs = irep->nregs;
- mrb_stack_extend(mrb, ci->nregs);
- stack_clear(regs+1, ci->nregs-1);
+ mrb_stack_extend(mrb, irep->nregs);
+ stack_clear(regs+1, irep->nregs-1);
pc = irep->iseq;
JUMP;
}
@@ -2946,7 +2964,6 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta
}
ci = cipush(mrb);
ci->mid = 0;
- ci->nregs = 1; /* protect the receiver */
ci->acc = CI_ACC_SKIP;
ci->target_class = mrb->object_class;
v = mrb_vm_run(mrb, proc, self, stack_keep);