diff options
| author | YAMAMOTO Masaya <[email protected]> | 2017-11-04 01:23:12 +0900 |
|---|---|---|
| committer | YAMAMOTO Masaya <[email protected]> | 2017-11-04 01:23:12 +0900 |
| commit | 625f9f6fa314872968632c5adbee7fb3823268b8 (patch) | |
| tree | fdde1700b13048212606e4a995907f3757e18e2f /src/vm.c | |
| parent | b70d69de09130ce2bc89289b4826b3deea8afaae (diff) | |
| parent | e7fe6ee2638dee438c1d79ab16a0403aebec0a60 (diff) | |
| download | mruby-625f9f6fa314872968632c5adbee7fb3823268b8.tar.gz mruby-625f9f6fa314872968632c5adbee7fb3823268b8.zip | |
Merge branch 'master' of github.com:mruby/mruby
Diffstat (limited to 'src/vm.c')
| -rw-r--r-- | src/vm.c | 320 |
1 files changed, 139 insertions, 181 deletions
@@ -211,38 +211,38 @@ stack_extend(mrb_state *mrb, int room) static inline struct REnv* uvenv(mrb_state *mrb, int up) { - struct REnv *e = mrb->c->ci->proc->env; + struct RProc *proc = mrb->c->ci->proc; + struct REnv *e; while (up--) { - if (!e) return NULL; - e = (struct REnv*)e->c; + proc = proc->upper; + if (!proc) return NULL; } - return e; -} - -static inline mrb_bool -is_strict(mrb_state *mrb, struct REnv *e) -{ - ptrdiff_t cioff = e->cioff; + e = MRB_PROC_ENV(proc); + if (e) return e; /* proc has enclosed env */ + else { + mrb_callinfo *ci = mrb->c->ci; + mrb_callinfo *cb = mrb->c->cibase; - if (MRB_ENV_STACK_SHARED_P(e) && e->cxt.c->cibase[cioff].proc && - MRB_PROC_STRICT_P(e->cxt.c->cibase[cioff].proc)) { - return TRUE; + while (cb <= ci) { + if (ci->proc == proc) { + return ci->env; + } + ci--; + } } - return FALSE; + return NULL; } -static inline struct REnv* -top_env(mrb_state *mrb, struct RProc *proc) +static inline struct RProc* +top_proc(mrb_state *mrb, struct RProc *proc) { - struct REnv *e = proc->env; - - if (is_strict(mrb, e)) return e; - while (e->c) { - e = (struct REnv*)e->c; - if (is_strict(mrb, e)) return e; + while (proc->upper) { + if (MRB_PROC_SCOPE_P(proc) || MRB_PROC_STRICT_P(proc)) + return proc; + proc = proc->upper; } - return e; + return proc; } #define CI_ACC_SKIP -1 @@ -273,25 +273,17 @@ cipush(mrb_state *mrb) return ci; } -MRB_API void +void mrb_env_unshare(mrb_state *mrb, struct REnv *e) { if (e == NULL) return; else { size_t len = (size_t)MRB_ENV_STACK_LEN(e); - ptrdiff_t cioff = e->cioff; mrb_value *p; if (!MRB_ENV_STACK_SHARED_P(e)) return; - if (e->cxt.c != mrb->c) return; - if (e->cioff == 0 && e->cxt.c == mrb->root_c) return; + if (e->cxt != mrb->c) return; MRB_ENV_UNSHARE_STACK(e); - if (!e->c) { - /* save block argument position (negated) */ - e->cioff = -e->cxt.c->cibase[cioff].argc-1; - if (e->cioff == 0) e->cioff = -2; /* blkarg position for vararg (1:args, 2:blk) */ - } - e->cxt.mid = e->cxt.c->cibase[cioff].mid; p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len); if (len > 0) { stack_copy(p, e->stack, len); @@ -317,20 +309,22 @@ static void ecall(mrb_state *mrb, int i) { struct RProc *p; - mrb_callinfo *ci = mrb->c->ci; - mrb_value *self = mrb->c->stack; + struct mrb_context *c = mrb->c; + mrb_callinfo *ci = c->ci; struct RObject *exc; + struct REnv *env; ptrdiff_t cioff; int ai = mrb_gc_arena_save(mrb); if (i<0) return; - if (ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { + if (ci - c->cibase > MRB_FUNCALL_DEPTH_MAX) { mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } - p = mrb->c->ensure[i]; + p = c->ensure[i]; if (!p) return; - mrb->c->ensure[i] = NULL; - cioff = ci - mrb->c->cibase; + mrb_assert(!MRB_PROC_CFUNC_P(p)); + c->ensure[i] = NULL; + cioff = ci - c->cibase; ci = cipush(mrb); ci->stackent = mrb->c->stack; ci->mid = ci[-1].mid; @@ -338,14 +332,17 @@ ecall(mrb_state *mrb, int i) ci->argc = 0; ci->proc = p; ci->nregs = p->body.irep->nregs; - ci->target_class = p->target_class; - mrb->c->stack = mrb->c->stack + ci[-1].nregs; + ci->target_class = MRB_PROC_TARGET_CLASS(p); + env = MRB_PROC_ENV(p); + mrb_assert(env); + c->stack += p->body.irep->nregs; exc = mrb->exc; mrb->exc = 0; if (exc) { mrb_gc_protect(mrb, mrb_obj_value(exc)); } - mrb_run(mrb, p, *self); - mrb->c->ci = mrb->c->cibase + cioff; + mrb_run(mrb, p, env->stack[0]); + mrb->c = c; + c->ci = c->cibase + cioff; if (!mrb->exc) mrb->exc = exc; mrb_gc_arena_restore(mrb, ai); } @@ -497,7 +494,7 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) mrb->c->stack[0] = self; ci->proc = p; - ci->target_class = p->target_class; + ci->target_class = MRB_PROC_TARGET_CLASS(p); if (MRB_PROC_CFUNC_P(p)) { return p->body.func(mrb, self); } @@ -734,7 +731,7 @@ mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv) { struct RProc *p = mrb_proc_ptr(b); - return mrb_yield_with_class(mrb, b, argc, argv, p->env->stack[0], p->target_class); + return mrb_yield_with_class(mrb, b, argc, argv, MRB_PROC_ENV(p)->stack[0], MRB_PROC_TARGET_CLASS(p)); } MRB_API mrb_value @@ -742,7 +739,7 @@ mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg) { struct RProc *p = mrb_proc_ptr(b); - return mrb_yield_with_class(mrb, b, 1, &arg, p->env->stack[0], p->target_class); + return mrb_yield_with_class(mrb, b, 1, &arg, MRB_PROC_ENV(p)->stack[0], MRB_PROC_TARGET_CLASS(p)); } mrb_value @@ -772,23 +769,23 @@ mrb_value mrb_mod_s_nesting(mrb_state *mrb, mrb_value mod) { struct RProc *proc; - mrb_irep *irep; mrb_value ary; - struct RClass *c; + struct RClass *c = NULL; mrb_get_args(mrb, ""); ary = mrb_ary_new(mrb); proc = mrb->c->ci[-1].proc; /* callee proc */ - c = proc->target_class; - mrb_ary_push(mrb, ary, mrb_obj_value(c)); mrb_assert(!MRB_PROC_CFUNC_P(proc)); - irep = proc->body.irep; - while (irep) { - if (irep->target_class && irep->target_class != c) { - c = irep->target_class; - mrb_ary_push(mrb, ary, mrb_obj_value(c)); + while (proc) { + if (MRB_PROC_SCOPE_P(proc)) { + struct RClass *c2 = MRB_PROC_TARGET_CLASS(proc); + + if (c2 != c) { + c = c2; + mrb_ary_push(mrb, ary, mrb_obj_value(c)); + } } - irep = irep->outer; + proc = proc->upper; } return ary; } @@ -854,18 +851,6 @@ argnum_error(mrb_state *mrb, mrb_int num) mrb_exc_set(mrb, exc); } -void -irep_uplink(mrb_state *mrb, mrb_irep *outer, mrb_irep *irep) -{ - if (irep->outer != outer) { - if (irep->outer) { - mrb_irep_decref(mrb, irep->outer); - } - irep->outer = outer; - mrb_irep_incref(mrb, outer); - } -} - #define ERR_PC_SET(mrb, pc) mrb->c->ci->err = pc; #define ERR_PC_CLR(mrb) mrb->c->ci->err = 0; #ifdef MRB_ENABLE_DEBUG_HOOK @@ -1323,9 +1308,10 @@ RETRY_TRY_BLOCK: CASE(OP_EPOP) { /* A A.times{ensure_pop().call} */ int a = GETARG_A(i); - int n, epos = mrb->c->ci->epos; - mrb_callinfo *ci; + mrb_callinfo *ci = mrb->c->ci; + int n, epos = ci->epos; mrb_value self = regs[0]; + struct RClass *target_class = ci->target_class; if (mrb->c->eidx == epos) { NEXT; @@ -1343,7 +1329,7 @@ RETRY_TRY_BLOCK: ci->proc = proc; ci->stackent = mrb->c->stack; ci->nregs = irep->nregs; - ci->target_class = proc->target_class; + ci->target_class = target_class; ci->pc = pc; ci->acc = ci[-1].nregs; mrb->c->stack += ci->acc; @@ -1445,7 +1431,7 @@ RETRY_TRY_BLOCK: if (GET_OPCODE(i) == OP_SENDB) { if (mrb_type(blk) == MRB_TT_PROC) { struct RProc *p = mrb_proc_ptr(blk); - if (p && !MRB_PROC_STRICT_P(p) && p->env == ci[-1].env) { + if (p && !MRB_PROC_STRICT_P(p) && MRB_PROC_ENV(p) == ci[-1].env) { p->flags |= MRB_PROC_ORPHAN; } } @@ -1497,20 +1483,16 @@ RETRY_TRY_BLOCK: /* replace callinfo */ ci = mrb->c->ci; - ci->target_class = m->target_class; + ci->target_class = MRB_PROC_TARGET_CLASS(m); ci->proc = m; - if (m->env) { + if (MRB_PROC_ENV_P(m)) { mrb_sym mid; + struct REnv *e = MRB_PROC_ENV(m); - if (MRB_ENV_STACK_SHARED_P(m->env)) { - mid = m->env->cxt.c->cibase[m->env->cioff].mid; - } - else { - mid = m->env->cxt.mid; - } + mid = e->mid; if (mid) ci->mid = mid; - if (!m->env->stack) { - m->env->stack = mrb->c->stack; + if (!e->stack) { + e->stack = mrb->c->stack; } } @@ -1551,8 +1533,8 @@ RETRY_TRY_BLOCK: else if (ci->argc+2 < irep->nregs) { stack_clear(regs+ci->argc+2, irep->nregs-ci->argc-2); } - if (m->env) { - regs[0] = m->env->stack[0]; + if (MRB_PROC_ENV_P(m)) { + regs[0] = MRB_PROC_ENV(m)->stack[0]; } pc = irep->iseq; JUMP; @@ -1837,6 +1819,12 @@ RETRY_TRY_BLOCK: /* A B return R(A) (B=normal,in-block return/break) */ mrb_callinfo *ci; +#define ecall_adjust() do {\ + ptrdiff_t cioff = ci - mrb->c->cibase;\ + ecall(mrb, --mrb->c->eidx);\ + ci = mrb->c->cibase + cioff;\ +} while (0) + ci = mrb->c->ci; if (ci->mid) { mrb_value blk; @@ -1851,7 +1839,7 @@ RETRY_TRY_BLOCK: struct RProc *p = mrb_proc_ptr(blk); if (!MRB_PROC_STRICT_P(p) && - ci > mrb->c->cibase && p->env == ci[-1].env) { + ci > mrb->c->cibase && MRB_PROC_ENV(p) == ci[-1].env) { p->flags |= MRB_PROC_ORPHAN; } } @@ -1901,8 +1889,7 @@ RETRY_TRY_BLOCK: if (ci[0].ridx == ci[-1].ridx) { mrb_value *org_stbase = mrb->c->stbase; while (mrb->c->eidx > ci->epos) { - ecall(mrb, --mrb->c->eidx); - ci = mrb->c->ci; + ecall_adjust(); if (org_stbase != mrb->c->stbase) { stk = mrb->c->stack; } @@ -1915,7 +1902,7 @@ RETRY_TRY_BLOCK: irep = proc->body.irep; pool = irep->pool; syms = irep->syms; - if (ci != ci0) { + if (ci < ci0) { mrb->c->stack = ci[1].stackent; } stack_extend(mrb, irep->nregs); @@ -1924,37 +1911,37 @@ RETRY_TRY_BLOCK: else { int acc; mrb_value v; + struct RProc *dst; + ci = mrb->c->ci; v = regs[GETARG_A(i)]; mrb_gc_protect(mrb, v); switch (GETARG_B(i)) { case OP_R_RETURN: /* Fall through to OP_R_NORMAL otherwise */ - if (ci->acc >=0 && proc->env && !MRB_PROC_STRICT_P(proc)) { - struct REnv *e = top_env(mrb, proc); - mrb_callinfo *ce; + if (ci->acc >=0 && MRB_PROC_ENV_P(proc) && !MRB_PROC_STRICT_P(proc)) { + mrb_callinfo *cibase = mrb->c->cibase; + dst = top_proc(mrb, proc); - if (!MRB_ENV_STACK_SHARED_P(e) || e->cxt.c != mrb->c) { - localjump_error(mrb, LOCALJUMP_ERROR_RETURN); - goto L_RAISE; + if (MRB_PROC_ENV_P(dst)) { + struct REnv *e = MRB_PROC_ENV(dst); + + if (!MRB_ENV_STACK_SHARED_P(e) || e->cxt != mrb->c) { + localjump_error(mrb, LOCALJUMP_ERROR_RETURN); + goto L_RAISE; + } } - - ce = mrb->c->cibase + e->cioff; - while (ci > ce) { - mrb_env_unshare(mrb, ci->env); + while (cibase <= ci && ci->proc != dst) { if (ci->acc < 0) { localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; } ci--; } - mrb_env_unshare(mrb, ci->env); - if (ce == mrb->c->cibase) { + if (ci <= cibase) { localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; } - mrb->c->stack = mrb->c->ci->stackent; - mrb->c->ci = ce; break; } case OP_R_NORMAL: @@ -1970,14 +1957,14 @@ RETRY_TRY_BLOCK: goto L_RAISE; } while (mrb->c->eidx > 0) { - ecall(mrb, --mrb->c->eidx); + ecall_adjust(); } /* automatic yield at the end */ mrb->c->status = MRB_FIBER_TERMINATED; mrb->c = mrb->c->prev; mrb->c->status = MRB_FIBER_RUNNING; + ci = mrb->c->ci; } - ci = mrb->c->ci; break; case OP_R_BREAK: if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN; @@ -1990,23 +1977,23 @@ RETRY_TRY_BLOCK: mrb_exc_set(mrb, exc); goto L_RAISE; } - if (!proc->env || !MRB_ENV_STACK_SHARED_P(proc->env)) { + if (!MRB_PROC_ENV_P(proc) || !MRB_ENV_STACK_SHARED_P(MRB_PROC_ENV(proc))) { goto L_BREAK_ERROR; } - if (proc->env->cxt.c != mrb->c) { + if (MRB_PROC_ENV(proc)->cxt != mrb->c) { goto L_BREAK_ERROR; } while (mrb->c->eidx > mrb->c->ci->epos) { - ecall(mrb, --mrb->c->eidx); + ecall_adjust(); } /* break from fiber block */ - if (mrb->c->ci == mrb->c->cibase && mrb->c->ci->pc) { + if (ci == mrb->c->cibase && ci->pc) { struct mrb_context *c = mrb->c; mrb->c = c->prev; c->prev = NULL; + ci = mrb->c->ci; } - ci = mrb->c->ci; if (ci->acc < 0) { mrb_gc_arena_restore(mrb, ai); mrb->c->vmexec = FALSE; @@ -2022,31 +2009,32 @@ RETRY_TRY_BLOCK: ci = mrb->c->ci; } mrb->c->stack = ci->stackent; - mrb->c->ci = mrb->c->cibase + proc->env->cioff + 1; - while (ci > mrb->c->ci) { - mrb_env_unshare(mrb, ci->env); + proc = proc->upper; + while (mrb->c->cibase < ci && ci[-1].proc != proc) { if (ci[-1].acc == CI_ACC_SKIP) { mrb->c->ci = ci; goto L_BREAK_ERROR; } ci--; } - mrb_env_unshare(mrb, ci->env); break; default: /* cannot happen */ break; } - while (mrb->c->eidx > mrb->c->ci->epos) { - ecall(mrb, --mrb->c->eidx); + while (mrb->c->eidx > ci->epos) { + ecall_adjust(); } - if (mrb->c->vmexec && !mrb->c->ci->target_class) { + if (mrb->c->vmexec && !ci->target_class) { mrb_gc_arena_restore(mrb, ai); mrb->c->vmexec = FALSE; mrb->jmp = prev_jmp; return v; } - ci = mrb->c->ci; + while (ci < mrb->c->ci) { + mrb_env_unshare(mrb, mrb->c->ci->env); + mrb->c->ci--; + } acc = ci->acc; mrb->c->stack = ci->stackent; cipop(mrb); @@ -2056,6 +2044,7 @@ RETRY_TRY_BLOCK: return v; } pc = ci->pc; + ci = mrb->c->ci; DEBUG(fprintf(stderr, "from :%s\n", mrb_sym2name(mrb, ci->mid))); proc = mrb->c->ci->proc; irep = proc->body.irep; @@ -2156,8 +2145,7 @@ RETRY_TRY_BLOCK: if (lv == 0) stack = regs + 1; else { struct REnv *e = uvenv(mrb, lv-1); - if (!e || e->cioff == 0 || - (!MRB_ENV_STACK_SHARED_P(e) && e->cxt.mid == 0) || + if (!e || (!MRB_ENV_STACK_SHARED_P(e) && e->mid == 0) || MRB_ENV_STACK_LEN(e) <= m1+r+m2+1) { localjump_error(mrb, LOCALJUMP_ERROR_YIELD); goto L_RAISE; @@ -2359,75 +2347,51 @@ RETRY_TRY_BLOCK: CASE(OP_DIV) { /* A B C R(A) := R(A)/R(A+1) (Syms[B]=:/,C=1)*/ int a = GETARG_A(i); +#ifndef MRB_WITHOUT_FLOAT + double x, y, f; +#endif /* need to check if op is overridden */ switch (TYPES2(mrb_type(regs[a]),mrb_type(regs[a+1]))) { case TYPES2(MRB_TT_FIXNUM,MRB_TT_FIXNUM): +#ifdef MRB_WITHOUT_FLOAT { mrb_int x = mrb_fixnum(regs[a]); mrb_int y = mrb_fixnum(regs[a+1]); -#ifdef MRB_WITHOUT_FLOAT SET_INT_VALUE(regs[a], y ? x / y : 0); -#else - double f; - if (y == 0) { - if (x > 0) f = INFINITY; - else if (x < 0) f = -INFINITY; - else /* if (x == 0) */ f = NAN; - } - else { - f = (mrb_float)x / (mrb_float)y; - } - SET_FLOAT_VALUE(mrb, regs[a], f); -#endif } break; -#ifndef MRB_WITHOUT_FLOAT +#else + x = (mrb_float)mrb_fixnum(regs[a]); + y = (mrb_float)mrb_fixnum(regs[a+1]); + break; case TYPES2(MRB_TT_FIXNUM,MRB_TT_FLOAT): - { - mrb_int x = mrb_fixnum(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], (mrb_float)x / y); - } + x = (mrb_float)mrb_fixnum(regs[a]); + y = mrb_float(regs[a+1]); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FIXNUM): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_int y = mrb_fixnum(regs[a+1]); - double f; - if (y == 0) { - f = INFINITY; - } - else { - f = x / y; - } - SET_FLOAT_VALUE(mrb, regs[a], f); - } -#else - OP_MATH_BODY(/,mrb_float,mrb_fixnum); -#endif + x = mrb_float(regs[a]); + y = (mrb_float)mrb_fixnum(regs[a+1]); break; case TYPES2(MRB_TT_FLOAT,MRB_TT_FLOAT): -#ifdef MRB_WORD_BOXING - { - mrb_float x = mrb_float(regs[a]); - mrb_float y = mrb_float(regs[a+1]); - SET_FLOAT_VALUE(mrb, regs[a], x / y); - } -#else - OP_MATH_BODY(/,mrb_float,mrb_float); -#endif + x = mrb_float(regs[a]); + y = mrb_float(regs[a+1]); break; #endif default: goto L_SEND; } -#ifdef MRB_NAN_BOXING - if (isnan(mrb_float(regs[a]))) { - mrb_value v = mrb_float_value(mrb, mrb_float(regs[a])); - regs[a] = v; + +#ifndef MRB_WITHOUT_FLOAT + if (y == 0) { + if (x > 0) f = INFINITY; + else if (x < 0) f = -INFINITY; + else /* if (x == 0) */ f = NAN; } + else { + f = x / y; + } + SET_FLOAT_VALUE(mrb, regs[a], f); #endif NEXT; } @@ -2738,7 +2702,6 @@ RETRY_TRY_BLOCK: int c = GETARG_c(i); mrb_irep *nirep = irep->reps[b]; - irep_uplink(mrb, irep, nirep); if (c & OP_L_CAPTURE) { p = mrb_closure_new(mrb, nirep); } @@ -2767,9 +2730,7 @@ RETRY_TRY_BLOCK: base = regs[a]; super = regs[a+1]; if (mrb_nil_p(base)) { - baseclass = mrb->c->ci->proc->target_class; - if (!baseclass) baseclass = mrb->c->ci->target_class; - + baseclass = mrb->c->ci->target_class; base = mrb_obj_value(baseclass); } c = mrb_vm_define_class(mrb, base, super, id); @@ -2787,9 +2748,7 @@ RETRY_TRY_BLOCK: base = regs[a]; if (mrb_nil_p(base)) { - baseclass = mrb->c->ci->proc->target_class; - if (!baseclass) baseclass = mrb->c->ci->target_class; - + baseclass = mrb->c->ci->target_class; base = mrb_obj_value(baseclass); } c = mrb_vm_define_module(mrb, base, id); @@ -2807,13 +2766,14 @@ RETRY_TRY_BLOCK: struct RProc *p; mrb_irep *nirep = irep->reps[bx]; - irep_uplink(mrb, irep, nirep); - nirep->target_class = mrb_class_ptr(recv); /* prepare closure */ - p = mrb_closure_new(mrb, nirep); + p = mrb_proc_new(mrb, nirep); p->c = NULL; + mrb_field_write_barrier(mrb, (struct RBasic*)p, (struct RBasic*)proc); + MRB_PROC_SET_TARGET_CLASS(p, mrb_class_ptr(recv)); + p->flags |= MRB_PROC_SCOPE; - /* prepare stack */ + /* prepare call stack */ ci = cipush(mrb); ci->pc = pc + 1; ci->acc = a; @@ -2825,8 +2785,7 @@ RETRY_TRY_BLOCK: /* prepare stack */ mrb->c->stack += a; - /* setup closure */ - p->target_class = ci->target_class; + /* setup block to call */ ci->proc = p; irep = p->body.irep; @@ -2957,7 +2916,6 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta return mrb_vm_run(mrb, proc, self, stack_keep); } if (mrb->c->ci == mrb->c->cibase) { - mrb->c->ci->env = NULL; return mrb_vm_run(mrb, proc, self, stack_keep); } ci = cipush(mrb); |
