diff --git a/bugs b/bugs index f3caeec23d..d796facb38 100644 --- a/bugs +++ b/bugs @@ -3680,9 +3680,9 @@ It needs an "interceptor" 'memcmp' function that continues reading memory after a difference is found.]], patch = [[ 2c2 -< ** $Id: bugs,v 1.156 2017/08/12 13:12:42 roberto Exp roberto $ +< ** $Id: bugs,v 1.158 2017/12/06 18:20:28 roberto Exp roberto $ --- -> ** $Id: bugs,v 1.156 2017/08/12 13:12:42 roberto Exp roberto $ +> ** $Id: bugs,v 1.158 2017/12/06 18:20:28 roberto Exp roberto $ 263c263,264 < for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) { --- @@ -3871,6 +3871,64 @@ patch = [[ } +Bug{ +what = [['lua_pushcclosure' should not call the garbage collector when +'n' is zero.]], +report = [[Andrew Gierth, 2017/12/05]], +since = [[5.3.3]], +fix = nil, +example = [[ ]], +patch = [[ +--- lapi.c 2017/04/19 17:13:00 2.259.1.1 ++++ lapi.c 2017/12/06 18:14:45 +@@ -533,6 +533,7 @@ + lua_lock(L); + if (n == 0) { + setfvalue(L->top, fn); ++ api_incr_top(L); + } + else { + CClosure *cl; +@@ -546,9 +547,9 @@ + /* does not need barrier because closure is white */ + } + setclCvalue(L, L->top, cl); ++ api_incr_top(L); ++ luaC_checkGC(L); + } +- api_incr_top(L); +- luaC_checkGC(L); + lua_unlock(L); + } +]] +} + + +Bug{ +what = [[memory-allocation error when resizing a table can leave it +in an inconsistent state.]], +report = [[Roberto, 2017/12/08]], +since = [[5.0]], +fix = nil, +example = [[ +local a = {x = 1, y = 1, z = 1} +a[1] = 10 -- goes to the hash part (which has 4 slots) +print(a[1]) --> 10 + +-- assume that the 2nd memory allocation from now fails +pcall(rawset, a, 2, 20) -- forces a rehash + +-- a[1] now exists both in the array part (because the array part +-- grew) and in the hash part (because the allocation of the hash +-- part failed, keeping it as it was). +-- This makes the following traversal goes forever... +for k,v in pairs(a) do print(k,v) end +]], +patch = [[ +]] +} + + --[=[ diff --git a/lapi.c b/lapi.c index 1c1e8f9e1b..d6aaf8a873 100644 --- a/lapi.c +++ b/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.273 2017/11/02 11:28:56 roberto Exp $ +** $Id: lapi.c,v 2.278 2017/12/06 18:08:03 roberto Exp roberto $ ** Lua API ** See Copyright Notice in lua.h */ @@ -99,16 +99,6 @@ static StkId index2stack (lua_State *L, int idx) { } -/* -** to be called by 'lua_checkstack' in protected mode, to grow stack -** capturing memory errors -*/ -static void growstack (lua_State *L, void *ud) { - int size = *(int *)ud; - luaD_growstack(L, size); -} - - LUA_API int lua_checkstack (lua_State *L, int n) { int res; CallInfo *ci = L->ci; @@ -121,7 +111,7 @@ LUA_API int lua_checkstack (lua_State *L, int n) { if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */ res = 0; /* no */ else /* try to grow stack */ - res = (luaD_rawrunprotected(L, &growstack, &n) == LUA_OK); + res = luaD_growstack(L, n, 0); } if (res && ci->top < L->top + n) ci->top = L->top + n; /* adjust frame top */ @@ -205,7 +195,7 @@ LUA_API void lua_settop (lua_State *L, int idx) { ** Reverse the stack segment from 'from' to 'to' ** (auxiliary to 'lua_rotate') ** Note that we move(copy) only the value inside the stack. -** (We do not move addicional fields that may exist.) +** (We do not move additional fields that may exist.) */ static void reverse (lua_State *L, StkId from, StkId to) { for (; from < to; from++, to--) { @@ -550,6 +540,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { lua_lock(L); if (n == 0) { setfvalue(s2v(L->top), fn); + api_incr_top(L); } else { CClosure *cl; @@ -563,9 +554,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { /* does not need barrier because closure is white */ } setclCvalue(L, s2v(L->top), cl); + api_incr_top(L); + luaC_checkGC(L); } - api_incr_top(L); - luaC_checkGC(L); lua_unlock(L); } diff --git a/lcode.c b/lcode.c index f2c9de7b7c..1eae475ab9 100644 --- a/lcode.c +++ b/lcode.c @@ -1,5 +1,5 @@ /* -** $Id: lcode.c,v 2.134 2017/11/22 18:41:20 roberto Exp roberto $ +** $Id: lcode.c,v 2.147 2017/12/22 14:16:46 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -108,7 +108,7 @@ static void fixjump (FuncState *fs, int pc, int dest) { Instruction *jmp = &fs->f->code[pc]; int offset = dest - (pc + 1); lua_assert(dest != NO_JUMP); - if (abs(offset) > MAXARG_sJ) + if (!(-OFFSET_sJ <= offset && offset <= MAXARG_sJ - OFFSET_sJ)) luaX_syntaxerror(fs->ls, "control structure too long"); lua_assert(GET_OPCODE(*jmp) == OP_JMP); SETARG_sJ(*jmp, offset); @@ -134,17 +134,10 @@ void luaK_concat (FuncState *fs, int *l1, int l2) { /* ** Create a jump instruction and return its position, so its destination -** can be fixed later (with 'fixjump'). If there are jumps to -** this position (kept in 'jpc'), link them all together so that -** 'patchlistaux' will fix all them directly to the final destination. +** can be fixed later (with 'fixjump'). */ int luaK_jump (FuncState *fs) { - int jpc = fs->jpc; /* save list of jumps to here */ - int j; - fs->jpc = NO_JUMP; /* no more jumps to here */ - j = codesJ(fs, OP_JMP, NO_JUMP, 0); - luaK_concat(fs, &j, jpc); /* keep them on hold */ - return j; + return codesJ(fs, OP_JMP, NO_JUMP, 0); } @@ -152,7 +145,17 @@ int luaK_jump (FuncState *fs) { ** Code a 'return' instruction */ void luaK_ret (FuncState *fs, int first, int nret) { - luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); + switch (nret) { + case 0: + luaK_codeABC(fs, OP_RETURN0, 0, 0, 0); + break; + case 1: + luaK_codeABC(fs, OP_RETURN1, first, 0, 0); + break; + default: + luaK_codeABC(fs, OP_RETURN, first, nret + 1, 0); + break; + } } @@ -160,8 +163,8 @@ void luaK_ret (FuncState *fs, int first, int nret) { ** Code a "conditional jump", that is, a test or comparison opcode ** followed by a jump. Return jump position. */ -static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { - luaK_codeABC(fs, op, A, B, C); +static int condjump (FuncState *fs, OpCode op, int A, int B, int C, int k) { + luaK_codeABCk(fs, op, A, B, C, k); return luaK_jump(fs); } @@ -206,7 +209,7 @@ static int patchtestreg (FuncState *fs, int node, int reg) { else { /* no register to put value or register already has the value; change instruction to simple test */ - *i = CREATE_ABCk(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i), 0); + *i = CREATE_ABCk(OP_TEST, GETARG_B(*i), 0, 0, GETARG_k(*i)); } return 1; } @@ -239,51 +242,20 @@ static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, } -/* -** Ensure all pending jumps to current position are fixed (jumping -** to current position with no values) and reset list of pending -** jumps -*/ -static void dischargejpc (FuncState *fs) { - patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); - fs->jpc = NO_JUMP; -} - - -/* -** Add elements in 'list' to list of pending jumps to "here" -** (current position) -*/ -void luaK_patchtohere (FuncState *fs, int list) { - luaK_getlabel(fs); /* mark "here" as a jump target */ - luaK_concat(fs, &fs->jpc, list); -} - - /* ** Path all jumps in 'list' to jump to 'target'. ** (The assert means that we cannot fix a jump to a forward address ** because we only know addresses once code is generated.) */ void luaK_patchlist (FuncState *fs, int list, int target) { - if (target == fs->pc) /* 'target' is current position? */ - luaK_patchtohere(fs, list); /* add list to pending jumps */ - else { - lua_assert(target < fs->pc); - patchlistaux(fs, list, target, NO_REG, target); - } + lua_assert(target <= fs->pc); + patchlistaux(fs, list, target, NO_REG, target); } -/* -** Check whether some jump in given list needs a close instruction. -*/ -int luaK_needclose (FuncState *fs, int list) { - for (; list != NO_JUMP; list = getjump(fs, list)) { - if (GETARG_A(fs->f->code[list])) /* needs close? */ - return 1; - } - return 0; +void luaK_patchtohere (FuncState *fs, int list) { + int hr = luaK_getlabel(fs); /* mark "here" as a jump target */ + luaK_patchlist(fs, list, hr); } @@ -355,7 +327,6 @@ static void savelineinfo (FuncState *fs, Proto *f, int pc, int line) { */ static int luaK_code (FuncState *fs, Instruction i) { Proto *f = fs->f; - dischargejpc(fs); /* 'pc' will change */ /* put new instruction in code array */ luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction, MAX_INT, "opcodes"); @@ -377,7 +348,7 @@ int luaK_codeABCk (FuncState *fs, OpCode o, int a, int b, int c, int k) { } -#define codeABsC(fs,o,a,b,c,k) luaK_codeABCk(fs,o,a,b,((c) + MAXARG_sC),k) +#define codeABsC(fs,o,a,b,c,k) luaK_codeABCk(fs,o,a,b,((c) + OFFSET_sC),k) @@ -395,7 +366,7 @@ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { ** Format and emit an 'iAsBx' instruction. */ int luaK_codeAsBx (FuncState *fs, OpCode o, int a, int bc) { - unsigned int b = bc + MAXARG_sBx; + unsigned int b = bc + OFFSET_sBx; lua_assert(getOpMode(o) == iAsBx); lua_assert(a <= MAXARG_A && b <= MAXARG_Bx); return luaK_code(fs, CREATE_ABx(o, a, b)); @@ -406,7 +377,7 @@ int luaK_codeAsBx (FuncState *fs, OpCode o, int a, int bc) { ** Format and emit an 'isJ' instruction. */ static int codesJ (FuncState *fs, OpCode o, int sj, int k) { - unsigned int j = sj + MAXARG_sJ; + unsigned int j = sj + OFFSET_sJ; lua_assert(getOpMode(o) == isJ); lua_assert(j <= MAXARG_sJ && (k & ~1) == 0); return luaK_code(fs, CREATE_sJ(o, j, k)); @@ -599,8 +570,26 @@ static int nilK (FuncState *fs) { } +/* +** Check whether 'i' can be stored in an 'sC' operand. +** Equivalent to (0 <= i + OFFSET_sC && i + OFFSET_sC <= MAXARG_C) +** but without risk of overflows in the addition. +*/ +static int fitsC (lua_Integer i) { + return (-OFFSET_sC <= i && i <= MAXARG_C - OFFSET_sC); +} + + +/* +** Check whether 'i' can be stored in an 'sBx' operand. +*/ +static int fitsBx (lua_Integer i) { + return (-OFFSET_sBx <= i && i <= MAXARG_Bx - OFFSET_sBx); +} + + void luaK_int (FuncState *fs, int reg, lua_Integer i) { - if (l_castS2U(i) + MAXARG_sBx <= l_castS2U(MAXARG_Bx)) + if (fitsBx(i)) luaK_codeAsBx(fs, OP_LOADI, reg, cast_int(i)); else luaK_codek(fs, reg, luaK_intK(fs, i)); @@ -610,8 +599,7 @@ void luaK_int (FuncState *fs, int reg, lua_Integer i) { static int floatI (lua_Number f, lua_Integer *fi) { TValue v; setfltvalue(&v, f); - return (luaV_flttointeger(&v, fi, 0) && - l_castS2U(*fi) + MAXARG_sBx <= l_castS2U(MAXARG_Bx)); + return (luaV_flttointeger(&v, fi, 0) && fitsBx(*fi)); } @@ -630,12 +618,11 @@ static void luaK_float (FuncState *fs, int reg, lua_Number f) { ** or 'nresults' is LUA_MULTRET (as any expression can satisfy that). */ void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { - if (e->k == VCALL) { /* expression is an open function call? */ - SETARG_C(getinstruction(fs, e), nresults + 1); - } + Instruction *pc = &getinstruction(fs, e); + if (e->k == VCALL) /* expression is an open function call? */ + SETARG_C(*pc, nresults + 1); else if (e->k == VVARARG) { - Instruction *pc = &getinstruction(fs, e); - SETARG_B(*pc, nresults + 1); + SETARG_C(*pc, nresults + 1); SETARG_A(*pc, fs->freereg); luaK_reserveregs(fs, 1); } @@ -649,7 +636,7 @@ void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { ** vararg), it already returns one result, so nothing needs to be done. ** Function calls become VNONRELOC expressions (as its result comes ** fixed in the base register of the call), while vararg expressions -** become VRELOCABLE (as OP_VARARG puts its results where it wants). +** become VRELOC (as OP_VARARG puts its results where it wants). ** (Calls are created returning one result, so that does not need ** to be fixed.) */ @@ -661,8 +648,8 @@ void luaK_setoneret (FuncState *fs, expdesc *e) { e->u.info = GETARG_A(getinstruction(fs, e)); } else if (e->k == VVARARG) { - SETARG_B(getinstruction(fs, e), 2); - e->k = VRELOCABLE; /* can relocate its simple result */ + SETARG_C(getinstruction(fs, e), 2); + e->k = VRELOC; /* can relocate its simple result */ } } @@ -678,30 +665,30 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { } case VUPVAL: { /* move value to some (pending) register */ e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); - e->k = VRELOCABLE; + e->k = VRELOC; break; } case VINDEXUP: { e->u.info = luaK_codeABC(fs, OP_GETTABUP, 0, e->u.ind.t, e->u.ind.idx); - e->k = VRELOCABLE; + e->k = VRELOC; break; } case VINDEXI: { freereg(fs, e->u.ind.t); e->u.info = luaK_codeABC(fs, OP_GETI, 0, e->u.ind.t, e->u.ind.idx); - e->k = VRELOCABLE; + e->k = VRELOC; break; } case VINDEXSTR: { freereg(fs, e->u.ind.t); e->u.info = luaK_codeABC(fs, OP_GETFIELD, 0, e->u.ind.t, e->u.ind.idx); - e->k = VRELOCABLE; + e->k = VRELOC; break; } case VINDEXED: { freeregs(fs, e->u.ind.t, e->u.ind.idx); e->u.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.ind.t, e->u.ind.idx); - e->k = VRELOCABLE; + e->k = VRELOC; break; } case VVARARG: case VCALL: { @@ -740,7 +727,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { luaK_int(fs, reg, e->u.ival); break; } - case VRELOCABLE: { + case VRELOC: { Instruction *pc = &getinstruction(fs, e); SETARG_A(*pc, reg); /* instruction will put result in 'reg' */ break; @@ -969,7 +956,7 @@ static void negatecondition (FuncState *fs, expdesc *e) { Instruction *pc = getjumpcontrol(fs, e->u.info); lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && GET_OPCODE(*pc) != OP_TEST); - SETARG_B(*pc, !(GETARG_B(*pc))); + SETARG_k(*pc, (GETARG_k(*pc) ^ 1)); } @@ -980,17 +967,17 @@ static void negatecondition (FuncState *fs, expdesc *e) { ** and removing the 'not'. */ static int jumponcond (FuncState *fs, expdesc *e, int cond) { - if (e->k == VRELOCABLE) { + if (e->k == VRELOC) { Instruction ie = getinstruction(fs, e); if (GET_OPCODE(ie) == OP_NOT) { fs->pc--; /* remove previous OP_NOT */ - return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); + return condjump(fs, OP_TEST, GETARG_B(ie), 0, 0, !cond); } /* else go through */ } discharge2anyreg(fs, e); freeexp(fs, e); - return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond); + return condjump(fs, OP_TESTSET, NO_REG, e->u.info, 0, cond); } @@ -1065,12 +1052,12 @@ static void codenot (FuncState *fs, expdesc *e) { negatecondition(fs, e); break; } - case VRELOCABLE: + case VRELOC: case VNONRELOC: { discharge2anyreg(fs, e); freeexp(fs, e); e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0); - e->k = VRELOCABLE; + e->k = VRELOC; break; } default: lua_assert(0); /* cannot happen */ @@ -1090,14 +1077,20 @@ static int isKstr (FuncState *fs, expdesc *e) { ttisshrstring(&fs->f->k[e->u.info])); } +/* +** Check whether expression 'e' is a literal integer. +*/ +int luaK_isKint (expdesc *e) { + return (e->k == VKINT && !hasjumps(e)); +} + /* ** Check whether expression 'e' is a literal integer in ** proper range to fit in register C */ static int isCint (expdesc *e) { - return (e->k == VKINT && !hasjumps(e) && - l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C)); + return luaK_isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C)); } @@ -1106,8 +1099,7 @@ static int isCint (expdesc *e) { ** proper range to fit in register sC */ static int isSCint (expdesc *e) { - return (e->k == VKINT && !hasjumps(e) && - l_castS2U(e->u.ival + MAXARG_sC) <= l_castS2U(MAXARG_C)); + return luaK_isKint(e) && fitsC(e->u.ival); } @@ -1120,8 +1112,12 @@ static int isSCnumber (expdesc *e, lua_Integer *i) { *i = e->u.ival; else if (!(e->k == VKFLT && floatI(e->u.nval, i))) return 0; /* not a number */ - *i += MAXARG_sC; - return (!hasjumps(e) && l_castS2U(*i) <= l_castS2U(MAXARG_C)); + if (!hasjumps(e) && fitsC(*i)) { + *i += OFFSET_sC; + return 1; + } + else + return 0; } @@ -1145,7 +1141,7 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { t->k = VINDEXSTR; } else if (isCint(k)) { - t->u.ind.idx = k->u.ival; /* integer constant */ + t->u.ind.idx = cast_int(k->u.ival); /* integer constant in proper range */ t->k = VINDEXI; } else { @@ -1208,7 +1204,16 @@ static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ freeexp(fs, e); e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ - e->k = VRELOCABLE; /* all those operations are relocatable */ + e->k = VRELOC; /* all those operations are relocatable */ + luaK_fixline(fs, line); +} + + +static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2, + int pc, int line) { + freeexps(fs, e1, e2); + e1->u.info = pc; + e1->k = VRELOC; /* all those operations are relocatable */ luaK_fixline(fs, line); } @@ -1226,10 +1231,20 @@ static void codebinexpval (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2, int line) { int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */ int v1 = luaK_exp2anyreg(fs, e1); - freeexps(fs, e1, e2); - e1->u.info = luaK_codeABC(fs, op, 0, v1, v2); /* generate opcode */ - e1->k = VRELOCABLE; /* all those operations are relocatable */ - luaK_fixline(fs, line); + int pc = luaK_codeABC(fs, op, 0, v1, v2); /* generate opcode */ + finishbinexpval(fs, e1, e2, pc, line); +} + + +/* +** Code binary operators ('+', '-', ...) with immediate operands. +*/ +static void codebini (FuncState *fs, OpCode op, + expdesc *e1, expdesc *e2, int k, int line) { + int v2 = cast_int(e2->u.ival); /* immediate operand */ + int v1 = luaK_exp2anyreg(fs, e1); + int pc = codeABsC(fs, op, 0, v1, v2, k); /* generate opcode */ + finishbinexpval(fs, e1, e2, pc, line); } @@ -1242,15 +1257,8 @@ static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2, int flip, int line) { if (!isSCint(e2)) codebinexpval(fs, op, e1, e2, line); /* use standard operators */ - else { /* use immediate operators */ - int v2 = cast_int(e2->u.ival); /* immediate operand */ - int v1 = luaK_exp2anyreg(fs, e1); - op = cast(OpCode, op - OP_ADD + OP_ADDI); - freeexp(fs, e1); - e1->u.info = codeABsC(fs, op, 0, v1, v2, flip); /* generate opcode */ - e1->k = VRELOCABLE; /* all those operations are relocatable */ - luaK_fixline(fs, line); - } + else /* use immediate operators */ + codebini(fs, cast(OpCode, op - OP_ADD + OP_ADDI), e1, e2, flip, line); } @@ -1275,26 +1283,84 @@ static void codecommutative (FuncState *fs, OpCode op, /* -** Emit code for order comparisons. -** 'e1' was already put in register by 'luaK_infix'. +** Code bitwise operations; they are all associative, so the function +** tries to put an integer constant as the 2nd operand (a K operand). */ -static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { - int rk1 = check_exp(e1->k == VNONRELOC, e1->u.info); - int rk2 = luaK_exp2anyreg(fs, e2); - freeexps(fs, e1, e2); - switch (opr) { - case OPR_GT: case OPR_GE: { - /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */ - OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); - e1->u.info = condjump(fs, op, rk2, 1, rk1); /* invert operands */ - break; - } - default: { /* '==', '<', '<=' use their own opcodes */ - OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); - e1->u.info = condjump(fs, op, rk1, 1, rk2); - break; +static void codebitwise (FuncState *fs, BinOpr opr, + expdesc *e1, expdesc *e2, int line) { + int inv = 0; + int v1, v2, pc; + OpCode op; + if (e1->k == VKINT && luaK_exp2RK(fs, e1)) { + swapexps(e1, e2); /* 'e2' will be the constant operand */ + inv = 1; + } + else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */ + op = cast(OpCode, opr - OPR_BAND + OP_BAND); + codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */ + return; + } + v1 = luaK_exp2anyreg(fs, e1); + v2 = e2->u.info; /* index in K array */ + op = cast(OpCode, opr - OPR_BAND + OP_BANDK); + lua_assert(ttisinteger(&fs->f->k[v2])); + pc = luaK_codeABCk(fs, op, 0, v1, v2, inv); + finishbinexpval(fs, e1, e2, pc, line); +} + + +/* +** Code shift operators. If second operand is constant, use immediate +** operand (negating it if shift is in the other direction). +*/ +static void codeshift (FuncState *fs, OpCode op, + expdesc *e1, expdesc *e2, int line) { + if (isSCint(e2)) { + int changedir = 0; + if (op == OP_SHL) { + changedir = 1; + e2->u.ival = -(e2->u.ival); } + codebini(fs, OP_SHRI, e1, e2, changedir, line); } + else + codebinexpval(fs, op, e1, e2, line); +} + + +/* +** Emit code for order comparisons. +** When the first operand is an integral value in the proper range, +** change (A < B) to (!(B <= A)) and (A <= B) to (!(B < A)) so that +** it can use an immediate operand. In this case, C indicates this +** change, for cases that cannot assume a total order (NaN and +** metamethods). +*/ +static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { + int r1, r2; + int cond = 1; + int C = 0; + lua_Integer im; + if (isSCnumber(e2, &im)) { + /* use immediate operand */ + r1 = luaK_exp2anyreg(fs, e1); + r2 = cast_int(im); + op = cast(OpCode, (op - OP_LT) + OP_LTI); + } + else if (isSCnumber(e1, &im)) { + /* transform (A < B) to (!(B <= A)) and (A <= B) to (!(B < A)) */ + r1 = luaK_exp2anyreg(fs, e2); + r2 = cast_int(im); + op = (op == OP_LT) ? OP_LEI : OP_LTI; + cond = 0; /* negate original test */ + C = 1; /* indication that it used the transformations */ + } + else { /* regular case, compare two registers */ + r1 = luaK_exp2anyreg(fs, e1); + r2 = luaK_exp2anyreg(fs, e2); + } + freeexps(fs, e1, e2); + e1->u.info = condjump(fs, op, r1, r2, C, cond); e1->k = VJMP; } @@ -1325,13 +1391,13 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { r2 = luaK_exp2anyreg(fs, e2); } freeexps(fs, e1, e2); - e1->u.info = condjump(fs, op, r1, (opr == OPR_EQ), r2); + e1->u.info = condjump(fs, op, r1, r2, 0, (opr == OPR_EQ)); e1->k = VJMP; } /* -** Aplly prefix operation 'op' to expression 'e'. +** Apply prefix operation 'op' to expression 'e'. */ void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; @@ -1385,7 +1451,10 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { } case OPR_LT: case OPR_LE: case OPR_GT: case OPR_GE: { - luaK_exp2anyreg(fs, v); + lua_Integer dummy; + if (!isSCnumber(v, &dummy)) + luaK_exp2anyreg(fs, v); + /* else keep numeral, which may be an immediate operand */ break; } default: lua_assert(0); @@ -1399,9 +1468,9 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { ** concatenation is right associative), merge second CONCAT into first ** one. */ -void luaK_posfix (FuncState *fs, BinOpr op, +void luaK_posfix (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2, int line) { - switch (op) { + switch (opr) { case OPR_AND: { lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */ luaK_dischargevars(fs, e2); @@ -1418,12 +1487,12 @@ void luaK_posfix (FuncState *fs, BinOpr op, } case OPR_CONCAT: { luaK_exp2val(fs, e2); - if (e2->k == VRELOCABLE && + if (e2->k == VRELOC && GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) { lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1); freeexp(fs, e1); SETARG_B(getinstruction(fs, e2), e1->u.info); - e1->k = VRELOCABLE; e1->u.info = e2->u.info; + e1->k = VRELOC; e1->u.info = e2->u.info; } else { luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ @@ -1432,28 +1501,50 @@ void luaK_posfix (FuncState *fs, BinOpr op, break; } case OPR_ADD: case OPR_MUL: { - if (!constfolding(fs, op + LUA_OPADD, e1, e2)) - codecommutative(fs, cast(OpCode, op + OP_ADD), e1, e2, line); + if (!constfolding(fs, opr + LUA_OPADD, e1, e2)) + codecommutative(fs, cast(OpCode, opr + OP_ADD), e1, e2, line); break; } case OPR_SUB: case OPR_DIV: case OPR_IDIV: case OPR_MOD: case OPR_POW: { - if (!constfolding(fs, op + LUA_OPADD, e1, e2)) - codearith(fs, cast(OpCode, op + OP_ADD), e1, e2, 0, line); + if (!constfolding(fs, opr + LUA_OPADD, e1, e2)) + codearith(fs, cast(OpCode, opr + OP_ADD), e1, e2, 0, line); break; } - case OPR_BAND: case OPR_BOR: case OPR_BXOR: - case OPR_SHL: case OPR_SHR: { - if (!constfolding(fs, op + LUA_OPADD, e1, e2)) - codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line); + case OPR_BAND: case OPR_BOR: case OPR_BXOR: { + if (!constfolding(fs, opr + LUA_OPADD, e1, e2)) + codebitwise(fs, opr, e1, e2, line); + break; + } + case OPR_SHL: { + if (!constfolding(fs, LUA_OPSHL, e1, e2)) { + if (isSCint(e1)) { + swapexps(e1, e2); + codebini(fs, OP_SHLI, e1, e2, 1, line); + } + else + codeshift(fs, OP_SHL, e1, e2, line); + } + break; + } + case OPR_SHR: { + if (!constfolding(fs, LUA_OPSHR, e1, e2)) + codeshift(fs, OP_SHR, e1, e2, line); break; } case OPR_EQ: case OPR_NE: { - codeeq(fs, op, e1, e2); + codeeq(fs, opr, e1, e2); + break; + } + case OPR_LT: case OPR_LE: { + OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); + codeorder(fs, op, e1, e2); break; } - case OPR_LT: case OPR_LE: case OPR_GT: case OPR_GE: { + /* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */ + OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); + swapexps(e1, e2); codeorder(fs, op, e1, e2); break; } @@ -1478,7 +1569,7 @@ void luaK_fixline (FuncState *fs, int line) { } else { fs->previousline -= f->lineinfo[fs->pc - 1]; /* undo previous info. */ - savelineinfo(fs, f, fs->pc - 1, line); /* redo it */ + savelineinfo(fs, f, fs->pc - 1, line); /* redo it */ } } @@ -1505,3 +1596,46 @@ void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { fs->freereg = base + 1; /* free registers with list values */ } + +/* +** return the final target of a jump (skipping jumps to jumps) +*/ +static int finaltarget (Instruction *code, int i) { + int count; + for (count = 0; count < 100; count++) { /* avoid infinite loops */ + Instruction pc = code[i]; + if (GET_OPCODE(pc) != OP_JMP) + break; + else + i += GETARG_sJ(pc) + 1; + } + return i; +} + + +/* +** Do a final pass over the code of a function, doing small peephole +** optimizations and adjustments. +*/ +void luaK_finish (FuncState *fs) { + int i; + Proto *p = fs->f; + for (i = 0; i < fs->pc; i++) { + Instruction *pc = &p->code[i]; + lua_assert(i == 0 || isOT(*(pc - 1)) == isIT(*pc)); + switch (GET_OPCODE(*pc)) { + case OP_RETURN: case OP_RETURN0: case OP_RETURN1: + case OP_TAILCALL: { + if (p->sizep > 0) + SETARG_k(*pc, 1); /* signal that they must close upvalues */ + break; + } + case OP_JMP: { + int target = finaltarget(p->code, i); + fixjump(fs, i, target); + break; + } + default: break; + } + } +} diff --git a/lcode.h b/lcode.h index 1c3229d982..beeba54f58 100644 --- a/lcode.h +++ b/lcode.h @@ -1,5 +1,5 @@ /* -** $Id: lcode.h,v 1.67 2017/09/28 16:53:29 roberto Exp roberto $ +** $Id: lcode.h,v 1.69 2017/11/30 13:29:18 roberto Exp roberto $ ** Code generator for Lua ** See Copyright Notice in lua.h */ @@ -55,6 +55,7 @@ LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, int B, int C, int k); +LUAI_FUNC int luaK_isKint (expdesc *e); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n); @@ -80,7 +81,6 @@ LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target); void luaK_patchgoto (FuncState *fs, int list, int target, int hasclose); LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list); LUAI_FUNC void luaK_patchclose (FuncState *fs, int list); -LUAI_FUNC int luaK_needclose (FuncState *fs, int list); LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2); LUAI_FUNC int luaK_getlabel (FuncState *fs); LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line); @@ -88,6 +88,7 @@ LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v); LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1, expdesc *v2, int line); LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore); +LUAI_FUNC void luaK_finish (FuncState *fs); #endif diff --git a/ldebug.c b/ldebug.c index 7323f23a8e..5233560044 100644 --- a/ldebug.c +++ b/ldebug.c @@ -1,5 +1,5 @@ /* -** $Id: ldebug.c,v 2.143 2017/11/13 12:20:51 roberto Exp roberto $ +** $Id: ldebug.c,v 2.150 2017/12/20 14:58:05 roberto Exp roberto $ ** Debug Interface ** See Copyright Notice in lua.h */ @@ -51,7 +51,7 @@ static int currentpc (CallInfo *ci) { /* ** Get a "base line" to find the line corresponding to an instruction. ** For that, search the array of absolute line info for the largest saved -** instruction smaller or equal to the wanted instrution. A special +** instruction smaller or equal to the wanted instruction. A special ** case is when there is no absolute info or the instruction is before ** the first absolute one. */ @@ -189,14 +189,10 @@ static const char *upvalname (Proto *p, int uv) { static const char *findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { - const char *name = NULL; - StkId base; - if (isLua(ci)) { - base = ci->func + 1; - name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); - } - else - base = ci->func + 1; + StkId base = ci->func + 1; + const char *name = (isLua(ci)) + ? luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)) + : NULL; if (name == NULL) { /* no 'standard' name? */ StkId limit = (ci == L->ci) ? L->top : ci->next->func; if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */ @@ -328,7 +324,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, } else { ar->isvararg = f->l.p->is_vararg; - ar->nparams = f->l.p->numparams; + ar->nparams = f->l.p->numparams + f->l.p->is_vararg; } break; } @@ -589,7 +585,8 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci, tm = TM_NEWINDEX; break; case OP_ADDI: case OP_SUBI: case OP_MULI: case OP_MODI: - case OP_POWI: case OP_DIVI: case OP_IDIVI: { + case OP_POWI: case OP_DIVI: case OP_IDIVI: + case OP_BANDK: case OP_BORK: case OP_BXORK: { int offset = GET_OPCODE(i) - OP_ADDI; /* ORDER OP */ tm = cast(TMS, offset + TM_ADD); /* ORDER TM */ break; @@ -606,12 +603,16 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci, case OP_LEN: tm = TM_LEN; break; case OP_CONCAT: tm = TM_CONCAT; break; case OP_EQ: tm = TM_EQ; break; - case OP_LT: tm = TM_LT; break; - case OP_LE: tm = TM_LE; break; + case OP_LT: case OP_LE: case OP_LTI: case OP_LEI: + *name = "order"; /* '<=' can call '__lt', etc. */ + return "metamethod"; + case OP_SHRI: case OP_SHLI: + *name = "shift"; + return "metamethod"; default: return NULL; /* cannot find a reasonable name */ } - *name = getstr(G(L)->tmname[tm]); + *name = getstr(G(L)->tmname[tm]) + 2; return "metamethod"; } @@ -724,6 +725,7 @@ l_noret luaG_errormsg (lua_State *L) { setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top - 1, errfunc); /* push function */ L->top++; /* assume EXTRA_STACK */ + luaE_incCcalls(L); luaD_callnoyield(L, L->top - 2, 1); /* call it */ } luaD_throw(L, LUA_ERRRUN); @@ -769,6 +771,8 @@ void luaG_traceexec (lua_State *L) { ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ return; /* do not call hook again (VM yielded, so it did not move) */ } + if (!isIT(*(ci->u.l.savedpc - 1))) + L->top = ci->top; /* prepare top */ if (counthook) luaD_hook(L, LUA_HOOKCOUNT, -1); /* call count hook */ if (mask & LUA_MASKLINE) { diff --git a/ldo.c b/ldo.c index 3095412310..1abd105c82 100644 --- a/ldo.c +++ b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.172 2017/11/13 15:36:52 roberto Exp roberto $ +** $Id: ldo.c,v 2.184 2017/12/28 14:17:09 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -135,7 +135,7 @@ l_noret luaD_throw (lua_State *L, int errcode) { int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { - unsigned short oldnCcalls = L->nCcalls; + unsigned short oldnCcalls = L->nCcalls - L->nci; struct lua_longjmp lj; lj.status = LUA_OK; lj.previous = L->errorJmp; /* chain new error handler */ @@ -144,7 +144,7 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { (*f)(L, ud); ); L->errorJmp = lj.previous; /* restore old error handler */ - L->nCcalls = oldnCcalls; + L->nCcalls = oldnCcalls + L->nci; return lj.status; } @@ -156,17 +156,17 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { ** Stack reallocation ** =================================================================== */ -static void correctstack (lua_State *L, StkId oldstack) { +static void correctstack (lua_State *L, StkId oldstack, StkId newstack) { CallInfo *ci; UpVal *up; - if (L->stack == oldstack) + if (oldstack == newstack) return; /* stack address did not change */ - L->top = (L->top - oldstack) + L->stack; + L->top = (L->top - oldstack) + newstack; for (up = L->openupval; up != NULL; up = up->u.open.next) - up->v = s2v((uplevel(up) - oldstack) + L->stack); + up->v = s2v((uplevel(up) - oldstack) + newstack); for (ci = L->ci; ci != NULL; ci = ci->previous) { - ci->top = (ci->top - oldstack) + L->stack; - ci->func = (ci->func - oldstack) + L->stack; + ci->top = (ci->top - oldstack) + newstack; + ci->func = (ci->func - oldstack) + newstack; if (isLua(ci)) ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */ } @@ -177,36 +177,53 @@ static void correctstack (lua_State *L, StkId oldstack) { #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) -void luaD_reallocstack (lua_State *L, int newsize) { - StkId oldstack = L->stack; +int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { int lim = L->stacksize; + StkId newstack = luaM_reallocvector(L, L->stack, lim, newsize, StackValue); lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK); - luaM_reallocvector(L, L->stack, L->stacksize, newsize, StackValue); + if (newstack == NULL) { /* reallocation failed? */ + if (raiseerror) + luaM_error(L); + else return 0; /* do not raise an error */ + } for (; lim < newsize; lim++) - setnilvalue(s2v(L->stack + lim)); /* erase new segment */ + setnilvalue(s2v(newstack + lim)); /* erase new segment */ + correctstack(L, L->stack, newstack); + L->stack = newstack; L->stacksize = newsize; L->stack_last = L->stack + newsize - EXTRA_STACK; - correctstack(L, oldstack); + return 1; } -void luaD_growstack (lua_State *L, int n) { +/* +** Try to grow the stack by at least 'n' elements. when 'raiseerror' +** is true, raises any error; otherwise, return 0 in case of errors. +*/ +int luaD_growstack (lua_State *L, int n, int raiseerror) { int size = L->stacksize; - if (size > LUAI_MAXSTACK) /* error after extra size? */ - luaD_throw(L, LUA_ERRERR); + int newsize = 2 * size; /* tentative new size */ + if (size > LUAI_MAXSTACK) { /* need more space after extra size? */ + if (raiseerror) + luaD_throw(L, LUA_ERRERR); /* error inside message handler */ + else return 0; + } else { int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK; - int newsize = 2 * size; - if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK; - if (newsize < needed) newsize = needed; + if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */ + newsize = LUAI_MAXSTACK; + if (newsize < needed) /* but must respect what was asked for */ + newsize = needed; if (newsize > LUAI_MAXSTACK) { /* stack overflow? */ - luaD_reallocstack(L, ERRORSTACKSIZE); - luaG_runerror(L, "stack overflow"); + /* add extra size to be able to handle the error message */ + luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror); + if (raiseerror) + luaG_runerror(L, "stack overflow"); + else return 0; } - else - luaD_reallocstack(L, newsize); - } + } /* else no errors */ + return luaD_reallocstack(L, newsize, raiseerror); } @@ -226,17 +243,14 @@ void luaD_shrinkstack (lua_State *L) { int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK; if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK; /* respect stack limit */ - if (L->stacksize > LUAI_MAXSTACK) /* had been handling stack overflow? */ - luaE_freeCI(L); /* free all CIs (list grew because of an error) */ - else - luaE_shrinkCI(L); /* shrink list */ /* if thread is currently not handling a stack overflow and its good size is smaller than current size, shrink its stack */ if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && goodsize < L->stacksize) - luaD_reallocstack(L, goodsize); + luaD_reallocstack(L, goodsize, 0); /* ok if that fails */ else /* don't change stack */ condmovestack(L,{},{}); /* (change only for debugging) */ + luaE_shrinkCI(L); /* shrink CI list */ } @@ -264,8 +278,8 @@ void luaD_hook (lua_State *L, int event, int line) { ar.currentline = line; ar.i_ci = ci; luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - ci->top = L->top + LUA_MINSTACK; - lua_assert(ci->top <= L->stack_last); + if (L->top + LUA_MINSTACK > ci->top) + ci->top = L->top + LUA_MINSTACK; L->allowhook = 0; /* cannot call hooks inside a hook */ ci->callstatus |= CIST_HOOKED; lua_unlock(L); @@ -280,11 +294,12 @@ void luaD_hook (lua_State *L, int event, int line) { } -static void callhook (lua_State *L, CallInfo *ci, int istail) { +static void hookcall (lua_State *L, CallInfo *ci, int istail) { int hook; ci->u.l.trap = 1; if (!(L->hookmask & LUA_MASKCALL)) return; /* some other hook */ + L->top = ci->top; /* prepare top */ ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ if (istail) { ci->callstatus |= CIST_TAIL; @@ -297,9 +312,19 @@ static void callhook (lua_State *L, CallInfo *ci, int istail) { } +static void rethook (lua_State *L, CallInfo *ci) { + if (isLuacode(ci)) + L->top = ci->top; /* prepare top */ + if (L->hookmask & LUA_MASKRET) /* is return hook on? */ + luaD_hook(L, LUA_HOOKRET, -1); /* call it */ + if (isLua(ci->previous)) + L->oldpc = ci->previous->u.l.savedpc; /* update 'oldpc' */ +} + + /* ** Check whether __call metafield of 'func' is a function. If so, put -** it in stack below original 'func' so that 'luaD_precall' can call +** it in stack below original 'func' so that 'luaD_call' can call ** it. Raise an error if __call metafield is not a function. */ StkId luaD_tryfuncTM (lua_State *L, StkId func) { @@ -323,8 +348,8 @@ StkId luaD_tryfuncTM (lua_State *L, StkId func) { ** expressions, multiple results for tail calls/single parameters) ** separated. */ -static int moveresults (lua_State *L, StkId firstResult, StkId res, - int nres, int wanted) { +static void moveresults (lua_State *L, StkId firstResult, StkId res, + int nres, int wanted) { switch (wanted) { /* handle typical cases separately */ case 0: break; /* nothing to move */ case 1: { /* one result needed */ @@ -338,8 +363,8 @@ static int moveresults (lua_State *L, StkId firstResult, StkId res, int i; for (i = 0; i < nres; i++) /* move all results to correct place */ setobjs2s(L, res + i, firstResult + i); - L->top = res + nres; - return 0; /* wanted == LUA_MULTRET */ + wanted = nres; /* it wanted what it had */ + break; } default: { int i; @@ -357,7 +382,6 @@ static int moveresults (lua_State *L, StkId firstResult, StkId res, } } L->top = res + wanted; /* top points after the last result */ - return 1; } @@ -366,22 +390,15 @@ static int moveresults (lua_State *L, StkId firstResult, StkId res, ** moves current number of results to proper place; returns 0 iff call ** wanted multiple (variable number of) results. */ -int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { - StkId res; - int wanted = ci->nresults; - if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) { - if (L->hookmask & LUA_MASKRET) { - ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ - luaD_hook(L, LUA_HOOKRET, -1); - firstResult = restorestack(L, fr); - } - if (isLua(ci->previous)) - L->oldpc = ci->previous->u.l.savedpc; +void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) { + if (L->hookmask) { + ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */ + rethook(L, ci); + firstResult = restorestack(L, fr); } - res = ci->func; /* res == final position of 1st result */ L->ci = ci->previous; /* back to caller */ /* move results to proper place */ - return moveresults(L, firstResult, res, nres, wanted); + moveresults(L, firstResult, ci->func, nres, ci->nresults); } @@ -401,29 +418,28 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n) { for (i = 0; i < n; i++) /* move down function and arguments */ setobjs2s(L, ci->func + i, func + i); checkstackp(L, fsize, func); - for (; i < p->numparams - p->is_vararg; i++) - setnilvalue(s2v(ci->func + i)); /* complete missing parameters */ + for (; i <= p->numparams; i++) + setnilvalue(s2v(ci->func + i)); /* complete missing arguments */ if (p->is_vararg) { L->top -= (func - ci->func); /* move down top */ luaT_adjustvarargs(L, p, n - 1); } - L->top = ci->top = ci->func + 1 + fsize; /* top for new function */ + ci->top = ci->func + 1 + fsize; /* top for new function */ lua_assert(ci->top <= L->stack_last); ci->u.l.savedpc = p->code; /* starting point */ ci->callstatus |= CIST_TAIL; if (L->hookmask) - callhook(L, ci, 1); + hookcall(L, ci, 1); } /* -** Prepares a function call: checks the stack, creates a new CallInfo -** entry, fills in the relevant information, calls hook if needed. -** If function is a C function, does the call, too. (Otherwise, leave -** the execution ('luaV_execute') to the caller, to allow stackless -** calls.) Returns true iff function has been executed (C function). +** Call a function (C or Lua). The function to be called is at *func. +** The arguments are on the stack, right after the function. +** When returns, all the results are on the stack, starting at the original +** function position. */ -int luaD_precall (lua_State *L, StkId func, int nresults) { +void luaD_call (lua_State *L, StkId func, int nresults) { lua_CFunction f; TValue *funcv = s2v(func); CallInfo *ci; @@ -441,7 +457,7 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { ci->func = func; ci->top = L->top + LUA_MINSTACK; lua_assert(ci->top <= L->stack_last); - ci->callstatus = 0; + ci->callstatus = CIST_C; if (L->hookmask & LUA_MASKCALL) luaD_hook(L, LUA_HOOKCALL, -1); lua_unlock(L); @@ -449,66 +465,38 @@ int luaD_precall (lua_State *L, StkId func, int nresults) { lua_lock(L); api_checknelems(L, n); luaD_poscall(L, ci, L->top - n, n); - return 1; + break; } case LUA_TLCL: { /* Lua function: prepare its call */ Proto *p = clLvalue(funcv)->p; int n = cast_int(L->top - func) - 1; /* number of real arguments */ int fsize = p->maxstacksize; /* frame size */ checkstackp(L, fsize, func); - for (; n < p->numparams - p->is_vararg; n++) + for (; n < p->numparams; n++) setnilvalue(s2v(L->top++)); /* complete missing arguments */ if (p->is_vararg) luaT_adjustvarargs(L, p, n); ci = next_ci(L); /* now 'enter' new function */ ci->nresults = nresults; ci->func = func; - L->top = ci->top = func + 1 + fsize; + ci->top = func + 1 + fsize; lua_assert(ci->top <= L->stack_last); ci->u.l.savedpc = p->code; /* starting point */ - ci->callstatus = CIST_LUA; + ci->callstatus = 0; if (L->hookmask) - callhook(L, ci, 0); - return 0; + hookcall(L, ci, 0); + luaV_execute(L, ci); /* run the function */ + break; } default: { /* not a function */ func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ - return luaD_precall(L, func, nresults); /* now it must be a function */ + luaD_call(L, func, nresults); /* now it must be a function */ + break; } } } -/* -** Check appropriate error for stack overflow ("regular" overflow or -** overflow while handling stack overflow). If 'nCalls' is larger than -** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but -** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to -** allow overflow handling to work) -*/ -static void stackerror (lua_State *L) { - if (L->nCcalls == LUAI_MAXCCALLS) - luaG_runerror(L, "C stack overflow"); - else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) - luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ -} - - -/* -** Call a function (C or Lua). The function to be called is at *func. -** The arguments are on the stack, right after the function. -** When returns, all the results are on the stack, starting at the original -** function position. -*/ -void luaD_call (lua_State *L, StkId func, int nResults) { - if (++L->nCcalls >= LUAI_MAXCCALLS) - stackerror(L); - if (!luaD_precall(L, func, nResults)) /* is a Lua function? */ - luaV_execute(L); /* call it */ - L->nCcalls--; -} - - /* ** Similar to 'luaD_call', but does not allow yields during the call */ @@ -541,7 +529,7 @@ static void finishCcall (lua_State *L, int status) { n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ lua_lock(L); api_checknelems(L, n); - luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */ + luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_call' */ } @@ -554,14 +542,15 @@ static void finishCcall (lua_State *L, int status) { ** status is LUA_YIELD). */ static void unroll (lua_State *L, void *ud) { + CallInfo *ci; if (ud != NULL) /* error status? */ finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ - while (L->ci != &L->base_ci) { /* something in the stack */ - if (!isLua(L->ci)) /* C function? */ + while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ + if (!isLua(ci)) /* C function? */ finishCcall(L, LUA_YIELD); /* complete its execution */ else { /* Lua function */ luaV_finishOp(L); /* finish interrupted instruction */ - luaV_execute(L); /* execute down to higher C 'boundary' */ + luaV_execute(L, ci); /* execute down to higher C 'boundary' */ } } } @@ -629,14 +618,13 @@ static void resume (lua_State *L, void *ud) { StkId firstArg = L->top - n; /* first argument */ CallInfo *ci = L->ci; if (L->status == LUA_OK) { /* starting a coroutine? */ - if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */ - luaV_execute(L); /* call it */ + luaD_call(L, firstArg - 1, LUA_MULTRET); } else { /* resuming from previous yield */ lua_assert(L->status == LUA_YIELD); L->status = LUA_OK; /* mark that it is running (again) */ if (isLua(ci)) /* yielded inside a hook? */ - luaV_execute(L); /* just continue running Lua code */ + luaV_execute(L, ci); /* just continue running Lua code */ else { /* 'common' yield */ if (ci->u.c.k != NULL) { /* does it have a continuation function? */ lua_unlock(L); @@ -645,7 +633,7 @@ static void resume (lua_State *L, void *ud) { api_checknelems(L, n); firstArg = L->top - n; /* yield results come from continuation */ } - luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */ + luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_call' */ } unroll(L, NULL); /* run continuation */ } @@ -688,7 +676,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, : L->top - (L->ci->func + 1); L->nny = oldnny; /* restore 'nny' */ L->nCcalls--; - lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); + // lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0)); lua_unlock(L); return status; } @@ -713,6 +701,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, } L->status = LUA_YIELD; if (isLua(ci)) { /* inside a hook? */ + lua_assert(!isLuacode(ci)); api_check(L, k == NULL, "hooks cannot continue after yielding"); ci->u2.nyield = 0; /* no results */ } diff --git a/ldo.h b/ldo.h index 2640c08830..765f6cef5f 100644 --- a/ldo.h +++ b/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 2.33 2017/11/07 13:25:26 roberto Exp roberto $ +** $Id: ldo.h,v 2.37 2017/12/08 17:28:25 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -22,7 +22,8 @@ */ #define luaD_checkstackaux(L,n,pre,pos) \ if (L->stack_last - L->top <= (n)) \ - { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); } + { pre; luaD_growstack(L, n, 1); pos; } \ + else { condmovestack(L,pre,pos); } /* In general, 'pre'/'pos' are empty (nothing to save) */ #define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0) @@ -47,17 +48,16 @@ typedef void (*Pfunc) (lua_State *L, void *ud); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, const char *mode); LUAI_FUNC void luaD_hook (lua_State *L, int event, int line); -LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults); LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); -LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, +LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres); -LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize); -LUAI_FUNC void luaD_growstack (lua_State *L, int n); +LUAI_FUNC int luaD_reallocstack (lua_State *L, int newsize, int raiseerror); +LUAI_FUNC int luaD_growstack (lua_State *L, int n, int raiseerror); LUAI_FUNC void luaD_shrinkstack (lua_State *L); LUAI_FUNC void luaD_inctop (lua_State *L); diff --git a/ldump.c b/ldump.c index 16a95f9bd6..4d3f643574 100644 --- a/ldump.c +++ b/ldump.c @@ -1,5 +1,5 @@ /* -** $Id: ldump.c,v 2.38 2017/06/27 11:35:31 roberto Exp roberto $ +** $Id: ldump.c,v 2.39 2017/06/27 14:21:12 roberto Exp roberto $ ** save precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -113,23 +113,22 @@ static void DumpConstants (const Proto *f, DumpState *D) { const TValue *o = &f->k[i]; DumpByte(ttype(o), D); switch (ttype(o)) { - case LUA_TNIL: - break; - case LUA_TBOOLEAN: - DumpByte(bvalue(o), D); - break; - case LUA_TNUMFLT: - DumpNumber(fltvalue(o), D); - break; - case LUA_TNUMINT: - DumpInteger(ivalue(o), D); - break; - case LUA_TSHRSTR: - case LUA_TLNGSTR: - DumpString(tsvalue(o), D); - break; - default: - lua_assert(0); + case LUA_TNIL: + break; + case LUA_TBOOLEAN: + DumpByte(bvalue(o), D); + break; + case LUA_TNUMFLT: + DumpNumber(fltvalue(o), D); + break; + case LUA_TNUMINT: + DumpInteger(ivalue(o), D); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + DumpString(tsvalue(o), D); + break; + default: lua_assert(0); } } } diff --git a/lgc.c b/lgc.c index 036020ae85..d02dc031c9 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.236 2017/10/31 15:29:28 roberto Exp $ +** $Id: lgc.c,v 2.243 2017/12/20 14:58:05 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -507,7 +507,7 @@ static lu_mem traversetable (global_State *g, Table *h) { ** mode, check the generational invariant. If the cache is old, ** everything is ok. If the prototype is 'old0', everything ** is ok too. (It will naturally be visited again.) If the -** prototype is older than 'old0', then its cache (whith is new) +** prototype is older than 'old0', then its cache (which is new) ** must be visited again in the next collection, so the prototype ** goes to the 'protogray' list. (If the prototype has a cache, ** it is already immutable and does not need other barriers; @@ -569,6 +569,11 @@ static int traverseLclosure (global_State *g, LClosure *cl) { } +/* +** Traverse a thread, marking the elements in the stack up to its top +** and cleaning the rest of the stack in the final traversal. +** That ensures that the entire stack have valid (non-dead) objects. +*/ static int traversethread (global_State *g, lua_State *th) { StkId o = th->stack; if (o == NULL) @@ -816,14 +821,14 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p) { */ /* -** If possible, shrink string table +** If possible, shrink string table. */ static void checkSizes (lua_State *L, global_State *g) { if (!g->gcemergency) { l_mem olddebt = g->GCdebt; if (g->strt.nuse < g->strt.size / 4) /* string table too big? */ - luaS_resize(L, g->strt.size / 2); /* shrink it a little */ - g->GCestimate += g->GCdebt - olddebt; /* update estimate */ + luaS_resize(L, g->strt.size / 2); + g->GCestimate += g->GCdebt - olddebt; /* correct estimate */ } } @@ -1195,7 +1200,7 @@ static void entergen (lua_State *L, global_State *g) { luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ atomic(L); - /* sweep all ellements making them old */ + /* sweep all elements making them old */ sweep2old(L, &g->allgc); /* everything alive now is old */ g->reallyold = g->old = g->survival = g->allgc; @@ -1270,7 +1275,7 @@ static void genstep (lua_State *L, global_State *g) { lu_mem mem; youngcollection(L, g); mem = gettotalbytes(g); - luaE_setdebt(g, -((mem / 100) * g->genminormul)); + luaE_setdebt(g, -(cast(l_mem, (mem / 100)) * g->genminormul)); g->GCestimate = majorbase; /* preserve base value */ } } diff --git a/llimits.h b/llimits.h index 4b35dfcb8f..a9295645b2 100644 --- a/llimits.h +++ b/llimits.h @@ -1,5 +1,5 @@ /* -** $Id: llimits.h,v 1.143 2017/06/01 19:16:34 roberto Exp roberto $ +** $Id: llimits.h,v 1.147 2017/12/11 18:53:53 roberto Exp roberto $ ** Limits, basic types, and some other 'installation-dependent' definitions ** See Copyright Notice in lua.h */ @@ -140,10 +140,11 @@ typedef LUAI_UACINT l_uacInt; /* ** maximum depth for nested C calls and syntactical nested non-terminals -** in a program. (Value must fit in an unsigned short int.) +** in a program. (Value must fit in an unsigned short int. It must also +** be compatible with the size of the C stack.) */ #if !defined(LUAI_MAXCCALLS) -#define LUAI_MAXCCALLS 200 +#define LUAI_MAXCCALLS 2200 #endif @@ -218,8 +219,7 @@ typedef unsigned long Instruction; /* -** these macros allow user-specific actions on threads when you defined -** LUAI_EXTRASPACE and need to do something extra when a thread is +** these macros allow user-specific actions when a thread is ** created/deleted/resumed/yielded. */ #if !defined(luai_userstateopen) @@ -303,7 +303,7 @@ typedef unsigned long Instruction; #else /* realloc stack keeping its size */ #define condmovestack(L,pre,pos) \ - { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; } + { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_, 0); pos; } #endif #if !defined(HARDMEMTESTS) diff --git a/lmem.c b/lmem.c index 83a9082c5f..ecafef4932 100644 --- a/lmem.c +++ b/lmem.c @@ -1,5 +1,5 @@ /* -** $Id: lmem.c,v 1.90 2015/03/03 18:18:29 roberto Exp roberto $ +** $Id: lmem.c,v 1.94 2017/12/08 17:28:25 roberto Exp roberto $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -22,6 +22,14 @@ #include "lstate.h" +#if defined(HARDMEMTESTS) +#define hardtest(L,os,s) /* force a GC whenever possible */ \ + if ((s) > (os) && (G(L))->gcrunning) luaC_fullgc(L, 1); +#else +#define hardtest(L,os,s) ((void)0) +#endif + + /* ** About the realloc function: @@ -45,31 +53,67 @@ #define MINSIZEARRAY 4 -void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems, - int limit, const char *what) { +void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize, + int size_elems, int limit, const char *what) { void *newblock; - int newsize; - if (*size >= limit/2) { /* cannot double it? */ - if (*size >= limit) /* cannot grow even a little? */ + int size = *psize; + if (nelems + 1 <= size) /* does one extra element still fit? */ + return block; /* nothing to be done */ + if (size >= limit / 2) { /* cannot double it? */ + if (size >= limit) /* cannot grow even a little? */ luaG_runerror(L, "too many %s (limit is %d)", what, limit); - newsize = limit; /* still have at least one free place */ + size = limit; /* still have at least one free place */ } else { - newsize = (*size)*2; - if (newsize < MINSIZEARRAY) - newsize = MINSIZEARRAY; /* minimum size */ + size *= 2; + if (size < MINSIZEARRAY) + size = MINSIZEARRAY; /* minimum size */ } - newblock = luaM_reallocv(L, block, *size, newsize, size_elems); - *size = newsize; /* update only when everything else is OK */ + lua_assert(nelems + 1 <= size && size <= limit); + /* 'limit' ensures that multiplication will not overflow */ + newblock = luaM_realloc_(L, block, cast(size_t, *psize) * size_elems, + cast(size_t, size) * size_elems); + if (newblock == NULL) + luaM_error(L); + *psize = size; /* update only when everything else is OK */ return newblock; } +void *luaM_shrinkvector_ (lua_State *L, void *block, int *size, + int final_n, int size_elem) { + global_State *g = G(L); + void *newblock; + size_t oldsize = cast(size_t, (*size) * size_elem); + size_t newsize = cast(size_t, final_n * size_elem); + lua_assert(newsize <= oldsize); + newblock = (*g->frealloc)(g->ud, block, oldsize, newsize); + if (newblock == NULL && final_n > 0) /* allocation failed? */ + luaM_error(L); + else { + g->GCdebt += newsize - oldsize; + *size = final_n; + return newblock; + } +} + + l_noret luaM_toobig (lua_State *L) { luaG_runerror(L, "memory allocation error: block too big"); } +/* +** Free memory +*/ +void luaM_free_ (lua_State *L, void *block, size_t osize) { + global_State *g = G(L); + lua_assert((block == 0) == (block == NULL)); + (*g->frealloc)(g->ud, block, osize, 0); + g->GCdebt -= osize; +} + + /* ** generic allocation routine. @@ -77,24 +121,49 @@ l_noret luaM_toobig (lua_State *L) { void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { void *newblock; global_State *g = G(L); - size_t realosize = (block) ? osize : 0; - lua_assert((realosize == 0) == (block == NULL)); -#if defined(HARDMEMTESTS) - if (nsize > realosize && g->gcrunning) - luaC_fullgc(L, 1); /* force a GC whenever possible */ -#endif + lua_assert((osize == 0) == (block == NULL)); + hardtest(L, osize, nsize); newblock = (*g->frealloc)(g->ud, block, osize, nsize); if (newblock == NULL && nsize > 0) { - lua_assert(nsize > realosize); /* cannot fail when shrinking a block */ - if (g->version) { /* is state fully built? */ + /* Is state fully built? Not shrinking a block? */ + if (g->version && nsize > osize) { luaC_fullgc(L, 1); /* try to free some memory... */ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ } if (newblock == NULL) - luaD_throw(L, LUA_ERRMEM); + return NULL; } lua_assert((nsize == 0) == (newblock == NULL)); - g->GCdebt = (g->GCdebt + nsize) - realosize; + g->GCdebt = (g->GCdebt + nsize) - osize; + return newblock; +} + + +void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize, + size_t nsize) { + void *newblock = luaM_realloc_(L, block, osize, nsize); + if (newblock == NULL && nsize > 0) /* allocation failed? */ + luaM_error(L); return newblock; } + +void *luaM_malloc_ (lua_State *L, size_t size, int tag) { + hardtest(L, 0, size); + if (size == 0) + return NULL; /* that's all */ + else { + global_State *g = G(L); + void *newblock = (*g->frealloc)(g->ud, NULL, tag, size); + if (newblock == NULL) { + if (g->version) { /* is state fully built? */ + luaC_fullgc(L, 1); /* try to free some memory... */ + newblock = (*g->frealloc)(g->ud, NULL, tag, size); /* try again */ + } + if (newblock == NULL) + luaM_error(L); + } + g->GCdebt += size; + return newblock; + } +} diff --git a/lmem.h b/lmem.h index 7af316f020..e98aabdbdc 100644 --- a/lmem.h +++ b/lmem.h @@ -1,5 +1,5 @@ /* -** $Id: lmem.h,v 1.42 2014/12/19 13:45:40 roberto Exp roberto $ +** $Id: lmem.h,v 1.45 2017/12/07 18:59:52 roberto Exp roberto $ ** Interface to Memory Manager ** See Copyright Notice in lua.h */ @@ -14,12 +14,13 @@ #include "lua.h" +#define luaM_error(L) luaD_throw(L, LUA_ERRMEM) + + /* -** This macro reallocs a vector 'b' from 'on' to 'n' elements, where -** each element has size 'e'. In case of arithmetic overflow of the -** product 'n'*'e', it raises an error (calling 'luaM_toobig'). Because -** 'e' is always constant, it avoids the runtime division MAX_SIZET/(e). -** +** This macro tests whether it is safe to multiply 'n' by the size of +** type 't' without overflows. Because 'e' is always constant, it avoids +** the runtime division MAX_SIZET/(e). ** (The macro is somewhat complex to avoid warnings: The 'sizeof' ** comparison avoids a runtime comparison when overflow cannot occur. ** The compiler should be able to optimize the real test by itself, but @@ -27,43 +28,64 @@ ** false due to limited range of data type"; the +1 tricks the compiler, ** avoiding this warning but also this optimization.) */ -#define luaM_reallocv(L,b,on,n,e) \ - (((sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) \ - ? luaM_toobig(L) : cast_void(0)) , \ - luaM_realloc_(L, (b), (on)*(e), (n)*(e))) +#define luaM_testsize(n,e) \ + (sizeof(n) >= sizeof(size_t) && cast(size_t, (n)) + 1 > MAX_SIZET/(e)) + +#define luaM_checksize(L,n,e) \ + (luaM_testsize(n,e) ? luaM_toobig(L) : cast_void(0)) + + +/* +** Computes the minimum between 'n' and 'MAX_SIZET/sizeof(t)', so that +** the result is not larger than 'n' and cannot overflow a 'size_t' +** when multiplied by the size of type 't'. (Assumes that 'n' is an +** 'int' or 'unsigned int' and that 'int' is not larger than 'size_t'.) +*/ +#define luaM_limitN(n,t) \ + ((cast(size_t, n) > MAX_SIZET/sizeof(t)) ? (MAX_SIZET/sizeof(t)) : (n)) /* ** Arrays of chars do not need any test */ #define luaM_reallocvchar(L,b,on,n) \ - cast(char *, luaM_realloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) + cast(char *, luaM_saferealloc_(L, (b), (on)*sizeof(char), (n)*sizeof(char))) -#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0) -#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0) -#define luaM_freearray(L, b, n) luaM_realloc_(L, (b), (n)*sizeof(*(b)), 0) +#define luaM_freemem(L, b, s) luaM_free_(L, (b), (s)) +#define luaM_free(L, b) luaM_free_(L, (b), sizeof(*(b))) +#define luaM_freearray(L, b, n) luaM_free_(L, (b), (n)*sizeof(*(b))) -#define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s)) -#define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t))) -#define luaM_newvector(L,n,t) \ - cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t))) +#define luaM_new(L,t) cast(t*, luaM_malloc_(L, sizeof(t), 0)) +#define luaM_newvector(L,n,t) cast(t*, luaM_malloc_(L, (n)*sizeof(t), 0)) +#define luaM_newvectorchecked(L,n,t) \ + (luaM_checksize(L,n,sizeof(t)), luaM_newvector(L,n,t)) -#define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s)) +#define luaM_newobject(L,tag,s) luaM_malloc_(L, (s), tag) #define luaM_growvector(L,v,nelems,size,t,limit,e) \ - if ((nelems)+1 > (size)) \ - ((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) + ((v)=cast(t *, luaM_growaux_(L,v,nelems,&(size),sizeof(t), \ + luaM_limitN(limit,t),e))) #define luaM_reallocvector(L, v,oldn,n,t) \ - ((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t)))) + (cast(t *, luaM_realloc_(L, v, cast(size_t, oldn) * sizeof(t), \ + cast(size_t, n) * sizeof(t)))) + +#define luaM_shrinkvector(L,v,size,fs,t) \ + ((v)=cast(t *, luaM_shrinkvector_(L, v, &(size), fs, sizeof(t)))) LUAI_FUNC l_noret luaM_toobig (lua_State *L); /* not to be called directly */ LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize, size_t size); -LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size, - size_t size_elem, int limit, +LUAI_FUNC void *luaM_saferealloc_ (lua_State *L, void *block, size_t oldsize, + size_t size); +LUAI_FUNC void luaM_free_ (lua_State *L, void *block, size_t osize); +LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int nelems, + int *size, int size_elem, int limit, const char *what); +LUAI_FUNC void *luaM_shrinkvector_ (lua_State *L, void *block, int *nelem, + int final_n, int size_elem); +LUAI_FUNC void *luaM_malloc_ (lua_State *L, size_t size, int tag); #endif diff --git a/loadlib.c b/loadlib.c index d1941a99fa..176330428d 100644 --- a/loadlib.c +++ b/loadlib.c @@ -1,5 +1,5 @@ /* -** $Id: loadlib.c,v 1.129 2016/12/04 20:17:24 roberto Exp roberto $ +** $Id: loadlib.c,v 1.130 2017/01/12 17:14:26 roberto Exp roberto $ ** Dynamic library loader for Lua ** See Copyright Notice in lua.h ** @@ -437,9 +437,9 @@ static const char *searchpath (lua_State *L, const char *name, const char *sep, const char *dirsep) { luaL_Buffer msg; /* to build error message */ - luaL_buffinit(L, &msg); if (*sep != '\0') /* non-empty separator? */ name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ + luaL_buffinit(L, &msg); while ((path = pushnexttemplate(L, path)) != NULL) { const char *filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); @@ -569,10 +569,10 @@ static int searcher_preload (lua_State *L) { static void findloader (lua_State *L, const char *name) { int i; luaL_Buffer msg; /* to build error message */ - luaL_buffinit(L, &msg); /* push 'package.searchers' to index 3 in the stack */ if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) luaL_error(L, "'package.searchers' must be a table"); + luaL_buffinit(L, &msg); /* iterate over available searchers to find a loader */ for (i = 1; ; i++) { if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ diff --git a/lobject.c b/lobject.c index fb2c172c04..c7d4c06a66 100644 --- a/lobject.c +++ b/lobject.c @@ -1,5 +1,5 @@ /* -** $Id: lobject.c,v 2.119 2017/11/08 14:50:23 roberto Exp roberto $ +** $Id: lobject.c,v 2.121 2017/11/23 19:29:04 roberto Exp roberto $ ** Some generic functions over Lua objects ** See Copyright Notice in lua.h */ @@ -193,7 +193,7 @@ static int isneg (const char **s) { #define MAXSIGDIG 30 /* -** convert an hexadecimal numeric string to a number, following +** convert a hexadecimal numeric string to a number, following ** C99 specification for 'strtod' */ static lua_Number lua_strx2number (const char *s, char **endptr) { @@ -268,11 +268,11 @@ static const char *l_str2dloc (const char *s, lua_Number *result, int mode) { ** Convert string 's' to a Lua number (put in 'result'). Return NULL ** on fail or the address of the ending '\0' on success. ** 'pmode' points to (and 'mode' contains) special things in the string: -** - 'x'/'X' means an hexadecimal numeral +** - 'x'/'X' means a hexadecimal numeral ** - 'n'/'N' means 'inf' or 'nan' (which should be rejected) ** - '.' just optimizes the search for the common case (nothing special) ** This function accepts both the current locale or a dot as the radix -** mark. If the convertion fails, it may mean number has a dot but +** mark. If the conversion fails, it may mean number has a dot but ** locale accepts something else. In that case, the code copies 's' ** to a buffer (because 's' is read-only), changes the dot to the ** current locale radix mark, and tries to convert again. diff --git a/lobject.h b/lobject.h index 372ec13b1f..c7b6be18d4 100644 --- a/lobject.h +++ b/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 2.125 2017/06/29 15:06:44 roberto Exp $ +** $Id: lobject.h,v 2.130 2017/11/07 13:25:26 roberto Exp roberto $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -529,7 +529,7 @@ typedef union Closure { /* ** Nodes for Hash tables. A pack of two TValue's (key-value pairs) -** plus a 'next' field to link colliding entries. The distribuition +** plus a 'next' field to link colliding entries. The distribution ** of the key's fields ('key_tt' and 'key_val') not forming a proper ** 'TValue' allows for a smaller size for 'Node' both in 4-byte ** and 8-byte alignments. diff --git a/lopcodes.c b/lopcodes.c index 05700950a6..a5867d2358 100644 --- a/lopcodes.c +++ b/lopcodes.c @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.c,v 1.68 2017/11/16 12:59:14 roberto Exp roberto $ +** $Id: lopcodes.c,v 1.74 2017/12/18 17:49:31 roberto Exp $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -44,6 +44,11 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "POWI", "DIVI", "IDIVI", + "BANDK", + "BORK", + "BXORK", + "SHRI", + "SHLI", "ADD", "SUB", "MUL", @@ -68,11 +73,17 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { "LE", "EQK", "EQI", + "LTI", + "LEI", "TEST", "TESTSET", "CALL", "TAILCALL", "RETURN", + "RETURN0", + "RETURN1", + "FORLOOP1", + "FORPREP1", "FORLOOP", "FORPREP", "TFORCALL", @@ -86,69 +97,80 @@ LUAI_DDEF const char *const luaP_opnames[NUM_OPCODES+1] = { LUAI_DDEF const lu_byte luaP_opmodes[NUM_OPCODES] = { -/* T A mode opcode */ - opmode(0, 1, iABC) /* OP_MOVE */ - ,opmode(0, 1, iAsBx) /* OP_LOADI */ - ,opmode(0, 1, iAsBx) /* OP_LOADF */ - ,opmode(0, 1, iABx) /* OP_LOADK */ - ,opmode(0, 1, iABx) /* OP_LOADKX */ - ,opmode(0, 1, iABC) /* OP_LOADBOOL */ - ,opmode(0, 1, iABC) /* OP_LOADNIL */ - ,opmode(0, 1, iABC) /* OP_GETUPVAL */ - ,opmode(0, 0, iABC) /* OP_SETUPVAL */ - ,opmode(0, 1, iABC) /* OP_GETTABUP */ - ,opmode(0, 1, iABC) /* OP_GETTABLE */ - ,opmode(0, 1, iABC) /* OP_GETI */ - ,opmode(0, 1, iABC) /* OP_GETFIELD */ - ,opmode(0, 0, iABC) /* OP_SETTABUP */ - ,opmode(0, 0, iABC) /* OP_SETTABLE */ - ,opmode(0, 0, iABC) /* OP_SETI */ - ,opmode(0, 0, iABC) /* OP_SETFIELD */ - ,opmode(0, 1, iABC) /* OP_NEWTABLE */ - ,opmode(0, 1, iABC) /* OP_SELF */ - ,opmode(0, 1, iABC) /* OP_ADDI */ - ,opmode(0, 1, iABC) /* OP_SUBI */ - ,opmode(0, 1, iABC) /* OP_MULI */ - ,opmode(0, 1, iABC) /* OP_MODI */ - ,opmode(0, 1, iABC) /* OP_POWI */ - ,opmode(0, 1, iABC) /* OP_DIVI */ - ,opmode(0, 1, iABC) /* OP_IDIVI */ - ,opmode(0, 1, iABC) /* OP_ADD */ - ,opmode(0, 1, iABC) /* OP_SUB */ - ,opmode(0, 1, iABC) /* OP_MUL */ - ,opmode(0, 1, iABC) /* OP_MOD */ - ,opmode(0, 1, iABC) /* OP_POW */ - ,opmode(0, 1, iABC) /* OP_DIV */ - ,opmode(0, 1, iABC) /* OP_IDIV */ - ,opmode(0, 1, iABC) /* OP_BAND */ - ,opmode(0, 1, iABC) /* OP_BOR */ - ,opmode(0, 1, iABC) /* OP_BXOR */ - ,opmode(0, 1, iABC) /* OP_SHL */ - ,opmode(0, 1, iABC) /* OP_SHR */ - ,opmode(0, 1, iABC) /* OP_UNM */ - ,opmode(0, 1, iABC) /* OP_BNOT */ - ,opmode(0, 1, iABC) /* OP_NOT */ - ,opmode(0, 1, iABC) /* OP_LEN */ - ,opmode(0, 1, iABC) /* OP_CONCAT */ - ,opmode(0, 0, iABC) /* OP_CLOSE */ - ,opmode(0, 0, isJ) /* OP_JMP */ - ,opmode(1, 0, iABC) /* OP_EQ */ - ,opmode(1, 0, iABC) /* OP_LT */ - ,opmode(1, 0, iABC) /* OP_LE */ - ,opmode(1, 0, iABC) /* OP_EQK */ - ,opmode(1, 0, iABC) /* OP_EQI */ - ,opmode(1, 0, iABC) /* OP_TEST */ - ,opmode(1, 1, iABC) /* OP_TESTSET */ - ,opmode(0, 1, iABC) /* OP_CALL */ - ,opmode(0, 1, iABC) /* OP_TAILCALL */ - ,opmode(0, 0, iABC) /* OP_RETURN */ - ,opmode(0, 1, iABx) /* OP_FORLOOP */ - ,opmode(0, 1, iABx) /* OP_FORPREP */ - ,opmode(0, 0, iABC) /* OP_TFORCALL */ - ,opmode(0, 1, iABx) /* OP_TFORLOOP */ - ,opmode(0, 0, iABC) /* OP_SETLIST */ - ,opmode(0, 1, iABx) /* OP_CLOSURE */ - ,opmode(0, 1, iABC) /* OP_VARARG */ - ,opmode(0, 0, iAx) /* OP_EXTRAARG */ +/* OT IT T A mode opcode */ + opmode(0, 0, 0, 1, iABC) /* OP_MOVE */ + ,opmode(0, 0, 0, 1, iAsBx) /* OP_LOADI */ + ,opmode(0, 0, 0, 1, iAsBx) /* OP_LOADF */ + ,opmode(0, 0, 0, 1, iABx) /* OP_LOADK */ + ,opmode(0, 0, 0, 1, iABx) /* OP_LOADKX */ + ,opmode(0, 0, 0, 1, iABC) /* OP_LOADBOOL */ + ,opmode(0, 0, 0, 1, iABC) /* OP_LOADNIL */ + ,opmode(0, 0, 0, 1, iABC) /* OP_GETUPVAL */ + ,opmode(0, 0, 0, 0, iABC) /* OP_SETUPVAL */ + ,opmode(0, 0, 0, 1, iABC) /* OP_GETTABUP */ + ,opmode(0, 0, 0, 1, iABC) /* OP_GETTABLE */ + ,opmode(0, 0, 0, 1, iABC) /* OP_GETI */ + ,opmode(0, 0, 0, 1, iABC) /* OP_GETFIELD */ + ,opmode(0, 0, 0, 0, iABC) /* OP_SETTABUP */ + ,opmode(0, 0, 0, 0, iABC) /* OP_SETTABLE */ + ,opmode(0, 0, 0, 0, iABC) /* OP_SETI */ + ,opmode(0, 0, 0, 0, iABC) /* OP_SETFIELD */ + ,opmode(0, 0, 0, 1, iABC) /* OP_NEWTABLE */ + ,opmode(0, 0, 0, 1, iABC) /* OP_SELF */ + ,opmode(0, 0, 0, 1, iABC) /* OP_ADDI */ + ,opmode(0, 0, 0, 1, iABC) /* OP_SUBI */ + ,opmode(0, 0, 0, 1, iABC) /* OP_MULI */ + ,opmode(0, 0, 0, 1, iABC) /* OP_MODI */ + ,opmode(0, 0, 0, 1, iABC) /* OP_POWI */ + ,opmode(0, 0, 0, 1, iABC) /* OP_DIVI */ + ,opmode(0, 0, 0, 1, iABC) /* OP_IDIVI */ + ,opmode(0, 0, 0, 1, iABC) /* OP_BANDK */ + ,opmode(0, 0, 0, 1, iABC) /* OP_BORK */ + ,opmode(0, 0, 0, 1, iABC) /* OP_BXORK */ + ,opmode(0, 0, 0, 1, iABC) /* OP_SHRI */ + ,opmode(0, 0, 0, 1, iABC) /* OP_SHLI */ + ,opmode(0, 0, 0, 1, iABC) /* OP_ADD */ + ,opmode(0, 0, 0, 1, iABC) /* OP_SUB */ + ,opmode(0, 0, 0, 1, iABC) /* OP_MUL */ + ,opmode(0, 0, 0, 1, iABC) /* OP_MOD */ + ,opmode(0, 0, 0, 1, iABC) /* OP_POW */ + ,opmode(0, 0, 0, 1, iABC) /* OP_DIV */ + ,opmode(0, 0, 0, 1, iABC) /* OP_IDIV */ + ,opmode(0, 0, 0, 1, iABC) /* OP_BAND */ + ,opmode(0, 0, 0, 1, iABC) /* OP_BOR */ + ,opmode(0, 0, 0, 1, iABC) /* OP_BXOR */ + ,opmode(0, 0, 0, 1, iABC) /* OP_SHL */ + ,opmode(0, 0, 0, 1, iABC) /* OP_SHR */ + ,opmode(0, 0, 0, 1, iABC) /* OP_UNM */ + ,opmode(0, 0, 0, 1, iABC) /* OP_BNOT */ + ,opmode(0, 0, 0, 1, iABC) /* OP_NOT */ + ,opmode(0, 0, 0, 1, iABC) /* OP_LEN */ + ,opmode(0, 0, 0, 1, iABC) /* OP_CONCAT */ + ,opmode(0, 0, 0, 0, iABC) /* OP_CLOSE */ + ,opmode(0, 0, 0, 0, isJ) /* OP_JMP */ + ,opmode(0, 0, 1, 0, iABC) /* OP_EQ */ + ,opmode(0, 0, 1, 0, iABC) /* OP_LT */ + ,opmode(0, 0, 1, 0, iABC) /* OP_LE */ + ,opmode(0, 0, 1, 0, iABC) /* OP_EQK */ + ,opmode(0, 0, 1, 0, iABC) /* OP_EQI */ + ,opmode(0, 0, 1, 0, iABC) /* OP_LTI */ + ,opmode(0, 0, 1, 0, iABC) /* OP_LEI */ + ,opmode(0, 0, 1, 0, iABC) /* OP_TEST */ + ,opmode(0, 0, 1, 1, iABC) /* OP_TESTSET */ + ,opmode(1, 1, 0, 1, iABC) /* OP_CALL */ + ,opmode(1, 1, 0, 1, iABC) /* OP_TAILCALL */ + ,opmode(0, 1, 0, 0, iABC) /* OP_RETURN */ + ,opmode(0, 0, 0, 0, iABC) /* OP_RETURN0 */ + ,opmode(0, 0, 0, 0, iABC) /* OP_RETURN1 */ + ,opmode(0, 0, 0, 1, iABx) /* OP_FORLOOP1 */ + ,opmode(0, 0, 0, 1, iABx) /* OP_FORPREP1 */ + ,opmode(0, 0, 0, 1, iABx) /* OP_FORLOOP */ + ,opmode(0, 0, 0, 1, iABx) /* OP_FORPREP */ + ,opmode(0, 0, 0, 0, iABC) /* OP_TFORCALL */ + ,opmode(0, 0, 0, 1, iABx) /* OP_TFORLOOP */ + ,opmode(0, 1, 0, 0, iABC) /* OP_SETLIST */ + ,opmode(0, 0, 0, 1, iABx) /* OP_CLOSURE */ + ,opmode(1, 0, 0, 1, iABC) /* OP_VARARG */ + ,opmode(0, 0, 0, 0, iAx) /* OP_EXTRAARG */ }; diff --git a/lopcodes.h b/lopcodes.h index a964562026..eae0dfaf53 100644 --- a/lopcodes.h +++ b/lopcodes.h @@ -1,5 +1,5 @@ /* -** $Id: lopcodes.h,v 1.169 2017/11/22 18:41:20 roberto Exp roberto $ +** $Id: lopcodes.h,v 1.180 2017/12/18 17:49:31 roberto Exp roberto $ ** Opcodes for Lua virtual machine ** See Copyright Notice in lua.h */ @@ -62,13 +62,14 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */ ** so they must fit in LUAI_BITSINT-1 bits (-1 for sign) */ #if SIZE_Bx < LUAI_BITSINT-1 -#define MAXARG_Bx ((1<>1) /* 'sBx' is signed */ +#define MAXARG_Bx ((1<>1) /* 'sBx' is signed */ + + #if SIZE_Ax < LUAI_BITSINT-1 #define MAXARG_Ax ((1<> 1) + #define MAXARG_A ((1<> 1) +#define OFFSET_sC (MAXARG_C >> 1) #define MAXARG_Cx ((1<<(SIZE_C + 1))-1) @@ -114,13 +117,15 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */ #define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A) #define GETARG_B(i) check_exp(checkopm(i, iABC), getarg(i, POS_B, SIZE_B)) +#define GETARG_sB(i) (GETARG_B(i) - OFFSET_sC) #define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B) #define GETARG_C(i) check_exp(checkopm(i, iABC), getarg(i, POS_C, SIZE_C)) -#define GETARG_sC(i) (GETARG_C(i) - MAXARG_sC) +#define GETARG_sC(i) (GETARG_C(i) - OFFSET_sC) #define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C) -#define GETARG_k(i) (cast(int, ((i) & (1 << POS_k)))) +#define TESTARG_k(i) (cast(int, ((i) & (1u << POS_k)))) +#define GETARG_k(i) getarg(i, POS_k, 1) #define SETARG_k(i,v) setarg(i, v, POS_k, 1) #define GETARG_Bx(i) check_exp(checkopm(i, iABx), getarg(i, POS_Bx, SIZE_Bx)) @@ -130,13 +135,13 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */ #define SETARG_Ax(i,v) setarg(i, v, POS_Ax, SIZE_Ax) #define GETARG_sBx(i) \ - check_exp(checkopm(i, iAsBx), getarg(i, POS_Bx, SIZE_Bx) - MAXARG_sBx) -#define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx)) + check_exp(checkopm(i, iAsBx), getarg(i, POS_Bx, SIZE_Bx) - OFFSET_sBx) +#define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+OFFSET_sBx)) #define GETARG_sJ(i) \ - check_exp(checkopm(i, isJ), getarg(i, POS_sJ, SIZE_sJ) - MAXARG_sJ) + check_exp(checkopm(i, isJ), getarg(i, POS_sJ, SIZE_sJ) - OFFSET_sJ) #define SETARG_sJ(i,j) \ - setarg(i, cast(unsigned int, (j)+MAXARG_sJ), POS_sJ, SIZE_sJ) + setarg(i, cast(unsigned int, (j)+OFFSET_sJ), POS_sJ, SIZE_sJ) #define CREATE_ABCk(o,a,b,c,k) ((cast(Instruction, o)<> C */ +OP_SHLI,/* A B C R(A) := C << R(B) */ + OP_ADD,/* A B C R(A) := R(B) + R(C) */ OP_SUB,/* A B C R(A) := R(B) - R(C) */ OP_MUL,/* A B C R(A) := R(B) * R(C) */ @@ -236,32 +248,41 @@ OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ OP_CLOSE,/* A close all upvalues >= R(A) */ OP_JMP,/* k sJ pc += sJ (k is used in code generation) */ -OP_EQ,/* A B C if ((R(A) == R(C)) ~= B) then pc++ */ -OP_LT,/* A B C if ((R(A) < R(C)) ~= B) then pc++ */ -OP_LE,/* A B C if ((R(A) <= R(C)) ~= B) then pc++ */ +OP_EQ,/* A B if ((R(A) == R(B)) ~= k) then pc++ */ +OP_LT,/* A B if ((R(A) < R(B)) ~= k) then pc++ */ +OP_LE,/* A B if ((R(A) <= R(B)) ~= k) then pc++ */ -OP_EQK,/* A B C if ((R(A) == K(C)) ~= B) then pc++ */ -OP_EQI,/* A B C if ((R(A) == C) ~= B) then pc++ */ +OP_EQK,/* A B if ((R(A) == K(B)) ~= k) then pc++ */ +OP_EQI,/* A sB if ((R(A) == sB) ~= k) then pc++ */ +OP_LTI,/* A sB if ((R(A) < sB) ~= k) then pc++ */ +OP_LEI,/* A sB if ((R(A) <= sB) ~= k) then pc++ */ -OP_TEST,/* A C if not (R(A) <=> C) then pc++ */ -OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */ +OP_TEST,/* A if (not R(A) == k) then pc++ */ +OP_TESTSET,/* A B if (not R(B) == k) then R(A) := R(B) else pc++ */ OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */ OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */ + OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */ +OP_RETURN0,/* return */ +OP_RETURN1,/* A return R(A) */ + +OP_FORLOOP1,/* A Bx R(A)++; + if R(A) <= R(A+1) then { pc-=Bx; R(A+3)=R(A) } */ +OP_FORPREP1,/* A Bx R(A)--; pc+=Bx */ OP_FORLOOP,/* A Bx R(A)+=R(A+2); - if R(A) (!(B<=A)) or (A<=B) => (!(Btop' for next instruction (when C == 0) +** bit 6: instruction uses 'L->top' set by previous instruction (when B == 0) */ LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES]; @@ -307,8 +339,16 @@ LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES]; #define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 7)) #define testAMode(m) (luaP_opmodes[m] & (1 << 3)) #define testTMode(m) (luaP_opmodes[m] & (1 << 4)) +#define testOTMode(m) (luaP_opmodes[m] & (1 << 5)) +#define testITMode(m) (luaP_opmodes[m] & (1 << 6)) + +/* "out top" (set top for next instruction) */ +#define isOT(i) (testOTMode(GET_OPCODE(i)) && GETARG_C(i) == 0) + +/* "in top" (uses top from previous instruction) */ +#define isIT(i) (testITMode(GET_OPCODE(i)) && GETARG_B(i) == 0) -#define opmode(t,a,m) (((t)<<4) | ((a)<<3) | (m)) +#define opmode(ot,it,t,a,m) (((ot)<<5) | ((it)<<6) | ((t)<<4) | ((a)<<3) | (m)) LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */ diff --git a/lparser.c b/lparser.c index 0637a0b753..e99b33ffb2 100644 --- a/lparser.c +++ b/lparser.c @@ -1,5 +1,5 @@ /* -** $Id: lparser.c,v 2.166 2017/09/28 16:53:29 roberto Exp roberto $ +** $Id: lparser.c,v 2.174 2017/12/18 17:49:31 roberto Exp roberto $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -330,11 +330,7 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) { } -static void enterlevel (LexState *ls) { - lua_State *L = ls->L; - ++L->nCcalls; - checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels"); -} +#define enterlevel(ls) luaE_incCcalls((ls)->L) #define leavelevel(ls) ((ls)->L->nCcalls--) @@ -537,7 +533,7 @@ static Proto *addprototype (LexState *ls) { */ static void codeclosure (LexState *ls, expdesc *v) { FuncState *fs = ls->fs->prev; - init_exp(v, VRELOCABLE, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); + init_exp(v, VRELOC, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1)); luaK_exp2nextreg(fs, v); /* fix it at the last register */ } @@ -551,7 +547,6 @@ static void open_func (LexState *ls, FuncState *fs, BlockCnt *bl) { fs->previousline = f->linedefined; fs->iwthabs = 0; fs->lasttarget = 0; - fs->jpc = NO_JUMP; fs->freereg = 0; fs->nk = 0; fs->nabslineinfo = 0; @@ -573,21 +568,15 @@ static void close_func (LexState *ls) { Proto *f = fs->f; luaK_ret(fs, 0, 0); /* final return */ leaveblock(fs); - luaM_reallocvector(L, f->code, f->sizecode, fs->pc, Instruction); - f->sizecode = fs->pc; - luaM_reallocvector(L, f->lineinfo, f->sizelineinfo, fs->pc, ls_byte); - f->sizelineinfo = fs->pc; - luaM_reallocvector(L, f->abslineinfo, f->sizeabslineinfo, - fs->nabslineinfo, AbsLineInfo); - f->sizeabslineinfo = fs->nabslineinfo; - luaM_reallocvector(L, f->k, f->sizek, fs->nk, TValue); - f->sizek = fs->nk; - luaM_reallocvector(L, f->p, f->sizep, fs->np, Proto *); - f->sizep = fs->np; - luaM_reallocvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); - f->sizelocvars = fs->nlocvars; - luaM_reallocvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); - f->sizeupvalues = fs->nups; + luaK_finish(fs); + luaM_shrinkvector(L, f->code, f->sizecode, fs->pc, Instruction); + luaM_shrinkvector(L, f->lineinfo, f->sizelineinfo, fs->pc, ls_byte); + luaM_shrinkvector(L, f->abslineinfo, f->sizeabslineinfo, + fs->nabslineinfo, AbsLineInfo); + luaM_shrinkvector(L, f->k, f->sizek, fs->nk, TValue); + luaM_shrinkvector(L, f->p, f->sizep, fs->np, Proto *); + luaM_shrinkvector(L, f->locvars, f->sizelocvars, fs->nlocvars, LocVar); + luaM_shrinkvector(L, f->upvalues, f->sizeupvalues, fs->nups, Upvaldesc); lua_assert(fs->bl == NULL); ls->fs = fs->prev; luaC_checkGC(L); @@ -665,7 +654,7 @@ struct ConsControl { static void recfield (LexState *ls, struct ConsControl *cc) { - /* recfield -> (NAME | '['exp1']') = exp1 */ + /* recfield -> (NAME | '['exp']') = exp */ FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc tab, key, val; @@ -751,7 +740,7 @@ static void constructor (LexState *ls, expdesc *t) { struct ConsControl cc; cc.na = cc.nh = cc.tostore = 0; cc.t = t; - init_exp(t, VRELOCABLE, pc); + init_exp(t, VRELOC, pc); init_exp(&cc.v, VVOID, 0); /* no value (yet) */ luaK_exp2nextreg(ls->fs, t); /* fix it at stack top */ checknext(ls, '{'); @@ -776,7 +765,6 @@ static void parlist (LexState *ls) { FuncState *fs = ls->fs; Proto *f = fs->f; int nparams = 0; - f->is_vararg = 0; if (ls->t.token != ')') { /* is 'parlist' not empty? */ do { switch (ls->t.token) { @@ -800,7 +788,7 @@ static void parlist (LexState *ls) { } while (!f->is_vararg && testnext(ls, ',')); } adjustlocalvars(ls, nparams); - f->numparams = cast_byte(fs->nactvar); + f->numparams = cast_byte(fs->nactvar) - f->is_vararg; luaK_reserveregs(fs, fs->nactvar); /* reserve register for parameters */ } @@ -928,7 +916,7 @@ static void suffixedexp (LexState *ls, expdesc *v) { fieldsel(ls, v); break; } - case '[': { /* '[' exp1 ']' */ + case '[': { /* '[' exp ']' */ expdesc key; luaK_exp2anyregup(fs, v); yindex(ls, &key); @@ -986,10 +974,10 @@ static void simpleexp (LexState *ls, expdesc *v) { } case TK_DOTS: { /* vararg */ FuncState *fs = ls->fs; - int lastparam = fs->f->numparams - 1; + int lastparam = fs->f->numparams; check_condition(ls, fs->f->is_vararg, "cannot use '...' outside a vararg function"); - init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, lastparam)); + init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, lastparam, 1)); break; } case '{': { /* constructor */ @@ -1188,9 +1176,9 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) { suffixedexp(ls, &nv.v); if (!vkisindexed(nv.v.k)) check_conflict(ls, lh, &nv.v); - checklimit(ls->fs, nvars + ls->L->nCcalls, LUAI_MAXCCALLS, - "C levels"); + luaE_incCcalls(ls->L); /* control recursion depth */ assignment(ls, &nv, nvars+1); + ls->L->nCcalls--; } else { /* assignment -> '=' explist */ int nexps; @@ -1325,14 +1313,20 @@ static void repeatstat (LexState *ls, int line) { } -static int exp1 (LexState *ls) { +/* +** Read an expression and generate code to put its results in next +** stack slot. Return true if expression is a constant integer and, +** if 'i' is not-zero, its value is equal to 'i'. +** +*/ +static int exp1 (LexState *ls, int i) { expdesc e; - int reg; + int res; expr(ls, &e); + res = luaK_isKint(&e) && (i == 0 || i == e.u.ival); luaK_exp2nextreg(ls->fs, &e); lua_assert(e.k == VNONRELOC); - reg = e.u.info; - return reg; + return res; } @@ -1352,53 +1346,65 @@ static void fixforjump (FuncState *fs, int pc, int dest, int back) { } -static void forbody (LexState *ls, int base, int line, int nvars, int isnum) { +/* +** Generate code for a 'for' loop. 'kind' can be zero (a common for +** loop), one (a basic for loop, with integer values and increment of +** 1), or two (a generic for loop). +*/ +static void forbody (LexState *ls, int base, int line, int nvars, int kind) { /* forbody -> DO block */ BlockCnt bl; FuncState *fs = ls->fs; int prep, endfor; adjustlocalvars(ls, 3); /* control variables */ checknext(ls, TK_DO); - prep = isnum ? luaK_codeABx(fs, OP_FORPREP, base, 0) : luaK_jump(fs); + prep = (kind == 0) ? luaK_codeABx(fs, OP_FORPREP, base, 0) + : (kind == 1) ? luaK_codeABx(fs, OP_FORPREP1, base, 0) + : luaK_jump(fs); enterblock(fs, &bl, 0); /* scope for declared variables */ adjustlocalvars(ls, nvars); luaK_reserveregs(fs, nvars); block(ls); leaveblock(fs); /* end of scope for declared variables */ - if (isnum) { /* numeric for? */ - fixforjump(fs, prep, luaK_getlabel(fs), 0); - endfor = luaK_codeABx(fs, OP_FORLOOP, base, 0); - } - else { /* generic for */ + if (kind == 2) { /* generic for? */ luaK_patchtohere(fs, prep); luaK_codeABC(fs, OP_TFORCALL, base, 0, nvars); luaK_fixline(fs, line); endfor = luaK_codeABx(fs, OP_TFORLOOP, base + 2, 0); } + else { + fixforjump(fs, prep, luaK_getlabel(fs), 0); + endfor = (kind == 0) ? luaK_codeABx(fs, OP_FORLOOP, base, 0) + : luaK_codeABx(fs, OP_FORLOOP1, base, 0); + } fixforjump(fs, endfor, prep + 1, 1); luaK_fixline(fs, line); } static void fornum (LexState *ls, TString *varname, int line) { - /* fornum -> NAME = exp1,exp1[,exp1] forbody */ + /* fornum -> NAME = exp,exp[,exp] forbody */ FuncState *fs = ls->fs; int base = fs->freereg; + int basicfor = 1; /* true if it is a "basic" 'for' (integer + 1) */ new_localvarliteral(ls, "(for index)"); new_localvarliteral(ls, "(for limit)"); new_localvarliteral(ls, "(for step)"); new_localvar(ls, varname); checknext(ls, '='); - exp1(ls); /* initial value */ + if (!exp1(ls, 0)) /* initial value not an integer? */ + basicfor = 0; /* not a basic 'for' */ checknext(ls, ','); - exp1(ls); /* limit */ - if (testnext(ls, ',')) - exp1(ls); /* optional step */ + exp1(ls, 0); /* limit */ + if (testnext(ls, ',')) { + if (!exp1(ls, 1)) /* optional step not 1? */ + basicfor = 0; /* not a basic 'for' */ + } else { /* default step = 1 */ luaK_int(fs, fs->freereg, 1); luaK_reserveregs(fs, 1); } - forbody(ls, base, line, 1, 1); + forbody(ls, base, line, 1, basicfor); } @@ -1423,7 +1429,7 @@ static void forlist (LexState *ls, TString *indexname) { line = ls->linenumber; adjust_assign(ls, 3, explist(ls, &e), &e); luaK_checkstack(fs, 3); /* extra space to call generator */ - forbody(ls, base, line, nvars - 3, 0); + forbody(ls, base, line, nvars - 3, 2); } @@ -1687,7 +1693,7 @@ static void mainfunc (LexState *ls, FuncState *fs) { expdesc v; open_func(ls, fs, &bl); fs->f->is_vararg = 1; /* main function is always declared vararg */ - fs->f->numparams = 1; + fs->f->numparams = 0; new_localvarliteral(ls, "_ARG"); adjustlocalvars(ls, 1); luaK_reserveregs(fs, 1); /* reserve register for vararg */ diff --git a/lparser.h b/lparser.h index 3ab6065daf..6007d618bf 100644 --- a/lparser.h +++ b/lparser.h @@ -1,5 +1,5 @@ /* -** $Id: lparser.h,v 1.77 2017/04/28 20:57:45 roberto Exp roberto $ +** $Id: lparser.h,v 1.79 2017/11/30 13:29:18 roberto Exp roberto $ ** Lua Parser ** See Copyright Notice in lua.h */ @@ -49,8 +49,8 @@ typedef enum { ind.idx = key's K index */ VJMP, /* expression is a test/comparison; info = pc of corresponding jump instruction */ - VRELOCABLE, /* expression can put result in any register; - info = instruction pc */ + VRELOC, /* expression can put result in any register; + info = instruction pc */ VCALL, /* expression is a function call; info = instruction pc */ VVARARG /* vararg expression; info = instruction pc */ } expkind; @@ -124,7 +124,6 @@ typedef struct FuncState { int pc; /* next position to code (equivalent to 'ncode') */ int lasttarget; /* 'label' of last 'jump label' */ int previousline; /* last line that was saved in 'lineinfo' */ - int jpc; /* list of pending jumps to 'pc' */ int nk; /* number of elements in 'k' */ int np; /* number of elements in 'p' */ int nabslineinfo; /* number of elements in 'abslineinfo' */ diff --git a/lstate.c b/lstate.c index 54e390b504..81e10851a3 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.146 2017/11/07 13:25:26 roberto Exp roberto $ +** $Id: lstate.c,v 2.148 2017/11/23 16:35:54 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -97,8 +97,28 @@ void luaE_setdebt (global_State *g, l_mem debt) { } +/* +** Increment count of "C calls" and check for overflows. In case of +** a stack overflow, check appropriate error ("regular" overflow or +** overflow while handling stack overflow). If 'nCalls' is larger than +** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but +** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to +** allow overflow handling to work) +*/ +void luaE_incCcalls (lua_State *L) { + if (++L->nCcalls >= LUAI_MAXCCALLS) { + if (L->nCcalls == LUAI_MAXCCALLS) + luaG_runerror(L, "C stack overflow"); + else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3))) + luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ + } +} + + CallInfo *luaE_extendCI (lua_State *L) { - CallInfo *ci = luaM_new(L, CallInfo); + CallInfo *ci; + luaE_incCcalls(L); + ci = luaM_new(L, CallInfo); lua_assert(L->ci->next == NULL); L->ci->next = ci; ci->previous = L->ci; @@ -116,11 +136,13 @@ void luaE_freeCI (lua_State *L) { CallInfo *ci = L->ci; CallInfo *next = ci->next; ci->next = NULL; + L->nCcalls -= L->nci; /* to subtract removed elements from 'nCcalls' */ while ((ci = next) != NULL) { next = ci->next; luaM_free(L, ci); L->nci--; } + L->nCcalls += L->nci; /* to subtract removed elements from 'nCcalls' */ } @@ -130,6 +152,7 @@ void luaE_freeCI (lua_State *L) { void luaE_shrinkCI (lua_State *L) { CallInfo *ci = L->ci; CallInfo *next2; /* next's next */ + L->nCcalls -= L->nci; /* to subtract removed elements from 'nCcalls' */ /* while there are two nexts */ while (ci->next != NULL && (next2 = ci->next->next) != NULL) { luaM_free(L, ci->next); /* free next */ @@ -138,6 +161,7 @@ void luaE_shrinkCI (lua_State *L) { next2->previous = ci; ci = next2; /* keep next's next */ } + L->nCcalls += L->nci; /* to subtract removed elements from 'nCcalls' */ } @@ -153,7 +177,7 @@ static void stack_init (lua_State *L1, lua_State *L) { /* initialize first ci */ ci = &L1->base_ci; ci->next = ci->previous = NULL; - ci->callstatus = 0; + ci->callstatus = CIST_C; ci->func = L1->top; setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */ L1->top++; diff --git a/lstate.h b/lstate.h index 02715dfbd9..bc4df4e561 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.150 2017/11/07 13:25:26 roberto Exp roberto $ +** $Id: lstate.h,v 2.152 2017/11/23 16:35:54 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -104,7 +104,7 @@ typedef struct CallInfo { int nyield; /* number of values yielded */ } u2; short nresults; /* expected number of results from this function */ - unsigned short callstatus; + lu_byte callstatus; } CallInfo; @@ -112,17 +112,19 @@ typedef struct CallInfo { ** Bits in CallInfo status */ #define CIST_OAH (1<<0) /* original value of 'allowhook' */ -#define CIST_LUA (1<<1) /* call is running a Lua function */ +#define CIST_C (1<<1) /* call is running a C function */ #define CIST_HOOKED (1<<2) /* call is running a debug hook */ -#define CIST_FRESH (1<<3) /* call is running on a fresh invocation - of luaV_execute */ -#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ -#define CIST_TAIL (1<<5) /* call was tail called */ -#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ -#define CIST_LEQ (1<<7) /* using __lt for __le */ -#define CIST_FIN (1<<8) /* call is running a finalizer */ +#define CIST_YPCALL (1<<3) /* call is a yieldable protected call */ +#define CIST_TAIL (1<<4) /* call was tail called */ +#define CIST_HOOKYIELD (1<<5) /* last hook called yielded */ +#define CIST_LEQ (1<<6) /* using __lt for __le */ +#define CIST_FIN (1<<7) /* call is running a finalizer */ -#define isLua(ci) ((ci)->callstatus & CIST_LUA) +/* active function is a Lua function */ +#define isLua(ci) (!((ci)->callstatus & CIST_C)) + +/* call is running Lua code (not a hook) */ +#define isLuacode(ci) (!((ci)->callstatus & (CIST_C | CIST_HOOKED))) /* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */ #define setoah(st,v) ((st) = ((st) & ~CIST_OAH) | (v)) @@ -256,6 +258,7 @@ LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); LUAI_FUNC void luaE_freeCI (lua_State *L); LUAI_FUNC void luaE_shrinkCI (lua_State *L); +LUAI_FUNC void luaE_incCcalls (lua_State *L); #endif diff --git a/lstring.c b/lstring.c index a851fd7415..60d4702de6 100644 --- a/lstring.c +++ b/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp roberto $ +** $Id: lstring.c,v 2.61 2017/12/12 11:52:35 roberto Exp roberto $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -31,6 +31,13 @@ #endif + +/* +** Maximum size for string table. +*/ +#define MAXSTRTB cast_int(luaM_limitN(MAX_INT, TString*)) + + /* ** equality for long strings */ @@ -62,34 +69,47 @@ unsigned int luaS_hashlongstr (TString *ts) { } -/* -** resizes the string table -*/ -void luaS_resize (lua_State *L, int newsize) { +static void tablerehash (TString **vect, int osize, int nsize) { int i; - stringtable *tb = &G(L)->strt; - if (newsize > tb->size) { /* grow table if needed */ - luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); - for (i = tb->size; i < newsize; i++) - tb->hash[i] = NULL; - } - for (i = 0; i < tb->size; i++) { /* rehash */ - TString *p = tb->hash[i]; - tb->hash[i] = NULL; - while (p) { /* for each node in the list */ + for (i = osize; i < nsize; i++) /* clear new elements */ + vect[i] = NULL; + for (i = 0; i < osize; i++) { /* rehash old part of the array */ + TString *p = vect[i]; + vect[i] = NULL; + while (p) { /* for each string in the list */ TString *hnext = p->u.hnext; /* save next */ - unsigned int h = lmod(p->hash, newsize); /* new position */ - p->u.hnext = tb->hash[h]; /* chain it */ - tb->hash[h] = p; + unsigned int h = lmod(p->hash, nsize); /* new position */ + p->u.hnext = vect[h]; /* chain it into array */ + vect[h] = p; p = hnext; } } - if (newsize < tb->size) { /* shrink table if needed */ - /* vanishing slice should be empty */ - lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL); - luaM_reallocvector(L, tb->hash, tb->size, newsize, TString *); +} + + +/* +** Resize the string table. If allocation fails, keep the current size. +** (This can degrade performance, but any non-zero size should work +** correctly.) +*/ +void luaS_resize (lua_State *L, int nsize) { + stringtable *tb = &G(L)->strt; + int osize = tb->size; + TString **newvect; + if (nsize < osize) /* shrinking table? */ + tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */ + newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*); + if (newvect == NULL) { /* reallocation failed? */ + if (nsize < osize) /* was it shrinking table? */ + tablerehash(tb->hash, nsize, osize); /* restore to original size */ + /* leave table as it was */ + } + else { /* allocation succeeded */ + tb->hash = newvect; + tb->size = nsize; + if (nsize > osize) + tablerehash(newvect, osize, nsize); /* rehash for new size */ } - tb->size = newsize; } @@ -114,7 +134,10 @@ void luaS_init (lua_State *L) { global_State *g = G(L); int i, j; TString *memerrmsg; - luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */ + stringtable *tb = &G(L)->strt; + tb->hash = luaM_newvector(L, MINSTRTABSIZE, TString*); + tablerehash(tb->hash, 0, MINSTRTABSIZE); /* clear array */ + tb->size = MINSTRTABSIZE; /* pre-create memory-error message */ memerrmsg = luaS_newliteral(L, MEMERRMSG); luaC_fix(L, obj2gco(memerrmsg)); /* it should never be collected */ @@ -161,34 +184,46 @@ void luaS_remove (lua_State *L, TString *ts) { } +static void growstrtab (lua_State *L, stringtable *tb) { + if (tb->nuse == MAX_INT) { /* too many strings? */ + luaC_fullgc(L, 1); /* try to free some... */ + if (tb->nuse == MAX_INT) /* still too many? */ + luaM_error(L); /* cannot even create a message... */ + } + if (tb->size <= MAXSTRTB / 2) /* can grow string table? */ + luaS_resize(L, tb->size * 2); +} + + /* -** checks whether short string exists and reuses it or creates a new one +** Checks whether short string exists and reuses it or creates a new one. */ static TString *internshrstr (lua_State *L, const char *str, size_t l) { TString *ts; global_State *g = G(L); + stringtable *tb = &g->strt; unsigned int h = luaS_hash(str, l, g->seed); - TString **list = &g->strt.hash[lmod(h, g->strt.size)]; + TString **list = &tb->hash[lmod(h, tb->size)]; lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ for (ts = *list; ts != NULL; ts = ts->u.hnext) { - if (l == ts->shrlen && - (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { + if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { /* found! */ if (isdead(g, ts)) /* dead (but not collected yet)? */ changewhite(ts); /* resurrect it */ return ts; } } - if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) { - luaS_resize(L, g->strt.size * 2); - list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */ + /* else must create a new string */ + if (tb->nuse >= tb->size) { /* need to grow string table? */ + growstrtab(L, tb); + list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ } ts = createstrobj(L, l, LUA_TSHRSTR, h); memcpy(getstr(ts), str, l * sizeof(char)); ts->shrlen = cast_byte(l); ts->u.hnext = *list; *list = ts; - g->strt.nuse++; + tb->nuse++; return ts; } diff --git a/lstring.h b/lstring.h index 416d951928..a994fe1e5b 100644 --- a/lstring.h +++ b/lstring.h @@ -1,5 +1,5 @@ /* -** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp roberto $ +** $Id: lstring.h,v 1.62 2017/07/27 13:50:16 roberto Exp roberto $ ** String table (keep all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -14,7 +14,7 @@ /* ** Memory-allocation error message must be preallocated (it cannot -** be created after memory is exausted) +** be created after memory is exhausted) */ #define MEMERRMSG "not enough memory" diff --git a/lstrlib.c b/lstrlib.c index 9a4cf90d49..84b6e4eb2e 100644 --- a/lstrlib.c +++ b/lstrlib.c @@ -1,5 +1,5 @@ /* -** $Id: lstrlib.c,v 1.258 2017/11/08 14:50:23 roberto Exp roberto $ +** $Id: lstrlib.c,v 1.259 2017/11/16 13:19:06 roberto Exp roberto $ ** Standard library for string operations and pattern-matching ** See Copyright Notice in lua.h */ @@ -1117,7 +1117,7 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { else { /* integers */ lua_Integer n = lua_tointeger(L, arg); const char *format = (n == LUA_MININTEGER) /* corner case? */ - ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */ + ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hex */ : LUA_INTEGER_FMT; /* else use default format */ nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n); } diff --git a/ltable.c b/ltable.c index 33c6852a03..419f9f6c5d 100644 --- a/ltable.c +++ b/ltable.c @@ -1,5 +1,5 @@ /* -** $Id: ltable.c,v 2.125 2017/06/29 15:06:44 roberto Exp roberto $ +** $Id: ltable.c,v 2.129 2017/12/08 17:28:25 roberto Exp roberto $ ** Lua tables (hash) ** See Copyright Notice in lua.h */ @@ -40,21 +40,34 @@ /* -** Maximum size of array part (MAXASIZE) is 2^MAXABITS. MAXABITS is -** the largest integer such that MAXASIZE fits in an unsigned int. +** MAXABITS is the largest integer such that MAXASIZE fits in an +** unsigned int. */ #define MAXABITS cast_int(sizeof(int) * CHAR_BIT - 1) -#define MAXASIZE (1u << MAXABITS) + + +/* +** MAXASIZE is the maximum size of the array part. It is the minimum +** between 2^MAXABITS and the maximum size such that, measured in bytes, +** it fits in a 'size_t'. +*/ +#define MAXASIZE luaM_limitN(1u << MAXABITS, TValue) /* -** Maximum size of hash part is 2^MAXHBITS. MAXHBITS is the largest -** integer such that 2^MAXHBITS fits in a signed int. (Note that the -** maximum number of elements in a table, 2^MAXABITS + 2^MAXHBITS, still -** fits comfortably in an unsigned int.) +** MAXHBITS is the largest integer such that 2^MAXHBITS fits in a +** signed int. */ #define MAXHBITS (MAXABITS - 1) +/* +** MAXHSIZE is the maximum size of the hash part. It is the minimum +** between 2^MAXHBITS and the maximum size such that, measured in bytes, +** it fits in a 'size_t'. +*/ +#define MAXHSIZE luaM_limitN(1u << MAXHBITS, Node) + + #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) #define hashstr(t,str) hashpow2(t, (str)->hash) @@ -249,6 +262,12 @@ int luaH_next (lua_State *L, Table *t, StkId key) { } +static void freehash (lua_State *L, Table *t) { + if (!isdummy(t)) + luaM_freearray(L, t->node, cast(size_t, sizenode(t))); +} + + /* ** {============================================================= ** Rehash @@ -344,15 +363,13 @@ static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) { } -static void setarrayvector (lua_State *L, Table *t, unsigned int size) { - unsigned int i; - luaM_reallocvector(L, t->array, t->sizearray, size, TValue); - for (i=t->sizearray; iarray[i]); - t->sizearray = size; -} - - +/* +** Creates an array for the hash part of a table with the given +** size, or reuses the dummy node if size is zero. +** The computation for size overflow is in two steps: the first +** comparison ensures that the shift in the second one does not +** overflow. +*/ static void setnodevector (lua_State *L, Table *t, unsigned int size) { if (size == 0) { /* no elements to hash part? */ t->node = cast(Node *, dummynode); /* use common 'dummynode' */ @@ -362,7 +379,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { else { int i; int lsize = luaO_ceillog2(size); - if (lsize > MAXHBITS) + if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE) luaG_runerror(L, "table overflow"); size = twoto(lsize); t->node = luaM_newvector(L, size, Node); @@ -378,39 +395,88 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) { } -void luaH_resize (lua_State *L, Table *t, unsigned int nasize, +/* +** (Re)insert all elements from the hash part of 'ot' into table 't'. +*/ +static void reinsert (lua_State *L, Table *ot, Table *t) { + int j; + int size = sizenode(ot); + for (j = 0; j < size; j++) { + Node *old = gnode(ot, j); + if (!ttisnil(gval(old))) { + /* doesn't need barrier/invalidate cache, as entry was + already present in the table */ + TValue k; + getnodekey(L, &k, old); + setobjt2t(L, luaH_set(L, t, &k), gval(old)); + } + } +} + + +/* +** Exchange the hash part of 't1' and 't2'. +*/ +static void exchangehashpart (Table *t1, Table *t2) { + lu_byte lsizenode = t1->lsizenode; + Node *node = t1->node; + Node *lastfree = t1->lastfree; + t1->lsizenode = t2->lsizenode; + t1->node = t2->node; + t1->lastfree = t2->lastfree; + t2->lsizenode = lsizenode; + t2->node = node; + t2->lastfree = lastfree; +} + + +/* +** Resize table 't' for the new given sizes. Both allocations (for +** the hash part and for the array part) can fail, which creates some +** subtleties. If the first allocation, for the hash part, fails, an +** error is raised and that is it. Otherwise, it copies the elements from +** the shrinking part of the array (if it is shrinking) into the new +** hash. Then it reallocates the array part. If that fails, the table +** is in its original state; the function frees the new hash part and then +** raises the allocation error. Otherwise, it sets the new hash part +** into the table, initializes the new part of the array (if any) with +** nils and reinserts the elements of the old hash back into the new +** parts of the table. +*/ +void luaH_resize (lua_State *L, Table *t, unsigned int newasize, unsigned int nhsize) { unsigned int i; - int j; + Table newt; /* to keep the new hash part */ unsigned int oldasize = t->sizearray; - int oldhsize = allocsizenode(t); - Node *nold = t->node; /* save old hash ... */ - if (nasize > oldasize) /* array part must grow? */ - setarrayvector(L, t, nasize); - /* create new hash part with appropriate size */ - setnodevector(L, t, nhsize); - if (nasize < oldasize) { /* array part must shrink? */ - t->sizearray = nasize; - /* re-insert elements from vanishing slice */ - for (i=nasize; isizearray = newasize; /* pretend array has new size... */ + exchangehashpart(t, &newt); /* and new hash */ + /* re-insert into the new hash the elements from vanishing slice */ + for (i = newasize; i < oldasize; i++) { if (!ttisnil(&t->array[i])) luaH_setint(L, t, i + 1, &t->array[i]); } - /* shrink array */ - luaM_reallocvector(L, t->array, oldasize, nasize, TValue); + t->sizearray = oldasize; /* restore current size... */ + exchangehashpart(t, &newt); /* and hash (in case of errors) */ } - /* re-insert elements from hash part */ - for (j = oldhsize - 1; j >= 0; j--) { - Node *old = nold + j; - if (!ttisnil(gval(old))) { - /* doesn't need barrier/invalidate cache, as entry was - already present in the table */ - TValue k; getnodekey(L, &k, old); - setobjt2t(L, luaH_set(L, t, &k), gval(old)); - } + /* allocate new array */ + newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); + if (newarray == NULL && newasize > 0) { /* allocation failed? */ + freehash(L, &newt); /* release new hash part */ + luaM_error(L); /* raise error (with array unchanged) */ } - if (oldhsize > 0) /* not the dummy node? */ - luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */ + /* allocation ok; initialize new part of the array */ + exchangehashpart(t, &newt); /* 't' has the new hash ('newt' has the old) */ + t->array = newarray; /* set new array part */ + t->sizearray = newasize; + for (i = oldasize; i < newasize; i++) /* clear new slice of the array */ + setnilvalue(&t->array[i]); + /* re-insert elements from old hash part into new parts */ + reinsert(L, &newt, t); /* 'newt' now has the old hash */ + freehash(L, &newt); /* free old hash part */ } @@ -462,8 +528,7 @@ Table *luaH_new (lua_State *L) { void luaH_free (lua_State *L, Table *t) { - if (!isdummy(t)) - luaM_freearray(L, t->node, cast(size_t, sizenode(t))); + freehash(L, t); luaM_freearray(L, t->array, t->sizearray); luaM_free(L, t); } @@ -685,7 +750,7 @@ static lua_Unsigned hash_search (Table *t, lua_Unsigned j) { ** First, try the array part: if there is an array part and its last ** element is nil, there must be a boundary there; a binary search ** finds that boundary. Otherwise, if the hash part is empty or does not -** contain 'j + 1', 'j' is a boundary. Othersize, call 'hash_search' +** contain 'j + 1', 'j' is a boundary. Otherwize, call 'hash_search' ** to find a boundary in the hash part. */ lua_Unsigned luaH_getn (Table *t) { diff --git a/ltests.c b/ltests.c index a2bbb49fc3..513c846b45 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 2.232 2017/11/09 13:31:29 roberto Exp roberto $ +** $Id: ltests.c,v 2.237 2017/12/15 18:53:48 roberto Exp roberto $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -102,7 +102,7 @@ typedef union Header { Memcontrol l_memcontrol = - {0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}}; + {0L, 0L, 0L, 0L, (~0L), {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}}; static void freeblock (Memcontrol *mc, Header *block) { @@ -141,7 +141,12 @@ void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) { freeblock(mc, block); return NULL; } - else if (size > oldsize && mc->total+size-oldsize > mc->memlimit) + if (mc->countlimit != ~0UL && size > 0) { /* count limit in use? */ + if (mc->countlimit == 0) + return NULL; /* fake a memory allocation error */ + mc->countlimit--; + } + if (size > oldsize && mc->total+size-oldsize > mc->memlimit) return NULL; /* fake a memory allocation error */ else { Header *newblock; @@ -660,7 +665,7 @@ static int get_limits (lua_State *L) { setnameval(L, "BITS_INT", LUAI_BITSINT); setnameval(L, "MAXARG_Ax", MAXARG_Ax); setnameval(L, "MAXARG_Bx", MAXARG_Bx); - setnameval(L, "MAXARG_sBx", MAXARG_sBx); + setnameval(L, "OFFSET_sBx", OFFSET_sBx); setnameval(L, "BITS_INT", LUAI_BITSINT); setnameval(L, "LFPF", LFIELDS_PER_FLUSH); setnameval(L, "NUM_OPCODES", NUM_OPCODES); @@ -695,6 +700,15 @@ static int mem_query (lua_State *L) { } +static int alloc_count (lua_State *L) { + if (lua_isnone(L, 1)) + l_memcontrol.countlimit = ~0L; + else + l_memcontrol.countlimit = luaL_checkinteger(L, 1); + return 0; +} + + static int settrick (lua_State *L) { if (ttisnil(obj_at(L, 1))) l_Trick = NULL; @@ -987,6 +1001,7 @@ static int loadlib (lua_State *L) { {"math", luaopen_math}, {"string", luaopen_string}, {"table", luaopen_table}, + {"T", luaB_opentests}, {NULL, NULL} }; lua_State *L1 = getstate(L); @@ -1241,6 +1256,10 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { msg = NULL; /* to test 'luaL_checkstack' with no message */ luaL_checkstack(L1, sz, msg); } + else if EQ("rawcheckstack") { + int sz = getnum; + lua_pushboolean(L1, lua_checkstack(L1, sz)); + } else if EQ("compare") { const char *opt = getstring; /* EQ, LT, or LE */ int op = (opt[0] == 'E') ? LUA_OPEQ @@ -1358,7 +1377,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { else if EQ("pop") { lua_pop(L1, getnum); } - else if EQ("print") { + else if EQ("printstack") { int n = getnum; if (n != 0) { printf("%s\n", luaL_tolstring(L1, n, NULL)); @@ -1366,6 +1385,10 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { } else printstack(L1); } + else if EQ("print") { + const char *msg = getstring; + printf("%s\n", msg); + } else if EQ("pushbool") { lua_pushboolean(L1, getnum); } @@ -1420,8 +1443,17 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) { int n = getnum; if (L1 != L) { int i; - for (i = 0; i < n; i++) - lua_pushstring(L, lua_tostring(L1, -(n - i))); + for (i = 0; i < n; i++) { + int idx = -(n - i); + switch (lua_type(L1, idx)) { + case LUA_TBOOLEAN: + lua_pushboolean(L, lua_toboolean(L1, idx)); + break; + default: + lua_pushstring(L, lua_tostring(L1, idx)); + break; + } + } } return n; } @@ -1673,6 +1705,7 @@ static const struct luaL_Reg tests_funcs[] = { {"testC", testC}, {"makeCfunc", makeCfunc}, {"totalmem", mem_query}, + {"alloccount", alloc_count}, {"trick", settrick}, {"udataval", udataval}, {"unref", unref}, diff --git a/ltests.h b/ltests.h index e3d1ca1e0f..001b205ce5 100644 --- a/ltests.h +++ b/ltests.h @@ -1,5 +1,5 @@ /* -** $Id: ltests.h,v 2.51 2017/06/27 11:35:31 roberto Exp roberto $ +** $Id: ltests.h,v 2.54 2017/12/07 18:51:39 roberto Exp roberto $ ** Internal Header for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -11,18 +11,18 @@ #include #include -/* test Lua with no compatibility code */ -#undef LUA_COMPAT_MATHLIB -#undef LUA_COMPAT_IPAIRS -#undef LUA_COMPAT_BITLIB -#undef LUA_COMPAT_APIINTCASTS -#undef LUA_COMPAT_FLOATSTRING -#undef LUA_COMPAT_UNPACK -#undef LUA_COMPAT_LOADERS -#undef LUA_COMPAT_LOG10 -#undef LUA_COMPAT_LOADSTRING -#undef LUA_COMPAT_MAXN -#undef LUA_COMPAT_MODULE +/* test Lua with compatibility code */ +#define LUA_COMPAT_MATHLIB +#define LUA_COMPAT_IPAIRS +#define LUA_COMPAT_BITLIB +#define LUA_COMPAT_APIINTCASTS +#define LUA_COMPAT_FLOATSTRING +#define LUA_COMPAT_UNPACK +#define LUA_COMPAT_LOADERS +#define LUA_COMPAT_LOG10 +#define LUA_COMPAT_LOADSTRING +#define LUA_COMPAT_MAXN +#define LUA_COMPAT_MODULE #define LUA_DEBUG @@ -34,6 +34,10 @@ #define lua_assert(c) assert(c) +/* compiled with -O0, Lua uses a lot of C stack space... */ +#undef LUAI_MAXCCALLS +#define LUAI_MAXCCALLS 200 + /* to avoid warnings, and to make sure value is really unused */ #define UNUSED(x) (x=0, (void)(x)) @@ -53,6 +57,7 @@ typedef struct Memcontrol { unsigned long total; unsigned long maxmem; unsigned long memlimit; + unsigned long countlimit; unsigned long objcount[LUA_NUMTAGS]; } Memcontrol; diff --git a/ltm.c b/ltm.c index 4c03d2e410..4b14f197db 100644 --- a/ltm.c +++ b/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 2.47 2017/11/07 13:25:26 roberto Exp roberto $ +** $Id: ltm.c,v 2.55 2017/12/20 14:58:05 roberto Exp roberto $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -106,9 +106,9 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, setobj2s(L, func + 1, p1); /* 1st argument */ setobj2s(L, func + 2, p2); /* 2nd argument */ setobj2s(L, func + 3, p3); /* 3rd argument */ - L->top += 4; + L->top = func + 4; /* metamethod may yield only when called from Lua code */ - if (isLua(L->ci)) + if (isLuacode(L->ci)) luaD_call(L, func, 0); else luaD_callnoyield(L, func, 0); @@ -124,12 +124,12 @@ void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, setobj2s(L, func + 2, p2); /* 2nd argument */ L->top += 3; /* metamethod may yield only when called from Lua code */ - if (isLua(L->ci)) + if (isLuacode(L->ci)) luaD_call(L, func, 1); else luaD_callnoyield(L, func, 1); res = restorestack(L, result); - setobjs2s(L, res, --L->top); /* more result to its place */ + setobjs2s(L, res, --L->top); /* move result to its place */ } @@ -166,24 +166,52 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, } +void luaT_trybinassocTM (lua_State *L, const TValue *p1, const TValue *p2, + StkId res, int inv, TMS event) { + if (inv) + luaT_trybinTM(L, p2, p1, res, event); + else + luaT_trybinTM(L, p1, p2, res, event); +} + + void luaT_trybiniTM (lua_State *L, const TValue *p1, int i2, int inv, StkId res, TMS event) { - TValue aux; const TValue *p2; + TValue aux; setivalue(&aux, i2); - if (inv) { /* arguments were exchanged? */ - p2 = p1; p1 = &aux; /* correct them */ - } - else p2 = &aux; - luaT_trybinTM(L, p1, p2, res, event); + luaT_trybinassocTM(L, p1, &aux, res, inv, event); } int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event) { - if (!callbinTM(L, p1, p2, L->top, event)) - return -1; /* no metamethod */ - else + if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ return !l_isfalse(s2v(L->top)); + else if (event == TM_LE) { + /* try '!(p2 < p1)' for '(p1 <= p2)' */ + L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ + if (callbinTM(L, p2, p1, L->top, TM_LT)) { + L->ci->callstatus ^= CIST_LEQ; /* clear mark */ + return l_isfalse(s2v(L->top)); + } + /* else error will remove this 'ci'; no need to clear mark */ + } + luaG_ordererror(L, p1, p2); /* no metamethod found */ + return 0; /* to avoid warnings */ +} + + +int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, + int inv, TMS event) { + TValue aux; const TValue *p2; + setivalue(&aux, v2); + if (inv) { /* arguments were exchanged? */ + p2 = p1; p1 = &aux; /* correct them */ + event = (event == TM_LE) ? TM_LT : TM_LE; + } + else + p2 = &aux; + return (luaT_callorderTM(L, p1, p2, event) != inv); } @@ -191,7 +219,7 @@ void luaT_adjustvarargs (lua_State *L, Proto *p, int actual) { int i; Table *vtab; TValue nname; - int nfixparams = p->numparams - 1; /* number of fixed parameters */ + int nfixparams = p->numparams; /* number of fixed parameters */ actual -= nfixparams; /* number of extra arguments */ vtab = luaH_new(L); /* create vararg table */ sethvalue2s(L, L->top, vtab); /* anchor it for resizing */ @@ -214,7 +242,7 @@ void luaT_getvarargs (lua_State *L, TValue *t, StkId where, int wanted) { Table *h = hvalue(t); if (wanted < 0) { /* get all? */ const TValue *ns = luaH_getstr(h, G(L)->nfield); - int n = (ttisinteger(ns)) ? ivalue(ns) : 0; + int n = (ttisinteger(ns)) ? cast_int(ivalue(ns)) : 0; wanted = n; checkstackp(L, n, where); L->top = where + n; diff --git a/ltm.h b/ltm.h index 31454a5cac..34dbc82cc4 100644 --- a/ltm.h +++ b/ltm.h @@ -1,5 +1,5 @@ /* -** $Id: ltm.h,v 2.25 2017/06/29 15:06:44 roberto Exp roberto $ +** $Id: ltm.h,v 2.27 2017/11/27 17:44:31 roberto Exp roberto $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -68,10 +68,14 @@ LUAI_FUNC void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, const TValue *p2, StkId p3); LUAI_FUNC void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event); +LUAI_FUNC void luaT_trybinassocTM (lua_State *L, const TValue *p1, + const TValue *p2, StkId res, int inv, TMS event); LUAI_FUNC void luaT_trybiniTM (lua_State *L, const TValue *p1, int i2, int inv, StkId res, TMS event); LUAI_FUNC int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, TMS event); +LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, + int inv, TMS event); LUAI_FUNC void luaT_adjustvarargs (lua_State *L, Proto *p, int actual); LUAI_FUNC void luaT_getvarargs (lua_State *L, TValue *t, StkId where, diff --git a/luaconf.h b/luaconf.h index f7ac7160a2..888e402b33 100644 --- a/luaconf.h +++ b/luaconf.h @@ -1,5 +1,5 @@ /* -** $Id: luaconf.h,v 1.260 2017/04/19 16:34:35 roberto Exp roberto $ +** $Id: luaconf.h,v 1.262 2017/12/07 18:53:33 roberto Exp roberto $ ** Configuration file for Lua ** See Copyright Notice in lua.h */ @@ -610,7 +610,7 @@ /* -@@ lua_strx2number converts an hexadecimal numeric string to a number. +@@ lua_strx2number converts a hexadecimal numeric string to a number. ** In C99, 'strtod' does that conversion. Otherwise, you can ** leave 'lua_strx2number' undefined and Lua will provide its own ** implementation. @@ -628,7 +628,7 @@ /* -@@ lua_number2strx converts a float to an hexadecimal numeric string. +@@ lua_number2strx converts a float to a hexadecimal numeric string. ** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that. ** Otherwise, you can leave 'lua_number2strx' undefined and Lua will ** provide its own implementation. @@ -724,6 +724,7 @@ ** CHANGE it if you need a different limit. This limit is arbitrary; ** its only purpose is to stop Lua from consuming unlimited stack ** space (and to reserve some numbers for pseudo-indices). +** (It must fit into max(size_t)/32.) */ #if LUAI_BITSINT >= 32 #define LUAI_MAXSTACK 1000000 diff --git a/lundump.c b/lundump.c index 1f2f1a925a..25ab102dab 100644 --- a/lundump.c +++ b/lundump.c @@ -1,5 +1,5 @@ /* -** $Id: lundump.c,v 2.46 2017/06/27 14:21:12 roberto Exp roberto $ +** $Id: lundump.c,v 2.48 2017/11/28 11:19:07 roberto Exp roberto $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -114,7 +114,7 @@ static TString *LoadString (LoadState *S) { static void LoadCode (LoadState *S, Proto *f) { int n = LoadInt(S); - f->code = luaM_newvector(S->L, n, Instruction); + f->code = luaM_newvectorchecked(S->L, n, Instruction); f->sizecode = n; LoadVector(S, f->code, n); } @@ -126,7 +126,7 @@ static void LoadFunction(LoadState *S, Proto *f, TString *psource); static void LoadConstants (LoadState *S, Proto *f) { int i; int n = LoadInt(S); - f->k = luaM_newvector(S->L, n, TValue); + f->k = luaM_newvectorchecked(S->L, n, TValue); f->sizek = n; for (i = 0; i < n; i++) setnilvalue(&f->k[i]); @@ -134,24 +134,23 @@ static void LoadConstants (LoadState *S, Proto *f) { TValue *o = &f->k[i]; int t = LoadByte(S); switch (t) { - case LUA_TNIL: - setnilvalue(o); - break; - case LUA_TBOOLEAN: - setbvalue(o, LoadByte(S)); - break; - case LUA_TNUMFLT: - setfltvalue(o, LoadNumber(S)); - break; - case LUA_TNUMINT: - setivalue(o, LoadInteger(S)); - break; - case LUA_TSHRSTR: - case LUA_TLNGSTR: - setsvalue2n(S->L, o, LoadString(S)); - break; - default: - lua_assert(0); + case LUA_TNIL: + setnilvalue(o); + break; + case LUA_TBOOLEAN: + setbvalue(o, LoadByte(S)); + break; + case LUA_TNUMFLT: + setfltvalue(o, LoadNumber(S)); + break; + case LUA_TNUMINT: + setivalue(o, LoadInteger(S)); + break; + case LUA_TSHRSTR: + case LUA_TLNGSTR: + setsvalue2n(S->L, o, LoadString(S)); + break; + default: lua_assert(0); } } } @@ -160,7 +159,7 @@ static void LoadConstants (LoadState *S, Proto *f) { static void LoadProtos (LoadState *S, Proto *f) { int i; int n = LoadInt(S); - f->p = luaM_newvector(S->L, n, Proto *); + f->p = luaM_newvectorchecked(S->L, n, Proto *); f->sizep = n; for (i = 0; i < n; i++) f->p[i] = NULL; @@ -174,7 +173,7 @@ static void LoadProtos (LoadState *S, Proto *f) { static void LoadUpvalues (LoadState *S, Proto *f) { int i, n; n = LoadInt(S); - f->upvalues = luaM_newvector(S->L, n, Upvaldesc); + f->upvalues = luaM_newvectorchecked(S->L, n, Upvaldesc); f->sizeupvalues = n; for (i = 0; i < n; i++) f->upvalues[i].name = NULL; @@ -188,18 +187,18 @@ static void LoadUpvalues (LoadState *S, Proto *f) { static void LoadDebug (LoadState *S, Proto *f) { int i, n; n = LoadInt(S); - f->lineinfo = luaM_newvector(S->L, n, ls_byte); + f->lineinfo = luaM_newvectorchecked(S->L, n, ls_byte); f->sizelineinfo = n; LoadVector(S, f->lineinfo, n); n = LoadInt(S); - f->abslineinfo = luaM_newvector(S->L, n, AbsLineInfo); + f->abslineinfo = luaM_newvectorchecked(S->L, n, AbsLineInfo); f->sizeabslineinfo = n; for (i = 0; i < n; i++) { f->abslineinfo[i].pc = LoadInt(S); f->abslineinfo[i].line = LoadInt(S); } n = LoadInt(S); - f->locvars = luaM_newvector(S->L, n, LocVar); + f->locvars = luaM_newvectorchecked(S->L, n, LocVar); f->sizelocvars = n; for (i = 0; i < n; i++) f->locvars[i].varname = NULL; diff --git a/lvm.c b/lvm.c index 457da1ddf7..2b03593256 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.314 2017/11/22 18:41:20 roberto Exp roberto $ +** $Id: lvm.c,v 2.330 2017/12/28 15:42:57 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -374,13 +374,11 @@ static int LEnum (const TValue *l, const TValue *r) { ** return 'l < r' for non-numbers. */ static int lessthanothers (lua_State *L, const TValue *l, const TValue *r) { - int res; lua_assert(!ttisnumber(l) || !ttisnumber(r)); if (ttisstring(l) && ttisstring(r)) /* both are strings? */ return l_strcmp(tsvalue(l), tsvalue(r)) < 0; - else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */ - luaG_ordererror(L, l, r); /* error */ - return res; + else + return luaT_callorderTM(L, l, r, TM_LT); } @@ -403,20 +401,11 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) { ** keeps that information. */ static int lessequalothers (lua_State *L, const TValue *l, const TValue *r) { - int res; lua_assert(!ttisnumber(l) || !ttisnumber(r)); if (ttisstring(l) && ttisstring(r)) /* both are strings? */ return l_strcmp(tsvalue(l), tsvalue(r)) <= 0; - else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */ - return res; - else { /* try 'lt': */ - L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ - res = luaT_callorderTM(L, r, l, TM_LT); - L->ci->callstatus ^= CIST_LEQ; /* clear mark */ - if (res < 0) - luaG_ordererror(L, l, r); - return !res; /* result is negated */ - } + else + return luaT_callorderTM(L, l, r, TM_LE); } @@ -685,7 +674,7 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base, /* -** finish execution of an opcode interrupted by an yield +** finish execution of an opcode interrupted by a yield */ void luaV_finishOp (lua_State *L) { CallInfo *ci = L->ci; @@ -698,7 +687,9 @@ void luaV_finishOp (lua_State *L) { case OP_MODI: case OP_POWI: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_IDIV: - case OP_BAND: case OP_BOR: case OP_BXOR: case OP_SHL: case OP_SHR: + case OP_BANDK: case OP_BORK: case OP_BXORK: + case OP_BAND: case OP_BOR: case OP_BXOR: + case OP_SHRI: case OP_SHL: case OP_SHR: case OP_MOD: case OP_POW: case OP_UNM: case OP_BNOT: case OP_LEN: case OP_GETTABUP: case OP_GETTABLE: case OP_GETI: @@ -706,16 +697,21 @@ void luaV_finishOp (lua_State *L) { setobjs2s(L, base + GETARG_A(inst), --L->top); break; } - case OP_LE: case OP_LT: case OP_EQ: { + case OP_LT: case OP_LE: + case OP_LTI: case OP_LEI: + case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */ int res = !l_isfalse(s2v(L->top - 1)); L->top--; if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ - lua_assert(op == OP_LE); + lua_assert(op == OP_LE || + (op == OP_LTI && GETARG_C(inst)) || + (op == OP_LEI && !GETARG_C(inst))); ci->callstatus ^= CIST_LEQ; /* clear mark */ res = !res; /* negate result */ } lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP); - if (res != GETARG_B(inst)) /* condition failed? */ + if (GETARG_C(inst)) res = !res; + if (res != GETARG_k(inst)) /* condition failed? */ ci->u.l.savedpc++; /* skip jump instruction */ break; } @@ -730,20 +726,10 @@ void luaV_finishOp (lua_State *L) { } /* move final result to final position */ setobjs2s(L, ci->func + 1 + GETARG_A(inst), L->top - 1); - L->top = ci->top; /* restore top */ - break; - } - case OP_TFORCALL: { - lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_TFORLOOP); - L->top = ci->top; /* correct top */ - break; - } - case OP_CALL: { - if (GETARG_C(inst) - 1 >= 0) /* nresults >= 0? */ - L->top = ci->top; /* adjust results */ break; } - case OP_TAILCALL: case OP_SETTABUP: case OP_SETTABLE: + case OP_TFORCALL: case OP_CALL: case OP_TAILCALL: + case OP_SETTABUP: case OP_SETTABLE: case OP_SETI: case OP_SETFIELD: break; default: lua_assert(0); @@ -772,7 +758,7 @@ void luaV_finishOp (lua_State *L) { #define RC(i) (base+GETARG_C(i)) #define vRC(i) s2v(RC(i)) #define KC(i) (k+GETARG_C(i)) -#define RKC(i) ((GETARG_k(i)) ? k + GETARG_C(i) : s2v(base + GETARG_C(i))) +#define RKC(i) ((TESTARG_k(i)) ? k + GETARG_C(i) : s2v(base + GETARG_C(i))) @@ -792,22 +778,36 @@ void luaV_finishOp (lua_State *L) { #define donextjump(ci) { i = *pc; dojump(ci, i, 1); } /* -** Whenever code can raise errors (including memory errors), the global -** 'pc' must be correct to report occasional errors. +** Correct global 'pc'. */ #define savepc(L) (ci->u.l.savedpc = pc) +/* +** Whenever code can raise errors, the global 'pc' and the global +** 'top' must be correct to report occasional errors. +*/ +#define savestate(L,ci) (savepc(L), L->top = ci->top) + + /* ** Protect code that, in general, can raise errors, reallocate the ** stack, and change the hooks. */ -#define Protect(exp) (savepc(L), (exp), updatetrap(ci)) +#define Protect(exp) (savestate(L,ci), (exp), updatetrap(ci)) + +/* special version that does not change the top */ +#define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) + +/* +** Protect code that will finish the loop (returns). +*/ +#define halfProtect(exp) (savepc(L), (exp)) #define checkGC(L,c) \ { luaC_condGC(L, L->top = (c), /* limit of live values */ \ - (L->top = ci->top, updatetrap(ci))); /* restore top */ \ + updatetrap(ci)); \ luai_threadyield(L); } @@ -821,6 +821,7 @@ void luaV_finishOp (lua_State *L) { updatebase(ci); /* the trap may be just for that */ \ } \ ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \ + vra = s2v(ra); \ } #define vmdispatch(o) switch(o) @@ -828,28 +829,27 @@ void luaV_finishOp (lua_State *L) { #define vmbreak break -void luaV_execute (lua_State *L) { - CallInfo *ci = L->ci; /* local copy of 'L->ci' */ +void luaV_execute (lua_State *L, CallInfo *ci) { LClosure *cl; TValue *k; - StkId base; /* local copy of 'ci->func + 1' */ - int trap; - const Instruction *pc; /* local copy of 'ci->u.l.savedpc' */ - ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */ - newframe: /* reentry point when frame changes (call/return) */ - lua_assert(ci == L->ci); - cl = clLvalue(s2v(ci->func)); /* local reference to function's closure */ - k = cl->p->k; /* local reference to function's constant table */ - updatetrap(ci); - updatebase(ci); + StkId base; + const Instruction *pc; + int trap = ci->u.l.trap; + tailcall: + cl = clLvalue(s2v(ci->func)); + k = cl->p->k; + base = ci->func + 1; pc = ci->u.l.savedpc; /* main loop of interpreter */ for (;;) { - Instruction i; - StkId ra; + int cond; /* flag for conditional jumps */ + Instruction i; /* instruction being executed */ + StkId ra; /* instruction's A register */ + TValue *vra; /* corresponding value */ vmfetch(); lua_assert(base == ci->func + 1); lua_assert(base <= L->top && L->top < L->stack + L->stacksize); + lua_assert(ci->top < L->stack + L->stacksize); vmdispatch (GET_OPCODE(i)) { vmcase(OP_MOVE) { setobjs2s(L, ra, RB(i)); @@ -862,12 +862,12 @@ void luaV_execute (lua_State *L) { } vmcase(OP_LOADI) { lua_Integer b = GETARG_sBx(i); - setivalue(s2v(ra), b); + setivalue(vra, b); vmbreak; } vmcase(OP_LOADF) { int b = GETARG_sBx(i); - setfltvalue(s2v(ra), cast_num(b)); + setfltvalue(vra, cast_num(b)); vmbreak; } vmcase(OP_LOADKX) { @@ -877,7 +877,7 @@ void luaV_execute (lua_State *L) { vmbreak; } vmcase(OP_LOADBOOL) { - setbvalue(s2v(ra), GETARG_B(i)); + setbvalue(vra, GETARG_B(i)); if (GETARG_C(i)) pc++; /* skip next instruction (if C) */ vmbreak; } @@ -895,8 +895,8 @@ void luaV_execute (lua_State *L) { } vmcase(OP_SETUPVAL) { UpVal *uv = cl->upvals[GETARG_B(i)]; - setobj(L, uv->v, s2v(ra)); - luaC_barrier(L, uv, s2v(ra)); + setobj(L, uv->v, vra); + luaC_barrier(L, uv, vra); vmbreak; } vmcase(OP_GETTABUP) { @@ -970,25 +970,25 @@ void luaV_execute (lua_State *L) { TValue *rc = RKC(i); /* value */ lua_Unsigned n; if (ttisinteger(rb) /* fast track for integers? */ - ? (n = ivalue(rb), luaV_fastgeti(L, s2v(ra), n, slot)) - : luaV_fastget(L, s2v(ra), rb, slot, luaH_get)) { - luaV_finishfastset(L, s2v(ra), slot, rc); + ? (n = ivalue(rb), luaV_fastgeti(L, vra, n, slot)) + : luaV_fastget(L, vra, rb, slot, luaH_get)) { + luaV_finishfastset(L, vra, slot, rc); } else - Protect(luaV_finishset(L, s2v(ra), rb, rc, slot)); + Protect(luaV_finishset(L, vra, rb, rc, slot)); vmbreak; } vmcase(OP_SETI) { const TValue *slot; int c = GETARG_B(i); TValue *rc = RKC(i); - if (luaV_fastgeti(L, s2v(ra), c, slot)) { - luaV_finishfastset(L, s2v(ra), slot, rc); + if (luaV_fastgeti(L, vra, c, slot)) { + luaV_finishfastset(L, vra, slot, rc); } else { TValue key; setivalue(&key, c); - Protect(luaV_finishset(L, s2v(ra), &key, rc, slot)); + Protect(luaV_finishset(L, vra, &key, rc, slot)); } vmbreak; } @@ -997,22 +997,22 @@ void luaV_execute (lua_State *L) { TValue *rb = KB(i); TValue *rc = RKC(i); TString *key = tsvalue(rb); /* key must be a string */ - if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) { - luaV_finishfastset(L, s2v(ra), slot, rc); + if (luaV_fastget(L, vra, key, slot, luaH_getshortstr)) { + luaV_finishfastset(L, vra, slot, rc); } else - Protect(luaV_finishset(L, s2v(ra), rb, rc, slot)); + Protect(luaV_finishset(L, vra, rb, rc, slot)); vmbreak; } vmcase(OP_NEWTABLE) { int b = GETARG_B(i); int c = GETARG_C(i); Table *t; - savepc(L); /* in case of allocation errors */ - t = luaH_new(L); + L->top = ci->top; /* correct top in case of GC */ + t = luaH_new(L); /* memory allocation */ sethvalue2s(L, ra, t); if (b != 0 || c != 0) - luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); + luaH_resize(L, t, luaO_fb2int(b), luaO_fb2int(c)); /* idem */ checkGC(L, ra + 1); vmbreak; } @@ -1034,10 +1034,10 @@ void luaV_execute (lua_State *L) { int ic = GETARG_sC(i); lua_Number nb; if (ttisinteger(rb)) { - setivalue(s2v(ra), intop(+, ivalue(rb), ic)); + setivalue(vra, intop(+, ivalue(rb), ic)); } else if (tonumberns(rb, nb)) { - setfltvalue(s2v(ra), luai_numadd(L, nb, cast_num(ic))); + setfltvalue(vra, luai_numadd(L, nb, cast_num(ic))); } else Protect(luaT_trybiniTM(L, rb, ic, GETARG_k(i), ra, TM_ADD)); @@ -1048,10 +1048,10 @@ void luaV_execute (lua_State *L) { int ic = GETARG_sC(i); lua_Number nb; if (ttisinteger(rb)) { - setivalue(s2v(ra), intop(-, ivalue(rb), ic)); + setivalue(vra, intop(-, ivalue(rb), ic)); } else if (tonumberns(rb, nb)) { - setfltvalue(s2v(ra), luai_numsub(L, nb, cast_num(ic))); + setfltvalue(vra, luai_numsub(L, nb, cast_num(ic))); } else Protect(luaT_trybiniTM(L, rb, ic, 0, ra, TM_SUB)); @@ -1062,10 +1062,10 @@ void luaV_execute (lua_State *L) { int ic = GETARG_sC(i); lua_Number nb; if (ttisinteger(rb)) { - setivalue(s2v(ra), intop(*, ivalue(rb), ic)); + setivalue(vra, intop(*, ivalue(rb), ic)); } else if (tonumberns(rb, nb)) { - setfltvalue(s2v(ra), luai_nummul(L, nb, cast_num(ic))); + setfltvalue(vra, luai_nummul(L, nb, cast_num(ic))); } else Protect(luaT_trybiniTM(L, rb, ic, GETARG_k(i), ra, TM_MUL)); @@ -1076,13 +1076,13 @@ void luaV_execute (lua_State *L) { int ic = GETARG_sC(i); lua_Number nb; if (ttisinteger(rb)) { - setivalue(s2v(ra), luaV_mod(L, ivalue(rb), ic)); + setivalue(vra, luaV_mod(L, ivalue(rb), ic)); } else if (tonumberns(rb, nb)) { lua_Number m; lua_Number nc = cast_num(ic); luai_nummod(L, nb, nc, m); - setfltvalue(s2v(ra), m); + setfltvalue(vra, m); } else Protect(luaT_trybiniTM(L, rb, ic, 0, ra, TM_MOD)); @@ -1094,7 +1094,7 @@ void luaV_execute (lua_State *L) { lua_Number nb; if (tonumberns(rb, nb)) { lua_Number nc = cast_num(ic); - setfltvalue(s2v(ra), luai_numpow(L, nb, nc)); + setfltvalue(vra, luai_numpow(L, nb, nc)); } else Protect(luaT_trybiniTM(L, rb, ic, 0, ra, TM_POW)); @@ -1106,7 +1106,7 @@ void luaV_execute (lua_State *L) { lua_Number nb; if (tonumberns(rb, nb)) { lua_Number nc = cast_num(ic); - setfltvalue(s2v(ra), luai_numdiv(L, nb, nc)); + setfltvalue(vra, luai_numdiv(L, nb, nc)); } else Protect(luaT_trybiniTM(L, rb, ic, 0, ra, TM_DIV)); @@ -1117,11 +1117,11 @@ void luaV_execute (lua_State *L) { int ic = GETARG_sC(i); lua_Number nb; if (ttisinteger(rb)) { - setivalue(s2v(ra), luaV_div(L, ivalue(rb), ic)); + setivalue(vra, luaV_div(L, ivalue(rb), ic)); } else if (tonumberns(rb, nb)) { lua_Number nc = cast_num(ic); - setfltvalue(s2v(ra), luai_numdiv(L, nb, nc)); + setfltvalue(vra, luai_numdiv(L, nb, nc)); } else Protect(luaT_trybiniTM(L, rb, ic, 0, ra, TM_IDIV)); @@ -1133,10 +1133,10 @@ void luaV_execute (lua_State *L) { lua_Number nb; lua_Number nc; if (ttisinteger(rb) && ttisinteger(rc)) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(s2v(ra), intop(+, ib, ic)); + setivalue(vra, intop(+, ib, ic)); } else if (tonumberns(rb, nb) && tonumberns(rc, nc)) { - setfltvalue(s2v(ra), luai_numadd(L, nb, nc)); + setfltvalue(vra, luai_numadd(L, nb, nc)); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); @@ -1148,10 +1148,10 @@ void luaV_execute (lua_State *L) { lua_Number nb; lua_Number nc; if (ttisinteger(rb) && ttisinteger(rc)) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(s2v(ra), intop(-, ib, ic)); + setivalue(vra, intop(-, ib, ic)); } else if (tonumberns(rb, nb) && tonumberns(rc, nc)) { - setfltvalue(s2v(ra), luai_numsub(L, nb, nc)); + setfltvalue(vra, luai_numsub(L, nb, nc)); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_SUB)); @@ -1163,10 +1163,10 @@ void luaV_execute (lua_State *L) { lua_Number nb; lua_Number nc; if (ttisinteger(rb) && ttisinteger(rc)) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(s2v(ra), intop(*, ib, ic)); + setivalue(vra, intop(*, ib, ic)); } else if (tonumberns(rb, nb) && tonumberns(rc, nc)) { - setfltvalue(s2v(ra), luai_nummul(L, nb, nc)); + setfltvalue(vra, luai_nummul(L, nb, nc)); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_MUL)); @@ -1177,18 +1177,51 @@ void luaV_execute (lua_State *L) { TValue *rc = vRC(i); lua_Number nb; lua_Number nc; if (tonumberns(rb, nb) && tonumberns(rc, nc)) { - setfltvalue(s2v(ra), luai_numdiv(L, nb, nc)); + setfltvalue(vra, luai_numdiv(L, nb, nc)); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); vmbreak; } + vmcase(OP_BANDK) { + TValue *p1 = vRB(i); + TValue *p2 = KC(i); + lua_Integer i1; + if (tointegerns(p1, &i1)) { + setivalue(vra, intop(&, i1, ivalue(p2))); + } + else + Protect(luaT_trybinassocTM(L, p1, p2, ra, TESTARG_k(i), TM_BAND)); + vmbreak; + } + vmcase(OP_BORK) { + TValue *p1 = vRB(i); + TValue *p2 = KC(i); + lua_Integer i1; + if (tointegerns(p1, &i1)) { + setivalue(vra, intop(|, i1, ivalue(p2))); + } + else + Protect(luaT_trybinassocTM(L, p1, p2, ra, TESTARG_k(i), TM_BOR)); + vmbreak; + } + vmcase(OP_BXORK) { + TValue *p1 = vRB(i); + TValue *p2 = KC(i); + lua_Integer i1; + if (tointegerns(p1, &i1)) { + setivalue(vra, intop(^, i1, ivalue(p2))); + } + else + Protect(luaT_trybinassocTM(L, p1, p2, ra, TESTARG_k(i), TM_BXOR)); + vmbreak; + } vmcase(OP_BAND) { TValue *rb = vRB(i); TValue *rc = vRC(i); lua_Integer ib; lua_Integer ic; if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) { - setivalue(s2v(ra), intop(&, ib, ic)); + setivalue(vra, intop(&, ib, ic)); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_BAND)); @@ -1199,7 +1232,7 @@ void luaV_execute (lua_State *L) { TValue *rc = vRC(i); lua_Integer ib; lua_Integer ic; if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) { - setivalue(s2v(ra), intop(|, ib, ic)); + setivalue(vra, intop(|, ib, ic)); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_BOR)); @@ -1210,18 +1243,45 @@ void luaV_execute (lua_State *L) { TValue *rc = vRC(i); lua_Integer ib; lua_Integer ic; if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) { - setivalue(s2v(ra), intop(^, ib, ic)); + setivalue(vra, intop(^, ib, ic)); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_BXOR)); vmbreak; } + vmcase(OP_SHRI) { + TValue *rb = vRB(i); + int ic = GETARG_sC(i); + lua_Integer ib; + if (tointegerns(rb, &ib)) { + setivalue(vra, luaV_shiftl(ib, -ic)); + } + else { + TMS ev = TM_SHR; + if (TESTARG_k(i)) { + ic = -ic; ev = TM_SHL; + } + Protect(luaT_trybiniTM(L, rb, ic, 0, ra, ev)); + } + vmbreak; + } + vmcase(OP_SHLI) { + TValue *rb = vRB(i); + int ic = GETARG_sC(i); + lua_Integer ib; + if (tointegerns(rb, &ib)) { + setivalue(vra, luaV_shiftl(ic, ib)); + } + else + Protect(luaT_trybiniTM(L, rb, ic, 1, ra, TM_SHL)); + vmbreak; + } vmcase(OP_SHL) { TValue *rb = vRB(i); TValue *rc = vRC(i); lua_Integer ib; lua_Integer ic; if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) { - setivalue(s2v(ra), luaV_shiftl(ib, ic)); + setivalue(vra, luaV_shiftl(ib, ic)); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHL)); @@ -1232,7 +1292,7 @@ void luaV_execute (lua_State *L) { TValue *rc = vRC(i); lua_Integer ib; lua_Integer ic; if (tointegerns(rb, &ib) && tointegerns(rc, &ic)) { - setivalue(s2v(ra), luaV_shiftl(ib, -ic)); + setivalue(vra, luaV_shiftl(ib, -ic)); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_SHR)); @@ -1244,12 +1304,12 @@ void luaV_execute (lua_State *L) { lua_Number nb; lua_Number nc; if (ttisinteger(rb) && ttisinteger(rc)) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(s2v(ra), luaV_mod(L, ib, ic)); + setivalue(vra, luaV_mod(L, ib, ic)); } else if (tonumberns(rb, nb) && tonumberns(rc, nc)) { lua_Number m; luai_nummod(L, nb, nc, m); - setfltvalue(s2v(ra), m); + setfltvalue(vra, m); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); @@ -1261,10 +1321,10 @@ void luaV_execute (lua_State *L) { lua_Number nb; lua_Number nc; if (ttisinteger(rb) && ttisinteger(rc)) { lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); - setivalue(s2v(ra), luaV_div(L, ib, ic)); + setivalue(vra, luaV_div(L, ib, ic)); } else if (tonumberns(rb, nb) && tonumberns(rc, nc)) { - setfltvalue(s2v(ra), luai_numidiv(L, nb, nc)); + setfltvalue(vra, luai_numidiv(L, nb, nc)); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); @@ -1275,7 +1335,7 @@ void luaV_execute (lua_State *L) { TValue *rc = vRC(i); lua_Number nb; lua_Number nc; if (tonumberns(rb, nb) && tonumberns(rc, nc)) { - setfltvalue(s2v(ra), luai_numpow(L, nb, nc)); + setfltvalue(vra, luai_numpow(L, nb, nc)); } else Protect(luaT_trybinTM(L, rb, rc, ra, TM_POW)); @@ -1286,10 +1346,10 @@ void luaV_execute (lua_State *L) { lua_Number nb; if (ttisinteger(rb)) { lua_Integer ib = ivalue(rb); - setivalue(s2v(ra), intop(-, 0, ib)); + setivalue(vra, intop(-, 0, ib)); } else if (tonumberns(rb, nb)) { - setfltvalue(s2v(ra), luai_numunm(L, nb)); + setfltvalue(vra, luai_numunm(L, nb)); } else Protect(luaT_trybinTM(L, rb, rb, ra, TM_UNM)); @@ -1299,7 +1359,7 @@ void luaV_execute (lua_State *L) { TValue *rb = vRB(i); lua_Integer ib; if (tointegerns(rb, &ib)) { - setivalue(s2v(ra), intop(^, ~l_castS2U(0), ib)); + setivalue(vra, intop(^, ~l_castS2U(0), ib)); } else Protect(luaT_trybinTM(L, rb, rb, ra, TM_BNOT)); @@ -1307,8 +1367,8 @@ void luaV_execute (lua_State *L) { } vmcase(OP_NOT) { TValue *rb = vRB(i); - int res = l_isfalse(rb); /* next assignment may change this value */ - setbvalue(s2v(ra), res); + int nrb = l_isfalse(rb); /* next assignment may change this value */ + setbvalue(vra, nrb); vmbreak; } vmcase(OP_LEN) { @@ -1320,7 +1380,7 @@ void luaV_execute (lua_State *L) { int c = GETARG_C(i); StkId rb; L->top = base + c + 1; /* mark the end of concat operands */ - Protect(luaV_concat(L, c - b + 1)); + ProtectNT(luaV_concat(L, c - b + 1)); if (trap) { /* 'luaV_concat' may move the stack */ updatebase(ci); ra = RA(i); @@ -1328,7 +1388,6 @@ void luaV_execute (lua_State *L) { rb = base + b; setobjs2s(L, ra, rb); checkGC(L, (ra >= rb ? ra + 1 : rb)); - L->top = ci->top; /* restore top */ vmbreak; } vmcase(OP_CLOSE) { @@ -1340,74 +1399,84 @@ void luaV_execute (lua_State *L) { vmbreak; } vmcase(OP_EQ) { - TValue *rc = vRC(i); - int res; - Protect(res = luaV_equalobj(L, s2v(ra), rc)); - if (res != GETARG_B(i)) - pc++; + TValue *rb = vRB(i); + Protect(cond = luaV_equalobj(L, vra, rb)); + condjump: + if (cond != GETARG_k(i)) + pc++; /* skip next jump */ else donextjump(ci); vmbreak; } vmcase(OP_LT) { - TValue *rc = vRC(i); - int res; - if (ttisinteger(s2v(ra)) && ttisinteger(rc)) - res = (ivalue(s2v(ra)) < ivalue(rc)); - else if (ttisnumber(s2v(ra)) && ttisnumber(rc)) - res = LTnum(s2v(ra), rc); - else - Protect(res = lessthanothers(L, s2v(ra), rc)); - if (res != GETARG_B(i)) - pc++; + TValue *rb = vRB(i); + if (ttisinteger(vra) && ttisinteger(rb)) + cond = (ivalue(vra) < ivalue(rb)); + else if (ttisnumber(vra) && ttisnumber(rb)) + cond = LTnum(vra, rb); else - donextjump(ci); - vmbreak; + Protect(cond = lessthanothers(L, vra, rb)); + goto condjump; } vmcase(OP_LE) { - TValue *rc = vRC(i); - int res; - if (ttisinteger(s2v(ra)) && ttisinteger(rc)) - res = (ivalue(s2v(ra)) <= ivalue(rc)); - else if (ttisnumber(s2v(ra)) && ttisnumber(rc)) - res = LEnum(s2v(ra), rc); - else - Protect(res = lessequalothers(L, s2v(ra), rc)); - if (res != GETARG_B(i)) - pc++; + TValue *rb = vRB(i); + if (ttisinteger(vra) && ttisinteger(rb)) + cond = (ivalue(vra) <= ivalue(rb)); + else if (ttisnumber(vra) && ttisnumber(rb)) + cond = LEnum(vra, rb); else - donextjump(ci); - vmbreak; + Protect(cond = lessequalothers(L, vra, rb)); + goto condjump; } vmcase(OP_EQK) { - TValue *rc = KC(i); + TValue *rb = KB(i); /* basic types do not use '__eq'; we can use raw equality */ - if (luaV_equalobj(NULL, s2v(ra), rc) != GETARG_B(i)) - pc++; - else - donextjump(ci); - vmbreak; + cond = luaV_equalobj(NULL, vra, rb); + goto condjump; } vmcase(OP_EQI) { - int ic = GETARG_sC(i); - if ((ttisinteger(s2v(ra)) ? (ivalue(s2v(ra)) == ic) - :ttisfloat(s2v(ra)) ? luai_numeq(fltvalue(s2v(ra)), cast_num(ic)) - : 0) != GETARG_B(i)) - pc++; + int im = GETARG_sB(i); + if (ttisinteger(vra)) + cond = (ivalue(vra) == im); + else if (ttisfloat(vra)) + cond = luai_numeq(fltvalue(vra), cast_num(im)); else - donextjump(ci); - vmbreak; + cond = 0; /* other types cannot be equal to a number */ + goto condjump; + } + vmcase(OP_LTI) { + int im = GETARG_sB(i); + if (ttisinteger(vra)) + cond = (ivalue(vra) < im); + else if (ttisfloat(vra)) { + lua_Number f = fltvalue(vra); + cond = (!luai_numisnan(f)) ? luai_numlt(f, cast_num(im)) + : GETARG_C(i); /* NaN */ + } + else + Protect(cond = luaT_callorderiTM(L, vra, im, GETARG_C(i), TM_LT)); + goto condjump; + } + vmcase(OP_LEI) { + int im = GETARG_sB(i); + if (ttisinteger(vra)) + cond = (ivalue(vra) <= im); + else if (ttisfloat(vra)) { + lua_Number f = fltvalue(vra); + cond = (!luai_numisnan(f)) ? luai_numle(f, cast_num(im)) + : GETARG_C(i); /* NaN? */ + } + else + Protect(cond = luaT_callorderiTM(L, vra, im, GETARG_C(i), TM_LE)); + goto condjump; } vmcase(OP_TEST) { - if (GETARG_C(i) ? l_isfalse(s2v(ra)) : !l_isfalse(s2v(ra))) - pc++; - else - donextjump(ci); - vmbreak; + cond = !l_isfalse(vra); + goto condjump; } vmcase(OP_TESTSET) { TValue *rb = vRB(i); - if (GETARG_C(i) ? l_isfalse(rb) : !l_isfalse(rb)) + if (l_isfalse(rb) == GETARG_k(i)) pc++; else { setobj2s(L, ra, rb); @@ -1418,20 +1487,10 @@ void luaV_execute (lua_State *L) { vmcase(OP_CALL) { int b = GETARG_B(i); int nresults = GETARG_C(i) - 1; - int isC; if (b != 0) /* fixed number of arguments? */ L->top = ra + b; /* top signals number of arguments */ /* else previous instruction set top */ - Protect(isC = luaD_precall(L, ra, nresults)); - if (isC) { /* C function? */ - if (nresults >= 0) /* fixed number of results? */ - L->top = ci->top; /* correct top */ - /* else leave top for next instruction */ - } - else { /* Lua function */ - ci = L->ci; - goto newframe; /* restart luaV_execute over new Lua function */ - } + ProtectNT(luaD_call(L, ra, nresults)); vmbreak; } vmcase(OP_TAILCALL) { @@ -1441,57 +1500,112 @@ void luaV_execute (lua_State *L) { else /* previous instruction set top */ b = L->top - ra; lua_assert(GETARG_C(i) - 1 == LUA_MULTRET); - if (!ttisfunction(s2v(ra))) { /* not a function? */ + if (!ttisfunction(vra)) { /* not a function? */ /* try to get '__call' metamethod */ - Protect(ra = luaD_tryfuncTM(L, ra)); + ProtectNT(ra = luaD_tryfuncTM(L, ra)); + vra = s2v(ra); b++; /* there is now one extra argument */ } - if (!ttisLclosure(s2v(ra))) /* C function? */ - Protect(luaD_precall(L, ra, LUA_MULTRET)); /* call it */ + if (!ttisLclosure(vra)) { /* C function? */ + ProtectNT(luaD_call(L, ra, LUA_MULTRET)); /* call it */ + /* next instruction will do the return */ + } else { /* tail call */ - if (cl->p->sizep > 0) /* close upvalues from previous call */ + if (TESTARG_k(i)) /* close upvalues from previous call */ luaF_close(L, ci->func + 1); luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ - goto newframe; /* restart luaV_execute over new Lua function */ + goto tailcall; } vmbreak; } vmcase(OP_RETURN) { int b = GETARG_B(i); - if (cl->p->sizep > 0) + if (TESTARG_k(i)) + luaF_close(L, base); + halfProtect( + luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))) + ); + return; + } + vmcase(OP_RETURN0) { + if (TESTARG_k(i)) luaF_close(L, base); - savepc(L); - b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra))); - if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */ - return; /* external invocation: return */ - else { /* invocation via reentry: continue execution */ - ci = L->ci; - if (b) L->top = ci->top; - lua_assert(isLua(ci)); - lua_assert(GET_OPCODE(*((ci)->u.l.savedpc - 1)) == OP_CALL); - goto newframe; /* restart luaV_execute over new Lua function */ + if (L->hookmask) + halfProtect(luaD_poscall(L, ci, ra, 0)); /* no hurry... */ + else { + int nres = ci->nresults; + L->ci = ci->previous; /* back to caller */ + L->top = base - 1; + while (nres-- > 0) + setnilvalue(s2v(L->top++)); /* all results are nil */ } + return; + } + vmcase(OP_RETURN1) { + if (TESTARG_k(i)) + luaF_close(L, base); + if (L->hookmask) + halfProtect(luaD_poscall(L, ci, ra, 1)); /* no hurry... */ + else { + int nres = ci->nresults; + L->ci = ci->previous; /* back to caller */ + if (nres == 0) + L->top = base - 1; /* asked for no results */ + else { + setobjs2s(L, base - 1, ra); /* at least this result */ + L->top = base; + while (--nres > 0) /* complete missing results */ + setnilvalue(s2v(L->top++)); + } + } + return; + } + vmcase(OP_FORLOOP1) { + lua_Integer idx = intop(+, ivalue(vra), 1); /* increment index */ + lua_Integer limit = ivalue(s2v(ra + 1)); + if (idx <= limit) { + pc -= GETARG_Bx(i); /* jump back */ + chgivalue(vra, idx); /* update internal index... */ + setivalue(s2v(ra + 3), idx); /* ...and external index */ + } + updatetrap(ci); + vmbreak; + } + vmcase(OP_FORPREP1) { + TValue *init = vra; + TValue *plimit = s2v(ra + 1); + lua_Integer ilimit, initv; + int stopnow; + if (!forlimit(plimit, &ilimit, 1, &stopnow)) { + savestate(L, ci); /* for the error message */ + luaG_runerror(L, "'for' limit must be a number"); + } + initv = (stopnow ? 0 : ivalue(init)); + setivalue(plimit, ilimit); + setivalue(init, intop(-, initv, 1)); + pc += GETARG_Bx(i); + vmbreak; } vmcase(OP_FORLOOP) { - if (ttisinteger(s2v(ra))) { /* integer loop? */ + if (ttisinteger(vra)) { /* integer loop? */ lua_Integer step = ivalue(s2v(ra + 2)); - lua_Integer idx = intop(+, ivalue(s2v(ra)), step); /* increment index */ + lua_Integer idx = intop(+, ivalue(vra), step); /* increment index */ lua_Integer limit = ivalue(s2v(ra + 1)); if ((0 < step) ? (idx <= limit) : (limit <= idx)) { pc -= GETARG_Bx(i); /* jump back */ - chgivalue(s2v(ra), idx); /* update internal index... */ + chgivalue(vra, idx); /* update internal index... */ setivalue(s2v(ra + 3), idx); /* ...and external index */ } } else { /* floating loop */ lua_Number step = fltvalue(s2v(ra + 2)); lua_Number limit = fltvalue(s2v(ra + 1)); - lua_Number idx = fltvalue(s2v(ra)); + lua_Number idx = fltvalue(vra); idx = luai_numadd(L, idx, step); /* inc. index */ if (luai_numlt(0, step) ? luai_numle(idx, limit) : luai_numle(limit, idx)) { pc -= GETARG_Bx(i); /* jump back */ - chgfltvalue(s2v(ra), idx); /* update internal index... */ + chgfltvalue(vra, idx); /* update internal index... */ setfltvalue(s2v(ra + 3), idx); /* ...and external index */ } } @@ -1499,7 +1613,7 @@ void luaV_execute (lua_State *L) { vmbreak; } vmcase(OP_FORPREP) { - TValue *init = s2v(ra); + TValue *init = vra; TValue *plimit = s2v(ra + 1); TValue *pstep = s2v(ra + 2); lua_Integer ilimit; @@ -1513,7 +1627,7 @@ void luaV_execute (lua_State *L) { } else { /* try making all values floats */ lua_Number ninit; lua_Number nlimit; lua_Number nstep; - savepc(L); /* in case of errors */ + savestate(L, ci); /* in case of errors */ if (!tonumber(plimit, &nlimit)) luaG_runerror(L, "'for' limit must be a number"); setfltvalue(plimit, nlimit); @@ -1534,7 +1648,6 @@ void luaV_execute (lua_State *L) { setobjs2s(L, cb, ra); L->top = cb + 3; /* func. + 2 args (state and index) */ Protect(luaD_call(L, cb, GETARG_C(i))); - L->top = ci->top; if (trap) /* keep 'base' correct for next instruction */ updatebase(ci); i = *(pc++); /* go to next instruction */ @@ -1555,13 +1668,15 @@ void luaV_execute (lua_State *L) { int c = GETARG_C(i); unsigned int last; Table *h; - if (n == 0) n = cast_int(L->top - ra) - 1; + if (n == 0) + n = cast_int(L->top - ra) - 1; + else + L->top = ci->top; /* correct top in case of GC */ if (c == 0) { c = GETARG_Ax(*pc); pc++; } - h = hvalue(s2v(ra)); + h = hvalue(vra); last = ((c-1)*LFIELDS_PER_FLUSH) + n; - savepc(L); /* in case of allocation errors */ if (last > h->sizearray) /* needs more space? */ luaH_resizearray(L, h, last); /* preallocate it at once */ for (; n > 0; n--) { @@ -1570,14 +1685,13 @@ void luaV_execute (lua_State *L) { last--; luaC_barrierback(L, h, val); } - L->top = ci->top; /* correct top (in case of previous open call) */ vmbreak; } vmcase(OP_CLOSURE) { Proto *p = cl->p->p[GETARG_Bx(i)]; LClosure *ncl = getcached(p, cl->upvals, base); /* cached closure */ if (ncl == NULL) { /* no match? */ - savepc(L); /* in case of allocation errors */ + savestate(L, ci); /* in case of allocation errors */ pushclosure(L, p, cl->upvals, base, ra); /* create a new one */ } else @@ -1586,9 +1700,9 @@ void luaV_execute (lua_State *L) { vmbreak; } vmcase(OP_VARARG) { - int b = GETARG_B(i) - 1; /* required results */ - TValue *vtab = vRC(i); /* vararg table */ - Protect(luaT_getvarargs(L, vtab, ra, b)); + int n = GETARG_C(i) - 1; /* required results */ + TValue *vtab = vRB(i); /* vararg table */ + Protect(luaT_getvarargs(L, vtab, ra, n)); vmbreak; } vmcase(OP_EXTRAARG) { diff --git a/lvm.h b/lvm.h index c2e2557420..0d2eed14f4 100644 --- a/lvm.h +++ b/lvm.h @@ -1,5 +1,5 @@ /* -** $Id: lvm.h,v 2.46 2017/07/07 16:34:32 roberto Exp roberto $ +** $Id: lvm.h,v 2.47 2017/11/08 14:50:23 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -112,7 +112,7 @@ LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key, LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key, TValue *val, const TValue *slot); LUAI_FUNC void luaV_finishOp (lua_State *L); -LUAI_FUNC void luaV_execute (lua_State *L); +LUAI_FUNC void luaV_execute (lua_State *L, CallInfo *ci); LUAI_FUNC void luaV_concat (lua_State *L, int total); LUAI_FUNC lua_Integer luaV_div (lua_State *L, lua_Integer x, lua_Integer y); LUAI_FUNC lua_Integer luaV_mod (lua_State *L, lua_Integer x, lua_Integer y);