void luaV_concat (lua_State *L, int total, int last) { do { StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!tostring(L, top-2) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); } else if (tsvalue(top-1)->tsv.len > 0) { /* if len=0, do nothing */ /* at least two string values; get as many as possible */ lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) + cast(lu_mem, tsvalue(top-2)->tsv.len); char *buffer; int i; while (n < total && tostring(L, top-n-1)) { /* collect total length */ tl += tsvalue(top-n-1)->tsv.len; n++; } if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow"); buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ size_t l = tsvalue(top-i)->tsv.len; memcpy(buffer+tl, svalue(top-i), l); tl += l; } setsvalue2s(top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; } while (total > 1); /* repeat until only 1 result left */ }
static int call_orderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { if (!call_binTM(L, p1, p2, L->top, event)) return -1; /* no metamethod */ else return !l_isfalse(L->top); }
static void Arith (lua_State *L, StkId ra, const TValue *rb, const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { lua_Number nb = nvalue(b), nc = nvalue(c); switch (op) { case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; case TM_DIV: setnvalue(ra, luai_lnumdiv(nb, nc)); break; case TM_MOD: setnvalue(ra, luai_lnummod(nb, nc)); break; case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; default: lua_assert(0); break; } } else { ptrdiff_t br = savestack(L, rb); ptrdiff_t cr = savestack(L, rc); if (!call_binTM(L, rb, rc, ra, op)) { luaG_aritherror(L, restorestack(L, br), restorestack(L, cr)); } } }
// [@ltm] 对参数栈上的参数执行concat操作 // total 需要concat的参数的个数 // last concat的数组最后一个元素下标 void luaV_concat (lua_State *L, int total, int last) { do { StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!tostring(L, top-2) || !tostring(L, top-1)) { // 两个参数不全都是string,所以只能通过metamethod来处理 if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); } else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing<优化的套路呀> */ /* at least two string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; char *buffer; int i; /* collect total length */ for (n = 1; n < total && tostring(L, top-n-1); n++) { size_t l = tsvalue(top-n-1)->len; if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); tl += l; } // 这里保存了要concat的string的总大小 buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ size_t l = tsvalue(top-i)->len; memcpy(buffer+tl, svalue(top-i), l); tl += l; } setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; } while (total > 1); /* repeat until only 1 result left */ }
void luaV_strconc (lua_State *L, int total, StkId top) { do { int n = 2; /* number of elements handled in this pass (at least 2) */ if (tostring(L, top-2) || tostring(L, top-1)) { if (!call_binTM(L, top, TM_CONCAT)) luaG_binerror(L, top-2, LUA_TSTRING, "concat"); } else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */ /* at least two string values; get as many as possible */ lint32 tl = (lint32)tsvalue(top-1)->len + (lint32)tsvalue(top-2)->len; char *buffer; int i; while (n < total && !tostring(L, top-n-1)) { /* collect total length */ tl += tsvalue(top-n-1)->len; n++; } if (tl > MAX_SIZET) lua_error(L, "string size overflow"); buffer = luaO_openspace(L, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ size_t l = tsvalue(top-i)->len; memcpy(buffer+tl, tsvalue(top-i)->str, l); tl += l; } tsvalue(top-n) = luaS_newlstr(L, buffer, tl); } total -= n-1; /* got `n' strings to create 1 new */ top -= n-1; } while (total > 1); /* repeat until only 1 result left */ }
void luaV_concat (lua_State *L, int total, int last) { do { StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); } else if (tsvalue(top-1)->len == 0) /* second op is empty? */ (void)tostring(L, top - 2); /* result is first op (as string) */ else { /* at least two string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; char *buffer; int i; /* collect total length */ for (n = 1; n < total && tostring(L, top-n-1); n++) { size_t l = tsvalue(top-n-1)->len; if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); tl += l; } buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ size_t l = tsvalue(top-i)->len; memcpy(buffer+tl, svalue(top-i), l); tl += l; } setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; } while (total > 1); /* repeat until only 1 result left */ }
static void Arith (lua_State *L, StkId ra, const TObject *rb, const TObject *rc, TMS op) { TObject tempb, tempc; const TObject *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { switch (op) { case TM_ADD: setnvalue(ra, nvalue(b) + nvalue(c)); break; case TM_SUB: setnvalue(ra, nvalue(b) - nvalue(c)); break; case TM_MUL: setnvalue(ra, nvalue(b) * nvalue(c)); break; case TM_DIV: setnvalue(ra, nvalue(b) / nvalue(c)); break; case TM_POW: { const TObject *f = luaH_getstr(hvalue(gt(L)), G(L)->tmname[TM_POW]); ptrdiff_t res = savestack(L, ra); if (!ttisfunction(f)) luaG_runerror(L, "`__pow' (`^' operator) is not a function"); callTMres(L, f, b, c); ra = restorestack(L, res); /* previous call may change stack */ setobjs2s(ra, L->top); break; } default: lua_assert(0); break; } } else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); }
void luaV_arith (lua_State *L, StkId ra, const TValue *rb, const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { lua_Number res = luaO_arith(op - TM_ADD + LUA_OPADD, nvalue(b), nvalue(c)); setnvalue(ra, res); } else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); }
int luaV_lessthan (lua_State *L, const TObject *l, const TObject *r, StkId top) { if (ttype(l) == LUA_TNUMBER && ttype(r) == LUA_TNUMBER) return (nvalue(l) < nvalue(r)); else if (ttype(l) == LUA_TSTRING && ttype(r) == LUA_TSTRING) return (luaV_strcomp(tsvalue(l), tsvalue(r)) < 0); else { /* call TM */ luaD_checkstack(L, 2); *top++ = *l; *top++ = *r; if (!call_binTM(L, top, TM_LT)) luaG_ordererror(L, top-2); L->top--; return (ttype(L->top) != LUA_TNIL); } }
static void comparison(lua_Type ttype_less, lua_Type ttype_equal, lua_Type ttype_great, IMS op) { Stack *S = &lua_state->stack; TObject *l = S->top-2; TObject *r = S->top-1; int32 result; if (ttype(l) == LUA_T_NUMBER && ttype(r) == LUA_T_NUMBER) result = (nvalue(l) < nvalue(r)) ? -1 : (nvalue(l) == nvalue(r)) ? 0 : 1; else if (ttype(l) == LUA_T_STRING && ttype(r) == LUA_T_STRING) result = strcoll(svalue(l), svalue(r)); else { call_binTM(op, "unexpected type in comparison"); return; } S->top--; nvalue(S->top - 1) = 1; ttype(S->top - 1) = (result < 0) ? ttype_less : (result == 0) ? ttype_equal : ttype_great; }
void luaV_concat (lua_State *L, int total, int last) { lu_mem max_sizet = MAX_SIZET; if (G(L)->memlimit < max_sizet) max_sizet = G(L)->memlimit; do { /* Any call which does a memory allocation may trim the stack, invalidating top unless the stack is fixed duri ng the allocation */ StkId top = L->base + last + 1; fixedstack(L); int n = 2; /* number of elements handled in this pass (at least 2) */ if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { unfixedstack(L); if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) { /* restore 'top' pointer, since stack might have been reallocted */ top = L->base + last + 1; luaG_concaterror(L, top-2, top-1); } } else if (tsvalue(top-1)->len == 0) { /* second op is empty? */ (void)tostring(L, top - 2); /* result is first op (as string) */ } else { /* at least two string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; char *buffer; int i; /* collect total length */ for (n = 1; n < total && tostring(L, top-n-1); n++) { size_t l = tsvalue(top-n-1)->len; if (l >= max_sizet - tl) luaG_runerror(L, "string length overflow"); tl += l; } G(L)->buff.n = tl; buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ size_t l = tsvalue(top-i)->len; c_memcpy(buffer+tl, svalue(top-i), l); tl += l; } setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); luaZ_resetbuffer(&G(L)->buff); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; unfixedstack(L); } while (total > 1); /* repeat until only 1 result left */ }
static void comparison (lua_Type ttype_less, lua_Type ttype_equal, lua_Type ttype_great, IMS op) { TObject *l = top-2; TObject *r = top-1; int result; if (ttype(l) == LUA_T_NUMBER && ttype(r) == LUA_T_NUMBER) result = (nvalue(l) < nvalue(r)) ? -1 : (nvalue(l) == nvalue(r)) ? 0 : 1; else if (ttype(l) == LUA_T_STRING && ttype(r) == LUA_T_STRING) result = strcmp(svalue(l), svalue(r)); else { call_binTM(op, "unexpected type at comparison"); return; } top--; nvalue(top-1) = 1; ttype(top-1) = (result < 0) ? ttype_less : (result == 0) ? ttype_equal : ttype_great; }
void luaV_concat (lua_State *L, int total) { lua_assert(total >= 2); do { StkId top = L->top; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); } else if (tsvalue(top-1)->len == 0) /* second operand is empty? */ (void)tostring(L, top - 2); /* result is first operand */ else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) { setsvalue2s(L, top-2, rawtsvalue(top-1)); /* result is second op. */ } else { /* at least two non-empty string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; char *buffer; int i; /* collect total length */ for (i = 1; i < total && tostring(L, top-i-1); i++) { size_t l = tsvalue(top-i-1)->len; if (l >= (MAX_SIZET/sizeof(char)) - tl) luaG_runerror(L, "string length overflow"); tl += l; } buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; n = i; do { /* concat all strings */ size_t l = tsvalue(top-i)->len; memcpy(buffer+tl, svalue(top-i), l * sizeof(char)); tl += l; } while (--i > 0); setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got 'n' strings to create 1 new */ L->top -= n-1; /* popped 'n' strings and pushed one */ } while (total > 1); /* repeat until only 1 result left */ }
static void Logic (lua_State *L, StkId ra, const TValue *rb, const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { lua_Number nb = nvalue(b), nc = nvalue(c); lua_Integer r; switch (op) { case TM_BLSHFT: luai_loglshft(r, nb, nc); break; case TM_BRSHFT: luai_logrshft(r, nb, nc); break; case TM_BOR: luai_logor(r, nb, nc); break; case TM_BAND: luai_logand(r, nb, nc); break; case TM_BXOR: luai_logxor(r, nb, nc); break; case TM_BNOT: luai_lognot(r, nb); break; default: lua_assert(0); r = 0; break; } setnvalue(ra, r); } else if (!call_binTM(L, rb, rc, ra, op)) luaG_logicerror(L, rb, rc); }
static void Arith (lua_State *L, StkId ra, const TValue *rb, const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { lua_Number nb = nvalue(b), nc = nvalue(c); switch (op) { case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; #if defined(LUA_BITWISE_OPERATORS) case TM_INTDIV: setnvalue(ra, luai_numintdiv(nb, nc)); break; #endif default: lua_assert(0); break; } } else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); }
void luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; StkId base; TValue *k; const Instruction *pc; reentry: /* entry point */ lua_assert(isLua(L->ci)); pc = L->savedpc; cl = &clvalue(L->ci->func)->l; base = L->base; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L, pc); if (L->status == LUA_YIELD) { /* did hook yield? */ L->savedpc = pc - 1; return; } base = L->base; } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(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)); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(L, ra, RB(i)); continue; } case OP_LOADK: { setobj2s(L, ra, KBx(i)); continue; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ continue; } case OP_LOADNIL: { TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); continue; } case 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: { Protect(luaV_gettable(L, RB(i), RKC(i), ra)); continue; } case OP_SETGLOBAL: { TValue g; sethvalue(L, &g, cl->env); lua_assert(ttisstring(KBx(i))); Protect(luaV_settable(L, &g, KBx(i), ra)); continue; } case OP_SETUPVAL: { UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_barrier(L, uv, ra); continue; } case OP_SETTABLE: { Protect(luaV_settable(L, ra, RKB(i), RKC(i))); continue; } case 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(luaC_checkGC(L)); continue; } case OP_SELF: { StkId rb = RB(i); setobjs2s(L, ra+1, rb); Protect(luaV_gettable(L, rb, RKC(i), ra)); continue; } case OP_ADD: { arith_op(luai_numadd, TM_ADD); continue; } case OP_SUB: { arith_op(luai_numsub, TM_SUB); continue; } case OP_MUL: { arith_op(luai_nummul, TM_MUL); continue; } case OP_DIV: { arith_op(luai_numdiv, TM_DIV); continue; } case OP_MOD: { arith_op(luai_nummod, TM_MOD); continue; } case OP_POW: { arith_op(luai_numpow, TM_POW); continue; } case OP_UNM: { TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); setnvalue(ra, luai_numunm(nb)); } else { Protect(luaV_arith(L, ra, rb, rb, TM_UNM)); } continue; } case OP_NOT: { int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); continue; } case OP_LEN: { const TValue *rb = RB(i); switch (ttype(rb)) { case LUA_TTABLE: { setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); break; } case LUA_TSTRING: { setnvalue(ra, cast_num(tsvalue(rb)->len)); break; } default: { /* try metamethod */ Protect( if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) luaG_typeerror(L, rb, "get length of"); ) } } continue; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); setobjs2s(L, RA(i), base+b); continue; } case OP_JMP: { dojump(L, pc, GETARG_sBx(i)); continue; } case OP_EQ: { TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( if (equalobj(L, rb, rc) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_LT: { Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_LE: { Protect( if (luaV_lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; }
/* ** Executes the given Lua function. Parameters are between [base,top). ** Returns n such that the the results are between [n,top). */ StkId luaV_execute (lua_State *L, const Closure *cl, StkId base) { const Proto *const tf = cl->f.l; StkId top; /* keep top local, for performance */ const Instruction *pc = tf->code; TString **const kstr = tf->kstr; const lua_Hook linehook = L->linehook; infovalue(base-1)->pc = &pc; luaD_checkstack(L, tf->maxstacksize+EXTRA_STACK); if (tf->is_vararg) /* varargs? */ adjust_varargs(L, base, tf->numparams); else luaD_adjusttop(L, base, tf->numparams); top = L->top; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; if (linehook) traceexec(L, base, top, linehook); switch (GET_OPCODE(i)) { case OP_END: { L->top = top; return top; } case OP_RETURN: { L->top = top; return base+GETARG_U(i); } case OP_CALL: { int nres = GETARG_B(i); if (nres == MULT_RET) nres = LUA_MULTRET; L->top = top; luaD_call(L, base+GETARG_A(i), nres); top = L->top; break; } case OP_TAILCALL: { L->top = top; luaD_call(L, base+GETARG_A(i), LUA_MULTRET); return base+GETARG_B(i); } case OP_PUSHNIL: { int n = GETARG_U(i); LUA_ASSERT(n>0, "invalid argument"); do { ttype(top++) = LUA_TNIL; } while (--n > 0); break; } case OP_POP: { top -= GETARG_U(i); break; } case OP_PUSHINT: { ttype(top) = LUA_TNUMBER; nvalue(top) = (Number)GETARG_S(i); top++; break; } case OP_PUSHSTRING: { ttype(top) = LUA_TSTRING; tsvalue(top) = kstr[GETARG_U(i)]; top++; break; } case OP_PUSHNUM: { ttype(top) = LUA_TNUMBER; nvalue(top) = tf->knum[GETARG_U(i)]; top++; break; } case OP_PUSHNEGNUM: { ttype(top) = LUA_TNUMBER; nvalue(top) = -tf->knum[GETARG_U(i)]; top++; break; } case OP_PUSHUPVALUE: { *top++ = cl->upvalue[GETARG_U(i)]; break; } case OP_GETLOCAL: { *top++ = *(base+GETARG_U(i)); break; } case OP_GETGLOBAL: { L->top = top; *top = *luaV_getglobal(L, kstr[GETARG_U(i)]); top++; break; } case OP_GETTABLE: { L->top = top; top--; *(top-1) = *luaV_gettable(L, top-1); break; } case OP_GETDOTTED: { ttype(top) = LUA_TSTRING; tsvalue(top) = kstr[GETARG_U(i)]; L->top = top+1; *(top-1) = *luaV_gettable(L, top-1); break; } case OP_GETINDEXED: { *top = *(base+GETARG_U(i)); L->top = top+1; *(top-1) = *luaV_gettable(L, top-1); break; } case OP_PUSHSELF: { TObject receiver; receiver = *(top-1); ttype(top) = LUA_TSTRING; tsvalue(top++) = kstr[GETARG_U(i)]; L->top = top; *(top-2) = *luaV_gettable(L, top-2); *(top-1) = receiver; break; } case OP_CREATETABLE: { L->top = top; luaC_checkGC(L); hvalue(top) = luaH_new(L, GETARG_U(i)); ttype(top) = LUA_TTABLE; top++; break; } case OP_SETLOCAL: { *(base+GETARG_U(i)) = *(--top); break; } case OP_SETGLOBAL: { L->top = top; luaV_setglobal(L, kstr[GETARG_U(i)]); top--; break; } case OP_SETTABLE: { StkId t = top-GETARG_A(i); L->top = top; luaV_settable(L, t, t+1); top -= GETARG_B(i); /* pop values */ break; } case OP_SETLIST: { int aux = GETARG_A(i) * LFIELDS_PER_FLUSH; int n = GETARG_B(i); Hash *arr = hvalue(top-n-1); L->top = top-n; /* final value of `top' (in case of errors) */ for (; n; n--) *luaH_setint(L, arr, n+aux) = *(--top); break; } case OP_SETMAP: { int n = GETARG_U(i); StkId finaltop = top-2*n; Hash *arr = hvalue(finaltop-1); L->top = finaltop; /* final value of `top' (in case of errors) */ for (; n; n--) { top-=2; *luaH_set(L, arr, top) = *(top+1); } break; } case OP_ADD: { if (tonumber(top-2) || tonumber(top-1)) call_arith(L, top, TM_ADD); else nvalue(top-2) += nvalue(top-1); top--; break; } case OP_ADDI: { if (tonumber(top-1)) { ttype(top) = LUA_TNUMBER; nvalue(top) = (Number)GETARG_S(i); call_arith(L, top+1, TM_ADD); } else nvalue(top-1) += (Number)GETARG_S(i); break; } case OP_SUB: { if (tonumber(top-2) || tonumber(top-1)) call_arith(L, top, TM_SUB); else nvalue(top-2) -= nvalue(top-1); top--; break; } case OP_MULT: { if (tonumber(top-2) || tonumber(top-1)) call_arith(L, top, TM_MUL); else nvalue(top-2) *= nvalue(top-1); top--; break; } case OP_DIV: { if (tonumber(top-2) || tonumber(top-1)) call_arith(L, top, TM_DIV); else nvalue(top-2) /= nvalue(top-1); top--; break; } case OP_POW: { if (!call_binTM(L, top, TM_POW)) lua_error(L, "undefined operation"); top--; break; } case OP_CONCAT: { int n = GETARG_U(i); luaV_strconc(L, n, top); top -= n-1; L->top = top; luaC_checkGC(L); break; } case OP_MINUS: { if (tonumber(top-1)) { ttype(top) = LUA_TNIL; call_arith(L, top+1, TM_UNM); } else nvalue(top-1) = -nvalue(top-1); break; } case OP_NOT: { ttype(top-1) = (ttype(top-1) == LUA_TNIL) ? LUA_TNUMBER : LUA_TNIL; nvalue(top-1) = 1; break; } case OP_JMPNE: { top -= 2; if (!luaO_equalObj(top, top+1)) dojump(pc, i); break; } case OP_JMPEQ: { top -= 2; if (luaO_equalObj(top, top+1)) dojump(pc, i); break; } case OP_JMPLT: { top -= 2; if (luaV_lessthan(L, top, top+1, top+2)) dojump(pc, i); break; } case OP_JMPLE: { /* a <= b === !(b<a) */ top -= 2; if (!luaV_lessthan(L, top+1, top, top+2)) dojump(pc, i); break; } case OP_JMPGT: { /* a > b === (b<a) */ top -= 2; if (luaV_lessthan(L, top+1, top, top+2)) dojump(pc, i); break; } case OP_JMPGE: { /* a >= b === !(a<b) */ top -= 2; if (!luaV_lessthan(L, top, top+1, top+2)) dojump(pc, i); break; } case OP_JMPT: { if (ttype(--top) != LUA_TNIL) dojump(pc, i); break; } case OP_JMPF: { if (ttype(--top) == LUA_TNIL) dojump(pc, i); break; } case OP_JMPONT: { if (ttype(top-1) == LUA_TNIL) top--; else dojump(pc, i); break; } case OP_JMPONF: { if (ttype(top-1) != LUA_TNIL) top--; else dojump(pc, i); break; } case OP_JMP: { dojump(pc, i); break; } case OP_PUSHNILJMP: { ttype(top++) = LUA_TNIL; pc++; break; } case OP_FORPREP: { if (tonumber(top-1)) lua_error(L, "`for' step must be a number"); if (tonumber(top-2)) lua_error(L, "`for' limit must be a number"); if (tonumber(top-3)) lua_error(L, "`for' initial value must be a number"); if (nvalue(top-1) > 0 ? nvalue(top-3) > nvalue(top-2) : nvalue(top-3) < nvalue(top-2)) { /* `empty' loop? */ top -= 3; /* remove control variables */ dojump(pc, i); /* jump to loop end */ } break; } case OP_FORLOOP: { LUA_ASSERT(ttype(top-1) == LUA_TNUMBER, "invalid step"); LUA_ASSERT(ttype(top-2) == LUA_TNUMBER, "invalid limit"); if (ttype(top-3) != LUA_TNUMBER) lua_error(L, "`for' index must be a number"); nvalue(top-3) += nvalue(top-1); /* increment index */ if (nvalue(top-1) > 0 ? nvalue(top-3) > nvalue(top-2) : nvalue(top-3) < nvalue(top-2)) top -= 3; /* end loop: remove control variables */ else dojump(pc, i); /* repeat loop */ break; } case OP_LFORPREP: { Node *node; if (ttype(top-1) != LUA_TTABLE) lua_error(L, "`for' table must be a table"); node = luaH_next(L, hvalue(top-1), &luaO_nilobject); if (node == NULL) { /* `empty' loop? */ top--; /* remove table */ dojump(pc, i); /* jump to loop end */ } else { top += 2; /* index,value */ *(top-2) = *key(node); *(top-1) = *val(node); } break; } case OP_LFORLOOP: { Node *node; LUA_ASSERT(ttype(top-3) == LUA_TTABLE, "invalid table"); node = luaH_next(L, hvalue(top-3), top-2); if (node == NULL) /* end loop? */ top -= 3; /* remove table, key, and value */ else { *(top-2) = *key(node); *(top-1) = *val(node); dojump(pc, i); /* repeat loop */ } break; } case OP_CLOSURE: { L->top = top; luaV_Lclosure(L, tf->kproto[GETARG_A(i)], GETARG_B(i)); top = L->top; luaC_checkGC(L); break; } } } }
static void call_arith (lua_State *L, StkId top, TMS event) { if (!call_binTM(L, top, event)) luaG_binerror(L, top-2, LUA_TNUMBER, "perform arithmetic on"); }
static void call_arith (IMS event) { call_binTM(event, "unexpected type in arithmetic operation"); }
/* Note: if called for unary operations, 'rc'=='rb'. */ static void Arith (lua_State *L, StkId ra, const TValue *rb, const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; lua_Number nb,nc; if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { /* Keep integer arithmetics in the integer realm, if possible. */ #ifdef LUA_TINT if (ttisint(b) && ttisint(c)) { lua_Integer ib = ivalue(b), ic = ivalue(c); lua_Integer *ri = &ra->value.i; ra->tt= LUA_TINT; /* part of 'setivalue(ra)' */ switch (op) { case TM_ADD: if (try_addint( ri, ib, ic)) return; break; case TM_SUB: if (try_subint( ri, ib, ic)) return; break; case TM_MUL: if (try_mulint( ri, ib, ic)) return; break; case TM_DIV: if (try_divint( ri, ib, ic)) return; break; case TM_MOD: if (try_modint( ri, ib, ic)) return; break; case TM_POW: if (try_powint( ri, ib, ic)) return; break; case TM_UNM: if (try_unmint( ri, ib)) return; break; default: lua_assert(0); } } #endif /* Fallback to floating point, when leaving range. */ #ifdef LNUM_COMPLEX if ((nvalue_img(b)!=0) || (nvalue_img(c)!=0)) { lua_Complex r; if (op==TM_UNM) { r= -nvalue_complex_fast(b); /* never an integer (or scalar) */ setnvalue_complex_fast( ra, r ); } else { lua_Complex bb= nvalue_complex(b), cc= nvalue_complex(c); switch (op) { case TM_ADD: r= bb + cc; break; case TM_SUB: r= bb - cc; break; case TM_MUL: r= bb * cc; break; case TM_DIV: r= bb / cc; break; case TM_MOD: luaG_runerror(L, "attempt to use %% on complex numbers"); /* no return */ case TM_POW: r= luai_vectpow( bb, cc ); break; default: lua_assert(0); r=0; } setnvalue_complex( ra, r ); } return; } #endif nb = nvalue(b); nc = nvalue(c); switch (op) { case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); return; case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); return; case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); return; case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); return; case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); return; case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); return; case TM_UNM: setnvalue(ra, luai_numunm(nb)); return; default: lua_assert(0); } } /* Either operand not a number */ if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); }
StkId luaV_execute (lua_State *L) { LClosure *cl; TObject *k; const Instruction *pc; callentry: /* entry point when calling new functions */ L->ci->u.l.pc = &pc; if (L->hookmask & LUA_MASKCALL) luaD_callhook(L, LUA_HOOKCALL, -1); retentry: /* entry point when returning to old functions */ lua_assert(L->ci->state == CI_SAVEDPC || L->ci->state == (CI_SAVEDPC | CI_CALLING)); L->ci->state = CI_HASFRAME; /* activate frame */ pc = L->ci->u.l.savedpc; cl = &clvalue(L->base - 1)->l; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; StkId base, ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L); if (L->ci->state & CI_YIELD) { /* did hook yield? */ L->ci->u.l.savedpc = pc - 1; L->ci->state = CI_YIELD | CI_SAVEDPC; return NULL; } } /* warning!! several calls may realloc the stack and invalidate `ra' */ base = L->base; ra = RA(i); lua_assert(L->ci->state & CI_HASFRAME); lua_assert(base == L->ci->base); lua_assert(L->top <= L->stack + L->stacksize && L->top >= base); lua_assert(L->top == L->ci->top || GET_OPCODE(i) == OP_CALL || GET_OPCODE(i) == OP_TAILCALL || GET_OPCODE(i) == OP_RETURN || GET_OPCODE(i) == OP_SETLISTO); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(ra, RB(i)); break; } case OP_LOADK: { setobj2s(ra, KBx(i)); break; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ break; } case OP_LOADNIL: { TObject *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); break; } case OP_GETUPVAL: { int b = GETARG_B(i); setobj2s(ra, cl->upvals[b]->v); break; } case OP_GETGLOBAL: { TObject *rb = KBx(i); const TObject *v; lua_assert(ttisstring(rb) && ttistable(&cl->g)); v = luaH_getstr(hvalue(&cl->g), tsvalue(rb)); if (!ttisnil(v)) { setobj2s(ra, v); } else setobj2s(XRA(i), luaV_index(L, &cl->g, rb, 0)); break; } case OP_GETTABLE: { StkId rb = RB(i); TObject *rc = RKC(i); if (ttistable(rb)) { const TObject *v = luaH_get(hvalue(rb), rc); if (!ttisnil(v)) { setobj2s(ra, v); } else setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); } else setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); break; } case OP_SETGLOBAL: { lua_assert(ttisstring(KBx(i)) && ttistable(&cl->g)); luaV_settable(L, &cl->g, KBx(i), ra); break; } case OP_SETUPVAL: { int b = GETARG_B(i); setobj(cl->upvals[b]->v, ra); /* write barrier */ break; } case OP_SETTABLE: { luaV_settable(L, ra, RKB(i), RKC(i)); break; } case OP_NEWTABLE: { int b = GETARG_B(i); b = fb2int(b); sethvalue(ra, luaH_new(L, b, GETARG_C(i))); luaC_checkGC(L); break; } case OP_SELF: { StkId rb = RB(i); TObject *rc = RKC(i); runtime_check(L, ttisstring(rc)); setobjs2s(ra+1, rb); if (ttistable(rb)) { const TObject *v = luaH_getstr(hvalue(rb), tsvalue(rc)); if (!ttisnil(v)) { setobj2s(ra, v); } else setobj2s(XRA(i), luaV_index(L, rb, rc, 0)); } else setobj2s(XRA(i), luaV_getnotable(L, rb, rc, 0)); break; } case OP_ADD: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) + nvalue(rc)); } else Arith(L, ra, rb, rc, TM_ADD); break; } case OP_SUB: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) - nvalue(rc)); } else Arith(L, ra, rb, rc, TM_SUB); break; } case OP_MUL: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) * nvalue(rc)); } else Arith(L, ra, rb, rc, TM_MUL); break; } case OP_DIV: { TObject *rb = RKB(i); TObject *rc = RKC(i); if (ttisnumber(rb) && ttisnumber(rc)) { setnvalue(ra, nvalue(rb) / nvalue(rc)); } else Arith(L, ra, rb, rc, TM_DIV); break; } case OP_POW: { Arith(L, ra, RKB(i), RKC(i), TM_POW); break; } case OP_UNM: { const TObject *rb = RB(i); TObject temp; if (tonumber(rb, &temp)) { setnvalue(ra, -nvalue(rb)); } else { setnilvalue(&temp); if (!call_binTM(L, RB(i), &temp, ra, TM_UNM)) luaG_aritherror(L, RB(i), &temp); } break; } case OP_NOT: { int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); break; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); luaV_concat(L, c-b+1, c); /* may change `base' (and `ra') */ base = L->base; setobjs2s(RA(i), base+b); luaC_checkGC(L); break; } case OP_JMP: { dojump(pc, GETARG_sBx(i)); break; } case OP_EQ: { if (equalobj(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; else dojump(pc, GETARG_sBx(*pc) + 1); break; } case OP_LT: { if (luaV_lessthan(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; else dojump(pc, GETARG_sBx(*pc) + 1); break; } case OP_LE: { if (luaV_lessequal(L, RKB(i), RKC(i)) != GETARG_A(i)) pc++; else dojump(pc, GETARG_sBx(*pc) + 1); break; } case OP_TEST: { TObject *rb = RB(i); if (l_isfalse(rb) == GETARG_C(i)) pc++; else { setobjs2s(ra, rb); dojump(pc, GETARG_sBx(*pc) + 1); } break; } case OP_CALL: case OP_TAILCALL: { StkId firstResult; int b = GETARG_B(i); int nresults; if (b != 0) L->top = ra+b; /* else previous instruction set top */ nresults = GETARG_C(i) - 1; firstResult = luaD_precall(L, ra); if (firstResult) { if (firstResult > L->top) { /* yield? */ lua_assert(L->ci->state == (CI_C | CI_YIELD)); (L->ci - 1)->u.l.savedpc = pc; (L->ci - 1)->state = CI_SAVEDPC; return NULL; } /* it was a C function (`precall' called it); adjust results */ luaD_poscall(L, nresults, firstResult); if (nresults >= 0) L->top = L->ci->top; } else { /* it is a Lua function */ if (GET_OPCODE(i) == OP_CALL) { /* regular call? */ (L->ci-1)->u.l.savedpc = pc; /* save `pc' to return later */ (L->ci-1)->state = (CI_SAVEDPC | CI_CALLING); } else { /* tail call: put new frame in place of previous one */ int aux; base = (L->ci - 1)->base; /* `luaD_precall' may change the stack */ ra = RA(i); if (L->openupval) luaF_close(L, base); for (aux = 0; ra+aux < L->top; aux++) /* move frame down */ setobjs2s(base+aux-1, ra+aux); (L->ci - 1)->top = L->top = base+aux; /* correct top */ lua_assert(L->ci->state & CI_SAVEDPC); (L->ci - 1)->u.l.savedpc = L->ci->u.l.savedpc; (L->ci - 1)->u.l.tailcalls++; /* one more call lost */ (L->ci - 1)->state = CI_SAVEDPC; L->ci--; /* remove new frame */ L->base = L->ci->base; } goto callentry; } break; } case OP_RETURN: { CallInfo *ci = L->ci - 1; /* previous function frame */ int b = GETARG_B(i); if (b != 0) L->top = ra+b-1; lua_assert(L->ci->state & CI_HASFRAME); if (L->openupval) luaF_close(L, base); L->ci->state = CI_SAVEDPC; /* deactivate current function */ L->ci->u.l.savedpc = pc; /* previous function was running `here'? */ if (!(ci->state & CI_CALLING)) { lua_assert((ci->state & CI_C) || ci->u.l.pc != &pc); return ra; /* no: return */ } else { /* yes: continue its execution */ int nresults; lua_assert(ci->u.l.pc == &pc && ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC)); lua_assert(GET_OPCODE(*(ci->u.l.savedpc - 1)) == OP_CALL); nresults = GETARG_C(*(ci->u.l.savedpc - 1)) - 1; luaD_poscall(L, nresults, ra); if (nresults >= 0) L->top = L->ci->top; goto retentry; } } case OP_FORLOOP: { lua_Number step, idx, limit; const TObject *plimit = ra+1; const TObject *pstep = ra+2; if (!ttisnumber(ra)) luaG_runerror(L, "`for' initial value must be a number"); if (!tonumber(plimit, ra+1)) luaG_runerror(L, "`for' limit must be a number"); if (!tonumber(pstep, ra+2)) luaG_runerror(L, "`for' step must be a number"); step = nvalue(pstep); idx = nvalue(ra) + step; /* increment index */ limit = nvalue(plimit); if (step > 0 ? idx <= limit : idx >= limit) { dojump(pc, GETARG_sBx(i)); /* jump back */ chgnvalue(ra, idx); /* update index */ } break; } case OP_TFORLOOP: { int nvar = GETARG_C(i) + 1; StkId cb = ra + nvar + 2; /* call base */ setobjs2s(cb, ra); setobjs2s(cb+1, ra+1); setobjs2s(cb+2, ra+2); L->top = cb+3; /* func. + 2 args (state and index) */ luaD_call(L, cb, nvar); L->top = L->ci->top; ra = XRA(i) + 2; /* final position of first result */ cb = ra + nvar; do { /* move results to proper positions */ nvar--; setobjs2s(ra+nvar, cb+nvar); } while (nvar > 0); if (ttisnil(ra)) /* break loop? */ pc++; /* skip jump (break loop) */ else dojump(pc, GETARG_sBx(*pc) + 1); /* jump back */ break; } case OP_TFORPREP: { /* for compatibility only */ if (ttistable(ra)) { setobjs2s(ra+1, ra); setobj2s(ra, luaH_getstr(hvalue(gt(L)), luaS_new(L, "next"))); } dojump(pc, GETARG_sBx(i)); break; } case OP_SETLIST: case OP_SETLISTO: { int bc; int n; Table *h; runtime_check(L, ttistable(ra)); h = hvalue(ra); bc = GETARG_Bx(i); if (GET_OPCODE(i) == OP_SETLIST) n = (bc&(LFIELDS_PER_FLUSH-1)) + 1; else { n = L->top - ra - 1; L->top = L->ci->top; } bc &= ~(LFIELDS_PER_FLUSH-1); /* bc = bc - bc%FPF */ for (; n > 0; n--) setobj2t(luaH_setnum(L, h, bc+n), ra+n); /* write barrier */ break; } case OP_CLOSE: { luaF_close(L, ra); break; } case 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->g); ncl->l.p = p; for (j=0; j<nup; j++, pc++) { if (GET_OPCODE(*pc) == OP_GETUPVAL) ncl->l.upvals[j] = cl->upvals[GETARG_B(*pc)]; else { lua_assert(GET_OPCODE(*pc) == OP_MOVE); ncl->l.upvals[j] = luaF_findupval(L, base + GETARG_B(*pc)); } } setclvalue(ra, ncl); luaC_checkGC(L); break; } } } }
static void Arith (lua_State *L, StkId ra, const TValue *rb, const TValue *rc, TMS op) { TValue tempb, tempc; const TValue *b, *c; #if LUA_REFCOUNT luarc_newvalue(&tempb); luarc_newvalue(&tempc); if ((b = luaV_tonumber(L, rb, &tempb)) != NULL && (c = luaV_tonumber(L, rc, &tempc)) != NULL) { #else if ((b = luaV_tonumber(rb, &tempb)) != NULL && (c = luaV_tonumber(rc, &tempc)) != NULL) { #endif /* LUA_REFCOUNT */ lua_Number nb = nvalue(b), nc = nvalue(c); #if LUA_REFCOUNT luarc_cleanvalue(&tempb); luarc_cleanvalue(&tempc); #endif /* LUA_REFCOUNT */ switch (op) { case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break; case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break; case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break; case TM_DIV: setnvalue(ra, luai_numdiv(nb, nc)); break; case TM_MOD: setnvalue(ra, luai_nummod(nb, nc)); break; case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break; case TM_UNM: setnvalue(ra, luai_numunm(nb)); break; default: lua_assert(0); break; } } #if LUA_REFCOUNT else if (!call_binTM(L, rb, rc, ra, op)) { luarc_cleanvalue(&tempb); luarc_cleanvalue(&tempc); luaG_aritherror(L, rb, rc); } #else else if (!call_binTM(L, rb, rc, ra, op)) luaG_aritherror(L, rb, rc); #endif /* LUA_REFCOUNT */ } /* ** some macros for common tasks in `luaV_execute' */ #define runtime_check(L, c) { if (!(c)) break; } #define RA(i) (base+GETARG_A(i)) /* to be used after possible stack reallocation */ #define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i)) #define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i)) #define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i)) #define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \ ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i)) #define KBx(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, k+GETARG_Bx(i)) #define dojump(L,pc,i) {(pc) += (i); luai_threadyield(L);} #define Protect(x) { L->savedpc = pc; {x;}; base = L->base; } #define arith_op(op,tm) { \ TValue *rb = RKB(i); \ TValue *rc = RKC(i); \ if (ttisnumber(rb) && ttisnumber(rc)) { \ lua_Number nb = nvalue(rb), nc = nvalue(rc); \ setnvalue(ra, op(nb, nc)); \ } \ else \ Protect(Arith(L, ra, rb, rc, tm)); \ } #if LUA_BITFIELD_OPS #define bit_op(op) { \ TValue *rb = RKB(i); \ TValue *rc = RKC(i); \ if (ttisnumber(rb) && ttisnumber(rc)) { \ unsigned int nb = (unsigned int)nvalue(rb), nc = (unsigned int)nvalue(rc); \ setnvalue(ra, nb op nc); \ } \ else \ luaG_aritherror(L, rb, rc); \ } #endif /* LUA_BITFIELD_OPS */ void luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; StkId base; TValue *k; const Instruction *pc; reentry: /* entry point */ lua_assert(isLua(L->ci)); pc = L->savedpc; cl = &clvalue(L->ci->func)->l; base = L->base; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L, pc); if (L->status == LUA_YIELD) { /* did hook yield? */ L->savedpc = pc - 1; return; } base = L->base; } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(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)); switch (GET_OPCODE(i)) { case OP_MOVE: { setobjs2s(L, ra, RB(i)); continue; } case OP_LOADK: { setobj2s(L, ra, KBx(i)); continue; } case OP_LOADBOOL: { setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ continue; } case OP_LOADNIL: { TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); continue; } case OP_GETUPVAL: { int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); continue; } case OP_GETGLOBAL: { TValue g; TValue *rb = KBx(i); #if LUA_REFCOUNT sethvalue2n(L, &g, cl->env); #else sethvalue(L, &g, cl->env); #endif /* LUA_REFCOUNT */ lua_assert(ttisstring(rb)); Protect(luaV_gettable(L, &g, rb, ra)); #if LUA_REFCOUNT setnilvalue(&g); #endif /* LUA_REFCOUNT */ continue; } case OP_GETTABLE: { Protect(luaV_gettable(L, RB(i), RKC(i), ra)); continue; } case OP_SETGLOBAL: { TValue g; #if LUA_REFCOUNT sethvalue2n(L, &g, cl->env); #else sethvalue(L, &g, cl->env); #endif /* LUA_REFCOUNT */ lua_assert(ttisstring(KBx(i))); Protect(luaV_settable(L, &g, KBx(i), ra)); #if LUA_REFCOUNT setnilvalue(&g); #endif /* LUA_REFCOUNT */ continue; } case OP_SETUPVAL: { UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_barrier(L, uv, ra); continue; } case OP_SETTABLE: { Protect(luaV_settable(L, ra, RKB(i), RKC(i))); continue; } case 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(luaC_checkGC(L)); continue; } case OP_SELF: { StkId rb = RB(i); setobjs2s(L, ra+1, rb); Protect(luaV_gettable(L, rb, RKC(i), ra)); continue; } case OP_ADD: { arith_op(luai_numadd, TM_ADD); continue; } case OP_SUB: { arith_op(luai_numsub, TM_SUB); continue; } case OP_MUL: { arith_op(luai_nummul, TM_MUL); continue; } case OP_DIV: { arith_op(luai_numdiv, TM_DIV); continue; } case OP_MOD: { arith_op(luai_nummod, TM_MOD); continue; } case OP_POW: { arith_op(luai_numpow, TM_POW); continue; } case OP_UNM: { TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); setnvalue(ra, luai_numunm(nb)); } else { Protect(Arith(L, ra, rb, rb, TM_UNM)); } continue; } case OP_NOT: { int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); continue; } #if LUA_BITFIELD_OPS case OP_BAND: { bit_op(&); continue; } case OP_BOR: { bit_op(|); continue; } case OP_BXOR: { bit_op(^); continue; } case OP_BSHL: { bit_op(<<); continue; } case OP_BSHR: { bit_op(>>); continue; } #endif /* LUA_BITFIELD_OPS */ case OP_LEN: { const TValue *rb = RB(i); switch (ttype(rb)) { case LUA_TTABLE: { setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); break; } case LUA_TSTRING: { setnvalue(ra, cast_num(tsvalue(rb)->len)); break; } #if LUA_WIDESTRING case LUA_TWSTRING: { setnvalue(ra, cast_num(tsvalue(rb)->len)); break; } #endif /* LUA_WIDESTRING */ default: { /* try metamethod */ Protect( if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) luaG_typeerror(L, rb, "get length of"); ) } } continue; } case OP_CONCAT: { int b = GETARG_B(i); int c = GETARG_C(i); Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); setobjs2s(L, RA(i), base+b); continue; } case OP_JMP: { dojump(L, pc, GETARG_sBx(i)); continue; } case OP_EQ: { TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( if (equalobj(L, rb, rc) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_LT: { Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } case OP_LE: { Protect( if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; }
void luaV_concat (lua_State *L, int total, int last) { int useType = LUA_TSTRING; int i; StkId top = L->base + last + 1; for (i = 0; i < total; ++i) { if (ttype(top-1-i) == LUA_TSTRING || ttype(top-1-i) == LUA_TWSTRING) { useType = ttype(top-1-i); break; } } if (useType == LUA_TSTRING) { do { StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!tostring(L, top-2) || !tostring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); } else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */ /* at least two string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; char *buffer; int i; /* collect total length */ for (n = 1; n < total && tostring(L, top-n-1); n++) { size_t l = tsvalue(top-n-1)->len; if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); tl += l; } buffer = luaZ_openspace(L, &G(L)->buff, tl); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ size_t l = tsvalue(top-i)->len; memcpy(buffer+tl, svalue(top-i), l); tl += l; #if LUA_REFCOUNT luarc_cleanvalue(top-i); #endif /* LUA_REFCOUNT */ } setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; } while (total > 1); /* repeat until only 1 result left */ } else { do { StkId top = L->base + last + 1; int n = 2; /* number of elements handled in this pass (at least 2) */ if (!towstring(L, top-2) || !towstring(L, top-1)) { if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT)) luaG_concaterror(L, top-2, top-1); } else if (tsvalue(top-1)->len > 0) { /* if len=0, do nothing */ /* at least two string values; get as many as possible */ size_t tl = tsvalue(top-1)->len; char *buffer; int i; /* collect total length */ for (n = 1; n < total && towstring(L, top-n-1); n++) { size_t l = tsvalue(top-n-1)->len; if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow"); tl += l; } buffer = luaZ_openspace(L, &G(L)->buff, tl*2); tl = 0; for (i=n; i>0; i--) { /* concat all strings */ size_t l = tsvalue(top-i)->len; memcpy(buffer+tl*2, wsvalue(top-i), l*2); tl += l; #if LUA_REFCOUNT luarc_cleanvalue(top-i); #endif /* LUA_REFCOUNT */ } setwsvalue2s(L, top-n, luaS_newlwstr(L, (const lua_WChar*)buffer, tl)); } total -= n-1; /* got `n' strings to create 1 new */ last -= n-1; } while (total > 1); /* repeat until only 1 result left */ } }
/* ** Execute the given opcode, until a RET. Parameters are between ** [stack+base,top). Returns n such that the the results are between ** [stack+n,top). */ static StkId lua_execute (Byte *pc, StkId base) { if (lua_callhook) callHook (base, LUA_T_MARK, 0); while (1) { OpCode opcode; switch (opcode = (OpCode)*pc++) { case PUSHNIL: ttype(top) = LUA_T_NIL; incr_top; break; case PUSH0: case PUSH1: case PUSH2: ttype(top) = LUA_T_NUMBER; nvalue(top) = opcode-PUSH0; incr_top; break; case PUSHBYTE: ttype(top) = LUA_T_NUMBER; nvalue(top) = *pc++; incr_top; break; case PUSHWORD: { Word w; get_word(w,pc); ttype(top) = LUA_T_NUMBER; nvalue(top) = w; incr_top; } break; case PUSHFLOAT: { real num; get_float(num,pc); ttype(top) = LUA_T_NUMBER; nvalue(top) = num; incr_top; } break; case PUSHSTRING: { Word w; get_word(w,pc); ttype(top) = LUA_T_STRING; tsvalue(top) = lua_constant[w]; incr_top; } break; case PUSHFUNCTION: { TFunc *f; get_code(f,pc); luaI_insertfunction(f); /* may take part in GC */ top->ttype = LUA_T_FUNCTION; top->value.tf = f; incr_top; } break; case PUSHLOCAL0: case PUSHLOCAL1: case PUSHLOCAL2: case PUSHLOCAL3: case PUSHLOCAL4: case PUSHLOCAL5: case PUSHLOCAL6: case PUSHLOCAL7: case PUSHLOCAL8: case PUSHLOCAL9: *top = *((stack+base) + (int)(opcode-PUSHLOCAL0)); incr_top; break; case PUSHLOCAL: *top = *((stack+base) + (*pc++)); incr_top; break; case PUSHGLOBAL: { Word w; get_word(w,pc); getglobal(w); } break; case PUSHINDEXED: pushsubscript(); break; case PUSHSELF: { TObject receiver = *(top-1); Word w; get_word(w,pc); ttype(top) = LUA_T_STRING; tsvalue(top) = lua_constant[w]; incr_top; pushsubscript(); *top = receiver; incr_top; break; } case STORELOCAL0: case STORELOCAL1: case STORELOCAL2: case STORELOCAL3: case STORELOCAL4: case STORELOCAL5: case STORELOCAL6: case STORELOCAL7: case STORELOCAL8: case STORELOCAL9: *((stack+base) + (int)(opcode-STORELOCAL0)) = *(--top); break; case STORELOCAL: *((stack+base) + (*pc++)) = *(--top); break; case STOREGLOBAL: { Word w; get_word(w,pc); setglobal(w); } break; case STOREINDEXED0: storesubscript(top-3, 1); break; case STOREINDEXED: { int n = *pc++; storesubscript(top-3-n, 2); break; } case STORELIST0: case STORELIST: { int m, n; TObject *arr; if (opcode == STORELIST0) m = 0; else m = *(pc++) * FIELDS_PER_FLUSH; n = *(pc++); arr = top-n-1; while (n) { ttype(top) = LUA_T_NUMBER; nvalue(top) = n+m; *(lua_hashdefine (avalue(arr), top)) = *(top-1); top--; n--; } } break; case STORERECORD: /* opcode obsolete: supersed by STOREMAP */ { int n = *(pc++); TObject *arr = top-n-1; while (n) { Word w; get_word(w,pc); ttype(top) = LUA_T_STRING; tsvalue(top) = lua_constant[w]; *(lua_hashdefine (avalue(arr), top)) = *(top-1); top--; n--; } } break; case STOREMAP: { int n = *(pc++); TObject *arr = top-(2*n)-1; while (n--) { *(lua_hashdefine (avalue(arr), top-2)) = *(top-1); top-=2; } } break; case ADJUST0: adjust_top(base); break; case ADJUST: { StkId newtop = base + *(pc++); adjust_top(newtop); break; } case VARARGS: adjust_varargs(base + *(pc++)); break; case CREATEARRAY: { Word size; get_word(size,pc); avalue(top) = lua_createarray(size); ttype(top) = LUA_T_ARRAY; incr_top; } break; case EQOP: { int res = lua_equalObj(top-2, top-1); --top; ttype(top-1) = res ? LUA_T_NUMBER : LUA_T_NIL; nvalue(top-1) = 1; } break; case LTOP: comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); break; case LEOP: comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE); break; case GTOP: comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT); break; case GEOP: comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE); break; case ADDOP: { TObject *l = top-2; TObject *r = top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_ADD); else { nvalue(l) += nvalue(r); --top; } } break; case SUBOP: { TObject *l = top-2; TObject *r = top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_SUB); else { nvalue(l) -= nvalue(r); --top; } } break; case MULTOP: { TObject *l = top-2; TObject *r = top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_MUL); else { nvalue(l) *= nvalue(r); --top; } } break; case DIVOP: { TObject *l = top-2; TObject *r = top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_DIV); else { nvalue(l) /= nvalue(r); --top; } } break; case POWOP: call_arith(IM_POW); break; case CONCOP: { TObject *l = top-2; TObject *r = top-1; if (tostring(l) || tostring(r)) call_binTM(IM_CONCAT, "unexpected type for concatenation"); else { tsvalue(l) = lua_createstring(lua_strconc(svalue(l),svalue(r))); --top; } } break; case MINUSOP: if (tonumber(top-1)) { ttype(top) = LUA_T_NIL; incr_top; call_arith(IM_UNM); } else nvalue(top-1) = - nvalue(top-1); break; case NOTOP: ttype(top-1) = (ttype(top-1) == LUA_T_NIL) ? LUA_T_NUMBER : LUA_T_NIL; nvalue(top-1) = 1; break; case ONTJMP: { Word w; get_word(w,pc); if (ttype(top-1) != LUA_T_NIL) pc += w; } break; case ONFJMP: { Word w; get_word(w,pc); if (ttype(top-1) == LUA_T_NIL) pc += w; } break; case JMP: { Word w; get_word(w,pc); pc += w; } break; case UPJMP: { Word w; get_word(w,pc); pc -= w; } break; case IFFJMP: { Word w; get_word(w,pc); top--; if (ttype(top) == LUA_T_NIL) pc += w; } break; case IFFUPJMP: { Word w; get_word(w,pc); top--; if (ttype(top) == LUA_T_NIL) pc -= w; } break; case POP: --top; break; case CALLFUNC: { int nParams = *(pc++); int nResults = *(pc++); StkId newBase = (top-stack)-nParams; do_call(newBase, nResults); } break; case RETCODE0: case RETCODE: if (lua_callhook) callHook (base, LUA_T_MARK, 1); return (base + ((opcode==RETCODE0) ? 0 : *pc)); case SETLINE: { Word line; get_word(line,pc); if ((stack+base-1)->ttype != LUA_T_LINE) { /* open space for LINE value */ open_stack((top-stack)-base); base++; (stack+base-1)->ttype = LUA_T_LINE; } (stack+base-1)->value.i = line; if (lua_linehook) lineHook (line); break; } default: lua_error ("internal error - opcode doesn't match"); } } }
// 已经准备好了lua函数的调用环境,开始逐句执行lua函数的指令 void luaV_execute (lua_State *L, int nexeccalls) { LClosure *cl; StkId base; TValue *k; const Instruction *pc; reentry: /* entry point */ pc = L->savedpc; //这时候已经保存了lua函数的第一个指令位置 cl = &clvalue(L->ci->func)->l; base = L->base; k = cl->p->k; /* main loop of interpreter */ for (;;) { const Instruction i = *pc++; StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L, pc); if (L->status == LUA_YIELD) { /* did hook yield? */ L->savedpc = pc - 1; return; } base = L->base; } /* warning!! several calls may realloc the stack and invalidate `ra' */ ra = RA(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)); // 阅读说明: // 每lua的一个函数在编译器会生成这个函数的信息:函数引用到的upvalue,函数固定参数 // 数量,是否含有可变参数,指令序列等等,这些都记录在Proto结构体中。 // 可以通过 luac -o tmp <luafile> | luac -l tmp 来函数对应的字节码以及Proto信息 // 例如以下lua代码: // -- t.lua // local x, y, z // x = x*y + y*z + x*z - (x*x + y*y + z*z) // 得到以下输出: // main <t.lua:0,0> (12 instructions, 48 bytes at 0074B6A0) // 0 + params, 6 slots, 0 upvalues, 3 locals, 0 constants, 0 functions // 1[2] MUL 3 0 1 // 2[2] MUL 4 1 2 // 3[2] ADD 3 3 4 // 4[2] MUL 4 0 2 // 5[2] ADD 3 3 4 // 6[2] MUL 4 0 0 // 7[2] MUL 5 1 1 // 8[2] ADD 4 4 5 // 9[2] MUL 5 2 2 // 10[2] ADD 4 4 5 // 11[2] SUB 0 3 4 // 12[2] RETURN 0 1 // 从输出可以得到的信息包括: // 1 生成了多少个Proto // 2 Proto对应的lua源代码在哪里 (<t.lua:0,0>) // 3 Proto中的sizecode (12 instructions, 48 bytes at 0074B6A0) // 4 Proto中的固定参数数量numparams (0 + params,这里的0) // 5 Proto是否有可变参数is_vararg (0 + params,这里的+表示带有可变参数,没有可变参数就是 0 params) // 6 Proto中在栈上用到的临时变量总数maxstacksize (6 slots,表示local变量+计算中辅助用的临时变量=6个) // 7 Proto中用到的upvalue数量nups (0 upvalues,表示用到了0个upvalue) // 8 Proto中用到的local变量数量sizelocvars (3 locals,刚好t.lua用到了x,y,z三个local变量) // 9 Proto中用到的字面常量数量sizek (0 constants) // 10 Proto中用到的Closure数量sizep (0 functions) // 11 Proto中生成的字节码指令内容code,每条指令包括: // a 指令下标 // b 指令在源代码中对应的行号 // c 指令opcode // d 指令参数 // // PS:第6条和第8条,由于计算一条表达式需要用到的辅助临时变量数目是不定的,但是是可以通过 // 分析一条表达式的AST来确定最少需要几个临时变量(后续遍历+逆波兰式拟真)。 // PS:lua是会对表达式进行常量计算优化的!例如 x = x + 5*60*60*1000,只有一个常量18000000 // PS:函数执行的时候需要用到“一段”参数栈上的空间,也就是第6条所谓的临时变量。这一段空间的 // 范围由L->base开始,到L->top结束。通过相对L->base的下标来标识具体的变量是哪个。一般来说, // 固定参数的函数,L->base指向第一个固定参数,而L->base-1指向当前正在运行的函数;而可变参数 // 的函数,L->base和当前正在运行的函数中间,保存有全部的传入参数。 switch (GET_OPCODE(i)) { // 功能:用一个已有的变量创建一个新的变量 // 将一个 lua_TValue设置成另一个lua_TValue的样子 // iABC: A待创建变量在参数栈索引,B参数栈已有lua变量的索引。 case OP_MOVE: { // local x, y -----> 记录 index(x) = 0, index(y) = 1 // x = ... // ..... // y = x -----> OP_MOVE: 1, 0 setobjs2s(L, ra, RB(i)); continue; } // 功能:用一个常量来创建一个新的变量 // 从常量池(保存在Proto类型中)中保存的常量赋值给栈上的变量 // iABx: A待创建变量在参数栈索引,Bx常量在常量池的索引 case OP_LOADK: { // local x = 9 -----> 记录 index(x) = 0, index(constval(9)) = 1 // >----> OP_LOADK: 0, 1 setobj2s(L, ra, KBx(i)); continue; } // 功能:用一个布尔值来创建一个新的变量 // iABC: A待创建变量在参数栈索引,B布尔值,C通常是0 case OP_LOADBOOL: { // 注意,local c = true这种,true就不作为一个常量放到k里面 // 而是作为字面值放到参数B里面了!所以不需要KB(i)! // local a = false -----> 记录 index(a) = 0 // >----> OP_LOADBOOL 0 0 0 // local b = true -----> 记录 index(b) = 1 // >----> OP_LOADBOOL 1 1 0 setbvalue(ra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ continue; } // 功能:用nil来初始化一个到多个变量 // 类似于bzero,这个指令会把一段内存中的变量置为nil // iABC: A第一个要置nil的变量参数栈索引,B最后一个要置nil的变量参数栈索引 case OP_LOADNIL: { // local a, b, c, d, e, f, g = 1, 2, 3, 4 -----> index(a~g) = 0~6 // >----> OP_LOADNIL 4 6 TValue *rb = RB(i); do { setnilvalue(rb--); } while (rb >= ra); continue; } // 功能:用upvalue来创建一个新的变量 // 所谓的“创建”操作,其实创建的不是副本而是引用 // iABC: A待创建变量在参数栈索引,B当前函数的upvalue表的索引 case OP_GETUPVAL: { // local x = {} // ... -- do something to x // function f() local a = x[1] end -----> 记录index(a) = 0, index(upval(x)) = 1 // >----> OP_GETUPVAL 0 1 int b = GETARG_B(i); setobj2s(L, ra, cl->upvals[b]->v); continue; } // 功能:从全局表中取某个key的值来创建一个新的变量 // iABx:A待创建变量在参数栈索引,Bxkey对应的常量在常量池的索引 case OP_GETGLOBAL: { // local a = dofile ------> 记录 index(a) = 0, index(constval("dofile")) = 1 // >-----> OP_GETGLOBAL 0 1 TValue g; TValue *rb = KBx(i); sethvalue(L, &g, cl->env); lua_assert(ttisstring(rb)); Protect(luaV_gettable(L, &g, rb, ra)); continue; } // 功能:从某个table中取某个key的值来创建一个新的变量 // iABC:A待创建变量在参数栈索引,B要取出key的table变量在参数栈的索引,Ckey对应的参数栈下标或者常量池下标 case OP_GETTABLE: { // local a = hello["world"] -----> 记录 index(a) = 0, index(hello) = 1 index(constval("world")) = 0 // >----> OP_GETTABLE 0 1 0|BITRK Protect(luaV_gettable(L, RB(i), RKC(i), ra)); continue; } // 功能:将参数栈上变量设置到全局表中 // iABx:A要写入全局表的变量在栈上的索引,Bx写入到全局表的key在常量池中的下标 case OP_SETGLOBAL: { // 假设我要替换 bit库 // local mybit = {} // mybit.band = ... // mybit.bor = ... // mybit.bxor = ... // ... // bit = mybit -----> 记录 index(mybit) = 0, index(constval("bit")) = 1 // >----> OP_SETGLOBAL 0 1 TValue g; sethvalue(L, &g, cl->env); lua_assert(ttisstring(KBx(i))); Protect(luaV_settable(L, &g, KBx(i), ra)); continue; } // 功能:修改upvalue的值 // iABC:A要写入upvalue的变量在参数栈上的索引,B待写入的upvalue在upvalue表的索引 case OP_SETUPVAL: { // local a = 5 // function p() // a = "hello" -----> 记录 index(upval(a)) = 0, index(constval("hello")) = 1 // >----> OP_SETUPVAL 0 1 // end UpVal *uv = cl->upvals[GETARG_B(i)]; setobj(L, uv->v, ra); luaC_barrier(L, uv, ra); continue; } // 功能:修改某个table对应的key // iABC:A要写入table变量在参数栈的索引,B要写入的key的变量的栈索引或者常量索引,C要写入的value的变量索引或者常量索引 case OP_SETTABLE: { // local a = {} // a[5] = 3 Protect(luaV_settable(L, ra, RKB(i), RKC(i))); continue; } // 功能:在栈上创建一个table变量 // iABC:A存放table变量的参数栈索引,B创建的table变量的数组容量,C创建的table变量的字典容量 case OP_NEWTABLE: { // local a = {} -----> index(a) = 0 // >----> OP_NEWTABLE 0 szArray szHash int b = GETARG_B(i); int c = GETARG_C(i); sethvalue(L, ra, luaH_new(L, luaO_fb2int(b), luaO_fb2int(c))); Protect(luaC_checkGC(L)); // 注意,创建table可能会引起GC continue; } // 功能:把self.method和self放到参数栈上相邻的两个位置。 // 为成员方法调用的语法糖提供支持 // iABC:A存放self.method的参数栈索引,B存放self的参数栈索引,C需要从self中调用的方法对应的变量索引或者常量索引 // 执行完成后,栈上内容为: ... -> self.method -> self -> ... // ^ // RA // 当然,OP_SELF之后能看到OP_CALL的身影 case OP_SELF: { // CCNode:create() -> index(constants("CCNode")) = 1, index(constants("create")) = 2 // -> OP_GETGLOBAL 0 1 // -> OP_SELF 0 0 2 // -> OP_CALL 0 2 1 StkId rb = RB(i); setobjs2s(L, ra+1, rb); Protect(luaV_gettable(L, rb, RKC(i), ra)); continue; } //---------------------------------------------------------------------------运算符指令 // 功能:实现二元运算符:+, -, *, /, %, ^ // iABC:A存放运算结果的参数栈索引,B存放第一操作数的参数栈索引,C存放第二操作数的参数栈索引 case OP_ADD: { // local a, b, c = ... -----> index(a) = 0, index(b) = 1, index(c) = 2 // a = b + c -----> OP_ADD 0 1|BITRK 2|BITRK // a = 1 + b -----> index(constval(1)) = 0 // >----> OP_ADD 0 0 1|BITRK // a = 1 + 100 -----> index(constval(1)) = 0, index(constval(100)) = 1 // >----> OP_ADD 0 0 1 arith_op(luai_numadd, TM_ADD); continue; } case OP_SUB: { // see OP_ADD arith_op(luai_numsub, TM_SUB); continue; } case OP_MUL: { // see OP_ADD arith_op(luai_nummul, TM_MUL); continue; } case OP_DIV: { // see OP_ADD arith_op(luai_numdiv, TM_DIV); continue; } case OP_MOD: { // 这个很特殊!由于lua没有整数,所以mod可不是%这个运算符! // 这里定义 mod(x, y) => (x - floor(x/y)*y) // see OP_ADD arith_op(luai_nummod, TM_MOD); continue; } case OP_POW: { // see OP_ADD arith_op(luai_numpow, TM_POW); continue; } // 功能:实现一元运算符 -, not, # // iABC:A存放运算结果的参数栈索引,B存放操作数的参数栈索引 case OP_UNM: { // local a = -b -----> index(a) = 1, index(b) = 2 // >----> OP_UNM 1 2 TValue *rb = RB(i); if (ttisnumber(rb)) { lua_Number nb = nvalue(rb); setnvalue(ra, luai_numunm(nb)); } else { Protect(Arith(L, ra, rb, rb, TM_UNM)); } continue; } case OP_NOT: { // local a = not b -----> index(a) = 1, index(b) = 2 // >----> OP_NOT 1 2 // 那local a = not true呢?人家编译期就给你处理好了 int res = l_isfalse(RB(i)); /* next assignment may change this value */ setbvalue(ra, res); continue; } case OP_LEN: { // local a = #b -----> index(a) = 1, index(b) = 2 // >----> OP_LEN 1 2 const TValue *rb = RB(i); switch (ttype(rb)) { case LUA_TTABLE: { setnvalue(ra, cast_num(luaH_getn(hvalue(rb)))); break; } case LUA_TSTRING: { setnvalue(ra, cast_num(tsvalue(rb)->len)); break; } default: { /* try metamethod */ Protect( if (!call_binTM(L, rb, luaO_nilobject, ra, TM_LEN)) luaG_typeerror(L, rb, "get length of"); ) } } continue; } // 功能:实现字符串拼接运算符 .. // iABC:A拼接后存放结果的参数栈索引,B第一个要拼接的变量的参数栈索引,C最后一个要拼接的变量的参数栈索引 // 要执行这个指令,对参数栈有特殊要求: // ... -> string1 -> string2 ... -> stringN -> ... // ^ ^ // RB RC case OP_CONCAT: { // 类似OP_LOADNIL,只不过,这次范围是[rb,rc],loadnil是[ra,rb] // local b, c, d, a = "hello", "world", "!" // a = b .. c .. d -----> index(a) = 4, index(b~d) = 1~3 // >----> OP_CONCAT 4 1 3 // 问题是如果b~d不能保证是连续的怎么办?答案是一个个MOVE上去在OP_CONCAT... int b = GETARG_B(i); int c = GETARG_C(i); Protect(luaV_concat(L, c-b+1, c); luaC_checkGC(L)); setobjs2s(L, RA(i), base+b); continue; } //---------------------------------------------------------------------------跳转指令 // 功能:无条件跳转 // iAsBx:A不使用,sBx跳转偏移 // 一般这个语句不单独出现,都是在一些条件控制中和其他的条件跳转指令配合使用的。 case OP_JMP: { // 无条件跳转指令。由于跳转偏移总是有正向和反向之分的,所以需要用到 // 负数。那就只能用iAsBx类型的指令了。而sBx是有长度限制的! // 所以,如果生成的指令很多,超过了sBx的长度限制,可能就会编译失败 dojump(L, pc, GETARG_sBx(i)); continue; } // 功能:检查两个变量是否相等,满足预期则跳转。配合OP_JMP使用。 // iABC:A纯数字,对比较结果的预期,满足预期则跳转,B参数1的索引,C参数2的索引 case OP_EQ: { // if a == b then -----> index(a) = 1, index(b) = 2 // >----> 这里将生成两行指令: // >----> OP_EQ 0 1 2 // 用0,因为成立的话跳过,不成立才执行 // >----> OP_JMP N // N 表示then ... end中间的指令数量 // >----> ... // Instructions between "then" and "end" TValue *rb = RKB(i); TValue *rc = RKC(i); Protect( if (equalobj(L, rb, rc) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } // 功能:检查两个变量是否小于,满足预期则跳转。配合OP_JMP使用。 // iABC:A纯数字,对比较结果的预期,满足预期则跳转,B参数1的索引,C参数2的索引 case OP_LT: { // if a < b then -----> index(a) = 1, index(b) = 2 // >----> 这里将生成两行指令: // >----> OP_LT 0 1 2 // 用0,因为成立的话跳过,不成立才执行 // >----> OP_JMP N // N 表示then ... end中间的指令数量 // >----> ... // Instructions between "then" and "end" Protect( if (luaV_lessthan(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; } // 功能:检查两个变量是否小于等于,满足预期则跳转。配合OP_JMP使用。 // iABC:A纯数字,对比较结果的预期,满足预期则跳转,B参数1的索引,C参数2的索引 case OP_LE: { // if a <= b then -----> index(a) = 1, index(b) = 2 // >----> 这里将生成两行指令: // >----> OP_LE 0 1 2 // 用0,因为成立的话跳过,不成立才执行 // >----> OP_JMP N // N 表示then ... end中间的指令数量 // >----> ... // Instructions between "then" and "end" Protect( if (lessequal(L, RKB(i), RKC(i)) == GETARG_A(i)) dojump(L, pc, GETARG_sBx(*pc)); ) pc++; continue; }
StkId luaV_execute(lua_Task *task) { if (!task->some_flag) { luaD_checkstack((*task->pc++) + EXTRA_STACK); if (*task->pc < ZEROVARARG) { luaD_adjusttop(task->base + *(task->pc++)); } else { luaC_checkGC(); adjust_varargs(task->base + (*task->pc++) - ZEROVARARG); } task->some_flag = 1; } lua_state->state_counter2++; while (1) { switch ((OpCode)(task->aux = *task->pc++)) { case PUSHNIL0: ttype(task->S->top++) = LUA_T_NIL; break; case PUSHNIL: task->aux = *task->pc++; do { ttype(task->S->top++) = LUA_T_NIL; } while (task->aux--); break; case PUSHNUMBER: task->aux = *task->pc++; goto pushnumber; case PUSHNUMBERW: task->aux = next_word(task->pc); goto pushnumber; case PUSHNUMBER0: case PUSHNUMBER1: case PUSHNUMBER2: task->aux -= PUSHNUMBER0; pushnumber: ttype(task->S->top) = LUA_T_NUMBER; nvalue(task->S->top) = (float)task->aux; task->S->top++; break; case PUSHLOCAL: task->aux = *task->pc++; goto pushlocal; case PUSHLOCAL0: case PUSHLOCAL1: case PUSHLOCAL2: case PUSHLOCAL3: case PUSHLOCAL4: case PUSHLOCAL5: case PUSHLOCAL6: case PUSHLOCAL7: task->aux -= PUSHLOCAL0; pushlocal: *task->S->top++ = *((task->S->stack + task->base) + task->aux); break; case GETGLOBALW: task->aux = next_word(task->pc); goto getglobal; case GETGLOBAL: task->aux = *task->pc++; goto getglobal; case GETGLOBAL0: case GETGLOBAL1: case GETGLOBAL2: case GETGLOBAL3: case GETGLOBAL4: case GETGLOBAL5: case GETGLOBAL6: case GETGLOBAL7: task->aux -= GETGLOBAL0; getglobal: luaV_getglobal(tsvalue(&task->consts[task->aux])); break; case GETTABLE: luaV_gettable(); break; case GETDOTTEDW: task->aux = next_word(task->pc); goto getdotted; case GETDOTTED: task->aux = *task->pc++; goto getdotted; case GETDOTTED0: case GETDOTTED1: case GETDOTTED2: case GETDOTTED3: case GETDOTTED4: case GETDOTTED5: case GETDOTTED6: case GETDOTTED7: task->aux -= GETDOTTED0; getdotted: *task->S->top++ = task->consts[task->aux]; luaV_gettable(); break; case PUSHSELFW: task->aux = next_word(task->pc); goto pushself; case PUSHSELF: task->aux = *task->pc++; goto pushself; case PUSHSELF0: case PUSHSELF1: case PUSHSELF2: case PUSHSELF3: case PUSHSELF4: case PUSHSELF5: case PUSHSELF6: case PUSHSELF7: task->aux -= PUSHSELF0; pushself: { TObject receiver = *(task->S->top - 1); *task->S->top++ = task->consts[task->aux]; luaV_gettable(); *task->S->top++ = receiver; break; } case PUSHCONSTANTW: task->aux = next_word(task->pc); goto pushconstant; case PUSHCONSTANT: task->aux = *task->pc++; goto pushconstant; case PUSHCONSTANT0: case PUSHCONSTANT1: case PUSHCONSTANT2: case PUSHCONSTANT3: case PUSHCONSTANT4: case PUSHCONSTANT5: case PUSHCONSTANT6: case PUSHCONSTANT7: task->aux -= PUSHCONSTANT0; pushconstant: *task->S->top++ = task->consts[task->aux]; break; case PUSHUPVALUE: task->aux = *task->pc++; goto pushupvalue; case PUSHUPVALUE0: case PUSHUPVALUE1: task->aux -= PUSHUPVALUE0; pushupvalue: *task->S->top++ = task->cl->consts[task->aux + 1]; break; case SETLOCAL: task->aux = *task->pc++; goto setlocal; case SETLOCAL0: case SETLOCAL1: case SETLOCAL2: case SETLOCAL3: case SETLOCAL4: case SETLOCAL5: case SETLOCAL6: case SETLOCAL7: task->aux -= SETLOCAL0; setlocal: *((task->S->stack + task->base) + task->aux) = *(--task->S->top); break; case SETGLOBALW: task->aux = next_word(task->pc); goto setglobal; case SETGLOBAL: task->aux = *task->pc++; goto setglobal; case SETGLOBAL0: case SETGLOBAL1: case SETGLOBAL2: case SETGLOBAL3: case SETGLOBAL4: case SETGLOBAL5: case SETGLOBAL6: case SETGLOBAL7: task->aux -= SETGLOBAL0; setglobal: luaV_setglobal(tsvalue(&task->consts[task->aux])); break; case SETTABLE0: luaV_settable(task->S->top - 3, 1); break; case SETTABLE: luaV_settable(task->S->top - 3 - (*task->pc++), 2); break; case SETLISTW: task->aux = next_word(task->pc); task->aux *= LFIELDS_PER_FLUSH; goto setlist; case SETLIST: task->aux = *(task->pc++) * LFIELDS_PER_FLUSH; goto setlist; case SETLIST0: task->aux = 0; setlist: { int32 n = *(task->pc++); TObject *arr = task->S->top - n - 1; for (; n; n--) { ttype(task->S->top) = LUA_T_NUMBER; nvalue(task->S->top) = (float)(n + task->aux); *(luaH_set(avalue(arr), task->S->top)) = *(task->S->top - 1); task->S->top--; } break; } case SETMAP0: task->aux = 0; goto setmap; case SETMAP: task->aux = *task->pc++; setmap: { TObject *arr = task->S->top - (2 * task->aux) - 3; do { *(luaH_set(avalue(arr), task->S->top - 2)) = *(task->S->top - 1); task->S->top -= 2; } while (task->aux--); break; } case POP: task->aux = *task->pc++; goto pop; case POP0: case POP1: task->aux -= POP0; pop: task->S->top -= (task->aux + 1); break; case CREATEARRAYW: task->aux = next_word(task->pc); goto createarray; case CREATEARRAY0: case CREATEARRAY1: task->aux -= CREATEARRAY0; goto createarray; case CREATEARRAY: task->aux = *task->pc++; createarray: luaC_checkGC(); avalue(task->S->top) = luaH_new(task->aux); ttype(task->S->top) = LUA_T_ARRAY; task->S->top++; break; case EQOP: case NEQOP: { int32 res = luaO_equalObj(task->S->top - 2, task->S->top - 1); task->S->top--; if (task->aux == NEQOP) res = !res; ttype(task->S->top - 1) = res ? LUA_T_NUMBER : LUA_T_NIL; nvalue(task->S->top - 1) = 1; break; } case LTOP: comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); break; case LEOP: comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE); break; case GTOP: comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT); break; case GEOP: comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE); break; case ADDOP: { TObject *l = task->S->top - 2; TObject *r = task->S->top - 1; if (tonumber(r) || tonumber(l)) call_arith(IM_ADD); else { nvalue(l) += nvalue(r); --task->S->top; } break; } case SUBOP: { TObject *l = task->S->top - 2; TObject *r = task->S->top - 1; if (tonumber(r) || tonumber(l)) call_arith(IM_SUB); else { nvalue(l) -= nvalue(r); --task->S->top; } break; } case MULTOP: { TObject *l = task->S->top - 2; TObject *r = task->S->top - 1; if (tonumber(r) || tonumber(l)) call_arith(IM_MUL); else { nvalue(l) *= nvalue(r); --task->S->top; } break; } case DIVOP: { TObject *l = task->S->top - 2; TObject *r = task->S->top - 1; if (tonumber(r) || tonumber(l)) call_arith(IM_DIV); else { nvalue(l) /= nvalue(r); --task->S->top; } break; } case POWOP: call_arith(IM_POW); break; case CONCOP: { TObject *l = task->S->top - 2; TObject *r = task->S->top - 1; if (tostring(l) || tostring(r)) call_binTM(IM_CONCAT, "unexpected type for concatenation"); else { tsvalue(l) = strconc(svalue(l), svalue(r)); --task->S->top; } luaC_checkGC(); break; } case MINUSOP: if (tonumber(task->S->top - 1)) { ttype(task->S->top) = LUA_T_NIL; task->S->top++; call_arith(IM_UNM); } else nvalue(task->S->top - 1) = -nvalue(task->S->top - 1); break; case NOTOP: ttype(task->S->top - 1) = (ttype(task->S->top - 1) == LUA_T_NIL) ? LUA_T_NUMBER : LUA_T_NIL; nvalue(task->S->top - 1) = 1; break; case ONTJMPW: task->aux = next_word(task->pc); goto ontjmp; case ONTJMP: task->aux = *task->pc++; ontjmp: if (ttype(task->S->top - 1) != LUA_T_NIL) task->pc += task->aux; else task->S->top--; break; case ONFJMPW: task->aux = next_word(task->pc); goto onfjmp; case ONFJMP: task->aux = *task->pc++; onfjmp: if (ttype(task->S->top - 1) == LUA_T_NIL) task->pc += task->aux; else task->S->top--; break; case JMPW: task->aux = next_word(task->pc); goto jmp; case JMP: task->aux = *task->pc++; jmp: task->pc += task->aux; break; case IFFJMPW: task->aux = next_word(task->pc); goto iffjmp; case IFFJMP: task->aux = *task->pc++; iffjmp: if (ttype(--task->S->top) == LUA_T_NIL) task->pc += task->aux; break; case IFTUPJMPW: task->aux = next_word(task->pc); goto iftupjmp; case IFTUPJMP: task->aux = *task->pc++; iftupjmp: if (ttype(--task->S->top) != LUA_T_NIL) task->pc -= task->aux; break; case IFFUPJMPW: task->aux = next_word(task->pc); goto iffupjmp; case IFFUPJMP: task->aux = *task->pc++; iffupjmp: if (ttype(--task->S->top) == LUA_T_NIL) task->pc -= task->aux; break; case CLOSURE: task->aux = *task->pc++; goto closure; case CLOSURE0: case CLOSURE1: task->aux -= CLOSURE0; closure: luaV_closure(task->aux); luaC_checkGC(); break; case CALLFUNC: task->aux = *task->pc++; goto callfunc; case CALLFUNC0: case CALLFUNC1: task->aux -= CALLFUNC0; callfunc: lua_state->state_counter2--; return -((task->S->top - task->S->stack) - (*task->pc++)); case ENDCODE: task->S->top = task->S->stack + task->base; // goes through case RETCODE: lua_state->state_counter2--; return (task->base + ((task->aux == 123) ? *task->pc : 0)); case SETLINEW: task->aux = next_word(task->pc); goto setline; case SETLINE: task->aux = *task->pc++; setline: if ((task->S->stack + task->base - 1)->ttype != LUA_T_LINE) { // open space for LINE value */ luaD_openstack((task->S->top - task->S->stack) - task->base); task->base++; (task->S->stack + task->base - 1)->ttype = LUA_T_LINE; } (task->S->stack + task->base - 1)->value.i = task->aux; if (lua_linehook) luaD_lineHook(task->aux); break; #ifdef LUA_DEBUG default: LUA_INTERNALERROR("internal error - opcode doesn't match"); #endif } } }
/* ** Execute the given opcode, until a RET. Parameters are between ** [stack+base,top). Returns n such that the the results are between ** [stack+n,top). */ StkId luaV_execute (struct CallInfo *ci) { /* Save index in case CallInfo array is realloc'd */ int32 ci_index = ci - L->base_ci; struct Stack *S = &L->stack; /* to optimize */ Closure *cl; TProtoFunc *tf; StkId base; Byte *pc; TObject *consts; newfunc: cl = L->ci->c; tf = L->ci->tf; base = L->ci->base; if (S->top-S->stack > base && ttype(S->stack+base) == LUA_T_LINE) base++; pc = L->ci->pc; consts = tf->consts; while (1) { int32 aux; switch ((OpCode)(aux = *pc++)) { case PUSHNIL0: ttype(S->top++) = LUA_T_NIL; break; case PUSHNIL: aux = *pc++; do { ttype(S->top++) = LUA_T_NIL; } while (aux--); break; case PUSHNUMBER: aux = *pc++; goto pushnumber; case PUSHNUMBERW: aux = next_word(pc); goto pushnumber; case PUSHNUMBER0: case PUSHNUMBER1: case PUSHNUMBER2: aux -= PUSHNUMBER0; pushnumber: ttype(S->top) = LUA_T_NUMBER; nvalue(S->top) = (real)aux; S->top++; break; case PUSHLOCAL: aux = *pc++; goto pushlocal; case PUSHLOCAL0: case PUSHLOCAL1: case PUSHLOCAL2: case PUSHLOCAL3: case PUSHLOCAL4: case PUSHLOCAL5: case PUSHLOCAL6: case PUSHLOCAL7: aux -= PUSHLOCAL0; pushlocal: *S->top++ = *((S->stack+base) + aux); break; case GETGLOBALW: aux = next_word(pc); goto getglobal; case GETGLOBAL: aux = *pc++; goto getglobal; case GETGLOBAL0: case GETGLOBAL1: case GETGLOBAL2: case GETGLOBAL3: case GETGLOBAL4: case GETGLOBAL5: case GETGLOBAL6: case GETGLOBAL7: aux -= GETGLOBAL0; getglobal: luaV_getglobal(tsvalue(&consts[aux])); break; case GETTABLE: luaV_gettable(); break; case GETDOTTEDW: aux = next_word(pc); goto getdotted; case GETDOTTED: aux = *pc++; goto getdotted; case GETDOTTED0: case GETDOTTED1: case GETDOTTED2: case GETDOTTED3: case GETDOTTED4: case GETDOTTED5: case GETDOTTED6: case GETDOTTED7: aux -= GETDOTTED0; getdotted: *S->top++ = consts[aux]; luaV_gettable(); break; case PUSHSELFW: aux = next_word(pc); goto pushself; case PUSHSELF: aux = *pc++; goto pushself; case PUSHSELF0: case PUSHSELF1: case PUSHSELF2: case PUSHSELF3: case PUSHSELF4: case PUSHSELF5: case PUSHSELF6: case PUSHSELF7: aux -= PUSHSELF0; pushself: { TObject receiver = *(S->top-1); *S->top++ = consts[aux]; luaV_gettable(); *S->top++ = receiver; break; } case PUSHCONSTANTW: aux = next_word(pc); goto pushconstant; case PUSHCONSTANT: aux = *pc++; goto pushconstant; case PUSHCONSTANT0: case PUSHCONSTANT1: case PUSHCONSTANT2: case PUSHCONSTANT3: case PUSHCONSTANT4: case PUSHCONSTANT5: case PUSHCONSTANT6: case PUSHCONSTANT7: aux -= PUSHCONSTANT0; pushconstant: *S->top++ = consts[aux]; break; case PUSHUPVALUE: aux = *pc++; goto pushupvalue; case PUSHUPVALUE0: case PUSHUPVALUE1: aux -= PUSHUPVALUE0; pushupvalue: *S->top++ = cl->consts[aux+1]; break; case SETLOCAL: aux = *pc++; goto setlocal; case SETLOCAL0: case SETLOCAL1: case SETLOCAL2: case SETLOCAL3: case SETLOCAL4: case SETLOCAL5: case SETLOCAL6: case SETLOCAL7: aux -= SETLOCAL0; setlocal: *((S->stack+base) + aux) = *(--S->top); break; case SETGLOBALW: aux = next_word(pc); goto setglobal; case SETGLOBAL: aux = *pc++; goto setglobal; case SETGLOBAL0: case SETGLOBAL1: case SETGLOBAL2: case SETGLOBAL3: case SETGLOBAL4: case SETGLOBAL5: case SETGLOBAL6: case SETGLOBAL7: aux -= SETGLOBAL0; setglobal: luaV_setglobal(tsvalue(&consts[aux])); break; case SETTABLE0: luaV_settable(S->top-3, 1); break; case SETTABLE: luaV_settable(S->top-3-(*pc++), 2); break; case SETLISTW: aux = next_word(pc); aux *= LFIELDS_PER_FLUSH; goto setlist; case SETLIST: aux = *(pc++) * LFIELDS_PER_FLUSH; goto setlist; case SETLIST0: aux = 0; setlist: { int32 n = *(pc++); TObject *arr = S->top-n-1; for (; n; n--) { ttype(S->top) = LUA_T_NUMBER; nvalue(S->top) = (real)(n+aux); *(luaH_set(avalue(arr), S->top)) = *(S->top-1); S->top--; } break; } case SETMAP0: aux = 0; goto setmap; case SETMAP: aux = *pc++; setmap: { TObject *arr = S->top-(2*aux)-3; do { *(luaH_set(avalue(arr), S->top-2)) = *(S->top-1); S->top-=2; } while (aux--); break; } case POP: aux = *pc++; goto pop; case POP0: case POP1: aux -= POP0; pop: S->top -= (aux+1); break; case CREATEARRAYW: aux = next_word(pc); goto createarray; case CREATEARRAY0: case CREATEARRAY1: aux -= CREATEARRAY0; goto createarray; case CREATEARRAY: aux = *pc++; createarray: luaC_checkGC(); avalue(S->top) = luaH_new(aux); ttype(S->top) = LUA_T_ARRAY; S->top++; break; case EQOP: case NEQOP: { int32 res = luaO_equalObj(S->top-2, S->top-1); S->top--; if (aux == NEQOP) res = !res; ttype(S->top-1) = res ? LUA_T_NUMBER : LUA_T_NIL; nvalue(S->top-1) = 1; break; } case LTOP: comparison(LUA_T_NUMBER, LUA_T_NIL, LUA_T_NIL, IM_LT); break; case LEOP: comparison(LUA_T_NUMBER, LUA_T_NUMBER, LUA_T_NIL, IM_LE); break; case GTOP: comparison(LUA_T_NIL, LUA_T_NIL, LUA_T_NUMBER, IM_GT); break; case GEOP: comparison(LUA_T_NIL, LUA_T_NUMBER, LUA_T_NUMBER, IM_GE); break; case ADDOP: { TObject *l = S->top-2; TObject *r = S->top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_ADD); else { nvalue(l) += nvalue(r); --S->top; } break; } case SUBOP: { TObject *l = S->top-2; TObject *r = S->top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_SUB); else { nvalue(l) -= nvalue(r); --S->top; } break; } case MULTOP: { TObject *l = S->top-2; TObject *r = S->top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_MUL); else { nvalue(l) *= nvalue(r); --S->top; } break; } case DIVOP: { TObject *l = S->top-2; TObject *r = S->top-1; if (tonumber(r) || tonumber(l)) call_arith(IM_DIV); else { nvalue(l) /= nvalue(r); --S->top; } break; } case POWOP: call_binTM(IM_POW, "undefined operation"); break; case CONCOP: { TObject *l = S->top-2; TObject *r = S->top-1; if (tostring(l) || tostring(r)) call_binTM(IM_CONCAT, "unexpected type for concatenation"); else { tsvalue(l) = strconc(tsvalue(l), tsvalue(r)); --S->top; } luaC_checkGC(); break; } case MINUSOP: if (tonumber(S->top-1)) { ttype(S->top) = LUA_T_NIL; S->top++; call_arith(IM_UNM); } else nvalue(S->top-1) = - nvalue(S->top-1); break; case NOTOP: ttype(S->top-1) = (ttype(S->top-1) == LUA_T_NIL) ? LUA_T_NUMBER : LUA_T_NIL; nvalue(S->top-1) = 1; break; case ONTJMPW: aux = next_word(pc); goto ontjmp; case ONTJMP: aux = *pc++; ontjmp: if (ttype(S->top-1) != LUA_T_NIL) pc += aux; else S->top--; break; case ONFJMPW: aux = next_word(pc); goto onfjmp; case ONFJMP: aux = *pc++; onfjmp: if (ttype(S->top-1) == LUA_T_NIL) pc += aux; else S->top--; break; case JMPW: aux = next_word(pc); goto jmp; case JMP: aux = *pc++; jmp: pc += aux; break; case IFFJMPW: aux = next_word(pc); goto iffjmp; case IFFJMP: aux = *pc++; iffjmp: if (ttype(--S->top) == LUA_T_NIL) pc += aux; break; case IFTUPJMPW: aux = next_word(pc); goto iftupjmp; case IFTUPJMP: aux = *pc++; iftupjmp: if (ttype(--S->top) != LUA_T_NIL) pc -= aux; break; case IFFUPJMPW: aux = next_word(pc); goto iffupjmp; case IFFUPJMP: aux = *pc++; iffupjmp: if (ttype(--S->top) == LUA_T_NIL) pc -= aux; break; case CLOSURE: aux = *pc++; goto closure; case CLOSURE0: aux = 0; goto closure; case CLOSURE1: aux = 1; closure: luaV_closure(aux); luaC_checkGC(); break; case CALLFUNC: aux = *pc++; goto callfunc; case CALLFUNC0: case CALLFUNC1: aux -= CALLFUNC0; callfunc: { StkId newBase = (S->top-S->stack)-(*pc++); TObject *func = S->stack+newBase-1; L->ci->pc = pc; if (ttype(func) == LUA_T_PROTO || (ttype(func) == LUA_T_CLOSURE && ttype(&clvalue(func)->consts[0]) == LUA_T_PROTO)) { /* Calling another Lua function */ luaD_precall(func, newBase, aux); ttype(func) = (ttype(func) == LUA_T_PROTO) ? LUA_T_PMARK : LUA_T_CLMARK; goto newfunc; } luaD_call(newBase, aux); if (L->Tstate != RUN) { if (ci_index > 1) /* C functions detected by break_here */ lua_error("Cannot yield through method call"); return -1; } break; } case ENDCODE: S->top = S->stack + base; /* goes through */ case RETCODE: { StkId firstResult = (base + ((aux==RETCODE) ? *pc : 0)); if (lua_callhook) luaD_callHook(base, NULL, 1); /* If returning from the original stack frame, terminate */ if (L->ci == L->base_ci + ci_index) return firstResult; luaD_postret(firstResult); goto newfunc; } case SETLINEW: aux = next_word(pc); goto setline; case SETLINE: aux = *pc++; setline: if ((S->stack+base-1)->ttype != LUA_T_LINE) { /* open space for LINE value */ luaD_openstack((S->top-S->stack)-base); base++; (S->stack+base-1)->ttype = LUA_T_LINE; } (S->stack+base-1)->value.i = aux; if (lua_linehook) luaD_lineHook(aux); break; #ifdef DEBUG default: LUA_INTERNALERROR("opcode doesn't match"); #endif } } }