Upgrade Lua to 5.4.3 (#217)

Based on https://github.com/lua/lua/releases/tag/v5.4.3 (commit eadd8c7).
This commit is contained in:
Paul Kulchenko 2021-07-28 09:26:35 -07:00 committed by GitHub
parent 3ac6576fe5
commit a73e808b25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 464 additions and 264 deletions

View file

@ -166,7 +166,7 @@ LUA_API int lua_gettop (lua_State *L) {
LUA_API void lua_settop (lua_State *L, int idx) { LUA_API void lua_settop (lua_State *L, int idx) {
CallInfo *ci; CallInfo *ci;
StkId func; StkId func, newtop;
ptrdiff_t diff; /* difference for new top */ ptrdiff_t diff; /* difference for new top */
lua_lock(L); lua_lock(L);
ci = L->ci; ci = L->ci;
@ -181,12 +181,13 @@ LUA_API void lua_settop (lua_State *L, int idx) {
api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
diff = idx + 1; /* will "subtract" index (as it is negative) */ diff = idx + 1; /* will "subtract" index (as it is negative) */
} }
#if defined(LUA_COMPAT_5_4_0) api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
if (diff < 0 && hastocloseCfunc(ci->nresults)) newtop = L->top + diff;
luaF_close(L, L->top + diff, CLOSEKTOP, 0); if (diff < 0 && L->tbclist >= newtop) {
#endif lua_assert(hastocloseCfunc(ci->nresults));
api_check(L, L->tbclist < L->top + diff, "cannot pop an unclosed slot"); luaF_close(L, newtop, CLOSEKTOP, 0);
L->top += diff; }
L->top = newtop; /* correct top only after closing any upvalue */
lua_unlock(L); lua_unlock(L);
} }

View file

@ -178,7 +178,7 @@ LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
} }
int luaL_typeerror (lua_State *L, int arg, const char *tname) { LUALIB_API int luaL_typeerror (lua_State *L, int arg, const char *tname) {
const char *msg; const char *msg;
const char *typearg; /* name for the type of the actual argument */ const char *typearg; /* name for the type of the actual argument */
if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING)
@ -364,7 +364,7 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
** but without 'msg'.) ** but without 'msg'.)
*/ */
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
if (!lua_checkstack(L, space)) { if (l_unlikely(!lua_checkstack(L, space))) {
if (msg) if (msg)
luaL_error(L, "stack overflow (%s)", msg); luaL_error(L, "stack overflow (%s)", msg);
else else
@ -374,20 +374,20 @@ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) {
if (lua_type(L, arg) != t) if (l_unlikely(lua_type(L, arg) != t))
tag_error(L, arg, t); tag_error(L, arg, t);
} }
LUALIB_API void luaL_checkany (lua_State *L, int arg) { LUALIB_API void luaL_checkany (lua_State *L, int arg) {
if (lua_type(L, arg) == LUA_TNONE) if (l_unlikely(lua_type(L, arg) == LUA_TNONE))
luaL_argerror(L, arg, "value expected"); luaL_argerror(L, arg, "value expected");
} }
LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) {
const char *s = lua_tolstring(L, arg, len); const char *s = lua_tolstring(L, arg, len);
if (!s) tag_error(L, arg, LUA_TSTRING); if (l_unlikely(!s)) tag_error(L, arg, LUA_TSTRING);
return s; return s;
} }
@ -406,7 +406,7 @@ LUALIB_API const char *luaL_optlstring (lua_State *L, int arg,
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) {
int isnum; int isnum;
lua_Number d = lua_tonumberx(L, arg, &isnum); lua_Number d = lua_tonumberx(L, arg, &isnum);
if (!isnum) if (l_unlikely(!isnum))
tag_error(L, arg, LUA_TNUMBER); tag_error(L, arg, LUA_TNUMBER);
return d; return d;
} }
@ -428,7 +428,7 @@ static void interror (lua_State *L, int arg) {
LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) {
int isnum; int isnum;
lua_Integer d = lua_tointegerx(L, arg, &isnum); lua_Integer d = lua_tointegerx(L, arg, &isnum);
if (!isnum) { if (l_unlikely(!isnum)) {
interror(L, arg); interror(L, arg);
} }
return d; return d;
@ -461,7 +461,7 @@ static void *resizebox (lua_State *L, int idx, size_t newsize) {
lua_Alloc allocf = lua_getallocf(L, &ud); lua_Alloc allocf = lua_getallocf(L, &ud);
UBox *box = (UBox *)lua_touserdata(L, idx); UBox *box = (UBox *)lua_touserdata(L, idx);
void *temp = allocf(ud, box->box, box->bsize, newsize); void *temp = allocf(ud, box->box, box->bsize, newsize);
if (temp == NULL && newsize > 0) { /* allocation error? */ if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */
lua_pushliteral(L, "not enough memory"); lua_pushliteral(L, "not enough memory");
lua_error(L); /* raise a memory error */ lua_error(L); /* raise a memory error */
} }
@ -501,13 +501,22 @@ static void newbox (lua_State *L) {
#define buffonstack(B) ((B)->b != (B)->init.b) #define buffonstack(B) ((B)->b != (B)->init.b)
/*
** Whenever buffer is accessed, slot 'idx' must either be a box (which
** cannot be NULL) or it is a placeholder for the buffer.
*/
#define checkbufferlevel(B,idx) \
lua_assert(buffonstack(B) ? lua_touserdata(B->L, idx) != NULL \
: lua_touserdata(B->L, idx) == (void*)B)
/* /*
** Compute new size for buffer 'B', enough to accommodate extra 'sz' ** Compute new size for buffer 'B', enough to accommodate extra 'sz'
** bytes. ** bytes.
*/ */
static size_t newbuffsize (luaL_Buffer *B, size_t sz) { static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
size_t newsize = B->size * 2; /* double buffer size */ size_t newsize = B->size * 2; /* double buffer size */
if (MAX_SIZET - sz < B->n) /* overflow in (B->n + sz)? */ if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
return luaL_error(B->L, "buffer too large"); return luaL_error(B->L, "buffer too large");
if (newsize < B->n + sz) /* double is not big enough? */ if (newsize < B->n + sz) /* double is not big enough? */
newsize = B->n + sz; newsize = B->n + sz;
@ -517,10 +526,11 @@ static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
/* /*
** Returns a pointer to a free area with at least 'sz' bytes in buffer ** Returns a pointer to a free area with at least 'sz' bytes in buffer
** 'B'. 'boxidx' is the relative position in the stack where the ** 'B'. 'boxidx' is the relative position in the stack where is the
** buffer's box is or should be. ** buffer's box or its placeholder.
*/ */
static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) { static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) {
checkbufferlevel(B, boxidx);
if (B->size - B->n >= sz) /* enough space? */ if (B->size - B->n >= sz) /* enough space? */
return B->b + B->n; return B->b + B->n;
else { else {
@ -531,6 +541,7 @@ static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) {
if (buffonstack(B)) /* buffer already has a box? */ if (buffonstack(B)) /* buffer already has a box? */
newbuff = (char *)resizebox(L, boxidx, newsize); /* resize it */ newbuff = (char *)resizebox(L, boxidx, newsize); /* resize it */
else { /* no box yet */ else { /* no box yet */
lua_remove(L, boxidx); /* remove placeholder */
newbox(L); /* create a new box */ newbox(L); /* create a new box */
lua_insert(L, boxidx); /* move box to its intended position */ lua_insert(L, boxidx); /* move box to its intended position */
lua_toclose(L, boxidx); lua_toclose(L, boxidx);
@ -567,11 +578,11 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
LUALIB_API void luaL_pushresult (luaL_Buffer *B) { LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
lua_State *L = B->L; lua_State *L = B->L;
checkbufferlevel(B, -1);
lua_pushlstring(L, B->b, B->n); lua_pushlstring(L, B->b, B->n);
if (buffonstack(B)) { if (buffonstack(B))
lua_closeslot(L, -2); /* close the box */ lua_closeslot(L, -2); /* close the box */
lua_remove(L, -2); /* remove box from the stack */ lua_remove(L, -2); /* remove box or placeholder from the stack */
}
} }
@ -606,6 +617,7 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
B->b = B->init.b; B->b = B->init.b;
B->n = 0; B->n = 0;
B->size = LUAL_BUFFERSIZE; B->size = LUAL_BUFFERSIZE;
lua_pushlightuserdata(L, (void*)B); /* push placeholder */
} }
@ -847,7 +859,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
int isnum; int isnum;
lua_len(L, idx); lua_len(L, idx);
l = lua_tointegerx(L, -1, &isnum); l = lua_tointegerx(L, -1, &isnum);
if (!isnum) if (l_unlikely(!isnum))
luaL_error(L, "object length is not an integer"); luaL_error(L, "object length is not an integer");
lua_pop(L, 1); /* remove object */ lua_pop(L, 1); /* remove object */
return l; return l;
@ -1060,7 +1072,7 @@ static void warnfon (void *ud, const char *message, int tocont) {
LUALIB_API lua_State *luaL_newstate (void) { LUALIB_API lua_State *luaL_newstate (void) {
lua_State *L = lua_newstate(l_alloc, NULL); lua_State *L = lua_newstate(l_alloc, NULL);
if (L) { if (l_likely(L)) {
lua_atpanic(L, &panic); lua_atpanic(L, &panic);
lua_setwarnf(L, warnfoff, L); /* default is warnings off */ lua_setwarnf(L, warnfoff, L); /* default is warnings off */
} }

View file

@ -9,11 +9,9 @@
#define lauxlib_h #define lauxlib_h
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "third_party/lua/luaconf.h"
#include "third_party/lua/lua.h" #include "third_party/lua/lua.h"
/* clang-format off */
/* global table */ /* global table */
#define LUA_GNAME "_G" #define LUA_GNAME "_G"
@ -129,10 +127,10 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
(luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
#define luaL_argcheck(L, cond,arg,extramsg) \ #define luaL_argcheck(L, cond,arg,extramsg) \
((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) ((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg))))
#define luaL_argexpected(L,cond,arg,tname) \ #define luaL_argexpected(L,cond,arg,tname) \
((void)((cond) || luaL_typeerror(L, (arg), (tname)))) ((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))

View file

@ -132,7 +132,7 @@ static int luaB_setmetatable (lua_State *L) {
int t = lua_type(L, 2); int t = lua_type(L, 2);
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table"); luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table");
if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL) if (l_unlikely(luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL))
return luaL_error(L, "cannot change a protected metatable"); return luaL_error(L, "cannot change a protected metatable");
lua_settop(L, 2); lua_settop(L, 2);
lua_setmetatable(L, 1); lua_setmetatable(L, 1);
@ -294,7 +294,7 @@ static int luaB_ipairs (lua_State *L) {
static int load_aux (lua_State *L, int status, int envidx) { static int load_aux (lua_State *L, int status, int envidx) {
if (status == LUA_OK) { if (l_likely(status == LUA_OK)) {
if (envidx != 0) { /* 'env' parameter? */ if (envidx != 0) { /* 'env' parameter? */
lua_pushvalue(L, envidx); /* environment for loaded function */ lua_pushvalue(L, envidx); /* environment for loaded function */
if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
@ -350,7 +350,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
*size = 0; *size = 0;
return NULL; return NULL;
} }
else if (!lua_isstring(L, -1)) else if (l_unlikely(!lua_isstring(L, -1)))
luaL_error(L, "reader function must return a string"); luaL_error(L, "reader function must return a string");
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
return lua_tolstring(L, RESERVEDSLOT, size); return lua_tolstring(L, RESERVEDSLOT, size);
@ -388,7 +388,7 @@ static int dofilecont (lua_State *L, int d1, lua_KContext d2) {
static int luaB_dofile (lua_State *L) { static int luaB_dofile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL); const char *fname = luaL_optstring(L, 1, NULL);
lua_settop(L, 1); lua_settop(L, 1);
if (luaL_loadfile(L, fname) != LUA_OK) if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK))
return lua_error(L); return lua_error(L);
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
return dofilecont(L, 0, 0); return dofilecont(L, 0, 0);
@ -396,7 +396,7 @@ static int luaB_dofile (lua_State *L) {
static int luaB_assert (lua_State *L) { static int luaB_assert (lua_State *L) {
if (lua_toboolean(L, 1)) /* condition is true? */ if (l_likely(lua_toboolean(L, 1))) /* condition is true? */
return lua_gettop(L); /* return all arguments */ return lua_gettop(L); /* return all arguments */
else { /* error */ else { /* error */
luaL_checkany(L, 1); /* there must be a condition */ luaL_checkany(L, 1); /* there must be a condition */
@ -432,7 +432,7 @@ static int luaB_select (lua_State *L) {
** ignored). ** ignored).
*/ */
static int finishpcall (lua_State *L, int status, lua_KContext extra) { static int finishpcall (lua_State *L, int status, lua_KContext extra) {
if (status != LUA_OK && status != LUA_YIELD) { /* error? */ if (l_unlikely(status != LUA_OK && status != LUA_YIELD)) { /* error? */
lua_pushboolean(L, 0); /* first result (false) */ lua_pushboolean(L, 0); /* first result (false) */
lua_pushvalue(L, -2); /* error message */ lua_pushvalue(L, -2); /* error message */
return 2; /* return false, msg */ return 2; /* return false, msg */

View file

@ -1293,7 +1293,8 @@ static int validop (int op, TValue *v1, TValue *v2) {
case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR:
case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */
lua_Integer i; lua_Integer i;
return (tointegerns(v1, &i) && tointegerns(v2, &i)); return (luaV_tointegerns(v1, &i, LUA_FLOORN2I) &&
luaV_tointegerns(v2, &i, LUA_FLOORN2I));
} }
case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */
return (nvalue(v2) != 0); return (nvalue(v2) != 0);

View file

@ -27,14 +27,14 @@ static lua_State *getco (lua_State *L) {
*/ */
static int auxresume (lua_State *L, lua_State *co, int narg) { static int auxresume (lua_State *L, lua_State *co, int narg) {
int status, nres; int status, nres;
if (!lua_checkstack(co, narg)) { if (l_unlikely(!lua_checkstack(co, narg))) {
lua_pushliteral(L, "too many arguments to resume"); lua_pushliteral(L, "too many arguments to resume");
return -1; /* error flag */ return -1; /* error flag */
} }
lua_xmove(L, co, narg); lua_xmove(L, co, narg);
status = lua_resume(co, L, narg, &nres); status = lua_resume(co, L, narg, &nres);
if (status == LUA_OK || status == LUA_YIELD) { if (l_likely(status == LUA_OK || status == LUA_YIELD)) {
if (!lua_checkstack(L, nres + 1)) { if (l_unlikely(!lua_checkstack(L, nres + 1))) {
lua_pop(co, nres); /* remove results anyway */ lua_pop(co, nres); /* remove results anyway */
lua_pushliteral(L, "too many results to resume"); lua_pushliteral(L, "too many results to resume");
return -1; /* error flag */ return -1; /* error flag */
@ -53,7 +53,7 @@ static int luaB_coresume (lua_State *L) {
lua_State *co = getco(L); lua_State *co = getco(L);
int r; int r;
r = auxresume(L, co, lua_gettop(L) - 1); r = auxresume(L, co, lua_gettop(L) - 1);
if (r < 0) { if (l_unlikely(r < 0)) {
lua_pushboolean(L, 0); lua_pushboolean(L, 0);
lua_insert(L, -2); lua_insert(L, -2);
return 2; /* return false + error message */ return 2; /* return false + error message */
@ -69,7 +69,7 @@ static int luaB_coresume (lua_State *L) {
static int luaB_auxwrap (lua_State *L) { static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1)); lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L)); int r = auxresume(L, co, lua_gettop(L));
if (r < 0) { /* error? */ if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co); int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
stat = lua_resetthread(co); /* close its tbc variables */ stat = lua_resetthread(co); /* close its tbc variables */

View file

@ -30,7 +30,7 @@ static const char *const HOOKKEY = "_HOOKKEY";
** checked. ** checked.
*/ */
static void checkstack (lua_State *L, lua_State *L1, int n) { static void checkstack (lua_State *L, lua_State *L1, int n) {
if (L != L1 && !lua_checkstack(L1, n)) if (l_unlikely(L != L1 && !lua_checkstack(L1, n)))
luaL_error(L, "stack overflow"); luaL_error(L, "stack overflow");
} }
@ -210,7 +210,7 @@ static int db_getlocal (lua_State *L) {
lua_Debug ar; lua_Debug ar;
const char *name; const char *name;
int level = (int)luaL_checkinteger(L, arg + 1); int level = (int)luaL_checkinteger(L, arg + 1);
if (!lua_getstack(L1, level, &ar)) /* out of range? */ if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range"); return luaL_argerror(L, arg+1, "level out of range");
checkstack(L, L1, 1); checkstack(L, L1, 1);
name = lua_getlocal(L1, &ar, nvar); name = lua_getlocal(L1, &ar, nvar);
@ -235,7 +235,7 @@ static int db_setlocal (lua_State *L) {
lua_Debug ar; lua_Debug ar;
int level = (int)luaL_checkinteger(L, arg + 1); int level = (int)luaL_checkinteger(L, arg + 1);
int nvar = (int)luaL_checkinteger(L, arg + 2); int nvar = (int)luaL_checkinteger(L, arg + 2);
if (!lua_getstack(L1, level, &ar)) /* out of range? */ if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range"); return luaL_argerror(L, arg+1, "level out of range");
luaL_checkany(L, arg+3); luaL_checkany(L, arg+3);
lua_settop(L, arg+3); lua_settop(L, arg+3);

View file

@ -47,6 +47,8 @@ static int currentpc (CallInfo *ci) {
** an integer division gets the right place. When the source file has ** an integer division gets the right place. When the source file has
** large sequences of empty/comment lines, it may need extra entries, ** large sequences of empty/comment lines, it may need extra entries,
** so the original estimate needs a correction. ** so the original estimate needs a correction.
** If the original estimate is -1, the initial 'if' ensures that the
** 'while' will run at least once.
** The assertion that the estimate is a lower bound for the correct base ** The assertion that the estimate is a lower bound for the correct base
** is valid as long as the debug info has been generated with the same ** is valid as long as the debug info has been generated with the same
** value for MAXIWTHABS or smaller. (Previous releases use a little ** value for MAXIWTHABS or smaller. (Previous releases use a little
@ -60,7 +62,8 @@ static int getbaseline (const Proto *f, int pc, int *basepc) {
else { else {
int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */ int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */
/* estimate must be a lower bond of the correct base */ /* estimate must be a lower bond of the correct base */
lua_assert(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc); lua_assert(i < 0 ||
(i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc) while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
i++; /* low estimate; adjust it */ i++; /* low estimate; adjust it */
*basepc = f->abslineinfo[i].pc; *basepc = f->abslineinfo[i].pc;
@ -635,14 +638,18 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
/* /*
** The subtraction of two potentially unrelated pointers is ** Check whether pointer 'o' points to some value in the stack
** not ISO C, but it should not crash a program; the subsequent ** frame of the current function. Because 'o' may not point to a
** checks are ISO C and ensure a correct result. ** value in this stack, we cannot compare it with the region
** boundaries (undefined behaviour in ISO C).
*/ */
static int isinstack (CallInfo *ci, const TValue *o) { static int isinstack (CallInfo *ci, const TValue *o) {
StkId base = ci->func + 1; StkId pos;
ptrdiff_t i = cast(StkId, o) - base; for (pos = ci->func + 1; pos < ci->top; pos++) {
return (0 <= i && i < (ci->top - base) && s2v(base + i) == o); if (o == s2v(pos))
return 1;
}
return 0; /* not found */
} }
@ -723,7 +730,7 @@ l_noret luaG_opinterror (lua_State *L, const TValue *p1,
*/ */
l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
lua_Integer temp; lua_Integer temp;
if (!tointegerns(p1, &temp)) if (!luaV_tointegerns(p1, &temp, LUA_FLOORN2I))
p2 = p1; p2 = p1;
luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2));
} }

52
third_party/lua/ldo.c vendored
View file

@ -155,8 +155,6 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
static void correctstack (lua_State *L, StkId oldstack, StkId newstack) { static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
CallInfo *ci; CallInfo *ci;
UpVal *up; UpVal *up;
if (oldstack == newstack)
return; /* stack address did not change */
L->top = (L->top - oldstack) + newstack; L->top = (L->top - oldstack) + newstack;
L->tbclist = (L->tbclist - oldstack) + newstack; L->tbclist = (L->tbclist - oldstack) + newstack;
for (up = L->openupval; up != NULL; up = up->u.open.next) for (up = L->openupval; up != NULL; up = up->u.open.next)
@ -174,19 +172,35 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
/*
** Reallocate the stack to a new size, correcting all pointers into
** it. (There are pointers to a stack from its upvalues, from its list
** of call infos, plus a few individual pointers.) The reallocation is
** done in two steps (allocation + free) because the correction must be
** done while both addresses (the old stack and the new one) are valid.
** (In ISO C, any pointer use after the pointer has been deallocated is
** undefined behavior.)
** In case of allocation error, raise an error or return false according
** to 'raiseerror'.
*/
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int lim = stacksize(L); int oldsize = stacksize(L);
StkId newstack = luaM_reallocvector(L, L->stack, int i;
lim + EXTRA_STACK, newsize + EXTRA_STACK, StackValue); StkId newstack = luaM_reallocvector(L, NULL, 0,
newsize + EXTRA_STACK, StackValue);
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
if (unlikely(newstack == NULL)) { /* reallocation failed? */ if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
if (raiseerror) if (raiseerror)
luaM_error(L); luaM_error(L);
else return 0; /* do not raise an error */ else return 0; /* do not raise an error */
} }
for (; lim < newsize; lim++) /* number of elements to be copied to the new stack */
setnilvalue(s2v(newstack + lim + EXTRA_STACK)); /* erase new segment */ i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK;
memcpy(newstack, L->stack, i * sizeof(StackValue));
for (; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */
correctstack(L, L->stack, newstack); correctstack(L, L->stack, newstack);
luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
L->stack = newstack; L->stack = newstack;
L->stack_last = L->stack + newsize; L->stack_last = L->stack + newsize;
return 1; return 1;
@ -199,7 +213,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
*/ */
int luaD_growstack (lua_State *L, int n, int raiseerror) { int luaD_growstack (lua_State *L, int n, int raiseerror) {
int size = stacksize(L); int size = stacksize(L);
if (unlikely(size > LUAI_MAXSTACK)) { if (l_unlikely(size > LUAI_MAXSTACK)) {
/* if stack is larger than maximum, thread is already using the /* if stack is larger than maximum, thread is already using the
extra space reserved for errors, that is, thread is handling extra space reserved for errors, that is, thread is handling
a stack error; cannot grow further than that. */ a stack error; cannot grow further than that. */
@ -215,7 +229,7 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
newsize = LUAI_MAXSTACK; newsize = LUAI_MAXSTACK;
if (newsize < needed) /* but must respect what was asked for */ if (newsize < needed) /* but must respect what was asked for */
newsize = needed; newsize = needed;
if (likely(newsize <= LUAI_MAXSTACK)) if (l_likely(newsize <= LUAI_MAXSTACK))
return luaD_reallocstack(L, newsize, raiseerror); return luaD_reallocstack(L, newsize, raiseerror);
else { /* stack overflow */ else { /* stack overflow */
/* add extra size to be able to handle the error message */ /* add extra size to be able to handle the error message */
@ -371,7 +385,7 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
void luaD_tryfuncTM (lua_State *L, StkId func) { void luaD_tryfuncTM (lua_State *L, StkId func) {
const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL);
StkId p; StkId p;
if (unlikely(ttisnil(tm))) if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */ luaG_callerror(L, s2v(func)); /* nothing to call */
for (p = L->top; p > func; p--) /* open space for metamethod */ for (p = L->top; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1); setobjs2s(L, p, p-1);
@ -439,7 +453,7 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
*/ */
void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
int wanted = ci->nresults; int wanted = ci->nresults;
if (L->hookmask && !hastocloseCfunc(wanted)) if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
rethook(L, ci, nres); rethook(L, ci, nres);
/* move results to proper place */ /* move results to proper place */
moveresults(L, ci->func, nres, wanted); moveresults(L, ci->func, nres, wanted);
@ -505,7 +519,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
ci->top = L->top + LUA_MINSTACK; ci->top = L->top + LUA_MINSTACK;
ci->func = func; ci->func = func;
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top <= L->stack_last);
if (L->hookmask & LUA_MASKCALL) { if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
int narg = cast_int(L->top - func) - 1; int narg = cast_int(L->top - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
} }
@ -551,7 +565,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
static void ccall (lua_State *L, StkId func, int nResults, int inc) { static void ccall (lua_State *L, StkId func, int nResults, int inc) {
CallInfo *ci; CallInfo *ci;
L->nCcalls += inc; L->nCcalls += inc;
if (unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
luaE_checkcstack(L); luaE_checkcstack(L);
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
@ -595,7 +609,7 @@ void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
*/ */
static int finishpcallk (lua_State *L, CallInfo *ci) { static int finishpcallk (lua_State *L, CallInfo *ci) {
int status = getcistrecst(ci); /* get original status */ int status = getcistrecst(ci); /* get original status */
if (status == LUA_OK) /* no error? */ if (l_likely(status == LUA_OK)) /* no error? */
status = LUA_YIELD; /* was interrupted by an yield */ status = LUA_YIELD; /* was interrupted by an yield */
else { /* error */ else { /* error */
StkId func = restorestack(L, ci->u2.funcidx); StkId func = restorestack(L, ci->u2.funcidx);
@ -769,7 +783,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
status = luaD_rawrunprotected(L, resume, &nargs); status = luaD_rawrunprotected(L, resume, &nargs);
/* continue running after recoverable errors */ /* continue running after recoverable errors */
status = precover(L, status); status = precover(L, status);
if (likely(!errorstatus(status))) if (l_likely(!errorstatus(status)))
lua_assert(status == L->status); /* normal end or yield */ lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */ else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */ L->status = cast_byte(status); /* mark thread as 'dead' */
@ -795,7 +809,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
lua_lock(L); lua_lock(L);
ci = L->ci; ci = L->ci;
api_checknelems(L, nresults); api_checknelems(L, nresults);
if (unlikely(!yieldable(L))) { if (l_unlikely(!yieldable(L))) {
if (L != G(L)->mainthread) if (L != G(L)->mainthread)
luaG_runerror(L, "attempt to yield across a C-call boundary"); luaG_runerror(L, "attempt to yield across a C-call boundary");
else else
@ -848,7 +862,7 @@ int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status) {
struct CloseP pcl; struct CloseP pcl;
pcl.level = restorestack(L, level); pcl.status = status; pcl.level = restorestack(L, level); pcl.status = status;
status = luaD_rawrunprotected(L, &closepaux, &pcl); status = luaD_rawrunprotected(L, &closepaux, &pcl);
if (likely(status == LUA_OK)) /* no more errors? */ if (l_likely(status == LUA_OK)) /* no more errors? */
return pcl.status; return pcl.status;
else { /* an error occurred; restore saved state and repeat */ else { /* an error occurred; restore saved state and repeat */
L->ci = old_ci; L->ci = old_ci;
@ -871,7 +885,7 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t old_errfunc = L->errfunc; ptrdiff_t old_errfunc = L->errfunc;
L->errfunc = ef; L->errfunc = ef;
status = luaD_rawrunprotected(L, func, u); status = luaD_rawrunprotected(L, func, u);
if (unlikely(status != LUA_OK)) { /* an error occurred? */ if (l_unlikely(status != LUA_OK)) { /* an error occurred? */
L->ci = old_ci; L->ci = old_ci;
L->allowhook = old_allowhooks; L->allowhook = old_allowhooks;
status = luaD_closeprotected(L, old_top, status); status = luaD_closeprotected(L, old_top, status);

View file

@ -23,7 +23,7 @@
** at every check. ** at every check.
*/ */
#define luaD_checkstackaux(L,n,pre,pos) \ #define luaD_checkstackaux(L,n,pre,pos) \
if (L->stack_last - L->top <= (n)) \ if (l_unlikely(L->stack_last - L->top <= (n))) \
{ pre; luaD_growstack(L, n, 1); pos; } \ { pre; luaD_growstack(L, n, 1); pos; } \
else { condmovestack(L,pre,pos); } else { condmovestack(L,pre,pos); }

View file

@ -149,6 +149,15 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
} }
/*
** Maximum value for deltas in 'tbclist', dependent on the type
** of delta. (This macro assumes that an 'L' is in scope where it
** is used.)
*/
#define MAXDELTA \
((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
/* /*
** Insert a variable in the list of to-be-closed variables. ** Insert a variable in the list of to-be-closed variables.
*/ */
@ -157,13 +166,11 @@ void luaF_newtbcupval (lua_State *L, StkId level) {
if (l_isfalse(s2v(level))) if (l_isfalse(s2v(level)))
return; /* false doesn't need to be closed */ return; /* false doesn't need to be closed */
checkclosemth(L, level); /* value must have a close method */ checkclosemth(L, level); /* value must have a close method */
while (level - L->tbclist > USHRT_MAX) { /* is delta too large? */ while (cast_uint(level - L->tbclist) > MAXDELTA) {
L->tbclist += USHRT_MAX; /* create a dummy node at maximum delta */ L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
L->tbclist->tbclist.delta = USHRT_MAX; L->tbclist->tbclist.delta = 0;
L->tbclist->tbclist.isdummy = 1;
} }
level->tbclist.delta = level - L->tbclist; level->tbclist.delta = cast(unsigned short, level - L->tbclist);
level->tbclist.isdummy = 0;
L->tbclist = level; L->tbclist = level;
} }
@ -196,6 +203,19 @@ void luaF_closeupval (lua_State *L, StkId level) {
} }
/*
** Remove firt element from the tbclist plus its dummy nodes.
*/
static void poptbclist (lua_State *L) {
StkId tbc = L->tbclist;
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
tbc -= tbc->tbclist.delta;
while (tbc > L->stack && tbc->tbclist.delta == 0)
tbc -= MAXDELTA; /* remove dummy nodes */
L->tbclist = tbc;
}
/* /*
** Close all upvalues and to-be-closed variables up to the given stack ** Close all upvalues and to-be-closed variables up to the given stack
** level. ** level.
@ -205,12 +225,10 @@ void luaF_close (lua_State *L, StkId level, int status, int yy) {
luaF_closeupval(L, level); /* first, close the upvalues */ luaF_closeupval(L, level); /* first, close the upvalues */
while (L->tbclist >= level) { /* traverse tbc's down to that level */ while (L->tbclist >= level) { /* traverse tbc's down to that level */
StkId tbc = L->tbclist; /* get variable index */ StkId tbc = L->tbclist; /* get variable index */
L->tbclist -= tbc->tbclist.delta; /* remove it from list */ poptbclist(L); /* remove it from list */
if (!tbc->tbclist.isdummy) { /* not a dummy entry? */
prepcallclosemth(L, tbc, status, yy); /* close variable */ prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel); level = restorestack(L, levelrel);
} }
}
} }

38
third_party/lua/lgc.c vendored
View file

@ -911,7 +911,7 @@ static void GCTM (lua_State *L) {
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */ L->allowhook = oldah; /* restore hooks */
g->gcrunning = running; /* restore state */ g->gcrunning = running; /* restore state */
if (unlikely(status != LUA_OK)) { /* error while running __gc? */ if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc metamethod"); luaE_warnerror(L, "__gc metamethod");
L->top--; /* pops error object */ L->top--; /* pops error object */
} }
@ -1570,52 +1570,64 @@ static int sweepstep (lua_State *L, global_State *g,
static lu_mem singlestep (lua_State *L) { static lu_mem singlestep (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
lu_mem work;
lua_assert(!g->gcstopem); /* collector is not reentrant */
g->gcstopem = 1; /* no emergency collections while collecting */
switch (g->gcstate) { switch (g->gcstate) {
case GCSpause: { case GCSpause: {
restartcollection(g); restartcollection(g);
g->gcstate = GCSpropagate; g->gcstate = GCSpropagate;
return 1; work = 1;
break;
} }
case GCSpropagate: { case GCSpropagate: {
if (g->gray == NULL) { /* no more gray objects? */ if (g->gray == NULL) { /* no more gray objects? */
g->gcstate = GCSenteratomic; /* finish propagate phase */ g->gcstate = GCSenteratomic; /* finish propagate phase */
return 0; work = 0;
} }
else else
return propagatemark(g); /* traverse one gray object */ work = propagatemark(g); /* traverse one gray object */
break;
} }
case GCSenteratomic: { case GCSenteratomic: {
lu_mem work = atomic(L); /* work is what was traversed by 'atomic' */ work = atomic(L); /* work is what was traversed by 'atomic' */
entersweep(L); entersweep(L);
g->GCestimate = gettotalbytes(g); /* first estimate */; g->GCestimate = gettotalbytes(g); /* first estimate */;
return work; break;
} }
case GCSswpallgc: { /* sweep "regular" objects */ case GCSswpallgc: { /* sweep "regular" objects */
return sweepstep(L, g, GCSswpfinobj, &g->finobj); work = sweepstep(L, g, GCSswpfinobj, &g->finobj);
break;
} }
case GCSswpfinobj: { /* sweep objects with finalizers */ case GCSswpfinobj: { /* sweep objects with finalizers */
return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); work = sweepstep(L, g, GCSswptobefnz, &g->tobefnz);
break;
} }
case GCSswptobefnz: { /* sweep objects to be finalized */ case GCSswptobefnz: { /* sweep objects to be finalized */
return sweepstep(L, g, GCSswpend, NULL); work = sweepstep(L, g, GCSswpend, NULL);
break;
} }
case GCSswpend: { /* finish sweeps */ case GCSswpend: { /* finish sweeps */
checkSizes(L, g); checkSizes(L, g);
g->gcstate = GCScallfin; g->gcstate = GCScallfin;
return 0; work = 0;
break;
} }
case GCScallfin: { /* call remaining finalizers */ case GCScallfin: { /* call remaining finalizers */
if (g->tobefnz && !g->gcemergency) { if (g->tobefnz && !g->gcemergency) {
int n = runafewfinalizers(L, GCFINMAX); g->gcstopem = 0; /* ok collections during finalizers */
return n * GCFINALIZECOST; work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST;
} }
else { /* emergency mode or no more finalizers */ else { /* emergency mode or no more finalizers */
g->gcstate = GCSpause; /* finish collection */ g->gcstate = GCSpause; /* finish collection */
return 0; work = 0;
} }
break;
} }
default: lua_assert(0); return 0; default: lua_assert(0); return 0;
} }
g->gcstopem = 0;
return work;
} }

View file

@ -178,7 +178,7 @@ static int f_tostring (lua_State *L) {
static FILE *tofile (lua_State *L) { static FILE *tofile (lua_State *L) {
LStream *p = tolstream(L); LStream *p = tolstream(L);
if (isclosed(p)) if (l_unlikely(isclosed(p)))
luaL_error(L, "attempt to use a closed file"); luaL_error(L, "attempt to use a closed file");
lua_assert(p->f); lua_assert(p->f);
return p->f; return p->f;
@ -253,7 +253,7 @@ static LStream *newfile (lua_State *L) {
static void opencheck (lua_State *L, const char *fname, const char *mode) { static void opencheck (lua_State *L, const char *fname, const char *mode) {
LStream *p = newfile(L); LStream *p = newfile(L);
p->f = fopen(fname, mode); p->f = fopen(fname, mode);
if (p->f == NULL) if (l_unlikely(p->f == NULL))
luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno));
} }
@ -301,7 +301,7 @@ static FILE *getiofile (lua_State *L, const char *findex) {
LStream *p; LStream *p;
lua_getfield(L, LUA_REGISTRYINDEX, findex); lua_getfield(L, LUA_REGISTRYINDEX, findex);
p = (LStream *)lua_touserdata(L, -1); p = (LStream *)lua_touserdata(L, -1);
if (isclosed(p)) if (l_unlikely(isclosed(p)))
luaL_error(L, "default %s file is closed", findex + IOPREF_LEN); luaL_error(L, "default %s file is closed", findex + IOPREF_LEN);
return p->f; return p->f;
} }
@ -428,7 +428,7 @@ typedef struct {
** Add current char to buffer (if not out of space) and read next one ** Add current char to buffer (if not out of space) and read next one
*/ */
static int nextc (RN *rn) { static int nextc (RN *rn) {
if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */ if (l_unlikely(rn->n >= L_MAXLENNUM)) { /* buffer overflow? */
rn->buff[0] = '\0'; /* invalidate result */ rn->buff[0] = '\0'; /* invalidate result */
return 0; /* fail */ return 0; /* fail */
} }
@ -491,8 +491,8 @@ static int read_number (lua_State *L, FILE *f) {
ungetc(rn.c, rn.f); /* unread look-ahead char */ ungetc(rn.c, rn.f); /* unread look-ahead char */
l_unlockfile(rn.f); l_unlockfile(rn.f);
rn.buff[rn.n] = '\0'; /* finish string */ rn.buff[rn.n] = '\0'; /* finish string */
if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ if (l_likely(lua_stringtonumber(L, rn.buff)))
return 1; /* ok */ return 1; /* ok, it is a valid number */
else { /* invalid format */ else { /* invalid format */
lua_pushnil(L); /* "result" to be removed */ lua_pushnil(L); /* "result" to be removed */
return 0; /* read fails */ return 0; /* read fails */
@ -668,7 +668,8 @@ static int g_write (lua_State *L, FILE *f, int arg) {
status = status && (fwrite(s, sizeof(char), l, f) == l); status = status && (fwrite(s, sizeof(char), l, f) == l);
} }
} }
if (status) return 1; /* file handle already on stack top */ if (l_likely(status))
return 1; /* file handle already on stack top */
else return luaL_fileresult(L, status, NULL); else return luaL_fileresult(L, status, NULL);
} }
@ -695,7 +696,7 @@ static int f_seek (lua_State *L) {
luaL_argcheck(L, (lua_Integer)offset == p3, 3, luaL_argcheck(L, (lua_Integer)offset == p3, 3,
"not an integer in proper range"); "not an integer in proper range");
op = l_fseek(f, offset, mode[op]); op = l_fseek(f, offset, mode[op]);
if (op) if (l_unlikely(op))
return luaL_fileresult(L, 0, NULL); /* error */ return luaL_fileresult(L, 0, NULL); /* error */
else { else {
lua_pushinteger(L, (lua_Integer)l_ftell(f)); lua_pushinteger(L, (lua_Integer)l_ftell(f));

View file

@ -146,22 +146,6 @@ typedef LUAI_UACINT l_uacInt;
#endif #endif
/*
** macros to improve jump prediction (used mainly for error handling)
*/
#if !defined(likely)
#if defined(__GNUC__)
#define likely(x) (__builtin_expect(((x) != 0), 1))
#define unlikely(x) (__builtin_expect(((x) != 0), 0))
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
#endif
/* /*
** non-return type ** non-return type
*/ */

View file

@ -68,7 +68,7 @@ static int math_atan (lua_State *L) {
static int math_toint (lua_State *L) { static int math_toint (lua_State *L) {
int valid; int valid;
lua_Integer n = lua_tointegerx(L, 1, &valid); lua_Integer n = lua_tointegerx(L, 1, &valid);
if (valid) if (l_likely(valid))
lua_pushinteger(L, n); lua_pushinteger(L, n);
else { else {
luaL_checkany(L, 1); luaL_checkany(L, 1);
@ -170,7 +170,8 @@ static int math_log (lua_State *L) {
lua_Number base = luaL_checknumber(L, 2); lua_Number base = luaL_checknumber(L, 2);
#if !defined(LUA_USE_C89) #if !defined(LUA_USE_C89)
if (base == l_mathop(2.0)) if (base == l_mathop(2.0))
res = l_mathop(log2)(x); else res = l_mathop(log2)(x);
else
#endif #endif
if (base == l_mathop(10.0)) if (base == l_mathop(10.0))
res = l_mathop(log10)(x); res = l_mathop(log10)(x);

View file

@ -20,12 +20,12 @@
#if defined(EMERGENCYGCTESTS) #if defined(EMERGENCYGCTESTS)
/* /*
** First allocation will fail whenever not building initial state ** First allocation will fail whenever not building initial state.
** and not shrinking a block. (This fail will trigger 'tryagain' and ** (This fail will trigger 'tryagain' and a full GC cycle at every
** a full GC cycle at every allocation.) ** allocation.)
*/ */
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) { static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (completestate(g) && ns > os) if (completestate(g) && ns > 0) /* frees never fail */
return NULL; /* fail */ return NULL; /* fail */
else /* normal allocation */ else /* normal allocation */
return (*g->frealloc)(g->ud, block, os, ns); return (*g->frealloc)(g->ud, block, os, ns);
@ -79,7 +79,7 @@ void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize,
if (nelems + 1 <= size) /* does one extra element still fit? */ if (nelems + 1 <= size) /* does one extra element still fit? */
return block; /* nothing to be done */ return block; /* nothing to be done */
if (size >= limit / 2) { /* cannot double it? */ if (size >= limit / 2) { /* cannot double it? */
if (unlikely(size >= limit)) /* cannot grow even a little? */ if (l_unlikely(size >= limit)) /* cannot grow even a little? */
luaG_runerror(L, "too many %s (limit is %d)", what, limit); luaG_runerror(L, "too many %s (limit is %d)", what, limit);
size = limit; /* still have at least one free place */ size = limit; /* still have at least one free place */
} }
@ -134,15 +134,17 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
/* /*
** In case of allocation fail, this function will call the GC to try ** In case of allocation fail, this function will do an emergency
** to free some memory and then try the allocation again. ** collection to free some memory and then try the allocation again.
** (It should not be called when shrinking a block, because then the ** The GC should not be called while state is not fully built, as the
** interpreter may be in the middle of a collection step.) ** collector is not yet fully initialized. Also, it should not be called
** when 'gcstopem' is true, because then the interpreter is in the
** middle of a collection step.
*/ */
static void *tryagain (lua_State *L, void *block, static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) { size_t osize, size_t nsize) {
global_State *g = G(L); global_State *g = G(L);
if (completestate(g)) { /* is state fully build? */ if (completestate(g) && !g->gcstopem) {
luaC_fullgc(L, 1); /* try to free some memory... */ luaC_fullgc(L, 1); /* try to free some memory... */
return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
} }
@ -152,16 +154,13 @@ static void *tryagain (lua_State *L, void *block,
/* /*
** Generic allocation routine. ** Generic allocation routine.
** If allocation fails while shrinking a block, do not try again; the
** GC shrinks some blocks and it is not reentrant.
*/ */
void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
void *newblock; void *newblock;
global_State *g = G(L); global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL)); lua_assert((osize == 0) == (block == NULL));
newblock = firsttry(g, block, osize, nsize); newblock = firsttry(g, block, osize, nsize);
if (unlikely(newblock == NULL && nsize > 0)) { if (l_unlikely(newblock == NULL && nsize > 0)) {
if (nsize > osize) /* not shrinking a block? */
newblock = tryagain(L, block, osize, nsize); newblock = tryagain(L, block, osize, nsize);
if (newblock == NULL) /* still no memory? */ if (newblock == NULL) /* still no memory? */
return NULL; /* do not update 'GCdebt' */ return NULL; /* do not update 'GCdebt' */
@ -175,7 +174,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize, void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize,
size_t nsize) { size_t nsize) {
void *newblock = luaM_realloc_(L, block, osize, nsize); void *newblock = luaM_realloc_(L, block, osize, nsize);
if (unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */ if (l_unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */
luaM_error(L); luaM_error(L);
return newblock; return newblock;
} }
@ -187,7 +186,7 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) {
else { else {
global_State *g = G(L); global_State *g = G(L);
void *newblock = firsttry(g, NULL, tag, size); void *newblock = firsttry(g, NULL, tag, size);
if (unlikely(newblock == NULL)) { if (l_unlikely(newblock == NULL)) {
newblock = tryagain(L, NULL, tag, size); newblock = tryagain(L, NULL, tag, size);
if (newblock == NULL) if (newblock == NULL)
luaM_error(L); luaM_error(L);

View file

@ -125,14 +125,16 @@ static void lsys_unloadlib (void *lib) {
static void *lsys_load (lua_State *L, const char *path, int seeglb) { static void *lsys_load (lua_State *L, const char *path, int seeglb) {
void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL));
if (lib == NULL) lua_pushstring(L, dlerror()); if (l_unlikely(lib == NULL))
lua_pushstring(L, dlerror());
return lib; return lib;
} }
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
lua_CFunction f = cast_func(dlsym(lib, sym)); lua_CFunction f = cast_func(dlsym(lib, sym));
if (f == NULL) lua_pushstring(L, dlerror()); if (l_unlikely(f == NULL))
lua_pushstring(L, dlerror());
return f; return f;
} }
@ -402,7 +404,7 @@ static int ll_loadlib (lua_State *L) {
const char *path = luaL_checkstring(L, 1); const char *path = luaL_checkstring(L, 1);
const char *init = luaL_checkstring(L, 2); const char *init = luaL_checkstring(L, 2);
int stat = lookforfunc(L, path, init); int stat = lookforfunc(L, path, init);
if (stat == 0) /* no errors? */ if (l_likely(stat == 0)) /* no errors? */
return 1; /* return the loaded function */ return 1; /* return the loaded function */
else { /* error; error message is on stack top */ else { /* error; error message is on stack top */
luaL_pushfail(L); luaL_pushfail(L);
@ -515,14 +517,14 @@ static const char *findfile (lua_State *L, const char *name,
const char *path; const char *path;
lua_getfield(L, lua_upvalueindex(1), pname); lua_getfield(L, lua_upvalueindex(1), pname);
path = lua_tostring(L, -1); path = lua_tostring(L, -1);
if (path == NULL) if (l_unlikely(path == NULL))
luaL_error(L, "'package.%s' must be a string", pname); luaL_error(L, "'package.%s' must be a string", pname);
return searchpath(L, name, path, ".", dirsep); return searchpath(L, name, path, ".", dirsep);
} }
static int checkload (lua_State *L, int stat, const char *filename) { static int checkload (lua_State *L, int stat, const char *filename) {
if (stat) { /* module loaded successfully? */ if (l_likely(stat)) { /* module loaded successfully? */
lua_pushstring(L, filename); /* will be 2nd argument to module */ lua_pushstring(L, filename); /* will be 2nd argument to module */
return 2; /* return open function and file name */ return 2; /* return open function and file name */
} }
@ -615,13 +617,14 @@ static void findloader (lua_State *L, const char *name) {
int i; int i;
luaL_Buffer msg; /* to build error message */ luaL_Buffer msg; /* to build error message */
/* push 'package.searchers' to index 3 in the stack */ /* push 'package.searchers' to index 3 in the stack */
if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) if (l_unlikely(lua_getfield(L, lua_upvalueindex(1), "searchers")
!= LUA_TTABLE))
luaL_error(L, "'package.searchers' must be a table"); luaL_error(L, "'package.searchers' must be a table");
luaL_buffinit(L, &msg); luaL_buffinit(L, &msg);
/* iterate over available searchers to find a loader */ /* iterate over available searchers to find a loader */
for (i = 1; ; i++) { for (i = 1; ; i++) {
luaL_addstring(&msg, "\n\t"); /* error-message prefix */ luaL_addstring(&msg, "\n\t"); /* error-message prefix */
if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */
lua_pop(L, 1); /* remove nil */ lua_pop(L, 1); /* remove nil */
luaL_buffsub(&msg, 2); /* remove prefix */ luaL_buffsub(&msg, 2); /* remove prefix */
luaL_pushresult(&msg); /* create error message */ luaL_pushresult(&msg); /* create error message */

View file

@ -135,13 +135,14 @@ typedef struct TValue {
** Entries in a Lua stack. Field 'tbclist' forms a list of all ** Entries in a Lua stack. Field 'tbclist' forms a list of all
** to-be-closed variables active in this stack. Dummy entries are ** to-be-closed variables active in this stack. Dummy entries are
** used when the distance between two tbc variables does not fit ** used when the distance between two tbc variables does not fit
** in an unsigned short. ** in an unsigned short. They are represented by delta==0, and
** their real delta is always the maximum value that fits in
** that field.
*/ */
typedef union StackValue { typedef union StackValue {
TValue val; TValue val;
struct { struct {
TValuefields; TValuefields;
lu_byte isdummy;
unsigned short delta; unsigned short delta;
} tbclist; } tbclist;
} StackValue; } StackValue;

View file

@ -226,13 +226,13 @@ OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][RK(C):string] */
OP_ADDI,/* A B sC R[A] := R[B] + sC */ OP_ADDI,/* A B sC R[A] := R[B] + sC */
OP_ADDK,/* A B C R[A] := R[B] + K[C] */ OP_ADDK,/* A B C R[A] := R[B] + K[C]:number */
OP_SUBK,/* A B C R[A] := R[B] - K[C] */ OP_SUBK,/* A B C R[A] := R[B] - K[C]:number */
OP_MULK,/* A B C R[A] := R[B] * K[C] */ OP_MULK,/* A B C R[A] := R[B] * K[C]:number */
OP_MODK,/* A B C R[A] := R[B] % K[C] */ OP_MODK,/* A B C R[A] := R[B] % K[C]:number */
OP_POWK,/* A B C R[A] := R[B] ^ K[C] */ OP_POWK,/* A B C R[A] := R[B] ^ K[C]:number */
OP_DIVK,/* A B C R[A] := R[B] / K[C] */ OP_DIVK,/* A B C R[A] := R[B] / K[C]:number */
OP_IDIVK,/* A B C R[A] := R[B] // K[C] */ OP_IDIVK,/* A B C R[A] := R[B] // K[C]:number */
OP_BANDK,/* A B C R[A] := R[B] & K[C]:integer */ OP_BANDK,/* A B C R[A] := R[B] & K[C]:integer */
OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */ OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */

View file

@ -166,7 +166,7 @@ static int os_tmpname (lua_State *L) {
char buff[LUA_TMPNAMBUFSIZE]; char buff[LUA_TMPNAMBUFSIZE];
int err; int err;
lua_tmpnam(buff, err); lua_tmpnam(buff, err);
if (err) if (l_unlikely(err))
return luaL_error(L, "unable to generate a unique filename"); return luaL_error(L, "unable to generate a unique filename");
lua_pushstring(L, buff); lua_pushstring(L, buff);
return 1; return 1;
@ -204,7 +204,7 @@ static int os_clock (lua_State *L) {
*/ */
static void setfield (lua_State *L, const char *key, int value, int delta) { static void setfield (lua_State *L, const char *key, int value, int delta) {
#if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX) #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX)
if (value > LUA_MAXINTEGER - delta) if (l_unlikely(value > LUA_MAXINTEGER - delta))
luaL_error(L, "field '%s' is out-of-bound", key); luaL_error(L, "field '%s' is out-of-bound", key);
#endif #endif
lua_pushinteger(L, (lua_Integer)value + delta); lua_pushinteger(L, (lua_Integer)value + delta);
@ -249,9 +249,9 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
int t = lua_getfield(L, -1, key); /* get field and its type */ int t = lua_getfield(L, -1, key); /* get field and its type */
lua_Integer res = lua_tointegerx(L, -1, &isnum); lua_Integer res = lua_tointegerx(L, -1, &isnum);
if (!isnum) { /* field is not an integer? */ if (!isnum) { /* field is not an integer? */
if (t != LUA_TNIL) /* some other value? */ if (l_unlikely(t != LUA_TNIL)) /* some other value? */
return luaL_error(L, "field '%s' is not an integer", key); return luaL_error(L, "field '%s' is not an integer", key);
else if (d < 0) /* absent field; no default? */ else if (l_unlikely(d < 0)) /* absent field; no default? */
return luaL_error(L, "field '%s' missing in date table", key); return luaL_error(L, "field '%s' missing in date table", key);
res = d; res = d;
} }

View file

@ -123,7 +123,7 @@ static void checknext (LexState *ls, int c) {
** in line 'where' (if that is not the current line). ** in line 'where' (if that is not the current line).
*/ */
static void check_match (LexState *ls, int what, int who, int where) { static void check_match (LexState *ls, int what, int who, int where) {
if (unlikely(!testnext(ls, what))) { if (l_unlikely(!testnext(ls, what))) {
if (where == ls->linenumber) /* all in the same line? */ if (where == ls->linenumber) /* all in the same line? */
error_expected(ls, what); /* do not need a complex message */ error_expected(ls, what); /* do not need a complex message */
else { else {
@ -512,7 +512,7 @@ static void solvegoto (LexState *ls, int g, Labeldesc *label) {
Labellist *gl = &ls->dyd->gt; /* list of goto's */ Labellist *gl = &ls->dyd->gt; /* list of goto's */
Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */ Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */
lua_assert(eqstr(gt->name, label->name)); lua_assert(eqstr(gt->name, label->name));
if (unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */ if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
jumpscopeerror(ls, gt); jumpscopeerror(ls, gt);
luaK_patchlist(ls->fs, gt->pc, label->pc); luaK_patchlist(ls->fs, gt->pc, label->pc);
for (i = g; i < gl->n - 1; i++) /* remove goto from pending list */ for (i = g; i < gl->n - 1; i++) /* remove goto from pending list */
@ -1430,7 +1430,7 @@ static void breakstat (LexState *ls) {
*/ */
static void checkrepeated (LexState *ls, TString *name) { static void checkrepeated (LexState *ls, TString *name) {
Labeldesc *lb = findlabel(ls, name); Labeldesc *lb = findlabel(ls, name);
if (unlikely(lb != NULL)) { /* already defined? */ if (l_unlikely(lb != NULL)) { /* already defined? */
const char *msg = "label '%s' already defined on line %d"; const char *msg = "label '%s' already defined on line %d";
msg = luaO_pushfstring(ls->L, msg, getstr(name), lb->line); msg = luaO_pushfstring(ls->L, msg, getstr(name), lb->line);
luaK_semerror(ls, msg); /* error */ luaK_semerror(ls, msg); /* error */
@ -1515,7 +1515,7 @@ static void fixforjump (FuncState *fs, int pc, int dest, int back) {
int offset = dest - (pc + 1); int offset = dest - (pc + 1);
if (back) if (back)
offset = -offset; offset = -offset;
if (unlikely(offset > MAXARG_Bx)) if (l_unlikely(offset > MAXARG_Bx))
luaX_syntaxerror(fs->ls, "control structure too long"); luaX_syntaxerror(fs->ls, "control structure too long");
SETARG_Bx(*jmp, offset); SETARG_Bx(*jmp, offset);
} }

View file

@ -165,7 +165,7 @@ void luaE_checkcstack (lua_State *L) {
LUAI_FUNC void luaE_incCstack (lua_State *L) { LUAI_FUNC void luaE_incCstack (lua_State *L) {
L->nCcalls++; L->nCcalls++;
if (unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS))
luaE_checkcstack(L); luaE_checkcstack(L);
} }
@ -372,6 +372,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->panic = NULL; g->panic = NULL;
g->gcstate = GCSpause; g->gcstate = GCSpause;
g->gckind = KGC_INC; g->gckind = KGC_INC;
g->gcstopem = 0;
g->gcemergency = 0; g->gcemergency = 0;
g->finobj = g->tobefnz = g->fixedgc = NULL; g->finobj = g->tobefnz = g->fixedgc = NULL;
g->firstold1 = g->survival = g->old1 = g->reallyold = NULL; g->firstold1 = g->survival = g->old1 = g->reallyold = NULL;

View file

@ -260,6 +260,7 @@ typedef struct global_State {
lu_byte currentwhite; lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */ lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */ lu_byte gckind; /* kind of GC running */
lu_byte gcstopem; /* stops emergency collections */
lu_byte genminormul; /* control for minor generational collections */ lu_byte genminormul; /* control for minor generational collections */
lu_byte genmajormul; /* control for major generational collections */ lu_byte genmajormul; /* control for major generational collections */
lu_byte gcrunning; /* true if GC is running */ lu_byte gcrunning; /* true if GC is running */

View file

@ -85,7 +85,7 @@ void luaS_resize (lua_State *L, int nsize) {
if (nsize < osize) /* shrinking table? */ if (nsize < osize) /* shrinking table? */
tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */ tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */
newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*); newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*);
if (unlikely(newvect == NULL)) { /* reallocation failed? */ if (l_unlikely(newvect == NULL)) { /* reallocation failed? */
if (nsize < osize) /* was it shrinking table? */ if (nsize < osize) /* was it shrinking table? */
tablerehash(tb->hash, nsize, osize); /* restore to original size */ tablerehash(tb->hash, nsize, osize); /* restore to original size */
/* leave table as it was */ /* leave table as it was */
@ -168,7 +168,7 @@ void luaS_remove (lua_State *L, TString *ts) {
static void growstrtab (lua_State *L, stringtable *tb) { static void growstrtab (lua_State *L, stringtable *tb) {
if (unlikely(tb->nuse == MAX_INT)) { /* too many strings? */ if (l_unlikely(tb->nuse == MAX_INT)) { /* too many strings? */
luaC_fullgc(L, 1); /* try to free some... */ luaC_fullgc(L, 1); /* try to free some... */
if (tb->nuse == MAX_INT) /* still too many? */ if (tb->nuse == MAX_INT) /* still too many? */
luaM_error(L); /* cannot even create a message... */ luaM_error(L); /* cannot even create a message... */
@ -219,7 +219,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
return internshrstr(L, str, l); return internshrstr(L, str, l);
else { else {
TString *ts; TString *ts;
if (unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char)))
luaM_toobig(L); luaM_toobig(L);
ts = luaS_createlngstrobj(L, l); ts = luaS_createlngstrobj(L, l);
memcpy(getstr(ts), str, l * sizeof(char)); memcpy(getstr(ts), str, l * sizeof(char));
@ -255,7 +255,7 @@ Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) {
Udata *u; Udata *u;
int i; int i;
GCObject *o; GCObject *o;
if (unlikely(s > MAX_SIZE - udatamemoffset(nuvalue))) if (l_unlikely(s > MAX_SIZE - udatamemoffset(nuvalue)))
luaM_toobig(L); luaM_toobig(L);
o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s)); o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s));
u = gco2u(o); u = gco2u(o);

View file

@ -142,8 +142,9 @@ static int str_rep (lua_State *L) {
const char *s = luaL_checklstring(L, 1, &l); const char *s = luaL_checklstring(L, 1, &l);
lua_Integer n = luaL_checkinteger(L, 2); lua_Integer n = luaL_checkinteger(L, 2);
const char *sep = luaL_optlstring(L, 3, "", &lsep); const char *sep = luaL_optlstring(L, 3, "", &lsep);
if (n <= 0) lua_pushliteral(L, ""); if (n <= 0)
else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */ lua_pushliteral(L, "");
else if (l_unlikely(l + lsep < l || l + lsep > MAXSIZE / n))
return luaL_error(L, "resulting string too large"); return luaL_error(L, "resulting string too large");
else { else {
size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep;
@ -171,7 +172,7 @@ static int str_byte (lua_State *L) {
size_t pose = getendpos(L, 3, pi, l); size_t pose = getendpos(L, 3, pi, l);
int n, i; int n, i;
if (posi > pose) return 0; /* empty interval; return no values */ if (posi > pose) return 0; /* empty interval; return no values */
if (pose - posi >= (size_t)INT_MAX) /* arithmetic overflow? */ if (l_unlikely(pose - posi >= (size_t)INT_MAX)) /* arithmetic overflow? */
return luaL_error(L, "string slice too long"); return luaL_error(L, "string slice too long");
n = (int)(pose - posi) + 1; n = (int)(pose - posi) + 1;
luaL_checkstack(L, n, "string slice too long"); luaL_checkstack(L, n, "string slice too long");
@ -225,7 +226,7 @@ static int str_dump (lua_State *L) {
luaL_checktype(L, 1, LUA_TFUNCTION); luaL_checktype(L, 1, LUA_TFUNCTION);
lua_settop(L, 1); /* ensure function is on the top of the stack */ lua_settop(L, 1); /* ensure function is on the top of the stack */
state.init = 0; state.init = 0;
if (lua_dump(L, writer, &state, strip) != 0) if (l_unlikely(lua_dump(L, writer, &state, strip) != 0))
return luaL_error(L, "unable to dump given function"); return luaL_error(L, "unable to dump given function");
luaL_pushresult(&state.B); luaL_pushresult(&state.B);
return 1; return 1;
@ -265,7 +266,8 @@ static int tonum (lua_State *L, int arg) {
static void trymt (lua_State *L, const char *mtname) { static void trymt (lua_State *L, const char *mtname) {
lua_settop(L, 2); /* back to the original arguments */ lua_settop(L, 2); /* back to the original arguments */
if (lua_type(L, 2) == LUA_TSTRING || !luaL_getmetafield(L, 2, mtname)) if (l_unlikely(lua_type(L, 2) == LUA_TSTRING ||
!luaL_getmetafield(L, 2, mtname)))
luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2, luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2,
luaL_typename(L, -2), luaL_typename(L, -1)); luaL_typename(L, -2), luaL_typename(L, -1));
lua_insert(L, -3); /* put metamethod before arguments */ lua_insert(L, -3); /* put metamethod before arguments */
@ -373,7 +375,8 @@ static const char *match (MatchState *ms, const char *s, const char *p);
static int check_capture (MatchState *ms, int l) { static int check_capture (MatchState *ms, int l) {
l -= '1'; l -= '1';
if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) if (l_unlikely(l < 0 || l >= ms->level ||
ms->capture[l].len == CAP_UNFINISHED))
return luaL_error(ms->L, "invalid capture index %%%d", l + 1); return luaL_error(ms->L, "invalid capture index %%%d", l + 1);
return l; return l;
} }
@ -390,14 +393,14 @@ static int capture_to_close (MatchState *ms) {
static const char *classend (MatchState *ms, const char *p) { static const char *classend (MatchState *ms, const char *p) {
switch (*p++) { switch (*p++) {
case L_ESC: { case L_ESC: {
if (p == ms->p_end) if (l_unlikely(p == ms->p_end))
luaL_error(ms->L, "malformed pattern (ends with '%%')"); luaL_error(ms->L, "malformed pattern (ends with '%%')");
return p+1; return p+1;
} }
case '[': { case '[': {
if (*p == '^') p++; if (*p == '^') p++;
do { /* look for a ']' */ do { /* look for a ']' */
if (p == ms->p_end) if (l_unlikely(p == ms->p_end))
luaL_error(ms->L, "malformed pattern (missing ']')"); luaL_error(ms->L, "malformed pattern (missing ']')");
if (*(p++) == L_ESC && p < ms->p_end) if (*(p++) == L_ESC && p < ms->p_end)
p++; /* skip escapes (e.g. '%]') */ p++; /* skip escapes (e.g. '%]') */
@ -472,7 +475,7 @@ static int singlematch (MatchState *ms, const char *s, const char *p,
static const char *matchbalance (MatchState *ms, const char *s, static const char *matchbalance (MatchState *ms, const char *s,
const char *p) { const char *p) {
if (p >= ms->p_end - 1) if (l_unlikely(p >= ms->p_end - 1))
luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')");
if (*s != *p) return NULL; if (*s != *p) return NULL;
else { else {
@ -555,7 +558,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) {
static const char *match (MatchState *ms, const char *s, const char *p) { static const char *match (MatchState *ms, const char *s, const char *p) {
if (ms->matchdepth-- == 0) if (l_unlikely(ms->matchdepth-- == 0))
luaL_error(ms->L, "pattern too complex"); luaL_error(ms->L, "pattern too complex");
init: /* using goto's to optimize tail recursion */ init: /* using goto's to optimize tail recursion */
if (p != ms->p_end) { /* end of pattern? */ if (p != ms->p_end) { /* end of pattern? */
@ -589,7 +592,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
case 'f': { /* frontier? */ case 'f': { /* frontier? */
const char *ep; char previous; const char *ep; char previous;
p += 2; p += 2;
if (*p != '[') if (l_unlikely(*p != '['))
luaL_error(ms->L, "missing '[' after '%%f' in pattern"); luaL_error(ms->L, "missing '[' after '%%f' in pattern");
ep = classend(ms, p); /* points to what is next */ ep = classend(ms, p); /* points to what is next */
previous = (s == ms->src_init) ? '\0' : *(s - 1); previous = (s == ms->src_init) ? '\0' : *(s - 1);
@ -689,7 +692,7 @@ static const char *lmemfind (const char *s1, size_t l1,
static size_t get_onecapture (MatchState *ms, int i, const char *s, static size_t get_onecapture (MatchState *ms, int i, const char *s,
const char *e, const char **cap) { const char *e, const char **cap) {
if (i >= ms->level) { if (i >= ms->level) {
if (i != 0) if (l_unlikely(i != 0))
luaL_error(ms->L, "invalid capture index %%%d", i + 1); luaL_error(ms->L, "invalid capture index %%%d", i + 1);
*cap = s; *cap = s;
return e - s; return e - s;
@ -697,7 +700,7 @@ static size_t get_onecapture (MatchState *ms, int i, const char *s,
else { else {
ptrdiff_t capl = ms->capture[i].len; ptrdiff_t capl = ms->capture[i].len;
*cap = ms->capture[i].init; *cap = ms->capture[i].init;
if (capl == CAP_UNFINISHED) if (l_unlikely(capl == CAP_UNFINISHED))
luaL_error(ms->L, "unfinished capture"); luaL_error(ms->L, "unfinished capture");
else if (capl == CAP_POSITION) else if (capl == CAP_POSITION)
lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
@ -916,7 +919,7 @@ static int add_value (MatchState *ms, luaL_Buffer *b, const char *s,
luaL_addlstring(b, s, e - s); /* keep original text */ luaL_addlstring(b, s, e - s); /* keep original text */
return 0; /* no changes */ return 0; /* no changes */
} }
else if (!lua_isstring(L, -1)) else if (l_unlikely(!lua_isstring(L, -1)))
return luaL_error(L, "invalid replacement value (a %s)", return luaL_error(L, "invalid replacement value (a %s)",
luaL_typename(L, -1)); luaL_typename(L, -1));
else { else {
@ -1048,7 +1051,7 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
buff[i] = toupper(uchar(buff[i])); buff[i] = toupper(uchar(buff[i]));
} }
else if (fmt[SIZELENMOD] != 'a') else if (l_unlikely(fmt[SIZELENMOD] != 'a'))
return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
return n; return n;
} }
@ -1401,7 +1404,7 @@ static int getnum (const char **fmt, int df) {
*/ */
static int getnumlimit (Header *h, const char **fmt, int df) { static int getnumlimit (Header *h, const char **fmt, int df) {
int sz = getnum(fmt, df); int sz = getnum(fmt, df);
if (sz > MAXINTSIZE || sz <= 0) if (l_unlikely(sz > MAXINTSIZE || sz <= 0))
return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", return luaL_error(h->L, "integral size (%d) out of limits [1,%d]",
sz, MAXINTSIZE); sz, MAXINTSIZE);
return sz; return sz;
@ -1442,7 +1445,7 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring;
case 'c': case 'c':
*size = getnum(fmt, -1); *size = getnum(fmt, -1);
if (*size == -1) if (l_unlikely(*size == -1))
luaL_error(h->L, "missing size for format option 'c'"); luaL_error(h->L, "missing size for format option 'c'");
return Kchar; return Kchar;
case 'z': return Kzstr; case 'z': return Kzstr;
@ -1481,7 +1484,7 @@ static KOption getdetails (Header *h, size_t totalsize,
else { else {
if (align > h->maxalign) /* enforce maximum alignment */ if (align > h->maxalign) /* enforce maximum alignment */
align = h->maxalign; align = h->maxalign;
if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ if (l_unlikely((align & (align - 1)) != 0)) /* not a power of 2? */
luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); luaL_argerror(h->L, 1, "format asks for alignment not power of 2");
*ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1);
} }
@ -1673,7 +1676,7 @@ static lua_Integer unpackint (lua_State *L, const char *str,
else if (size > SZINT) { /* must check unread bytes */ else if (size > SZINT) { /* must check unread bytes */
int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC;
for (i = limit; i < size; i++) { for (i = limit; i < size; i++) {
if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) if (l_unlikely((unsigned char)str[islittle ? i : size - 1 - i] != mask))
luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); luaL_error(L, "%d-byte integer does not fit into Lua Integer", size);
} }
} }

View file

@ -64,20 +64,25 @@
#define MAXHSIZE luaM_limitN(1u << MAXHBITS, Node) #define MAXHSIZE luaM_limitN(1u << MAXHBITS, Node)
/*
** When the original hash value is good, hashing by a power of 2
** avoids the cost of '%'.
*/
#define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t))))
/*
** for other types, it is better to avoid modulo by power of 2, as
** they can have many 2 factors.
*/
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
#define hashstr(t,str) hashpow2(t, (str)->hash) #define hashstr(t,str) hashpow2(t, (str)->hash)
#define hashboolean(t,p) hashpow2(t, p) #define hashboolean(t,p) hashpow2(t, p)
#define hashint(t,i) hashpow2(t, i) #define hashint(t,i) hashpow2(t, i)
/*
** for some types, it is better to avoid modulus by power of 2, as
** they tend to have many 2 factors.
*/
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
#define hashpointer(t,p) hashmod(t, point2uint(p)) #define hashpointer(t,p) hashmod(t, point2uint(p))
@ -131,24 +136,38 @@ static int l_hashfloat (lua_Number n) {
*/ */
static Node *mainposition (const Table *t, int ktt, const Value *kvl) { static Node *mainposition (const Table *t, int ktt, const Value *kvl) {
switch (withvariant(ktt)) { switch (withvariant(ktt)) {
case LUA_VNUMINT: case LUA_VNUMINT: {
return hashint(t, ivalueraw(*kvl)); lua_Integer key = ivalueraw(*kvl);
case LUA_VNUMFLT: return hashint(t, key);
return hashmod(t, l_hashfloat(fltvalueraw(*kvl))); }
case LUA_VSHRSTR: case LUA_VNUMFLT: {
return hashstr(t, tsvalueraw(*kvl)); lua_Number n = fltvalueraw(*kvl);
case LUA_VLNGSTR: return hashmod(t, l_hashfloat(n));
return hashpow2(t, luaS_hashlongstr(tsvalueraw(*kvl))); }
case LUA_VSHRSTR: {
TString *ts = tsvalueraw(*kvl);
return hashstr(t, ts);
}
case LUA_VLNGSTR: {
TString *ts = tsvalueraw(*kvl);
return hashpow2(t, luaS_hashlongstr(ts));
}
case LUA_VFALSE: case LUA_VFALSE:
return hashboolean(t, 0); return hashboolean(t, 0);
case LUA_VTRUE: case LUA_VTRUE:
return hashboolean(t, 1); return hashboolean(t, 1);
case LUA_VLIGHTUSERDATA: case LUA_VLIGHTUSERDATA: {
return hashpointer(t, pvalueraw(*kvl)); void *p = pvalueraw(*kvl);
case LUA_VLCF: return hashpointer(t, p);
return hashpointer(t, fvalueraw(*kvl)); }
default: case LUA_VLCF: {
return hashpointer(t, gcvalueraw(*kvl)); lua_CFunction f = fvalueraw(*kvl);
return hashpointer(t, f);
}
default: {
GCObject *o = gcvalueraw(*kvl);
return hashpointer(t, o);
}
} }
} }
@ -303,7 +322,7 @@ static unsigned int findindex (lua_State *L, Table *t, TValue *key,
return i; /* yes; that's the index */ return i; /* yes; that's the index */
else { else {
const TValue *n = getgeneric(t, key, 1); const TValue *n = getgeneric(t, key, 1);
if (unlikely(isabstkey(n))) if (l_unlikely(isabstkey(n)))
luaG_runerror(L, "invalid key to 'next'"); /* key not found */ luaG_runerror(L, "invalid key to 'next'"); /* key not found */
i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */ i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */
/* hash elements are numbered after array ones */ /* hash elements are numbered after array ones */
@ -537,7 +556,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize,
} }
/* allocate new array */ /* allocate new array */
newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue);
if (unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */
freehash(L, &newt); /* release new hash part */ freehash(L, &newt); /* release new hash part */
luaM_error(L); /* raise error (with array unchanged) */ luaM_error(L); /* raise error (with array unchanged) */
} }
@ -631,7 +650,7 @@ static Node *getfreepos (Table *t) {
void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
Node *mp; Node *mp;
TValue aux; TValue aux;
if (unlikely(ttisnil(key))) if (l_unlikely(ttisnil(key)))
luaG_runerror(L, "table index is nil"); luaG_runerror(L, "table index is nil");
else if (ttisfloat(key)) { else if (ttisfloat(key)) {
lua_Number f = fltvalue(key); lua_Number f = fltvalue(key);
@ -640,7 +659,7 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) {
setivalue(&aux, k); setivalue(&aux, k);
key = &aux; /* insert it as an integer */ key = &aux; /* insert it as an integer */
} }
else if (unlikely(luai_numisnan(f))) else if (l_unlikely(luai_numisnan(f)))
luaG_runerror(L, "table index is NaN"); luaG_runerror(L, "table index is NaN");
} }
if (ttisnil(value)) if (ttisnil(value))

View file

@ -141,7 +141,7 @@ static int tmove (lua_State *L) {
static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) { static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
lua_geti(L, 1, i); lua_geti(L, 1, i);
if (!lua_isstring(L, -1)) if (l_unlikely(!lua_isstring(L, -1)))
luaL_error(L, "invalid value (%s) at index %I in table for 'concat'", luaL_error(L, "invalid value (%s) at index %I in table for 'concat'",
luaL_typename(L, -1), i); luaL_typename(L, -1), i);
luaL_addvalue(b); luaL_addvalue(b);
@ -192,7 +192,8 @@ static int tunpack (lua_State *L) {
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1)); lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
if (i > e) return 0; /* empty range */ if (i > e) return 0; /* empty range */
n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */ n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n))) if (l_unlikely(n >= (unsigned int)INT_MAX ||
!lua_checkstack(L, (int)(++n))))
return luaL_error(L, "too many results to unpack"); return luaL_error(L, "too many results to unpack");
for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */
lua_geti(L, 1, i); lua_geti(L, 1, i);
@ -294,14 +295,14 @@ static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
for (;;) { for (;;) {
/* next loop: repeat ++i while a[i] < P */ /* next loop: repeat ++i while a[i] < P */
while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ if (l_unlikely(i == up - 1)) /* a[i] < P but a[up - 1] == P ?? */
luaL_error(L, "invalid order function for sorting"); luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[i] */ lua_pop(L, 1); /* remove a[i] */
} }
/* after the loop, a[i] >= P and a[lo .. i - 1] < P */ /* after the loop, a[i] >= P and a[lo .. i - 1] < P */
/* next loop: repeat --j while P < a[j] */ /* next loop: repeat --j while P < a[j] */
while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { while ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
if (j < i) /* j < i but a[j] > P ?? */ if (l_unlikely(j < i)) /* j < i but a[j] > P ?? */
luaL_error(L, "invalid order function for sorting"); luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[j] */ lua_pop(L, 1); /* remove a[j] */
} }

View file

@ -112,6 +112,7 @@ static void warnf (void *ud, const char *msg, int tocont) {
strcat(buff, msg); /* add new message to current warning */ strcat(buff, msg); /* add new message to current warning */
if (!tocont) { /* message finished? */ if (!tocont) { /* message finished? */
lua_unlock(L); lua_unlock(L);
luaL_checkstack(L, 1, "warn stack space");
lua_getglobal(L, "_WARN"); lua_getglobal(L, "_WARN");
if (!lua_toboolean(L, -1)) if (!lua_toboolean(L, -1))
lua_pop(L, 1); /* ok, no previous unexpected warning */ lua_pop(L, 1); /* ok, no previous unexpected warning */
@ -133,6 +134,7 @@ static void warnf (void *ud, const char *msg, int tocont) {
} }
case 2: { /* store */ case 2: { /* store */
lua_unlock(L); lua_unlock(L);
luaL_checkstack(L, 1, "warn stack space");
lua_pushstring(L, buff); lua_pushstring(L, buff);
lua_setglobal(L, "_WARN"); /* assign message to global '_WARN' */ lua_setglobal(L, "_WARN"); /* assign message to global '_WARN' */
lua_lock(L); lua_lock(L);

View file

@ -143,7 +143,7 @@ static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2,
void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
StkId res, TMS event) { StkId res, TMS event) {
if (!callbinTM(L, p1, p2, res, event)) { if (l_unlikely(!callbinTM(L, p1, p2, res, event))) {
switch (event) { switch (event) {
case TM_BAND: case TM_BOR: case TM_BXOR: case TM_BAND: case TM_BOR: case TM_BXOR:
case TM_SHL: case TM_SHR: case TM_BNOT: { case TM_SHL: case TM_SHR: case TM_BNOT: {
@ -162,7 +162,8 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
void luaT_tryconcatTM (lua_State *L) { void luaT_tryconcatTM (lua_State *L) {
StkId top = L->top; StkId top = L->top;
if (!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, TM_CONCAT)) if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
TM_CONCAT)))
luaG_concaterror(L, s2v(top - 2), s2v(top - 1)); luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
} }

View file

@ -14,14 +14,14 @@
#define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4" #define LUA_VERSION_MINOR "4"
#define LUA_VERSION_RELEASE "2" #define LUA_VERSION_RELEASE "3"
#define LUA_VERSION_NUM 504 #define LUA_VERSION_NUM 504
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 0) #define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 0)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2020 Lua.org, PUC-Rio" #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2021 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@ -488,7 +488,7 @@ struct lua_Debug {
/****************************************************************************** /******************************************************************************
* Copyright (C) 1994-2020 Lua.org, PUC-Rio. * Copyright (C) 1994-2021 Lua.org, PUC-Rio.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View file

@ -659,6 +659,34 @@
#define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) #define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
#endif #endif
/*
** macros to improve jump prediction, used mostly for error handling
** and debug facilities. (Some macros in the Lua API use these macros.
** Define LUA_NOBUILTIN if you do not want '__builtin_expect' in your
** code.)
*/
#if !defined(luai_likely)
#if defined(__GNUC__) && !defined(LUA_NOBUILTIN)
#define luai_likely(x) (__builtin_expect(((x) != 0), 1))
#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0))
#else
#define luai_likely(x) (x)
#define luai_unlikely(x) (x)
#endif
#endif
#if defined(LUA_CORE) || defined(LUA_LIB)
/* shorter names for Lua's own use */
#define l_likely(x) luai_likely(x)
#define l_unlikely(x) luai_unlikely(x)
#endif
/* }================================================================== */ /* }================================================================== */

52
third_party/lua/lvm.c vendored
View file

@ -227,11 +227,11 @@ static int forprep (lua_State *L, StkId ra) {
} }
else { /* try making all values floats */ else { /* try making all values floats */
lua_Number init; lua_Number limit; lua_Number step; lua_Number init; lua_Number limit; lua_Number step;
if (unlikely(!tonumber(plimit, &limit))) if (l_unlikely(!tonumber(plimit, &limit)))
luaG_forerror(L, plimit, "limit"); luaG_forerror(L, plimit, "limit");
if (unlikely(!tonumber(pstep, &step))) if (l_unlikely(!tonumber(pstep, &step)))
luaG_forerror(L, pstep, "step"); luaG_forerror(L, pstep, "step");
if (unlikely(!tonumber(pinit, &init))) if (l_unlikely(!tonumber(pinit, &init)))
luaG_forerror(L, pinit, "initial value"); luaG_forerror(L, pinit, "initial value");
if (step == 0) if (step == 0)
luaG_runerror(L, "'for' step is zero"); luaG_runerror(L, "'for' step is zero");
@ -284,7 +284,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
if (slot == NULL) { /* 't' is not a table? */ if (slot == NULL) { /* 't' is not a table? */
lua_assert(!ttistable(t)); lua_assert(!ttistable(t));
tm = luaT_gettmbyobj(L, t, TM_INDEX); tm = luaT_gettmbyobj(L, t, TM_INDEX);
if (unlikely(notm(tm))) if (l_unlikely(notm(tm)))
luaG_typeerror(L, t, "index"); /* no metamethod */ luaG_typeerror(L, t, "index"); /* no metamethod */
/* else will try the metamethod */ /* else will try the metamethod */
} }
@ -338,7 +338,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
} }
else { /* not a table; check metamethod */ else { /* not a table; check metamethod */
tm = luaT_gettmbyobj(L, t, TM_NEWINDEX); tm = luaT_gettmbyobj(L, t, TM_NEWINDEX);
if (unlikely(notm(tm))) if (l_unlikely(notm(tm)))
luaG_typeerror(L, t, "index"); luaG_typeerror(L, t, "index");
} }
/* try the metamethod */ /* try the metamethod */
@ -560,8 +560,13 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER) if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER)
return 0; /* only numbers can be equal with different variants */ return 0; /* only numbers can be equal with different variants */
else { /* two numbers with different variants */ else { /* two numbers with different variants */
lua_Integer i1, i2; /* compare them as integers */ /* One of them is an integer. If the other does not have an
return (tointegerns(t1, &i1) && tointegerns(t2, &i2) && i1 == i2); integer value, they cannot be equal; otherwise, compare their
integer values. */
lua_Integer i1, i2;
return (luaV_tointegerns(t1, &i1, F2Ieq) &&
luaV_tointegerns(t2, &i2, F2Ieq) &&
i1 == i2);
} }
} }
/* values have same type and same variant */ /* values have same type and same variant */
@ -643,7 +648,7 @@ void luaV_concat (lua_State *L, int total) {
/* collect total length and number of strings */ /* collect total length and number of strings */
for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) {
size_t l = vslen(s2v(top - n - 1)); size_t l = vslen(s2v(top - n - 1));
if (unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl))
luaG_runerror(L, "string length overflow"); luaG_runerror(L, "string length overflow");
tl += l; tl += l;
} }
@ -687,7 +692,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
} }
default: { /* try metamethod */ default: { /* try metamethod */
tm = luaT_gettmbyobj(L, rb, TM_LEN); tm = luaT_gettmbyobj(L, rb, TM_LEN);
if (unlikely(notm(tm))) /* no metamethod? */ if (l_unlikely(notm(tm))) /* no metamethod? */
luaG_typeerror(L, rb, "get length of"); luaG_typeerror(L, rb, "get length of");
break; break;
} }
@ -703,7 +708,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
** otherwise 'floor(q) == trunc(q) - 1'. ** otherwise 'floor(q) == trunc(q) - 1'.
*/ */
lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) { lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) {
if (unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */
if (n == 0) if (n == 0)
luaG_runerror(L, "attempt to divide by zero"); luaG_runerror(L, "attempt to divide by zero");
return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */
@ -723,7 +728,7 @@ lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) {
** about luaV_idiv.) ** about luaV_idiv.)
*/ */
lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) {
if (unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */
if (n == 0) if (n == 0)
luaG_runerror(L, "attempt to perform 'n%%0'"); luaG_runerror(L, "attempt to perform 'n%%0'");
return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */
@ -913,7 +918,7 @@ void luaV_finishOp (lua_State *L) {
*/ */
#define op_arithfK(L,fop) { \ #define op_arithfK(L,fop) { \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \ TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arithf_aux(L, v1, v2, fop); } op_arithf_aux(L, v1, v2, fop); }
@ -942,7 +947,7 @@ void luaV_finishOp (lua_State *L) {
*/ */
#define op_arithK(L,iop,fop) { \ #define op_arithK(L,iop,fop) { \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \ TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arith_aux(L, v1, v2, iop, fop); } op_arith_aux(L, v1, v2, iop, fop); }
@ -1041,7 +1046,8 @@ void luaV_finishOp (lua_State *L) {
#define updatebase(ci) (base = ci->func + 1) #define updatebase(ci) (base = ci->func + 1)
#define updatestack(ci) { if (trap) { updatebase(ci); ra = RA(i); } } #define updatestack(ci) \
{ if (l_unlikely(trap)) { updatebase(ci); ra = RA(i); } }
/* /*
@ -1099,7 +1105,7 @@ void luaV_finishOp (lua_State *L) {
/* fetch an instruction and prepare its execution */ /* fetch an instruction and prepare its execution */
#define vmfetch() { \ #define vmfetch() { \
if (trap) { /* stack reallocation or hooks? */ \ if (l_unlikely(trap)) { /* stack reallocation or hooks? */ \
trap = luaG_traceexec(L, pc); /* handle hooks */ \ trap = luaG_traceexec(L, pc); /* handle hooks */ \
updatebase(ci); /* correct stack */ \ updatebase(ci); /* correct stack */ \
} \ } \
@ -1127,7 +1133,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
cl = clLvalue(s2v(ci->func)); cl = clLvalue(s2v(ci->func));
k = cl->p->k; k = cl->p->k;
pc = ci->u.l.savedpc; pc = ci->u.l.savedpc;
if (trap) { if (l_unlikely(trap)) {
if (pc == cl->p->code) { /* first instruction (not resuming)? */ if (pc == cl->p->code) { /* first instruction (not resuming)? */
if (cl->p->is_vararg) if (cl->p->is_vararg)
trap = 0; /* hooks will start after VARARGPREP instruction */ trap = 0; /* hooks will start after VARARGPREP instruction */
@ -1670,23 +1676,23 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
goto ret; goto ret;
} }
vmcase(OP_RETURN0) { vmcase(OP_RETURN0) {
if (L->hookmask) { if (l_unlikely(L->hookmask)) {
L->top = ra; L->top = ra;
savepc(ci); savepc(ci);
luaD_poscall(L, ci, 0); /* no hurry... */ luaD_poscall(L, ci, 0); /* no hurry... */
trap = 1; trap = 1;
} }
else { /* do the 'poscall' here */ else { /* do the 'poscall' here */
int nres = ci->nresults; int nres;
L->ci = ci->previous; /* back to caller */ L->ci = ci->previous; /* back to caller */
L->top = base - 1; L->top = base - 1;
while (nres-- > 0) for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
setnilvalue(s2v(L->top++)); /* all results are nil */ setnilvalue(s2v(L->top++)); /* all results are nil */
} }
goto ret; goto ret;
} }
vmcase(OP_RETURN1) { vmcase(OP_RETURN1) {
if (L->hookmask) { if (l_unlikely(L->hookmask)) {
L->top = ra + 1; L->top = ra + 1;
savepc(ci); savepc(ci);
luaD_poscall(L, ci, 1); /* no hurry... */ luaD_poscall(L, ci, 1); /* no hurry... */
@ -1700,8 +1706,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
else { else {
setobjs2s(L, base - 1, ra); /* at least this result */ setobjs2s(L, base - 1, ra); /* at least this result */
L->top = base; L->top = base;
while (--nres > 0) /* complete missing results */ for (; l_unlikely(nres > 1); nres--)
setnilvalue(s2v(L->top++)); setnilvalue(s2v(L->top++)); /* complete missing results */
} }
} }
ret: /* return from a Lua function */ ret: /* return from a Lua function */
@ -1804,7 +1810,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
} }
vmcase(OP_VARARGPREP) { vmcase(OP_VARARGPREP) {
ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p)); ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p));
if (trap) { if (l_unlikely(trap)) { /* previous "Protect" updated trap */
luaD_hookcall(L, ci); luaD_hookcall(L, ci);
L->oldpc = 1; /* next opcode will be seen as a "new" line */ L->oldpc = 1; /* next opcode will be seen as a "new" line */
} }

View file

@ -60,12 +60,14 @@ typedef enum {
/* convert an object to an integer (including string coercion) */ /* convert an object to an integer (including string coercion) */
#define tointeger(o,i) \ #define tointeger(o,i) \
(ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \
: luaV_tointeger(o,i,LUA_FLOORN2I))
/* convert an object to an integer (without string coercion) */ /* convert an object to an integer (without string coercion) */
#define tointegerns(o,i) \ #define tointegerns(o,i) \
(ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointegerns(o,i,LUA_FLOORN2I)) (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \
: luaV_tointegerns(o,i,LUA_FLOORN2I))
#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) #define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))

View file

@ -154,18 +154,8 @@ end
dofile('main.lua') dofile('main.lua')
do -- trace GC cycles
local next, setmetatable, stderr = next, setmetatable, io.stderr require"tracegc".start()
-- track collections
local mt = {}
-- each time a table is collected, remark it for finalization
-- on next cycle
mt.__gc = function (o)
stderr:write'.' -- mark progress
local n = setmetatable(o, mt) -- remark it
end
local n = setmetatable({}, mt) -- create object
end
report"gc.lua" report"gc.lua"
local f = assert(loadfile('gc.lua')) local f = assert(loadfile('gc.lua'))

View file

@ -1130,7 +1130,7 @@ do
-- closing resources with 'closeslot' -- closing resources with 'closeslot'
_ENV.xxx = true _ENV.xxx = true
local a = T.testC([[ local a = T.testC([[
pushvalue 2 # stack: S, NR, CH pushvalue 2 # stack: S, NR, CH, NR
call 0 1 # create resource; stack: S, NR, CH, R call 0 1 # create resource; stack: S, NR, CH, R
toclose -1 # mark it to be closed toclose -1 # mark it to be closed
pushvalue 2 # stack: S, NR, CH, R, NR pushvalue 2 # stack: S, NR, CH, R, NR
@ -1151,6 +1151,30 @@ do
]], newresource, check) ]], newresource, check)
assert(a == 3 and _ENV.xxx == nil) -- no extra items left in the stack assert(a == 3 and _ENV.xxx == nil) -- no extra items left in the stack
-- closing resources with 'pop'
local a = T.testC([[
pushvalue 2 # stack: S, NR, CH, NR
call 0 1 # create resource; stack: S, NR, CH, R
toclose -1 # mark it to be closed
pushvalue 2 # stack: S, NR, CH, R, NR
call 0 1 # create another resource; stack: S, NR, CH, R, R
toclose -1 # mark it to be closed
pushvalue 3 # stack: S, NR, CH, R, R, CH
pushint 2 # there should be two open resources
call 1 0 # stack: S, NR, CH, R, R
pop 1 # pop second resource
pushvalue 3 # stack: S, NR, CH, R, CH
pushint 1 # there should be one open resource
call 1 0 # stack: S, NR, CH, R
pop 1 # pop other resource from the stack
pushvalue 3 # stack: S, NR, CH, CH
pushint 0 # there should be no open resources
call 1 0 # stack: S, NR, CH
pushint *
return 1 # return stack size
]], newresource, check)
assert(a == 3) -- no extra items left in the stack
-- non-closable value -- non-closable value
local a, b = pcall(T.makeCfunc[[ local a, b = pcall(T.makeCfunc[[
pushint 32 pushint 32

View file

@ -2,6 +2,8 @@
-- See Copyright Notice in file all.lua -- See Copyright Notice in file all.lua
local tracegc = require"tracegc"
print"testing stack overflow detection" print"testing stack overflow detection"
-- Segmentation faults in these tests probably result from a C-stack -- Segmentation faults in these tests probably result from a C-stack
@ -21,7 +23,9 @@ do print("testing stack overflow in message handling")
count = count + 1 count = count + 1
return 1 + loop(x, y, z) return 1 + loop(x, y, z)
end end
tracegc.stop() -- __gc should not be called with a full stack
local res, msg = xpcall(loop, loop) local res, msg = xpcall(loop, loop)
tracegc.start()
assert(msg == "error in error handling") assert(msg == "error in error handling")
print("final count: ", count) print("final count: ", count)
end end
@ -135,18 +139,18 @@ if T then
local topB, sizeB -- top and size Before overflow local topB, sizeB -- top and size Before overflow
local topA, sizeA -- top and size After overflow local topA, sizeA -- top and size After overflow
topB, sizeB = T.stacklevel() topB, sizeB = T.stacklevel()
collectgarbage("stop") -- __gc should not be called with a full stack tracegc.stop() -- __gc should not be called with a full stack
xpcall(f, err) xpcall(f, err)
collectgarbage("restart") tracegc.start()
topA, sizeA = T.stacklevel() topA, sizeA = T.stacklevel()
-- sizes should be comparable -- sizes should be comparable
assert(topA == topB and sizeA < sizeB * 2) assert(topA == topB and sizeA < sizeB * 2)
print(string.format("maximum stack size: %d", stack1)) print(string.format("maximum stack size: %d", stack1))
LIM = N -- will stop recursion at maximum level LIM = N -- will stop recursion at maximum level
N = 0 -- to count again N = 0 -- to count again
collectgarbage("stop") -- __gc should not be called with a full stack tracegc.stop() -- __gc should not be called with a full stack
f() f()
collectgarbage("restart") tracegc.start()
print"+" print"+"
end end

View file

@ -191,6 +191,13 @@ checkmessage("a = 24 // 0", "divide by zero")
checkmessage("a = 1 % 0", "'n%0'") checkmessage("a = 1 % 0", "'n%0'")
-- type error for an object which is neither in an upvalue nor a register.
-- The following code will try to index the value 10 that is stored in
-- the metatable, without moving it to a register.
checkmessage("local a = setmetatable({}, {__index = 10}).x",
"attempt to index a number value")
-- numeric for loops -- numeric for loops
checkmessage("for i = {}, 10 do end", "table") checkmessage("for i = {}, 10 do end", "table")
checkmessage("for i = io.stdin, 10 do end", "FILE") checkmessage("for i = io.stdin, 10 do end", "FILE")
@ -413,6 +420,14 @@ if not b then
end end
end]], 5) end]], 5)
do
-- Force a negative estimate for base line. Error in instruction 2
-- (after VARARGPREP, GETGLOBAL), with first absolute line information
-- (forced by too many lines) in instruction 0.
local s = string.format("%s return __A.x", string.rep("\n", 300))
lineerror(s, 301)
end
if not _soft then if not _soft then
-- several tests that exaust the Lua stack -- several tests that exaust the Lua stack

View file

@ -676,6 +676,14 @@ end
-- just to make sure -- just to make sure
assert(collectgarbage'isrunning') assert(collectgarbage'isrunning')
do -- check that the collector is reentrant in incremental mode
setmetatable({}, {__gc = function ()
collectgarbage()
end})
collectgarbage()
end
collectgarbage(oldmode) collectgarbage(oldmode)
print('OK') print('OK')

View file

@ -5,6 +5,8 @@ print('testing local variables and environments')
local debug = require"debug" local debug = require"debug"
local tracegc = require"tracegc"
-- bug in 5.1: -- bug in 5.1:
@ -554,9 +556,9 @@ do -- test for tbc variable high in the stack
obj[1] = 100 obj[1] = 100
flag = obj flag = obj
end) end)
collectgarbage("stop") tracegc.stop()
st, obj = xpcall(overflow, errorh, 0) st, obj = xpcall(overflow, errorh, 0)
collectgarbage("restart") tracegc.start()
end) end)
co() co()
assert(not st and obj[1] == 10 and flag[1] == 100) assert(not st and obj[1] == 10 and flag[1] == 100)

View file

@ -33,6 +33,7 @@ $NAME/pm.lua \
$NAME/sort.lua \ $NAME/sort.lua \
$NAME/strings.lua \ $NAME/strings.lua \
$NAME/tpack.lua \ $NAME/tpack.lua \
$NAME/tracegc.lua \
$NAME/utf8.lua \ $NAME/utf8.lua \
$NAME/vararg.lua \ $NAME/vararg.lua \
$NAME/verybig.lua \ $NAME/verybig.lua \

40
third_party/lua/test/tracegc.lua vendored Normal file
View file

@ -0,0 +1,40 @@
-- track collections
local M = {}
-- import list
local setmetatable, stderr, collectgarbage =
setmetatable, io.stderr, collectgarbage
_ENV = nil
local active = false
-- each time a table is collected, remark it for finalization on next
-- cycle
local mt = {}
function mt.__gc (o)
stderr:write'.' -- mark progress
if active then
setmetatable(o, mt) -- remark object for finalization
end
end
function M.start ()
if not active then
active = true
setmetatable({}, mt) -- create initial object
end
end
function M.stop ()
if active then
active = false
collectgarbage() -- call finalizer for the last time
end
end
return M