rlm@1: /* rlm@1: ** $Id: lvm.c,v 2.63.1.3 2007/12/28 15:32:23 roberto Exp $ rlm@1: ** Lua virtual machine rlm@1: ** See Copyright Notice in lua.h rlm@1: */ rlm@1: rlm@1: rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: rlm@1: #define lvm_c rlm@1: #define LUA_CORE rlm@1: rlm@1: #include "lua.h" rlm@1: rlm@1: #include "ldebug.h" rlm@1: #include "ldo.h" rlm@1: #include "lfunc.h" rlm@1: #include "lgc.h" rlm@1: #include "lobject.h" rlm@1: #include "lopcodes.h" rlm@1: #include "lstate.h" rlm@1: #include "lstring.h" rlm@1: #include "ltable.h" rlm@1: #include "ltm.h" rlm@1: #include "lvm.h" rlm@1: rlm@1: rlm@1: rlm@1: /* limit for table tag-method chains (to avoid loops) */ rlm@1: #define MAXTAGLOOP 100 rlm@1: rlm@1: rlm@1: const TValue *luaV_tonumber (const TValue *obj, TValue *n) { rlm@1: lua_Number num; rlm@1: if (ttisnumber(obj)) return obj; rlm@1: if (ttisstring(obj) && luaO_str2d(svalue(obj), &num)) { rlm@1: setnvalue(n, num); rlm@1: return n; rlm@1: } rlm@1: else rlm@1: return NULL; rlm@1: } rlm@1: rlm@1: rlm@1: int luaV_tostring (lua_State *L, StkId obj) { rlm@1: if (!ttisnumber(obj)) rlm@1: return 0; rlm@1: else { rlm@1: char s[LUAI_MAXNUMBER2STR]; rlm@1: lua_Number n = nvalue(obj); rlm@1: lua_number2str(s, n); rlm@1: setsvalue2s(L, obj, luaS_new(L, s)); rlm@1: return 1; rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void traceexec (lua_State *L, const Instruction *pc) { rlm@1: lu_byte mask = L->hookmask; rlm@1: const Instruction *oldpc = L->savedpc; rlm@1: L->savedpc = pc; rlm@1: if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) { rlm@1: resethookcount(L); rlm@1: luaD_callhook(L, LUA_HOOKCOUNT, -1); rlm@1: } rlm@1: if (mask & LUA_MASKLINE) { rlm@1: Proto *p = ci_func(L->ci)->l.p; rlm@1: int npc = pcRel(pc, p); rlm@1: int newline = getline(p, npc); rlm@1: /* call linehook when enter a new function, when jump back (loop), rlm@1: or when enter a new line */ rlm@1: if (npc == 0 || pc <= oldpc || newline != getline(p, pcRel(oldpc, p))) rlm@1: luaD_callhook(L, LUA_HOOKLINE, newline); rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: static void callTMres (lua_State *L, StkId res, const TValue *f, rlm@1: const TValue *p1, const TValue *p2) { rlm@1: ptrdiff_t result = savestack(L, res); rlm@1: setobj2s(L, L->top, f); /* push function */ rlm@1: setobj2s(L, L->top+1, p1); /* 1st argument */ rlm@1: setobj2s(L, L->top+2, p2); /* 2nd argument */ rlm@1: luaD_checkstack(L, 3); rlm@1: L->top += 3; rlm@1: luaD_call(L, L->top - 3, 1); rlm@1: res = restorestack(L, result); rlm@1: L->top--; rlm@1: setobjs2s(L, res, L->top); rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: static void callTM (lua_State *L, const TValue *f, const TValue *p1, rlm@1: const TValue *p2, const TValue *p3) { rlm@1: setobj2s(L, L->top, f); /* push function */ rlm@1: setobj2s(L, L->top+1, p1); /* 1st argument */ rlm@1: setobj2s(L, L->top+2, p2); /* 2nd argument */ rlm@1: setobj2s(L, L->top+3, p3); /* 3th argument */ rlm@1: luaD_checkstack(L, 4); rlm@1: L->top += 4; rlm@1: luaD_call(L, L->top - 4, 0); rlm@1: } rlm@1: rlm@1: rlm@1: void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { rlm@1: int loop; rlm@1: for (loop = 0; loop < MAXTAGLOOP; loop++) { rlm@1: const TValue *tm; rlm@1: if (ttistable(t)) { /* `t' is a table? */ rlm@1: Table *h = hvalue(t); rlm@1: const TValue *res = luaH_get(h, key); /* do a primitive get */ rlm@1: if (!ttisnil(res) || /* result is no nil? */ rlm@1: (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ rlm@1: setobj2s(L, val, res); rlm@1: return; rlm@1: } rlm@1: /* else will try the tag method */ rlm@1: } rlm@1: else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) rlm@1: luaG_typeerror(L, t, "index"); rlm@1: if (ttisfunction(tm)) { rlm@1: callTMres(L, val, tm, t, key); rlm@1: return; rlm@1: } rlm@1: t = tm; /* else repeat with `tm' */ rlm@1: } rlm@1: luaG_runerror(L, "loop in gettable"); rlm@1: } rlm@1: rlm@1: rlm@1: void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { rlm@1: int loop; rlm@1: for (loop = 0; loop < MAXTAGLOOP; loop++) { rlm@1: const TValue *tm; rlm@1: if (ttistable(t)) { /* `t' is a table? */ rlm@1: Table *h = hvalue(t); rlm@1: TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ rlm@1: if (!ttisnil(oldval) || /* result is no nil? */ rlm@1: (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ rlm@1: setobj2t(L, oldval, val); rlm@1: luaC_barriert(L, h, val); rlm@1: return; rlm@1: } rlm@1: /* else will try the tag method */ rlm@1: } rlm@1: else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX))) rlm@1: luaG_typeerror(L, t, "index"); rlm@1: if (ttisfunction(tm)) { rlm@1: callTM(L, tm, t, key, val); rlm@1: return; rlm@1: } rlm@1: t = tm; /* else repeat with `tm' */ rlm@1: } rlm@1: luaG_runerror(L, "loop in settable"); rlm@1: } rlm@1: rlm@1: rlm@1: static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, rlm@1: StkId res, TMS event) { rlm@1: const TValue *tm = luaT_gettmbyobj(L, p1, event); /* try first operand */ rlm@1: if (ttisnil(tm)) rlm@1: tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ rlm@1: if (ttisnil(tm)) return 0; rlm@1: callTMres(L, res, tm, p1, p2); rlm@1: return 1; rlm@1: } rlm@1: rlm@1: rlm@1: static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, rlm@1: TMS event) { rlm@1: const TValue *tm1 = fasttm(L, mt1, event); rlm@1: const TValue *tm2; rlm@1: if (tm1 == NULL) return NULL; /* no metamethod */ rlm@1: if (mt1 == mt2) return tm1; /* same metatables => same metamethods */ rlm@1: tm2 = fasttm(L, mt2, event); rlm@1: if (tm2 == NULL) return NULL; /* no metamethod */ rlm@1: if (luaO_rawequalObj(tm1, tm2)) /* same metamethods? */ rlm@1: return tm1; rlm@1: return NULL; rlm@1: } rlm@1: rlm@1: rlm@1: static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, rlm@1: TMS event) { rlm@1: const TValue *tm1 = luaT_gettmbyobj(L, p1, event); rlm@1: const TValue *tm2; rlm@1: if (ttisnil(tm1)) return -1; /* no metamethod? */ rlm@1: tm2 = luaT_gettmbyobj(L, p2, event); rlm@1: if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ rlm@1: return -1; rlm@1: callTMres(L, L->top, tm1, p1, p2); rlm@1: return !l_isfalse(L->top); rlm@1: } rlm@1: rlm@1: rlm@1: static int l_strcmp (const TString *ls, const TString *rs) { rlm@1: const char *l = getstr(ls); rlm@1: size_t ll = ls->tsv.len; rlm@1: const char *r = getstr(rs); rlm@1: size_t lr = rs->tsv.len; rlm@1: for (;;) { rlm@1: int temp = strcoll(l, r); rlm@1: if (temp != 0) return temp; rlm@1: else { /* strings are equal up to a `\0' */ rlm@1: size_t len = strlen(l); /* index of first `\0' in both strings */ rlm@1: if (len == lr) /* r is finished? */ rlm@1: return (len == ll) ? 0 : 1; rlm@1: else if (len == ll) /* l is finished? */ rlm@1: return -1; /* l is smaller than r (because r is not finished) */ rlm@1: /* both strings longer than `len'; go on comparing (after the `\0') */ rlm@1: len++; rlm@1: l += len; ll -= len; r += len; lr -= len; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: rlm@1: int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { rlm@1: int res; rlm@1: if (ttype(l) != ttype(r)) rlm@1: return luaG_ordererror(L, l, r); rlm@1: else if (ttisnumber(l)) rlm@1: return luai_numlt(nvalue(l), nvalue(r)); rlm@1: else if (ttisstring(l)) rlm@1: return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; rlm@1: else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) rlm@1: return res; rlm@1: return luaG_ordererror(L, l, r); rlm@1: } rlm@1: rlm@1: rlm@1: static int lessequal (lua_State *L, const TValue *l, const TValue *r) { rlm@1: int res; rlm@1: if (ttype(l) != ttype(r)) rlm@1: return luaG_ordererror(L, l, r); rlm@1: else if (ttisnumber(l)) rlm@1: return luai_numle(nvalue(l), nvalue(r)); rlm@1: else if (ttisstring(l)) rlm@1: return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; rlm@1: else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ rlm@1: return res; rlm@1: else if ((res = call_orderTM(L, r, l, TM_LT)) != -1) /* else try `lt' */ rlm@1: return !res; rlm@1: return luaG_ordererror(L, l, r); rlm@1: } rlm@1: rlm@1: rlm@1: int luaV_equalval (lua_State *L, const TValue *t1, const TValue *t2) { rlm@1: const TValue *tm; rlm@1: lua_assert(ttype(t1) == ttype(t2)); rlm@1: switch (ttype(t1)) { rlm@1: case LUA_TNIL: return 1; rlm@1: case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); rlm@1: case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ rlm@1: case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); rlm@1: case LUA_TUSERDATA: { rlm@1: if (uvalue(t1) == uvalue(t2)) return 1; rlm@1: tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, rlm@1: TM_EQ); rlm@1: break; /* will try TM */ rlm@1: } rlm@1: case LUA_TTABLE: { rlm@1: if (hvalue(t1) == hvalue(t2)) return 1; rlm@1: tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); rlm@1: break; /* will try TM */ rlm@1: } rlm@1: default: return gcvalue(t1) == gcvalue(t2); rlm@1: } rlm@1: if (tm == NULL) return 0; /* no TM? */ rlm@1: callTMres(L, L->top, tm, t1, t2); /* call TM */ rlm@1: return !l_isfalse(L->top); rlm@1: } rlm@1: rlm@1: rlm@1: void luaV_concat (lua_State *L, int total, int last) { rlm@1: do { rlm@1: StkId top = L->base + last + 1; rlm@1: int n = 2; /* number of elements handled in this pass (at least 2) */ rlm@1: if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { rlm@1: if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) rlm@1: luaG_concaterror(L, top-2, top-1); rlm@1: } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ rlm@1: (void)tostring(L, top - 2); /* result is first op (as string) */ rlm@1: else { rlm@1: /* at least two string values; get as many as possible */ rlm@1: size_t tl = tsvalue(top-1)->len; rlm@1: char *buffer; rlm@1: int i; rlm@1: /* collect total length */ rlm@1: for (n = 1; n < total && tostring(L, top-n-1); n++) { rlm@1: size_t l = tsvalue(top-n-1)->len; rlm@1: if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); rlm@1: tl += l; rlm@1: } rlm@1: buffer = luaZ_openspace(L, &G(L)->buff, tl); rlm@1: tl = 0; rlm@1: for (i=n; i>0; i--) { /* concat all strings */ rlm@1: size_t l = tsvalue(top-i)->len; rlm@1: memcpy(buffer+tl, svalue(top-i), l); rlm@1: tl += l; rlm@1: } rlm@1: setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); rlm@1: } rlm@1: total -= n-1; /* got `n' strings to create 1 new */ rlm@1: last -= n-1; rlm@1: } while (total > 1); /* repeat until only 1 result left */ rlm@1: } rlm@1: rlm@1: rlm@1: static void Arith (lua_State *L, StkId ra, const TValue *rb, rlm@1: const TValue *rc, TMS op) { rlm@1: TValue tempb, tempc; rlm@1: const TValue *b, *c; rlm@1: if ((b = luaV_tonumber(rb, &tempb)) != NULL && rlm@1: (c = luaV_tonumber(rc, &tempc)) != NULL) { rlm@1: lua_Number nb = nvalue(b), nc = nvalue(c); rlm@1: switch (op) { rlm@1: case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; rlm@1: case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; rlm@1: case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; rlm@1: case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; rlm@1: case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; rlm@1: case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; rlm@1: case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; rlm@1: default: lua_assert(0); break; rlm@1: } rlm@1: } rlm@1: else if (!call_binTM(L, rb, rc, ra, op)) rlm@1: luaG_aritherror(L, rb, rc); rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: /* rlm@1: ** some macros for common tasks in `luaV_execute' rlm@1: */ rlm@1: rlm@1: #define runtime_check(L, c) { if (!(c)) break; } rlm@1: rlm@1: #define RA(i) (base+GETARG_A(i)) rlm@1: /* to be used after possible stack reallocation */ rlm@1: #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) rlm@1: #define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) rlm@1: #define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ rlm@1: ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) rlm@1: #define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ rlm@1: ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) rlm@1: #define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) rlm@1: rlm@1: rlm@1: #define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} rlm@1: rlm@1: rlm@1: #define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } rlm@1: rlm@1: rlm@1: #define arith_op(op,tm) { \ rlm@1: TValue *rb = RKB(i); \ rlm@1: TValue *rc = RKC(i); \ rlm@1: if (ttisnumber(rb) && ttisnumber(rc)) { \ rlm@1: lua_Number nb = nvalue(rb), nc = nvalue(rc); \ rlm@1: setnvalue(ra, op(nb, nc)); \ rlm@1: } \ rlm@1: else \ rlm@1: Protect(Arith(L, ra, rb, rc, tm)); \ rlm@1: } rlm@1: rlm@1: rlm@1: rlm@1: void luaV_execute (lua_State *L, int nexeccalls) { rlm@1: LClosure *cl; rlm@1: StkId base; rlm@1: TValue *k; rlm@1: const Instruction *pc; rlm@1: reentry: /* entry point */ rlm@1: lua_assert(isLua(L->ci)); rlm@1: pc = L->savedpc; rlm@1: cl = &clvalue(L->ci->func)->l; rlm@1: base = L->base; rlm@1: k = cl->p->k; rlm@1: /* main loop of interpreter */ rlm@1: for (;;) { rlm@1: const Instruction i = *pc++; rlm@1: StkId ra; rlm@1: if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && rlm@1: (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { rlm@1: traceexec(L, pc); rlm@1: if (L->status == LUA_YIELD) { /* did hook yield? */ rlm@1: L->savedpc = pc - 1; rlm@1: return; rlm@1: } rlm@1: base = L->base; rlm@1: } rlm@1: /* warning!! several calls may realloc the stack and invalidate `ra' */ rlm@1: ra = RA(i); rlm@1: lua_assert(base == L->base && L->base == L->ci->base); rlm@1: lua_assert(base <= L->top && L->top <= L->stack + L->stacksize); rlm@1: lua_assert(L->top == L->ci->top || luaG_checkopenop(i)); rlm@1: switch (GET_OPCODE(i)) { rlm@1: case OP_MOVE: { rlm@1: setobjs2s(L, ra, RB(i)); rlm@1: continue; rlm@1: } rlm@1: case OP_LOADK: { rlm@1: setobj2s(L, ra, KBx(i)); rlm@1: continue; rlm@1: } rlm@1: case OP_LOADBOOL: { rlm@1: setbvalue(ra, GETARG_B(i)); rlm@1: if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ rlm@1: continue; rlm@1: } rlm@1: case OP_LOADNIL: { rlm@1: TValue *rb = RB(i); rlm@1: do { rlm@1: setnilvalue(rb--); rlm@1: } while (rb >= ra); rlm@1: continue; rlm@1: } rlm@1: case OP_GETUPVAL: { rlm@1: int b = GETARG_B(i); rlm@1: setobj2s(L, ra, cl->upvals[b]->v); rlm@1: continue; rlm@1: } rlm@1: case OP_GETGLOBAL: { rlm@1: TValue g; rlm@1: TValue *rb = KBx(i); rlm@1: sethvalue(L, &g, cl->env); rlm@1: lua_assert(ttisstring(rb)); rlm@1: Protect(luaV_gettable(L, &g, rb, ra)); rlm@1: continue; rlm@1: } rlm@1: case OP_GETTABLE: { rlm@1: Protect(luaV_gettable(L, RB(i), RKC(i), ra)); rlm@1: continue; rlm@1: } rlm@1: case OP_SETGLOBAL: { rlm@1: TValue g; rlm@1: sethvalue(L, &g, cl->env); rlm@1: lua_assert(ttisstring(KBx(i))); rlm@1: Protect(luaV_settable(L, &g, KBx(i), ra)); rlm@1: continue; rlm@1: } rlm@1: case OP_SETUPVAL: { rlm@1: UpVal *uv = cl->upvals[GETARG_B(i)]; rlm@1: setobj(L, uv->v, ra); rlm@1: luaC_barrier(L, uv, ra); rlm@1: continue; rlm@1: } rlm@1: case OP_SETTABLE: { rlm@1: Protect(luaV_settable(L, ra, RKB(i), RKC(i))); rlm@1: continue; rlm@1: } rlm@1: case OP_NEWTABLE: { rlm@1: int b = GETARG_B(i); rlm@1: int c = GETARG_C(i); rlm@1: sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); rlm@1: Protect(luaC_checkGC(L)); rlm@1: continue; rlm@1: } rlm@1: case OP_SELF: { rlm@1: StkId rb = RB(i); rlm@1: setobjs2s(L, ra+1, rb); rlm@1: Protect(luaV_gettable(L, rb, RKC(i), ra)); rlm@1: continue; rlm@1: } rlm@1: case OP_ADD: { rlm@1: arith_op(luai_numadd, TM_ADD); rlm@1: continue; rlm@1: } rlm@1: case OP_SUB: { rlm@1: arith_op(luai_numsub, TM_SUB); rlm@1: continue; rlm@1: } rlm@1: case OP_MUL: { rlm@1: arith_op(luai_nummul, TM_MUL); rlm@1: continue; rlm@1: } rlm@1: case OP_DIV: { rlm@1: arith_op(luai_numdiv, TM_DIV); rlm@1: continue; rlm@1: } rlm@1: case OP_MOD: { rlm@1: arith_op(luai_nummod, TM_MOD); rlm@1: continue; rlm@1: } rlm@1: case OP_POW: { rlm@1: arith_op(luai_numpow, TM_POW); rlm@1: continue; rlm@1: } rlm@1: case OP_UNM: { rlm@1: TValue *rb = RB(i); rlm@1: if (ttisnumber(rb)) { rlm@1: lua_Number nb = nvalue(rb); rlm@1: setnvalue(ra, luai_numunm(nb)); rlm@1: } rlm@1: else { rlm@1: Protect(Arith(L, ra, rb, rb, TM_UNM)); rlm@1: } rlm@1: continue; rlm@1: } rlm@1: case OP_NOT: { rlm@1: int res = l_isfalse(RB(i)); /* next assignment may change this value */ rlm@1: setbvalue(ra, res); rlm@1: continue; rlm@1: } rlm@1: case OP_LEN: { rlm@1: const TValue *rb = RB(i); rlm@1: switch (ttype(rb)) { rlm@1: case LUA_TTABLE: { rlm@1: setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); rlm@1: break; rlm@1: } rlm@1: case LUA_TSTRING: { rlm@1: setnvalue(ra, cast_num(tsvalue(rb)->len)); rlm@1: break; rlm@1: } rlm@1: default: { /* try metamethod */ rlm@1: Protect( rlm@1: if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) rlm@1: luaG_typeerror(L, rb, "get length of"); rlm@1: ) rlm@1: } rlm@1: } rlm@1: continue; rlm@1: } rlm@1: case OP_CONCAT: { rlm@1: int b = GETARG_B(i); rlm@1: int c = GETARG_C(i); rlm@1: Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); rlm@1: setobjs2s(L, RA(i), base+b); rlm@1: continue; rlm@1: } rlm@1: case OP_JMP: { rlm@1: dojump(L, pc, GETARG_sBx(i)); rlm@1: continue; rlm@1: } rlm@1: case OP_EQ: { rlm@1: TValue *rb = RKB(i); rlm@1: TValue *rc = RKC(i); rlm@1: Protect( rlm@1: if (equalobj(L, rb, rc) == GETARG_A(i)) rlm@1: dojump(L, pc, GETARG_sBx(*pc)); rlm@1: ) rlm@1: pc++; rlm@1: continue; rlm@1: } rlm@1: case OP_LT: { rlm@1: Protect( rlm@1: if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) rlm@1: dojump(L, pc, GETARG_sBx(*pc)); rlm@1: ) rlm@1: pc++; rlm@1: continue; rlm@1: } rlm@1: case OP_LE: { rlm@1: Protect( rlm@1: if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) rlm@1: dojump(L, pc, GETARG_sBx(*pc)); rlm@1: ) rlm@1: pc++; rlm@1: continue; rlm@1: } rlm@1: case OP_TEST: { rlm@1: if (l_isfalse(ra) != GETARG_C(i)) rlm@1: dojump(L, pc, GETARG_sBx(*pc)); rlm@1: pc++; rlm@1: continue; rlm@1: } rlm@1: case OP_TESTSET: { rlm@1: TValue *rb = RB(i); rlm@1: if (l_isfalse(rb) != GETARG_C(i)) { rlm@1: setobjs2s(L, ra, rb); rlm@1: dojump(L, pc, GETARG_sBx(*pc)); rlm@1: } rlm@1: pc++; rlm@1: continue; rlm@1: } rlm@1: case OP_CALL: { rlm@1: int b = GETARG_B(i); rlm@1: int nresults = GETARG_C(i) - 1; rlm@1: if (b != 0) L->top = ra+b; /* else previous instruction set top */ rlm@1: L->savedpc = pc; rlm@1: switch (luaD_precall(L, ra, nresults)) { rlm@1: case PCRLUA: { rlm@1: nexeccalls++; rlm@1: goto reentry; /* restart luaV_execute over new Lua function */ rlm@1: } rlm@1: case PCRC: { rlm@1: /* it was a C function (`precall' called it); adjust results */ rlm@1: if (nresults >= 0) L->top = L->ci->top; rlm@1: base = L->base; rlm@1: continue; rlm@1: } rlm@1: default: { rlm@1: return; /* yield */ rlm@1: } rlm@1: } rlm@1: } rlm@1: case OP_TAILCALL: { rlm@1: int b = GETARG_B(i); rlm@1: if (b != 0) L->top = ra+b; /* else previous instruction set top */ rlm@1: L->savedpc = pc; rlm@1: lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); rlm@1: switch (luaD_precall(L, ra, LUA_MULTRET)) { rlm@1: case PCRLUA: { rlm@1: /* tail call: put new frame in place of previous one */ rlm@1: CallInfo *ci = L->ci - 1; /* previous frame */ rlm@1: int aux; rlm@1: StkId func = ci->func; rlm@1: StkId pfunc = (ci+1)->func; /* previous function index */ rlm@1: if (L->openupval) luaF_close(L, ci->base); rlm@1: L->base = ci->base = ci->func + ((ci+1)->base - pfunc); rlm@1: for (aux = 0; pfunc+aux < L->top; aux++) /* move frame down */ rlm@1: setobjs2s(L, func+aux, pfunc+aux); rlm@1: ci->top = L->top = func+aux; /* correct top */ rlm@1: lua_assert(L->top == L->base + clvalue(func)->l.p->maxstacksize); rlm@1: ci->savedpc = L->savedpc; rlm@1: ci->tailcalls++; /* one more call lost */ rlm@1: L->ci--; /* remove new frame */ rlm@1: goto reentry; rlm@1: } rlm@1: case PCRC: { /* it was a C function (`precall' called it) */ rlm@1: base = L->base; rlm@1: continue; rlm@1: } rlm@1: default: { rlm@1: return; /* yield */ rlm@1: } rlm@1: } rlm@1: } rlm@1: case OP_RETURN: { rlm@1: int b = GETARG_B(i); rlm@1: if (b != 0) L->top = ra+b-1; rlm@1: if (L->openupval) luaF_close(L, base); rlm@1: L->savedpc = pc; rlm@1: b = luaD_poscall(L, ra); rlm@1: if (--nexeccalls == 0) /* was previous function running `here'? */ rlm@1: return; /* no: return */ rlm@1: else { /* yes: continue its execution */ rlm@1: if (b) L->top = L->ci->top; rlm@1: lua_assert(isLua(L->ci)); rlm@1: lua_assert(GET_OPCODE(*((L->ci)->savedpc - 1)) == OP_CALL); rlm@1: goto reentry; rlm@1: } rlm@1: } rlm@1: case OP_FORLOOP: { rlm@1: lua_Number step = nvalue(ra+2); rlm@1: lua_Number idx = luai_numadd(nvalue(ra), step); /* increment index */ rlm@1: lua_Number limit = nvalue(ra+1); rlm@1: if (luai_numlt(0, step) ? luai_numle(idx, limit) rlm@1: : luai_numle(limit, idx)) { rlm@1: dojump(L, pc, GETARG_sBx(i)); /* jump back */ rlm@1: setnvalue(ra, idx); /* update internal index... */ rlm@1: setnvalue(ra+3, idx); /* ...and external index */ rlm@1: } rlm@1: continue; rlm@1: } rlm@1: case OP_FORPREP: { rlm@1: const TValue *init = ra; rlm@1: const TValue *plimit = ra+1; rlm@1: const TValue *pstep = ra+2; rlm@1: L->savedpc = pc; /* next steps may throw errors */ rlm@1: if (!tonumber(init, ra)) rlm@1: luaG_runerror(L, LUA_QL("for") " initial value must be a number"); rlm@1: else if (!tonumber(plimit, ra+1)) rlm@1: luaG_runerror(L, LUA_QL("for") " limit must be a number"); rlm@1: else if (!tonumber(pstep, ra+2)) rlm@1: luaG_runerror(L, LUA_QL("for") " step must be a number"); rlm@1: setnvalue(ra, luai_numsub(nvalue(ra), nvalue(pstep))); rlm@1: dojump(L, pc, GETARG_sBx(i)); rlm@1: continue; rlm@1: } rlm@1: case OP_TFORLOOP: { rlm@1: StkId cb = ra + 3; /* call base */ rlm@1: setobjs2s(L, cb+2, ra+2); rlm@1: setobjs2s(L, cb+1, ra+1); rlm@1: setobjs2s(L, cb, ra); rlm@1: L->top = cb+3; /* func. + 2 args (state and index) */ rlm@1: Protect(luaD_call(L, cb, GETARG_C(i))); rlm@1: L->top = L->ci->top; rlm@1: cb = RA(i) + 3; /* previous call may change the stack */ rlm@1: if (!ttisnil(cb)) { /* continue loop? */ rlm@1: setobjs2s(L, cb-1, cb); /* save control variable */ rlm@1: dojump(L, pc, GETARG_sBx(*pc)); /* jump back */ rlm@1: } rlm@1: pc++; rlm@1: continue; rlm@1: } rlm@1: case OP_SETLIST: { rlm@1: int n = GETARG_B(i); rlm@1: int c = GETARG_C(i); rlm@1: int last; rlm@1: Table *h; rlm@1: if (n == 0) { rlm@1: n = cast_int(L->top - ra) - 1; rlm@1: L->top = L->ci->top; rlm@1: } rlm@1: if (c == 0) c = cast_int(*pc++); rlm@1: runtime_check(L, ttistable(ra)); rlm@1: h = hvalue(ra); rlm@1: last = ((c-1)*LFIELDS_PER_FLUSH) + n; rlm@1: if (last > h->sizearray) /* needs more space? */ rlm@1: luaH_resizearray(L, h, last); /* pre-alloc it at once */ rlm@1: for (; n > 0; n--) { rlm@1: TValue *val = ra+n; rlm@1: setobj2t(L, luaH_setnum(L, h, last--), val); rlm@1: luaC_barriert(L, h, val); rlm@1: } rlm@1: continue; rlm@1: } rlm@1: case OP_CLOSE: { rlm@1: luaF_close(L, ra); rlm@1: continue; rlm@1: } rlm@1: case OP_CLOSURE: { rlm@1: Proto *p; rlm@1: Closure *ncl; rlm@1: int nup, j; rlm@1: p = cl->p->p[GETARG_Bx(i)]; rlm@1: nup = p->nups; rlm@1: ncl = luaF_newLclosure(L, nup, cl->env); rlm@1: ncl->l.p = p; rlm@1: for (j=0; jl.upvals[j] = cl->upvals[GETARG_B(*pc)]; rlm@1: else { rlm@1: lua_assert(GET_OPCODE(*pc) == OP_MOVE); rlm@1: ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); rlm@1: } rlm@1: } rlm@1: setclvalue(L, ra, ncl); rlm@1: Protect(luaC_checkGC(L)); rlm@1: continue; rlm@1: } rlm@1: case OP_VARARG: { rlm@1: int b = GETARG_B(i) - 1; rlm@1: int j; rlm@1: CallInfo *ci = L->ci; rlm@1: int n = cast_int(ci->base - ci->func) - cl->p->numparams - 1; rlm@1: if (b == LUA_MULTRET) { rlm@1: Protect(luaD_checkstack(L, n)); rlm@1: ra = RA(i); /* previous call may change the stack */ rlm@1: b = n; rlm@1: L->top = ra + n; rlm@1: } rlm@1: for (j = 0; j < b; j++) { rlm@1: if (j < n) { rlm@1: setobjs2s(L, ra + j, ci->base - n + j); rlm@1: } rlm@1: else { rlm@1: setnilvalue(ra + j); rlm@1: } rlm@1: } rlm@1: continue; rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: