Example #1
0
        public static int luaD_precall(LuaState L, StkId func, int nresults)
        {
            LClosure  cl;
            ptrdiff_t funcr;

            if (!ttisfunction(func))       /* `func' is not a function? */
            {
                func = tryfuncTM(L, func); /* check the `function' tag method */
            }
            funcr        = savestack(L, func);
            cl           = clvalue(func).l;
            L.ci.savedpc = InstructionPtr.Assign(L.savedpc);
            if (cl.isC == 0)
            {  /* Lua function? prepare its call */
                CallInfo ci;
                StkId    st, base_;
                Proto    p = cl.p;
                luaD_checkstack(L, p.maxstacksize);
                func = restorestack(L, funcr);
                if (p.is_vararg == 0)
                {  /* no varargs? */
                    base_ = L.stack[func + 1];
                    if (L.top > base_ + p.numparams)
                    {
                        L.top = base_ + p.numparams;
                    }
                }
                else
                {  /* vararg function */
                    int nargs = L.top - func - 1;
                    base_ = adjust_varargs(L, p, nargs);
                    func  = restorestack(L, funcr); /* previous call may change the stack */
                }
                ci      = inc_ci(L);                /* now `enter' new function */
                ci.func = func;
                L.base_ = ci.base_ = base_;
                ci.top  = L.base_ + p.maxstacksize;
                lua_assert(ci.top <= L.stack_last);
                L.savedpc    = new InstructionPtr(p.code, 0); /* starting point */
                ci.tailcalls = 0;
                ci.nresults  = nresults;
                for (st = L.top; st < ci.top; StkId.inc(ref st))
                {
                    setnilvalue(st);
                }
                L.top = ci.top;
                if ((L.hookmask & LUA_MASKCALL) != 0)
                {
                    InstructionPtr.inc(ref L._savedpc);  /* hooks assume 'pc' is already incremented */
                    luaD_callhook(L, LUA_HOOKCALL, -1);
                    InstructionPtr.dec(ref L._savedpc);  /* correct 'pc' */
                }
                return(PCRLUA);
            }
            else
            {  /* if is a C function, call it */
                CallInfo ci;
                int      n;
                luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
                ci      = inc_ci(L);              /* now `enter' new function */
                ci.func = restorestack(L, funcr);
                L.base_ = ci.base_ = ci.func + 1;
                ci.top  = L.top + LUA_MINSTACK;
                lua_assert(ci.top <= L.stack_last);
                ci.nresults = nresults;
                if ((L.hookmask & LUA_MASKCALL) != 0)
                {
                    luaD_callhook(L, LUA_HOOKCALL, -1);
                }
                lua_unlock(L);
                n = curr_func(L).c.f(L); /* do the actual call */
                lua_lock(L);
                if (n < 0)               /* yielding? */
                {
                    return(PCRYIELD);
                }
                else
                {
                    luaD_poscall(L, L.top - n);
                    return(PCRC);
                }
            }
        }
Example #2
0
        public static void luaV_execute(LuaState L, int nexeccalls)
        {
            LClosure cl;
            StkId    base_;

            TValue[] k;
            /*const*/
            InstructionPtr pc;

reentry:    /* entry point */
            lua_assert(isLua(L.ci));
            pc    = InstructionPtr.Assign(L.savedpc);
            cl    = clvalue(L.ci.func).l;
            base_ = L.base_;
            k     = cl.p.k;
            /* main loop of interpreter */
            for (; ;)
            {
                /*const*/
                Instruction i = InstructionPtr.inc(ref pc)[0];
                StkId       ra;
                if (((L.hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) != 0) &&
                    (((--L.hookcount) == 0) || ((L.hookmask & LUA_MASKLINE) != 0)))
                {
                    traceexec(L, pc);
                    if (L.status == LUA_YIELD)
                    {  /* did hook yield? */
                        L.savedpc = new InstructionPtr(pc.codes, pc.pc - 1);
                        return;
                    }
                    base_ = L.base_;
                }
                /* warning!! several calls may realloc the stack and invalidate `ra' */
                ra = RA(L, base_, i);
                lua_assert(base_ == L.base_ && L.base_ == L.ci.base_);
                lua_assert(base_ <= L.top && ((L.top - L.stack) <= L.stacksize));
                lua_assert(L.top == L.ci.top || (luaG_checkopenop(i) != 0));
                //Dump(pc.pc, i);
                switch (GET_OPCODE(i))
                {
                case OpCode.OP_MOVE:
                {
                    setobjs2s(L, ra, RB(L, base_, i));
                    continue;
                }

                case OpCode.OP_LOADK:
                {
                    setobj2s(L, ra, KBx(L, i, k));
                    continue;
                }

                case OpCode.OP_LOADBOOL:
                {
                    setbvalue(ra, GETARG_B(i));
                    if (GETARG_C(i) != 0)
                    {
                        InstructionPtr.inc(ref pc);                            /* skip next instruction (if C) */
                    }
                    continue;
                }

                case OpCode.OP_LOADNIL:
                {
                    TValue rb = RB(L, base_, i);
                    do
                    {
                        setnilvalue(StkId.dec(ref rb));
                    } while (rb >= ra);
                    continue;
                }

                case OpCode.OP_GETUPVAL:
                {
                    int b = GETARG_B(i);
                    setobj2s(L, ra, cl.upvals[b].v);
                    continue;
                }

                case OpCode.OP_GETGLOBAL:
                {
                    TValue g  = new TValue();
                    TValue rb = KBx(L, i, k);
                    sethvalue(L, g, cl.env);
                    lua_assert(ttisstring(rb));
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    luaV_gettable(L, g, rb, ra);
                    base_ = L.base_;
                    //);
                    L.savedpc = InstructionPtr.Assign(pc);
                    continue;
                }

                case OpCode.OP_GETTABLE:
                {
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    luaV_gettable(L, RB(L, base_, i), RKC(L, base_, i, k), ra);
                    base_ = L.base_;
                    //);
                    L.savedpc = InstructionPtr.Assign(pc);
                    continue;
                }

                case OpCode.OP_SETGLOBAL:
                {
                    TValue g = new TValue();
                    sethvalue(L, g, cl.env);
                    lua_assert(ttisstring(KBx(L, i, k)));
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    luaV_settable(L, g, KBx(L, i, k), ra);
                    base_ = L.base_;
                    //);
                    L.savedpc = InstructionPtr.Assign(pc);
                    continue;
                }

                case OpCode.OP_SETUPVAL:
                {
                    UpVal uv = cl.upvals[GETARG_B(i)];
                    setobj(L, uv.v, ra);
                    luaC_barrier(L, uv, ra);
                    continue;
                }

                case OpCode.OP_SETTABLE:
                {
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    luaV_settable(L, ra, RKB(L, base_, i, k), RKC(L, base_, i, k));
                    base_ = L.base_;
                    //);
                    L.savedpc = InstructionPtr.Assign(pc);
                    continue;
                }

                case OpCode.OP_NEWTABLE:
                {
                    int b = GETARG_B(i);
                    int c = GETARG_C(i);
                    sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c)));
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    luaC_checkGC(L);
                    base_ = L.base_;
                    //);
                    L.savedpc = InstructionPtr.Assign(pc);
                    continue;
                }

                case OpCode.OP_SELF:
                {
                    StkId rb = RB(L, base_, i);
                    setobjs2s(L, ra + 1, rb);
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    luaV_gettable(L, rb, RKC(L, base_, i, k), ra);
                    base_ = L.base_;
                    //);
                    L.savedpc = InstructionPtr.Assign(pc);
                    continue;
                }

                case OpCode.OP_ADD:
                {
                    arith_op(L, luai_numadd, TMS.TM_ADD, base_, i, k, ra, pc);
                    continue;
                }

                case OpCode.OP_SUB:
                {
                    arith_op(L, luai_numsub, TMS.TM_SUB, base_, i, k, ra, pc);
                    continue;
                }

                case OpCode.OP_MUL:
                {
                    arith_op(L, luai_nummul, TMS.TM_MUL, base_, i, k, ra, pc);
                    continue;
                }

                case OpCode.OP_DIV:
                {
                    arith_op(L, luai_numdiv, TMS.TM_DIV, base_, i, k, ra, pc);
                    continue;
                }

                case OpCode.OP_MOD:
                {
                    arith_op(L, luai_nummod, TMS.TM_MOD, base_, i, k, ra, pc);
                    continue;
                }

                case OpCode.OP_POW:
                {
                    arith_op(L, luai_numpow, TMS.TM_POW, base_, i, k, ra, pc);
                    continue;
                }

                case OpCode.OP_UNM:
                {
                    TValue rb = RB(L, base_, i);
                    if (ttisnumber(rb))
                    {
                        lua_Number nb = nvalue(rb);
                        setnvalue(ra, luai_numunm(nb));
                    }
                    else
                    {
                        //Protect(
                        L.savedpc = InstructionPtr.Assign(pc);
                        Arith(L, ra, rb, rb, TMS.TM_UNM);
                        base_ = L.base_;
                        //);
                        L.savedpc = InstructionPtr.Assign(pc);
                    }
                    continue;
                }

                case OpCode.OP_NOT:
                {
                    int res = l_isfalse(RB(L, base_, i)) == 0 ? 0 : 1;          /* next assignment may change this value */
                    setbvalue(ra, res);
                    continue;
                }

                case OpCode.OP_LEN:
                {
                    TValue rb = RB(L, base_, i);
                    switch (ttype(rb))
                    {
                    case LUA_TTABLE:
                    {
                        setnvalue(ra, (lua_Number)luaH_getn(hvalue(rb)));
                        break;
                    }

                    case LUA_TSTRING:
                    {
                        setnvalue(ra, (lua_Number)tsvalue(rb).len);
                        break;
                    }

                    default:
                    {                  /* try metamethod */
                        //Protect(
                        L.savedpc = InstructionPtr.Assign(pc);
                        if (call_binTM(L, rb, luaO_nilobject, ra, TMS.TM_LEN) == 0)
                        {
                            luaG_typeerror(L, rb, "get length of");
                        }
                        base_ = L.base_;
                        //)
                        break;
                    }
                    }
                    continue;
                }

                case OpCode.OP_CONCAT:
                {
                    int b = GETARG_B(i);
                    int c = GETARG_C(i);
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    luaV_concat(L, c - b + 1, c); luaC_checkGC(L);
                    base_ = L.base_;
                    //);
                    setobjs2s(L, RA(L, base_, i), base_ + b);
                    continue;
                }

                case OpCode.OP_JMP:
                {
                    dojump(L, pc, GETARG_sBx(i));
                    continue;
                }

                case OpCode.OP_EQ:
                {
                    TValue rb = RKB(L, base_, i, k);
                    TValue rc = RKC(L, base_, i, k);
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    if (equalobj(L, rb, rc) == GETARG_A(i))
                    {
                        dojump(L, pc, GETARG_sBx(pc[0]));
                    }
                    base_ = L.base_;
                    //);
                    InstructionPtr.inc(ref pc);
                    continue;
                }

                case OpCode.OP_LT:
                {
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    if (luaV_lessthan(L, RKB(L, base_, i, k), RKC(L, base_, i, k)) == GETARG_A(i))
                    {
                        dojump(L, pc, GETARG_sBx(pc[0]));
                    }
                    base_ = L.base_;
                    //);
                    InstructionPtr.inc(ref pc);
                    continue;
                }

                case OpCode.OP_LE:
                {
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    if (lessequal(L, RKB(L, base_, i, k), RKC(L, base_, i, k)) == GETARG_A(i))
                    {
                        dojump(L, pc, GETARG_sBx(pc[0]));
                    }
                    base_ = L.base_;
                    //);
                    InstructionPtr.inc(ref pc);
                    continue;
                }

                case OpCode.OP_TEST:
                {
                    if (l_isfalse(ra) != GETARG_C(i))
                    {
                        dojump(L, pc, GETARG_sBx(pc[0]));
                    }
                    InstructionPtr.inc(ref pc);
                    continue;
                }

                case OpCode.OP_TESTSET:
                {
                    TValue rb = RB(L, base_, i);
                    if (l_isfalse(rb) != GETARG_C(i))
                    {
                        setobjs2s(L, ra, rb);
                        dojump(L, pc, GETARG_sBx(pc[0]));
                    }
                    InstructionPtr.inc(ref pc);
                    continue;
                }

                case OpCode.OP_CALL:
                {
                    int b        = GETARG_B(i);
                    int nresults = GETARG_C(i) - 1;
                    if (b != 0)
                    {
                        L.top = ra + b;                  /* else previous instruction set top */
                    }
                    L.savedpc = InstructionPtr.Assign(pc);
                    switch (luaD_precall(L, ra, nresults))
                    {
                    case PCRLUA:
                    {
                        nexeccalls++;
                        goto reentry;                  /* restart luaV_execute over new Lua function */
                    }

                    case PCRC:
                    {
                        /* it was a C function (`precall' called it); adjust results */
                        if (nresults >= 0)
                        {
                            L.top = L.ci.top;
                        }
                        base_ = L.base_;
                        continue;
                    }

                    default:
                    {
                        return;                  /* yield */
                    }
                    }
                }

                case OpCode.OP_TAILCALL:
                {
                    int b = GETARG_B(i);
                    if (b != 0)
                    {
                        L.top = ra + b;                  /* else previous instruction set top */
                    }
                    L.savedpc = InstructionPtr.Assign(pc);
                    lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
                    switch (luaD_precall(L, ra, LUA_MULTRET))
                    {
                    case PCRLUA:
                    {
                        /* tail call: put new frame in place of previous one */
                        CallInfo ci = L.ci - 1;                  /* previous frame */
                        int      aux;
                        StkId    func  = ci.func;
                        StkId    pfunc = (ci + 1).func;               /* previous function index */
                        if (L.openupval != null)
                        {
                            luaF_close(L, ci.base_);
                        }
                        L.base_ = ci.base_ = ci.func + (ci[1].base_ - pfunc);
                        for (aux = 0; pfunc + aux < L.top; aux++)                  /* move frame down */
                        {
                            setobjs2s(L, func + aux, pfunc + aux);
                        }
                        ci.top = L.top = func + aux;                  /* correct top */
                        lua_assert(L.top == L.base_ + clvalue(func).l.p.maxstacksize);
                        ci.savedpc = InstructionPtr.Assign(L.savedpc);
                        ci.tailcalls++;                  /* one more call lost */
                        CallInfo.dec(ref L.ci);          /* remove new frame */
                        goto reentry;
                    }

                    case PCRC:
                    {                  /* it was a C function (`precall' called it) */
                        base_ = L.base_;
                        continue;
                    }

                    default:
                    {
                        return;                  /* yield */
                    }
                    }
                }

                case OpCode.OP_RETURN:
                {
                    int b = GETARG_B(i);
                    if (b != 0)
                    {
                        L.top = ra + b - 1;
                    }
                    if (L.openupval != null)
                    {
                        luaF_close(L, base_);
                    }
                    L.savedpc = InstructionPtr.Assign(pc);
                    b         = luaD_poscall(L, ra);
                    if (--nexeccalls == 0) /* was previous function running `here'? */
                    {
                        return;            /* no: return */
                    }
                    else
                    {          /* yes: continue its execution */
                        if (b != 0)
                        {
                            L.top = L.ci.top;
                        }
                        lua_assert(isLua(L.ci));
                        lua_assert(GET_OPCODE(L.ci.savedpc[-1]) == OpCode.OP_CALL);
                        goto reentry;
                    }
                }

                case OpCode.OP_FORLOOP:
                {
                    lua_Number step  = nvalue(ra + 2);
                    lua_Number idx   = luai_numadd(nvalue(ra), step);       /* increment index */
                    lua_Number limit = nvalue(ra + 1);
                    if (luai_numlt(0, step) ? luai_numle(idx, limit)
                                : luai_numle(limit, idx))
                    {
                        dojump(L, pc, GETARG_sBx(i)); /* jump back */
                        setnvalue(ra, idx);           /* update internal index... */
                        setnvalue(ra + 3, idx);       /* ...and external index */
                    }
                    continue;
                }

                case OpCode.OP_FORPREP:
                {
                    TValue init   = ra;
                    TValue plimit = ra + 1;
                    TValue pstep  = ra + 2;
                    L.savedpc = InstructionPtr.Assign(pc);          /* next steps may throw errors */
                    if (tonumber(ref init, ra) == 0)
                    {
                        luaG_runerror(L, LUA_QL("for") + " initial value must be a number");
                    }
                    else if (tonumber(ref plimit, ra + 1) == 0)
                    {
                        luaG_runerror(L, LUA_QL("for") + " limit must be a number");
                    }
                    else if (tonumber(ref pstep, ra + 2) == 0)
                    {
                        luaG_runerror(L, LUA_QL("for") + " step must be a number");
                    }
                    setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep)));
                    dojump(L, pc, GETARG_sBx(i));
                    continue;
                }

                case OpCode.OP_TFORLOOP:
                {
                    StkId cb = ra + 3;          /* call base */
                    setobjs2s(L, cb + 2, ra + 2);
                    setobjs2s(L, cb + 1, ra + 1);
                    setobjs2s(L, cb, ra);
                    L.top = cb + 3;          /* func. + 2 args (state and index) */
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    luaD_call(L, cb, GETARG_C(i));
                    base_ = L.base_;
                    //);
                    L.top = L.ci.top;
                    cb    = RA(L, base_, i) + 3;          /* previous call may change the stack */
                    if (!ttisnil(cb))
                    {                                     /* continue loop? */
                        setobjs2s(L, cb - 1, cb);         /* save control variable */
                        dojump(L, pc, GETARG_sBx(pc[0])); /* jump back */
                    }
                    InstructionPtr.inc(ref pc);
                    continue;
                }

                case OpCode.OP_SETLIST:
                {
                    int   n = GETARG_B(i);
                    int   c = GETARG_C(i);
                    int   last;
                    Table h;
                    if (n == 0)
                    {
                        n     = cast_int(L.top - ra) - 1;
                        L.top = L.ci.top;
                    }
                    if (c == 0)
                    {
                        c = cast_int(pc[0]);
                        InstructionPtr.inc(ref pc);
                    }
                    runtime_check(L, ttistable(ra));
                    h    = hvalue(ra);
                    last = ((c - 1) * LFIELDS_PER_FLUSH) + n;
                    if (last > h.sizearray)           /* needs more space? */
                    {
                        luaH_resizearray(L, h, last); /* pre-alloc it at once */
                    }
                    for (; n > 0; n--)
                    {
                        TValue val = ra + n;
                        setobj2t(L, luaH_setnum(L, h, last--), val);
                        luaC_barriert(L, h, val);
                    }
                    continue;
                }

                case OpCode.OP_CLOSE:
                {
                    luaF_close(L, ra);
                    continue;
                }

                case OpCode.OP_CLOSURE:
                {
                    Proto   p;
                    Closure ncl;
                    int     nup, j;
                    p       = cl.p.p[GETARG_Bx(i)];
                    nup     = p.nups;
                    ncl     = luaF_newLclosure(L, nup, cl.env);
                    ncl.l.p = p;
                    for (j = 0; j < nup; j++, InstructionPtr.inc(ref pc))
                    {
                        if (GET_OPCODE(pc[0]) == OpCode.OP_GETUPVAL)
                        {
                            ncl.l.upvals[j] = cl.upvals[GETARG_B(pc[0])];
                        }
                        else
                        {
                            lua_assert(GET_OPCODE(pc[0]) == OpCode.OP_MOVE);
                            ncl.l.upvals[j] = luaF_findupval(L, base_ + GETARG_B(pc[0]));
                        }
                    }
                    setclvalue(L, ra, ncl);
                    //Protect(
                    L.savedpc = InstructionPtr.Assign(pc);
                    luaC_checkGC(L);
                    base_ = L.base_;
                    //);
                    continue;
                }

                case OpCode.OP_VARARG:
                {
                    int      b = GETARG_B(i) - 1;
                    int      j;
                    CallInfo ci = L.ci;
                    int      n  = cast_int(ci.base_ - ci.func) - cl.p.numparams - 1;
                    if (b == LUA_MULTRET)
                    {
                        //Protect(
                        L.savedpc = InstructionPtr.Assign(pc);
                        luaD_checkstack(L, n);
                        base_ = L.base_;
                        //);
                        ra    = RA(L, base_, i);       /* previous call may change the stack */
                        b     = n;
                        L.top = ra + n;
                    }
                    for (j = 0; j < b; j++)
                    {
                        if (j < n)
                        {
                            setobjs2s(L, ra + j, ci.base_ - n + j);
                        }
                        else
                        {
                            setnilvalue(ra + j);
                        }
                    }
                    continue;
                }

                case OpCode.OP_RSHIFT:
                    arith_op(L, luai_numrshift, TMS.TM_RSHIFT, base_, i, k, ra, pc);
                    continue;

                case OpCode.OP_LSHIFT:
                    arith_op(L, luai_numlshift, TMS.TM_LSHIFT, base_, i, k, ra, pc);
                    continue;

                case OpCode.OP_BITAND:
                    arith_op(L, luai_numbitand, TMS.TM_BITAND, base_, i, k, ra, pc);
                    continue;

                case OpCode.OP_BITOR:
                    arith_op(L, luai_numbitor, TMS.TM_BITOR, base_, i, k, ra, pc);
                    continue;
                }
            }
        }