diff options
Diffstat (limited to 'src/lvm.c')
-rw-r--r-- | src/lvm.c | 334 |
1 files changed, 137 insertions, 197 deletions
@@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.102 2009/12/17 16:20:01 roberto Exp $ +** $Id: lvm.c,v 2.120 2010/05/13 19:53:05 roberto Exp $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -50,8 +50,8 @@ int luaV_tostring (lua_State *L, StkId obj) { else { char s[LUAI_MAXNUMBER2STR]; lua_Number n = nvalue(obj); - lua_number2str(s, n); - setsvalue2s(L, obj, luaS_new(L, s)); + int l = lua_number2str(s, n); + setsvalue2s(L, obj, luaS_newlstr(L, s, l)); return 1; } } @@ -74,6 +74,10 @@ static void traceexec (lua_State *L) { luaD_hook(L, LUA_HOOKLINE, newline); } L->oldpc = ci->u.l.savedpc; + if (L->status == LUA_YIELD) { /* did hook yield? */ + ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ + luaD_throw(L, LUA_YIELD); + } } @@ -102,7 +106,7 @@ void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ - if (!ttisnil(res) || /* result is no nil? */ + if (!ttisnil(res) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; @@ -129,7 +133,7 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) { if (ttistable(t)) { /* `t' is a table? */ Table *h = hvalue(t); TValue *oldval = luaH_set(L, h, key); /* do a primitive set */ - if (!ttisnil(oldval) || /* result is no nil? */ + if (!ttisnil(oldval) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL) { /* or no TM? */ setobj2t(L, oldval, val); luaC_barriert(L, h, val); @@ -157,12 +161,13 @@ static int call_binTM (lua_State *L, const TValue *p1, const TValue *p2, if (ttisnil(tm)) tm = luaT_gettmbyobj(L, p2, event); /* try second operand */ if (ttisnil(tm)) return 0; + if (event == TM_UNM) p2 = luaO_nilobject; callTM(L, tm, p1, p2, res, 1); return 1; } -static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, +static const TValue *get_equalTM (lua_State *L, Table *mt1, Table *mt2, TMS event) { const TValue *tm1 = fasttm(L, mt1, event); const TValue *tm2; @@ -178,14 +183,10 @@ static const TValue *get_compTM (lua_State *L, Table *mt1, Table *mt2, static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { - const TValue *tm1 = luaT_gettmbyobj(L, p1, event); - const TValue *tm2; - if (ttisnil(tm1)) return -1; /* no metamethod? */ - tm2 = luaT_gettmbyobj(L, p2, event); - if (!luaO_rawequalObj(tm1, tm2)) /* different metamethods? */ - return -1; - callTM(L, tm1, p1, p2, L->top, 1); - return !l_isfalse(L->top); + if (!call_binTM(L, p1, p2, L->top, event)) + return -1; /* no metamethod */ + else + return !l_isfalse(L->top); } @@ -213,11 +214,9 @@ static int l_strcmp (const TString *ls, const TString *rs) { int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int res; - if (ttype(l) != ttype(r)) - return luaG_ordererror(L, l, r); - else if (ttisnumber(l)) + if (ttisnumber(l) && ttisnumber(r)) return luai_numlt(L, nvalue(l), nvalue(r)); - else if (ttisstring(l)) + else if (ttisstring(l) && ttisstring(r)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) < 0; else if ((res = call_orderTM(L, l, r, TM_LT)) != -1) return res; @@ -227,11 +226,9 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) { int res; - if (ttype(l) != ttype(r)) - return luaG_ordererror(L, l, r); - else if (ttisnumber(l)) + if (ttisnumber(l) && ttisnumber(r)) return luai_numle(L, nvalue(l), nvalue(r)); - else if (ttisstring(l)) + else if (ttisstring(l) && ttisstring(r)) return l_strcmp(rawtsvalue(l), rawtsvalue(r)) <= 0; else if ((res = call_orderTM(L, l, r, TM_LE)) != -1) /* first try `le' */ return res; @@ -249,14 +246,16 @@ int luaV_equalval_ (lua_State *L, const TValue *t1, const TValue *t2) { case LUA_TNUMBER: return luai_numeq(nvalue(t1), nvalue(t2)); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); + case LUA_TLCF: return fvalue(t1) == fvalue(t2); + case LUA_TSTRING: return eqstr(rawtsvalue(t1), rawtsvalue(t2)); case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; - tm = get_compTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); + tm = get_equalTM(L, uvalue(t1)->metatable, uvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; - tm = get_compTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); + tm = get_equalTM(L, hvalue(t1)->metatable, hvalue(t2)->metatable, TM_EQ); break; /* will try TM */ } default: return gcvalue(t1) == gcvalue(t2); @@ -354,14 +353,10 @@ void luaV_finishOp (lua_State *L) { StkId base = ci->u.l.base; Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ OpCode op = GET_OPCODE(inst); - if (op == OP_EXTRAARG) { /* extra argument? */ - inst = *(ci->u.l.savedpc - 2); /* get its 'main' instruction */ - op = GET_OPCODE(inst); - } switch (op) { /* finish its execution */ case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_POW: case OP_UNM: case OP_LEN: - case OP_GETGLOBAL: case OP_GETTABLE: case OP_SELF: { + case OP_GETTABUP: case OP_GETTABLE: case OP_SELF: { setobjs2s(L, base + GETARG_A(inst), --L->top); break; } @@ -402,7 +397,7 @@ void luaV_finishOp (lua_State *L) { L->top = ci->top; /* adjust results */ break; } - case OP_TAILCALL: case OP_SETGLOBAL: case OP_SETTABLE: + case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: break; default: lua_assert(0); } @@ -426,11 +421,13 @@ void luaV_finishOp (lua_State *L) { (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++))) -#define dojump(i) { ci->u.l.savedpc += (i); luai_threadyield(L);} +#define dojump(i) (ci->u.l.savedpc += (i)) #define Protect(x) { {x;}; base = ci->u.l.base; } +#define checkGC(L) Protect(luaC_checkGC(L); luai_threadyield(L);) + #define arith_op(op,tm) { \ TValue *rb = RKB(i); \ @@ -439,133 +436,109 @@ void luaV_finishOp (lua_State *L) { lua_Number nb = nvalue(rb), nc = nvalue(rc); \ setnvalue(ra, op(L, nb, nc)); \ } \ - else \ - Protect(luaV_arith(L, ra, rb, rc, tm)); \ - } + else { Protect(luaV_arith(L, ra, rb, rc, tm)); } } +#define vmdispatch(o) switch(o) +#define vmcase(l,b) case l: {b} break; void luaV_execute (lua_State *L) { CallInfo *ci = L->ci; - LClosure *cl = &clvalue(ci->func)->l; - TValue *k = cl->p->k; - StkId base = ci->u.l.base; + LClosure *cl; + TValue *k; + StkId base; + newframe: /* reentry point when frame changes (call/return) */ lua_assert(isLua(ci)); + lua_assert(ci == L->ci); + cl = &clvalue(ci->func)->l; + k = cl->p->k; + base = ci->u.l.base; /* main loop of interpreter */ for (;;) { Instruction i = *(ci->u.l.savedpc++); StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { - traceexec(L); - if (L->status == LUA_YIELD) { /* did hook yield? */ - ci->u.l.savedpc--; /* undo increment */ - luaD_throw(L, LUA_YIELD); - } - base = ci->u.l.base; + Protect(traceexec(L)); } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(i); lua_assert(base == ci->u.l.base); lua_assert(base <= L->top && L->top < L->stack + L->stacksize); - switch (GET_OPCODE(i)) { - case OP_MOVE: { + vmdispatch (GET_OPCODE(i)) { + vmcase(OP_MOVE, setobjs2s(L, ra, RB(i)); - continue; - } - case OP_LOADK: { + ) + vmcase(OP_LOADK, TValue *rb = KBx(i); setobj2s(L, ra, rb); - continue; - } - case OP_LOADBOOL: { + ) + vmcase(OP_LOADBOOL, setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) ci->u.l.savedpc++; /* skip next instruction (if C) */ - continue; - } - case OP_LOADNIL: { + ) + vmcase(OP_LOADNIL, TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); - continue; - } - case OP_GETUPVAL: { + ) + vmcase(OP_GETUPVAL, int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); - continue; - } - case OP_GETGLOBAL: { - TValue g; - TValue *rb = KBx(i); - sethvalue(L, &g, cl->env); - lua_assert(ttisstring(rb)); - Protect(luaV_gettable(L, &g, rb, ra)); - continue; - } - case OP_GETTABLE: { + ) + vmcase(OP_GETTABUP, + int b = GETARG_B(i); + Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra)); + ) + vmcase(OP_GETTABLE, Protect(luaV_gettable(L, RB(i), RKC(i), ra)); - continue; - } - case OP_SETGLOBAL: { - TValue g; - TValue *rb = KBx(i); - sethvalue(L, &g, cl->env); - lua_assert(ttisstring(rb)); - Protect(luaV_settable(L, &g, rb, ra)); - continue; - } - case OP_SETUPVAL: { + ) + vmcase(OP_SETTABUP, + int a = GETARG_A(i); + Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i))); + ) + vmcase(OP_SETUPVAL, UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_barrier(L, uv, ra); - continue; - } - case OP_SETTABLE: { + ) + vmcase(OP_SETTABLE, Protect(luaV_settable(L, ra, RKB(i), RKC(i))); - continue; - } - case OP_NEWTABLE: { + ) + vmcase(OP_NEWTABLE, int b = GETARG_B(i); int c = GETARG_C(i); Table *t = luaH_new(L); sethvalue(L, ra, t); if (b != 0 || c != 0) luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); - Protect(luaC_checkGC(L)); - continue; - } - case OP_SELF: { + checkGC(L); + ) + vmcase(OP_SELF, StkId rb = RB(i); setobjs2s(L, ra+1, rb); Protect(luaV_gettable(L, rb, RKC(i), ra)); - continue; - } - case OP_ADD: { + ) + vmcase(OP_ADD, arith_op(luai_numadd, TM_ADD); - continue; - } - case OP_SUB: { + ) + vmcase(OP_SUB, arith_op(luai_numsub, TM_SUB); - continue; - } - case OP_MUL: { + ) + vmcase(OP_MUL, arith_op(luai_nummul, TM_MUL); - continue; - } - case OP_DIV: { + ) + vmcase(OP_DIV, arith_op(luai_numdiv, TM_DIV); - continue; - } - case OP_MOD: { + ) + vmcase(OP_MOD, arith_op(luai_nummod, TM_MOD); - continue; - } - case OP_POW: { + ) + vmcase(OP_POW, arith_op(luai_numpow, TM_POW); - continue; - } - case OP_UNM: { + ) + vmcase(OP_UNM, TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); @@ -574,31 +547,26 @@ void luaV_execute (lua_State *L) { else { Protect(luaV_arith(L, ra, rb, rb, TM_UNM)); } - continue; - } - case OP_NOT: { + ) + vmcase(OP_NOT, int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); - continue; - } - case OP_LEN: { + ) + vmcase(OP_LEN, Protect(luaV_objlen(L, ra, RB(i))); - continue; - } - case OP_CONCAT: { + ) + vmcase(OP_CONCAT, int b = GETARG_B(i); int c = GETARG_C(i); L->top = base + c + 1; /* mark the end of concat operands */ - Protect(luaV_concat(L, c-b+1); luaC_checkGC(L)); + Protect(luaV_concat(L, c-b+1); checkGC(L);) L->top = ci->top; /* restore top */ setobjs2s(L, RA(i), base+b); - continue; - } - case OP_JMP: { + ) + vmcase(OP_JMP, dojump(GETARG_sBx(i)); - continue; - } - case OP_EQ: { + ) + vmcase(OP_EQ, TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( @@ -606,62 +574,54 @@ void luaV_execute (lua_State *L) { dojump(GETARG_sBx(*ci->u.l.savedpc)); ) ci->u.l.savedpc++; - continue; - } - case OP_LT: { + ) + vmcase(OP_LT, Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(GETARG_sBx(*ci->u.l.savedpc)); ) ci->u.l.savedpc++; - continue; - } - case OP_LE: { + ) + vmcase(OP_LE, Protect( if (luaV_lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(GETARG_sBx(*ci->u.l.savedpc)); ) ci->u.l.savedpc++; - continue; - } - case OP_TEST: { + ) + vmcase(OP_TEST, if (GETARG_C(i) ? !l_isfalse(ra) : l_isfalse(ra)) dojump(GETARG_sBx(*ci->u.l.savedpc)); ci->u.l.savedpc++; - continue; - } - case OP_TESTSET: { + ) + vmcase(OP_TESTSET, TValue *rb = RB(i); if (GETARG_C(i) ? !l_isfalse(rb) : l_isfalse(rb)) { setobjs2s(L, ra, rb); dojump(GETARG_sBx(*ci->u.l.savedpc)); } ci->u.l.savedpc++; - continue; - } - case OP_CALL: { + ) + vmcase(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 */ if (luaD_precall(L, ra, nresults)) { /* C function? */ if (nresults >= 0) L->top = ci->top; /* adjust results */ base = ci->u.l.base; - continue; } else { /* Lua function */ ci = L->ci; ci->callstatus |= CIST_REENTRY; - break; /* restart luaV_execute over new Lua function */ + goto newframe; /* restart luaV_execute over new Lua function */ } - } - case OP_TAILCALL: { + ) + vmcase(OP_TAILCALL, int b = GETARG_B(i); if (b != 0) L->top = ra+b; /* else previous instruction set top */ lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */ + if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */ base = ci->u.l.base; - continue; - } else { /* tail call: put called frame (n) in place of caller one (o) */ CallInfo *nci = L->ci; /* called frame */ @@ -682,10 +642,10 @@ void luaV_execute (lua_State *L) { oci->callstatus |= CIST_TAIL; /* function was tail called */ ci = L->ci = oci; /* remove new frame */ lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize); - break; /* restart luaV_execute over new Lua function */ + goto newframe; /* restart luaV_execute over new Lua function */ } - } - case OP_RETURN: { + ) + vmcase(OP_RETURN, int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; if (cl->p->sizep > 0) luaF_close(L, base); @@ -697,10 +657,10 @@ void luaV_execute (lua_State *L) { if (b) L->top = ci->top; lua_assert(isLua(ci)); lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); - break; /* restart luaV_execute over new Lua function */ + goto newframe; /* restart luaV_execute over new Lua function */ } - } - case OP_FORLOOP: { + ) + vmcase(OP_FORLOOP, lua_Number step = nvalue(ra+2); lua_Number idx = luai_numadd(L, nvalue(ra), step); /* increment index */ lua_Number limit = nvalue(ra+1); @@ -710,9 +670,8 @@ void luaV_execute (lua_State *L) { setnvalue(ra, idx); /* update internal index... */ setnvalue(ra+3, idx); /* ...and external index */ } - continue; - } - case OP_FORPREP: { + ) + vmcase(OP_FORPREP, const TValue *init = ra; const TValue *plimit = ra+1; const TValue *pstep = ra+2; @@ -724,9 +683,8 @@ void luaV_execute (lua_State *L) { luaG_runerror(L, LUA_QL("for") " step must be a number"); setnvalue(ra, luai_numsub(L, nvalue(ra), nvalue(pstep))); dojump(GETARG_sBx(i)); - continue; - } - case OP_TFORCALL: { + ) + vmcase(OP_TFORCALL, StkId cb = ra + 3; /* call base */ setobjs2s(L, cb+2, ra+2); setobjs2s(L, cb+1, ra+1); @@ -737,16 +695,16 @@ void luaV_execute (lua_State *L) { i = *(ci->u.l.savedpc++); /* go to next instruction */ ra = RA(i); lua_assert(GET_OPCODE(i) == OP_TFORLOOP); - /* go through */ - } - case OP_TFORLOOP: { + goto l_tforloop; + ) + vmcase(OP_TFORLOOP, + l_tforloop: if (!ttisnil(ra + 1)) { /* continue loop? */ setobjs2s(L, ra, ra + 1); /* save control variable */ dojump(GETARG_sBx(i)); /* jump back */ } - continue; - } - case OP_SETLIST: { + ) + vmcase(OP_SETLIST, int n = GETARG_B(i); int c = GETARG_C(i); int last; @@ -759,45 +717,34 @@ void luaV_execute (lua_State *L) { 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 */ + luaH_resizearray(L, h, last); /* pre-allocate it at once */ for (; n > 0; n--) { TValue *val = ra+n; setobj2t(L, luaH_setint(L, h, last--), val); luaC_barriert(L, h, val); } L->top = ci->top; /* correct top (in case of previous open call) */ - continue; - } - case OP_CLOSE: { + ) + vmcase(OP_CLOSE, luaF_close(L, ra); - continue; - } - case OP_CLOSURE: { + ) + vmcase(OP_CLOSURE, Proto *p = cl->p->p[GETARG_Bx(i)]; /* prototype for new closure */ int nup = p->sizeupvalues; - Closure *ncl = luaF_newLclosure(L, nup, cl->env); + Closure *ncl = luaF_newLclosure(L, nup); Upvaldesc *uv = p->upvalues; int j; ncl->l.p = p; setclvalue(L, ra, ncl); /* anchor new closure in stack */ - if (p->envreg != NO_REG) { /* lexical environment? */ - StkId env = base + p->envreg; - if (!ttistable(env)) - luaG_runerror(L, "environment is not a table: " - "cannot create closure"); - else - ncl->l.env = hvalue(env); - } for (j = 0; j < nup; j++) { /* fill in upvalues */ if (uv[j].instack) /* upvalue refers to local variable? */ ncl->l.upvals[j] = luaF_findupval(L, base + uv[j].idx); else /* get upvalue from enclosing function */ ncl->l.upvals[j] = cl->upvals[uv[j].idx]; } - Protect(luaC_checkGC(L)); - continue; - } - case OP_VARARG: { + checkGC(L); + ) + vmcase(OP_VARARG, int b = GETARG_B(i) - 1; int j; int n = cast_int(base - ci->func) - cl->p->numparams - 1; @@ -815,18 +762,11 @@ void luaV_execute (lua_State *L) { setnilvalue(ra + j); } } - continue; - } - case OP_EXTRAARG: { - luaG_runerror(L, "bad opcode"); - return; - } + ) + vmcase(OP_EXTRAARG, + lua_assert(0); + ) } - /* function changed (call/return): update pointers */ - lua_assert(ci == L->ci); - cl = &clvalue(ci->func)->l; - k = cl->p->k; - base = ci->u.l.base; } } |