update Lua 5.4 module

This commit is contained in:
Syping 2021-05-01 15:04:09 +02:00
parent 1fd16e168c
commit 46effd4ada
39 changed files with 1047 additions and 699 deletions

View file

@ -39,7 +39,7 @@ const char lua_ident[] =
/* /*
** Test for a valid index. ** Test for a valid index (one that is not the 'nilvalue').
** '!ttisnil(o)' implies 'o != &G(L)->nilvalue', so it is not needed. ** '!ttisnil(o)' implies 'o != &G(L)->nilvalue', so it is not needed.
** However, it covers the most common cases in a faster way. ** However, it covers the most common cases in a faster way.
*/ */
@ -74,7 +74,8 @@ static TValue *index2value (lua_State *L, int idx) {
return &G(L)->nilvalue; /* it has no upvalues */ return &G(L)->nilvalue; /* it has no upvalues */
else { else {
CClosure *func = clCvalue(s2v(ci->func)); CClosure *func = clCvalue(s2v(ci->func));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : &G(L)->nilvalue; return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue;
} }
} }
} }
@ -172,7 +173,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;
@ -187,9 +188,26 @@ 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 (diff < 0 && hastocloseCfunc(ci->nresults)) api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot");
luaF_close(L, L->top + diff, LUA_OK); newtop = L->top + diff;
L->top += diff; /* correct top only after closing any upvalue */ if (diff < 0 && L->tbclist >= newtop) {
lua_assert(hastocloseCfunc(ci->nresults));
luaF_close(L, newtop, CLOSEKTOP, 0);
}
L->top = newtop; /* correct top only after closing any upvalue */
lua_unlock(L);
}
LUA_API void lua_closeslot (lua_State *L, int idx) {
StkId level;
lua_lock(L);
level = index2stack(L, idx);
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level,
"no variable to close at given level");
luaF_close(L, level, CLOSEKTOP, 0);
level = index2stack(L, idx); /* stack may be moved */
setnilvalue(s2v(level));
lua_unlock(L); lua_unlock(L);
} }
@ -629,11 +647,21 @@ static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
} }
/*
** Get the global table in the registry. Since all predefined
** indices in the registry were inserted right when the registry
** was created and never removed, they must always be in the array
** part of the registry.
*/
#define getGtable(L) \
(&hvalue(&G(L)->l_registry)->array[LUA_RIDX_GLOBALS - 1])
LUA_API int lua_getglobal (lua_State *L, const char *name) { LUA_API int lua_getglobal (lua_State *L, const char *name) {
Table *reg; const TValue *G;
lua_lock(L); lua_lock(L);
reg = hvalue(&G(L)->l_registry); G = getGtable(L);
return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); return auxgetstr(L, G, name);
} }
@ -811,10 +839,10 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
LUA_API void lua_setglobal (lua_State *L, const char *name) { LUA_API void lua_setglobal (lua_State *L, const char *name) {
Table *reg; const TValue *G;
lua_lock(L); /* unlock done in 'auxsetstr' */ lua_lock(L); /* unlock done in 'auxsetstr' */
reg = hvalue(&G(L)->l_registry); G = getGtable(L);
auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); auxsetstr(L, G, name);
} }
@ -861,12 +889,10 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
static void aux_rawset (lua_State *L, int idx, TValue *key, int n) { static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
Table *t; Table *t;
TValue *slot;
lua_lock(L); lua_lock(L);
api_checknelems(L, n); api_checknelems(L, n);
t = gettable(L, idx); t = gettable(L, idx);
slot = luaH_set(L, t, key); luaH_set(L, t, key, s2v(L->top - 1));
setobj2t(L, slot, s2v(L->top - 1));
invalidateTMcache(t); invalidateTMcache(t);
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1)); luaC_barrierback(L, obj2gco(t), s2v(L->top - 1));
L->top -= n; L->top -= n;
@ -1063,8 +1089,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */ LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */
if (f->nupvalues >= 1) { /* does it have an upvalue? */ if (f->nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */ /* get global table from registry */
Table *reg = hvalue(&G(L)->l_registry); const TValue *gt = getGtable(L);
const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
setobj(L, f->upvals[0]->v, gt); setobj(L, f->upvals[0]->v, gt);
luaC_barrier(L, f->upvals[0], gt); luaC_barrier(L, f->upvals[0], gt);
@ -1240,8 +1265,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
o = index2stack(L, idx); o = index2stack(L, idx);
nresults = L->ci->nresults; nresults = L->ci->nresults;
api_check(L, L->openupval == NULL || uplevel(L->openupval) <= o, api_check(L, L->tbclist < o, "given index below or equal a marked one");
"marked index below or equal new one");
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */ if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */ L->ci->nresults = codeNresults(nresults); /* mark it */

View file

@ -42,6 +42,8 @@
#define hastocloseCfunc(n) ((n) < LUA_MULTRET) #define hastocloseCfunc(n) ((n) < LUA_MULTRET)
/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */
#define codeNresults(n) (-(n) - 3) #define codeNresults(n) (-(n) - 3)
#define decodeNresults(n) (-(n) - 3)
#endif #endif

View file

@ -190,7 +190,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)
@ -378,7 +378,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
@ -388,20 +388,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;
} }
@ -420,7 +420,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;
} }
@ -442,7 +442,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;
@ -475,7 +475,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 */
} }
@ -515,13 +515,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;
@ -531,10 +540,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 {
@ -545,10 +555,9 @@ 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_pushnil(L); /* reserve slot for final result */ lua_remove(L, boxidx); /* remove placeholder */
newbox(L); /* create a new box */ newbox(L); /* create a new box */
/* move box (and slot) to its intended position */ lua_insert(L, boxidx); /* move box to its intended position */
lua_rotate(L, boxidx - 1, 2);
lua_toclose(L, boxidx); lua_toclose(L, boxidx);
newbuff = (char *)resizebox(L, boxidx, newsize); newbuff = (char *)resizebox(L, boxidx, newsize);
memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */
@ -583,11 +592,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_copy(L, -1, -3); /* move string to reserved slot */ lua_closeslot(L, -2); /* close the box */
lua_pop(L, 2); /* pop string and box (closing the box) */ lua_remove(L, -2); /* remove box or placeholder from the stack */
}
} }
@ -622,6 +631,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 */
} }
@ -639,10 +649,14 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
** ======================================================= ** =======================================================
*/ */
/* index of free-list header */ /* index of free-list header (after the predefined values) */
#define freelist 0 #define freelist (LUA_RIDX_LAST + 1)
/*
** The previously freed references form a linked list:
** t[freelist] is the index of a first free index, or zero if list is
** empty; t[t[freelist]] is the index of the second element; etc.
*/
LUALIB_API int luaL_ref (lua_State *L, int t) { LUALIB_API int luaL_ref (lua_State *L, int t) {
int ref; int ref;
if (lua_isnil(L, -1)) { if (lua_isnil(L, -1)) {
@ -650,9 +664,16 @@ LUALIB_API int luaL_ref (lua_State *L, int t) {
return LUA_REFNIL; /* 'nil' has a unique fixed reference */ return LUA_REFNIL; /* 'nil' has a unique fixed reference */
} }
t = lua_absindex(L, t); t = lua_absindex(L, t);
lua_rawgeti(L, t, freelist); /* get first free element */ if (lua_rawgeti(L, t, freelist) == LUA_TNIL) { /* first access? */
ref = 0; /* list is empty */
lua_pushinteger(L, 0); /* initialize as an empty list */
lua_rawseti(L, t, freelist); /* ref = t[freelist] = 0 */
}
else { /* already initialized */
lua_assert(lua_isinteger(L, -1));
ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */
lua_pop(L, 1); /* remove it from stack */ }
lua_pop(L, 1); /* remove element from stack */
if (ref != 0) { /* any free element? */ if (ref != 0) { /* any free element? */
lua_rawgeti(L, t, ref); /* remove it from list */ lua_rawgeti(L, t, ref); /* remove it from list */
lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */
@ -668,6 +689,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
if (ref >= 0) { if (ref >= 0) {
t = lua_absindex(L, t); t = lua_absindex(L, t);
lua_rawgeti(L, t, freelist); lua_rawgeti(L, t, freelist);
lua_assert(lua_isinteger(L, -1));
lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */
lua_pushinteger(L, ref); lua_pushinteger(L, ref);
lua_rawseti(L, t, freelist); /* t[freelist] = ref */ lua_rawseti(L, t, freelist); /* t[freelist] = ref */
@ -851,7 +873,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;
@ -1064,7 +1086,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

@ -12,6 +12,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include "luaconf.h"
#include "lua.h" #include "lua.h"
@ -130,10 +131,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))
@ -157,6 +158,22 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
#define luaL_pushfail(L) lua_pushnil(L) #define luaL_pushfail(L) lua_pushnil(L)
/*
** Internal assertions for in-house debugging
*/
#if !defined(lua_assert)
#if defined LUAI_ASSERT
#include <assert.h>
#define lua_assert(c) assert(c)
#else
#define lua_assert(c) ((void)0)
#endif
#endif
/* /*
** {====================================================== ** {======================================================
** Generic Buffer manipulation ** Generic Buffer manipulation

View file

@ -138,7 +138,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);
@ -182,7 +182,8 @@ static int luaB_rawset (lua_State *L) {
static int pushmode (lua_State *L, int oldmode) { static int pushmode (lua_State *L, int oldmode) {
lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" : "generational"); lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental"
: "generational");
return 1; return 1;
} }
@ -299,7 +300,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 */
@ -355,7 +356,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);
@ -393,7 +394,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);
@ -401,7 +402,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 */
@ -437,7 +438,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

@ -314,15 +314,6 @@ void luaK_patchtohere (FuncState *fs, int list) {
} }
/*
** MAXimum number of successive Instructions WiTHout ABSolute line
** information.
*/
#if !defined(MAXIWTHABS)
#define MAXIWTHABS 120
#endif
/* limit for difference between lines in relative line info. */ /* limit for difference between lines in relative line info. */
#define LIMLINEDIFF 0x80 #define LIMLINEDIFF 0x80
@ -337,13 +328,13 @@ void luaK_patchtohere (FuncState *fs, int list) {
static void savelineinfo (FuncState *fs, Proto *f, int line) { static void savelineinfo (FuncState *fs, Proto *f, int line) {
int linedif = line - fs->previousline; int linedif = line - fs->previousline;
int pc = fs->pc - 1; /* last instruction coded */ int pc = fs->pc - 1; /* last instruction coded */
if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ > MAXIWTHABS) { if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ >= MAXIWTHABS) {
luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo, luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo,
f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines"); f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines");
f->abslineinfo[fs->nabslineinfo].pc = pc; f->abslineinfo[fs->nabslineinfo].pc = pc;
f->abslineinfo[fs->nabslineinfo++].line = line; f->abslineinfo[fs->nabslineinfo++].line = line;
linedif = ABSLINEINFO; /* signal that there is absolute information */ linedif = ABSLINEINFO; /* signal that there is absolute information */
fs->iwthabs = 0; /* restart counter */ fs->iwthabs = 1; /* restart counter */
} }
luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte, luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte,
MAX_INT, "opcodes"); MAX_INT, "opcodes");
@ -545,11 +536,14 @@ static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) {
** and try to reuse constants. Because some values should not be used ** and try to reuse constants. Because some values should not be used
** as keys (nil cannot be a key, integer keys can collapse with float ** as keys (nil cannot be a key, integer keys can collapse with float
** keys), the caller must provide a useful 'key' for indexing the cache. ** keys), the caller must provide a useful 'key' for indexing the cache.
** Note that all functions share the same table, so entering or exiting
** a function can make some indices wrong.
*/ */
static int addk (FuncState *fs, TValue *key, TValue *v) { static int addk (FuncState *fs, TValue *key, TValue *v) {
TValue val;
lua_State *L = fs->ls->L; lua_State *L = fs->ls->L;
Proto *f = fs->f; Proto *f = fs->f;
TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ const TValue *idx = luaH_get(fs->ls->h, key); /* query scanner table */
int k, oldsize; int k, oldsize;
if (ttisinteger(idx)) { /* is there an index there? */ if (ttisinteger(idx)) { /* is there an index there? */
k = cast_int(ivalue(idx)); k = cast_int(ivalue(idx));
@ -563,7 +557,8 @@ static int addk (FuncState *fs, TValue *key, TValue *v) {
k = fs->nk; k = fs->nk;
/* numerical value does not need GC barrier; /* numerical value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */ table has no metatable, so it does not need to invalidate cache */
setivalue(idx, k); setivalue(&val, k);
luaH_finishset(L, fs->ls->h, key, idx, &val);
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
setobj(L, &f->k[k], v); setobj(L, &f->k[k], v);
@ -763,7 +758,7 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
break; break;
} }
case VLOCAL: { /* already in a register */ case VLOCAL: { /* already in a register */
e->u.info = e->u.var.sidx; e->u.info = e->u.var.ridx;
e->k = VNONRELOC; /* becomes a non-relocatable value */ e->k = VNONRELOC; /* becomes a non-relocatable value */
break; break;
} }
@ -1036,7 +1031,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
switch (var->k) { switch (var->k) {
case VLOCAL: { case VLOCAL: {
freeexp(fs, ex); freeexp(fs, ex);
exp2reg(fs, ex, var->u.var.sidx); /* compute 'ex' into proper place */ exp2reg(fs, ex, var->u.var.ridx); /* compute 'ex' into proper place */
return; return;
} }
case VUPVAL: { case VUPVAL: {
@ -1276,7 +1271,7 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
} }
else { else {
/* register index of the table */ /* register index of the table */
t->u.ind.t = (t->k == VLOCAL) ? t->u.var.sidx: t->u.info; t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info;
if (isKstr(fs, k)) { if (isKstr(fs, k)) {
t->u.ind.idx = k->u.info; /* literal string */ t->u.ind.idx = k->u.info; /* literal string */
t->k = VINDEXSTR; t->k = VINDEXSTR;
@ -1303,7 +1298,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

@ -31,14 +31,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 */
@ -57,7 +57,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 */
@ -73,10 +73,13 @@ 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? */
lua_resetthread(co); /* close its tbc variables */ stat = lua_resetthread(co); /* close its tbc variables */
lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* copy error message */
}
if (stat != LUA_ERRMEM && /* not a memory error and ... */ if (stat != LUA_ERRMEM && /* not a memory error and ... */
lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */ lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
luaL_where(L, 1); /* add extra info, if available */ luaL_where(L, 1); /* add extra info, if available */

View file

@ -33,7 +33,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");
} }
@ -152,6 +152,7 @@ static int db_getinfo (lua_State *L) {
lua_State *L1 = getthread(L, &arg); lua_State *L1 = getthread(L, &arg);
const char *options = luaL_optstring(L, arg+2, "flnSrtu"); const char *options = luaL_optstring(L, arg+2, "flnSrtu");
checkstack(L, L1, 3); checkstack(L, L1, 3);
luaL_argcheck(L, options[0] != '>', arg + 2, "invalid option '>'");
if (lua_isfunction(L, arg + 1)) { /* info about a function? */ if (lua_isfunction(L, arg + 1)) { /* info about a function? */
options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
@ -212,7 +213,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);
@ -237,7 +238,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);
@ -377,7 +378,7 @@ static int db_sethook (lua_State *L) {
} }
if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) { if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) {
/* table just created; initialize it */ /* table just created; initialize it */
lua_pushstring(L, "k"); lua_pushliteral(L, "k");
lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_setmetatable(L, -2); /* metatable(hooktable) = hooktable */ lua_setmetatable(L, -2); /* metatable(hooktable) = hooktable */
@ -420,7 +421,7 @@ static int db_debug (lua_State *L) {
for (;;) { for (;;) {
char buffer[250]; char buffer[250];
lua_writestringerror("%s", "lua_debug> "); lua_writestringerror("%s", "lua_debug> ");
if (fgets(buffer, sizeof(buffer), stdin) == 0 || if (fgets(buffer, sizeof(buffer), stdin) == NULL ||
strcmp(buffer, "cont\n") == 0) strcmp(buffer, "cont\n") == 0)
return 0; return 0;
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||

View file

@ -33,8 +33,6 @@
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL)
/* inverse of 'pcRel' */
#define invpcRel(pc, p) ((p)->code + (pc) + 1)
static const char *funcnamefromcode (lua_State *L, CallInfo *ci, static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
const char **name); const char **name);
@ -48,10 +46,16 @@ static int currentpc (CallInfo *ci) {
/* /*
** Get a "base line" to find the line corresponding to an instruction. ** Get a "base line" to find the line corresponding to an instruction.
** For that, search the array of absolute line info for the largest saved ** Base lines are regularly placed at MAXIWTHABS intervals, so usually
** instruction smaller or equal to the wanted instruction. A special ** an integer division gets the right place. When the source file has
** case is when there is no absolute info or the instruction is before ** large sequences of empty/comment lines, it may need extra entries,
** the first absolute one. ** 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
** is valid as long as the debug info has been generated with the same
** value for MAXIWTHABS or smaller. (Previous releases use a little
** smaller value.)
*/ */
static int getbaseline (const Proto *f, int pc, int *basepc) { static int getbaseline (const Proto *f, int pc, int *basepc) {
if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) { if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) {
@ -59,20 +63,12 @@ static int getbaseline (const Proto *f, int pc, int *basepc) {
return f->linedefined; return f->linedefined;
} }
else { else {
unsigned int i; int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */
if (pc >= f->abslineinfo[f->sizeabslineinfo - 1].pc) /* estimate must be a lower bond of the correct base */
i = f->sizeabslineinfo - 1; /* instruction is after last saved one */ lua_assert(i < 0 ||
else { /* binary search */ (i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc));
unsigned int j = f->sizeabslineinfo - 1; /* pc < anchorlines[j] */ while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc)
i = 0; /* abslineinfo[i] <= pc */ i++; /* low estimate; adjust it */
while (i < j - 1) {
unsigned int m = (j + i) / 2;
if (pc >= f->abslineinfo[m].pc)
i = m;
else
j = m;
}
}
*basepc = f->abslineinfo[i].pc; *basepc = f->abslineinfo[i].pc;
return f->abslineinfo[i].line; return f->abslineinfo[i].line;
} }
@ -305,8 +301,8 @@ static void collectvalidlines (lua_State *L, Closure *f) {
sethvalue2s(L, L->top, t); /* push it on stack */ sethvalue2s(L, L->top, t); /* push it on stack */
api_incr_top(L); api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */ setbtvalue(&v); /* boolean 'true' to be the value of all indices */
for (i = 0; i < p->sizelineinfo; i++) { /* for all lines with code */ for (i = 0; i < p->sizelineinfo; i++) { /* for all instructions */
currentline = nextline(p, currentline, i); currentline = nextline(p, currentline, i); /* get its line */
luaH_setint(L, t, currentline, &v); /* table[line] = true */ luaH_setint(L, t, currentline, &v); /* table[line] = true */
} }
} }
@ -629,12 +625,10 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
case OP_LEN: tm = TM_LEN; break; case OP_LEN: tm = TM_LEN; break;
case OP_CONCAT: tm = TM_CONCAT; break; case OP_CONCAT: tm = TM_CONCAT; break;
case OP_EQ: tm = TM_EQ; break; case OP_EQ: tm = TM_EQ; break;
case OP_LT: case OP_LE: case OP_LTI: case OP_LEI: /* no cases for OP_EQI and OP_EQK, as they don't call metamethods */
*name = "order"; /* '<=' can call '__lt', etc. */ case OP_LT: case OP_LTI: case OP_GTI: tm = TM_LT; break;
return "metamethod"; case OP_LE: case OP_LEI: case OP_GEI: tm = TM_LE; break;
case OP_CLOSE: case OP_RETURN: case OP_CLOSE: case OP_RETURN: tm = TM_CLOSE; break;
*name = "close";
return "metamethod";
default: default:
return NULL; /* cannot find a reasonable name */ return NULL; /* cannot find a reasonable name */
} }
@ -647,14 +641,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 */
} }
@ -697,6 +695,19 @@ l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
} }
l_noret luaG_callerror (lua_State *L, const TValue *o) {
CallInfo *ci = L->ci;
const char *name = NULL; /* to avoid warnings */
const char *what = (isLua(ci)) ? funcnamefromcode(L, ci, &name) : NULL;
if (what != NULL) {
const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "%s '%s' is not callable (a %s value)", what, name, t);
}
else
luaG_typeerror(L, o, "call");
}
l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) { l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what) {
luaG_runerror(L, "bad 'for' %s (number expected, got %s)", luaG_runerror(L, "bad 'for' %s (number expected, got %s)",
what, luaT_objtypename(L, o)); what, luaT_objtypename(L, o));
@ -722,7 +733,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));
} }
@ -780,16 +791,30 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
/* /*
** Check whether new instruction 'newpc' is in a different line from ** Check whether new instruction 'newpc' is in a different line from
** previous instruction 'oldpc'. ** previous instruction 'oldpc'. More often than not, 'newpc' is only
** one or a few instructions after 'oldpc' (it must be after, see
** caller), so try to avoid calling 'luaG_getfuncline'. If they are
** too far apart, there is a good chance of a ABSLINEINFO in the way,
** so it goes directly to 'luaG_getfuncline'.
*/ */
static int changedline (const Proto *p, int oldpc, int newpc) { static int changedline (const Proto *p, int oldpc, int newpc) {
if (p->lineinfo == NULL) /* no debug information? */ if (p->lineinfo == NULL) /* no debug information? */
return 0; return 0;
while (oldpc++ < newpc) { if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
if (p->lineinfo[oldpc] != 0) int delta = 0; /* line diference */
return (luaG_getfuncline(p, oldpc - 1) != luaG_getfuncline(p, newpc)); int pc = oldpc;
for (;;) {
int lineinfo = p->lineinfo[++pc];
if (lineinfo == ABSLINEINFO)
break; /* cannot compute delta; fall through */
delta += lineinfo;
if (pc == newpc)
return (delta != 0); /* delta computed successfully */
} }
return 0; /* no line changes between positions */ }
/* either instructions are too far apart or there is an absolute line
info in the way; compute line difference explicitly */
return (luaG_getfuncline(p, oldpc) != luaG_getfuncline(p, newpc));
} }
@ -797,20 +822,19 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
** Traces the execution of a Lua function. Called before the execution ** Traces the execution of a Lua function. Called before the execution
** of each opcode, when debug is on. 'L->oldpc' stores the last ** of each opcode, when debug is on. 'L->oldpc' stores the last
** instruction traced, to detect line changes. When entering a new ** instruction traced, to detect line changes. When entering a new
** function, 'npci' will be zero and will test as a new line without ** function, 'npci' will be zero and will test as a new line whatever
** the need for 'oldpc'; so, 'oldpc' does not need to be initialized ** the value of 'oldpc'. Some exceptional conditions may return to
** before. Some exceptional conditions may return to a function without ** a function without setting 'oldpc'. In that case, 'oldpc' may be
** updating 'oldpc'. In that case, 'oldpc' may be invalid; if so, it is ** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** reset to zero. (A wrong but valid 'oldpc' at most causes an extra ** at most causes an extra call to a line hook.)
** call to a line hook.) ** This function is not "Protected" when called, so it should correct
** 'L->top' before calling anything that can run the GC.
*/ */
int luaG_traceexec (lua_State *L, const Instruction *pc) { int luaG_traceexec (lua_State *L, const Instruction *pc) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
lu_byte mask = L->hookmask; lu_byte mask = L->hookmask;
const Proto *p = ci_func(ci)->p; const Proto *p = ci_func(ci)->p;
int counthook; int counthook;
/* 'L->oldpc' may be invalid; reset it in this case */
int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0;
if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */ if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */
ci->u.l.trap = 0; /* don't need to stop again */ ci->u.l.trap = 0; /* don't need to stop again */
return 0; /* turn off 'trap' */ return 0; /* turn off 'trap' */
@ -826,15 +850,16 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
return 1; /* do not call hook again (VM yielded, so it did not move) */ return 1; /* do not call hook again (VM yielded, so it did not move) */
} }
if (!isIT(*(ci->u.l.savedpc - 1))) if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
L->top = ci->top; /* prepare top */ L->top = ci->top; /* correct top */
if (counthook) if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
if (mask & LUA_MASKLINE) { if (mask & LUA_MASKLINE) {
/* 'L->oldpc' may be invalid; use zero in this case */
int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0;
int npci = pcRel(pc, p); int npci = pcRel(pc, p);
if (npci == 0 || /* call linehook when enter a new function, */ if (npci <= oldpc || /* call hook when jump back (loop), */
pc <= invpcRel(oldpc, p) || /* when jump back (loop), or when */ changedline(p, oldpc, npci)) { /* or when enter new line */
changedline(p, oldpc, npci)) { /* enter new line */
int newline = luaG_getfuncline(p, npci); int newline = luaG_getfuncline(p, npci);
luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */ luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */
} }

View file

@ -26,11 +26,22 @@
*/ */
#define ABSLINEINFO (-0x80) #define ABSLINEINFO (-0x80)
/*
** MAXimum number of successive Instructions WiTHout ABSolute line
** information. (A power of two allows fast divisions.)
*/
#if !defined(MAXIWTHABS)
#define MAXIWTHABS 128
#endif
LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc); LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc);
LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n,
StkId *pos); StkId *pos);
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
const char *opname); const char *opname);
LUAI_FUNC l_noret luaG_callerror (lua_State *L, const TValue *o);
LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o, LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o,
const char *what); const char *what);
LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1,

View file

@ -98,11 +98,12 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
break; break;
} }
case CLOSEPROTECT: { case LUA_OK: { /* special case only for closing upvalues */
setnilvalue(s2v(oldtop)); /* no error message */ setnilvalue(s2v(oldtop)); /* no error message */
break; break;
} }
default: { default: {
lua_assert(errorstatus(errcode)); /* real error */
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
break; break;
} }
@ -118,17 +119,13 @@ l_noret luaD_throw (lua_State *L, int errcode) {
} }
else { /* thread has no error handler */ else { /* thread has no error handler */
global_State *g = G(L); global_State *g = G(L);
errcode = luaF_close(L, L->stack, errcode); /* close all upvalues */ errcode = luaE_resetthread(L, errcode); /* close all upvalues */
L->status = cast_byte(errcode); /* mark it as dead */
if (g->mainthread->errorJmp) { /* main thread has a handler? */ if (g->mainthread->errorJmp) { /* main thread has a handler? */
setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
} }
else { /* no handler at all; abort */ else { /* no handler at all; abort */
if (g->panic) { /* panic function? */ if (g->panic) { /* panic function? */
luaD_seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */
if (L->ci->top < L->top)
L->ci->top = L->top; /* pushing msg. can break this invariant */
lua_unlock(L); lua_unlock(L);
g->panic(L); /* call panic function (last chance to jump out) */ g->panic(L); /* call panic function (last chance to jump out) */
} }
@ -163,9 +160,8 @@ 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;
for (up = L->openupval; up != NULL; up = up->u.open.next) for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v = s2v((uplevel(up) - oldstack) + newstack); up->v = s2v((uplevel(up) - oldstack) + newstack);
for (ci = L->ci; ci != NULL; ci = ci->previous) { for (ci = L->ci; ci != NULL; ci = ci->previous) {
@ -181,19 +177,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;
@ -206,7 +218,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. */
@ -222,7 +234,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 */
@ -297,8 +309,8 @@ void luaD_hook (lua_State *L, int event, int line,
if (hook && L->allowhook) { /* make sure there is a hook */ if (hook && L->allowhook) { /* make sure there is a hook */
int mask = CIST_HOOKED; int mask = CIST_HOOKED;
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top); ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */
ptrdiff_t ci_top = savestack(L, ci->top); ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */
lua_Debug ar; lua_Debug ar;
ar.event = event; ar.event = event;
ar.currentline = line; ar.currentline = line;
@ -308,8 +320,10 @@ void luaD_hook (lua_State *L, int event, int line,
ci->u2.transferinfo.ftransfer = ftransfer; ci->u2.transferinfo.ftransfer = ftransfer;
ci->u2.transferinfo.ntransfer = ntransfer; ci->u2.transferinfo.ntransfer = ntransfer;
} }
if (isLua(ci) && L->top < ci->top)
L->top = ci->top; /* protect entire activation register */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
if (L->top + LUA_MINSTACK > ci->top) if (ci->top < L->top + LUA_MINSTACK)
ci->top = L->top + LUA_MINSTACK; ci->top = L->top + LUA_MINSTACK;
L->allowhook = 0; /* cannot call hooks inside a hook */ L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= mask; ci->callstatus |= mask;
@ -331,38 +345,40 @@ void luaD_hook (lua_State *L, int event, int line,
** active. ** active.
*/ */
void luaD_hookcall (lua_State *L, CallInfo *ci) { void luaD_hookcall (lua_State *L, CallInfo *ci) {
int hook = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL : LUA_HOOKCALL; L->oldpc = 0; /* set 'oldpc' for new function */
Proto *p; if (L->hookmask & LUA_MASKCALL) { /* is call hook on? */
if (!(L->hookmask & LUA_MASKCALL)) /* some other hook? */ int event = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL
return; /* don't call hook */ : LUA_HOOKCALL;
p = clLvalue(s2v(ci->func))->p; Proto *p = ci_func(ci)->p;
L->top = ci->top; /* prepare top */
ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */
luaD_hook(L, hook, -1, 1, p->numparams); luaD_hook(L, event, -1, 1, p->numparams);
ci->u.l.savedpc--; /* correct 'pc' */ ci->u.l.savedpc--; /* correct 'pc' */
}
} }
static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) { /*
ptrdiff_t oldtop = savestack(L, L->top); /* hook may change top */ ** Executes a return hook for Lua and C functions and sets/corrects
int delta = 0; ** 'oldpc'. (Note that this correction is needed by the line hook, so it
if (isLuacode(ci)) { ** is done even when return hooks are off.)
*/
static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
StkId firstres = L->top - nres; /* index of first result */
int delta = 0; /* correction for vararg functions */
int ftransfer;
if (isLua(ci)) {
Proto *p = ci_func(ci)->p; Proto *p = ci_func(ci)->p;
if (p->is_vararg) if (p->is_vararg)
delta = ci->u.l.nextraargs + p->numparams + 1; delta = ci->u.l.nextraargs + p->numparams + 1;
if (L->top < ci->top)
L->top = ci->top; /* correct top to run hook */
} }
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
int ftransfer;
ci->func += delta; /* if vararg, back to virtual 'func' */ ci->func += delta; /* if vararg, back to virtual 'func' */
ftransfer = cast(unsigned short, firstres - ci->func); ftransfer = cast(unsigned short, firstres - ci->func);
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
ci->func -= delta; ci->func -= delta;
} }
if (isLua(ci = ci->previous)) if (isLua(ci = ci->previous))
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* update 'oldpc' */ L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
return restorestack(L, oldtop);
} }
@ -374,8 +390,8 @@ static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, 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_typeerror(L, s2v(func), "call"); /* 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);
L->top++; /* stack space pre-allocated by the caller */ L->top++; /* stack space pre-allocated by the caller */
@ -399,27 +415,34 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
case 1: /* one value needed */ case 1: /* one value needed */
if (nres == 0) /* no results? */ if (nres == 0) /* no results? */
setnilvalue(s2v(res)); /* adjust with nil */ setnilvalue(s2v(res)); /* adjust with nil */
else else /* at least one result */
setobjs2s(L, res, L->top - nres); /* move it to proper place */ setobjs2s(L, res, L->top - nres); /* move it to proper place */
L->top = res + 1; L->top = res + 1;
return; return;
case LUA_MULTRET: case LUA_MULTRET:
wanted = nres; /* we want all results */ wanted = nres; /* we want all results */
break; break;
default: /* multiple results (or to-be-closed variables) */ default: /* two/more results and/or to-be-closed variables */
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
ptrdiff_t savedres = savestack(L, res); ptrdiff_t savedres = savestack(L, res);
luaF_close(L, res, LUA_OK); /* may change the stack */ L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
res = restorestack(L, savedres); L->ci->u2.nres = nres;
wanted = codeNresults(wanted); /* correct value */ luaF_close(L, res, CLOSEKTOP, 1);
L->ci->callstatus &= ~CIST_CLSRET;
if (L->hookmask) /* if needed, call hook after '__close's */
rethook(L, L->ci, nres);
res = restorestack(L, savedres); /* close and hook can move stack */
wanted = decodeNresults(wanted);
if (wanted == LUA_MULTRET) if (wanted == LUA_MULTRET)
wanted = nres; wanted = nres; /* we want all results */
} }
break; break;
} }
/* generic case */
firstresult = L->top - nres; /* index of first result */ firstresult = L->top - nres; /* index of first result */
/* move all results to correct place */ if (nres > wanted) /* extra results? */
for (i = 0; i < nres && i < wanted; i++) nres = wanted; /* don't need them */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstresult + i); setobjs2s(L, res + i, firstresult + i);
for (; i < wanted; i++) /* complete wanted number of results */ for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(s2v(res + i)); setnilvalue(s2v(res + i));
@ -428,15 +451,21 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) {
/* /*
** Finishes a function call: calls hook if necessary, removes CallInfo, ** Finishes a function call: calls hook if necessary, moves current
** moves current number of results to proper place. ** number of results to proper place, and returns to previous call
** info. If function has to close variables, hook must be called after
** that.
*/ */
void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask) int wanted = ci->nresults;
L->top = rethook(L, ci, L->top - nres, nres); if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
L->ci = ci->previous; /* back to caller */ rethook(L, ci, nres);
/* move results to proper place */ /* move results to proper place */
moveresults(L, ci->func, nres, ci->nresults); moveresults(L, ci->func, nres, wanted);
/* function cannot be in any of these cases when returning */
lua_assert(!(ci->callstatus &
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
L->ci = ci->previous; /* back to caller (after closing variables) */
} }
@ -495,7 +524,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);
} }
@ -541,7 +570,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 */
@ -568,27 +597,74 @@ void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
/* /*
** Completes the execution of an interrupted C function, calling its ** Finish the job of 'lua_pcallk' after it was interrupted by an yield.
** continuation function. ** (The caller, 'finishCcall', does the final call to 'adjustresults'.)
** The main job is to complete the 'luaD_pcall' called by 'lua_pcallk'.
** If a '__close' method yields here, eventually control will be back
** to 'finishCcall' (when that '__close' method finally returns) and
** 'finishpcallk' will run again and close any still pending '__close'
** methods. Similarly, if a '__close' method errs, 'precover' calls
** 'unroll' which calls ''finishCcall' and we are back here again, to
** close any pending '__close' methods.
** Note that, up to the call to 'luaF_close', the corresponding
** 'CallInfo' is not modified, so that this repeated run works like the
** first one (except that it has at least one less '__close' to do). In
** particular, field CIST_RECST preserves the error status across these
** multiple runs, changing only if there is a new error.
*/ */
static void finishCcall (lua_State *L, int status) { static int finishpcallk (lua_State *L, CallInfo *ci) {
CallInfo *ci = L->ci; int status = getcistrecst(ci); /* get original status */
int n; if (l_likely(status == LUA_OK)) /* no error? */
status = LUA_YIELD; /* was interrupted by an yield */
else { /* error */
StkId func = restorestack(L, ci->u2.funcidx);
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
luaF_close(L, func, status, 1); /* can yield or raise an error */
func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
luaD_seterrorobj(L, status, func);
luaD_shrinkstack(L); /* restore stack size in case of overflow */
setcistrecst(ci, LUA_OK); /* clear original status */
}
ci->callstatus &= ~CIST_YPCALL;
L->errfunc = ci->u.c.old_errfunc;
/* if it is here, there were errors or yields; unlike 'lua_pcallk',
do not change status */
return status;
}
/*
** Completes the execution of a C function interrupted by an yield.
** The interruption must have happened while the function was either
** closing its tbc variables in 'moveresults' or executing
** 'lua_callk'/'lua_pcallk'. In the first case, it just redoes
** 'luaD_poscall'. In the second case, the call to 'finishpcallk'
** finishes the interrupted execution of 'lua_pcallk'. After that, it
** calls the continuation of the interrupted function and finally it
** completes the job of the 'luaD_call' that called the function. In
** the call to 'adjustresults', we do not know the number of results
** of the function called by 'lua_callk'/'lua_pcallk', so we are
** conservative and use LUA_MULTRET (always adjust).
*/
static void finishCcall (lua_State *L, CallInfo *ci) {
int n; /* actual number of results from C function */
if (ci->callstatus & CIST_CLSRET) { /* was returning? */
lua_assert(hastocloseCfunc(ci->nresults));
n = ci->u2.nres; /* just redo 'luaD_poscall' */
/* don't need to reset CIST_CLSRET, as it will be set again anyway */
}
else {
int status = LUA_YIELD; /* default if there were no errors */
/* must have a continuation and must be able to call it */ /* must have a continuation and must be able to call it */
lua_assert(ci->u.c.k != NULL && yieldable(L)); lua_assert(ci->u.c.k != NULL && yieldable(L));
/* error status can only happen in a protected call */ if (ci->callstatus & CIST_YPCALL) /* was inside a 'lua_pcallk'? */
lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD); status = finishpcallk(L, ci); /* finish it */
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */ adjustresults(L, LUA_MULTRET); /* finish 'lua_callk' */
ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */
L->errfunc = ci->u.c.old_errfunc; /* with the same error function */
}
/* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
handled */
adjustresults(L, ci->nresults);
lua_unlock(L); lua_unlock(L);
n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation */
lua_lock(L); lua_lock(L);
api_checknelems(L, n); api_checknelems(L, n);
}
luaD_poscall(L, ci, n); /* finish 'luaD_call' */ luaD_poscall(L, ci, n); /* finish 'luaD_call' */
} }
@ -596,18 +672,14 @@ static void finishCcall (lua_State *L, int status) {
/* /*
** Executes "full continuation" (everything in the stack) of a ** Executes "full continuation" (everything in the stack) of a
** previously interrupted coroutine until the stack is empty (or another ** previously interrupted coroutine until the stack is empty (or another
** interruption long-jumps out of the loop). If the coroutine is ** interruption long-jumps out of the loop).
** recovering from an error, 'ud' points to the error status, which must
** be passed to the first continuation function (otherwise the default
** status is LUA_YIELD).
*/ */
static void unroll (lua_State *L, void *ud) { static void unroll (lua_State *L, void *ud) {
CallInfo *ci; CallInfo *ci;
if (ud != NULL) /* error status? */ UNUSED(ud);
finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */
while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ while ((ci = L->ci) != &L->base_ci) { /* something in the stack */
if (!isLua(ci)) /* C function? */ if (!isLua(ci)) /* C function? */
finishCcall(L, LUA_YIELD); /* complete its execution */ finishCcall(L, ci); /* complete its execution */
else { /* Lua function */ else { /* Lua function */
luaV_finishOp(L); /* finish interrupted instruction */ luaV_finishOp(L); /* finish interrupted instruction */
luaV_execute(L, ci); /* execute down to higher C 'boundary' */ luaV_execute(L, ci); /* execute down to higher C 'boundary' */
@ -630,28 +702,6 @@ static CallInfo *findpcall (lua_State *L) {
} }
/*
** Recovers from an error in a coroutine. Finds a recover point (if
** there is one) and completes the execution of the interrupted
** 'luaD_pcall'. If there is no recover point, returns zero.
*/
static int recover (lua_State *L, int status) {
StkId oldtop;
CallInfo *ci = findpcall(L);
if (ci == NULL) return 0; /* no recovery point */
/* "finish" luaD_pcall */
oldtop = restorestack(L, ci->u2.funcidx);
L->ci = ci;
L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */
status = luaF_close(L, oldtop, status); /* may change the stack */
oldtop = restorestack(L, ci->u2.funcidx);
luaD_seterrorobj(L, status, oldtop);
luaD_shrinkstack(L); /* restore stack size in case of overflow */
L->errfunc = ci->u.c.old_errfunc;
return 1; /* continue running the coroutine */
}
/* /*
** Signal an error in the call to 'lua_resume', not in the execution ** Signal an error in the call to 'lua_resume', not in the execution
** of the coroutine itself. (Such errors should not be handled by any ** of the coroutine itself. (Such errors should not be handled by any
@ -683,8 +733,10 @@ static void resume (lua_State *L, void *ud) {
lua_assert(L->status == LUA_YIELD); lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */ L->status = LUA_OK; /* mark that it is running (again) */
luaE_incCstack(L); /* control the C stack */ luaE_incCstack(L); /* control the C stack */
if (isLua(ci)) /* yielded inside a hook? */ if (isLua(ci)) { /* yielded inside a hook? */
L->top = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */ luaV_execute(L, ci); /* just continue running Lua code */
}
else { /* 'common' yield */ else { /* 'common' yield */
if (ci->u.c.k != NULL) { /* does it have a continuation function? */ if (ci->u.c.k != NULL) { /* does it have a continuation function? */
lua_unlock(L); lua_unlock(L);
@ -698,6 +750,26 @@ static void resume (lua_State *L, void *ud) {
} }
} }
/*
** Unrolls a coroutine in protected mode while there are recoverable
** errors, that is, errors inside a protected call. (Any error
** interrupts 'unroll', and this loop protects it again so it can
** continue.) Stops with a normal end (status == LUA_OK), an yield
** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't
** find a recover point).
*/
static int precover (lua_State *L, int status) {
CallInfo *ci;
while (errorstatus(status) && (ci = findpcall(L)) != NULL) {
L->ci = ci; /* go down to recovery functions */
setcistrecst(ci, status); /* status to finish 'pcall' */
status = luaD_rawrunprotected(L, unroll, NULL);
}
return status;
}
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
int *nresults) { int *nresults) {
int status; int status;
@ -715,11 +787,8 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, &nargs); status = luaD_rawrunprotected(L, resume, &nargs);
/* continue running after recoverable errors */ /* continue running after recoverable errors */
while (errorstatus(status) && recover(L, status)) { status = precover(L, status);
/* unroll continuation */ if (l_likely(!errorstatus(status)))
status = luaD_rawrunprotected(L, unroll, &status);
}
if (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' */
@ -745,22 +814,22 @@ 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
luaG_runerror(L, "attempt to yield from outside a coroutine"); luaG_runerror(L, "attempt to yield from outside a coroutine");
} }
L->status = LUA_YIELD; L->status = LUA_YIELD;
ci->u2.nyield = nresults; /* save number of results */
if (isLua(ci)) { /* inside a hook? */ if (isLua(ci)) { /* inside a hook? */
lua_assert(!isLuacode(ci)); lua_assert(!isLuacode(ci));
api_check(L, nresults == 0, "hooks cannot yield values");
api_check(L, k == NULL, "hooks cannot continue after yielding"); api_check(L, k == NULL, "hooks cannot continue after yielding");
ci->u2.nyield = 0; /* no results */
} }
else { else {
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
ci->u.c.ctx = ctx; /* save context */ ci->u.c.ctx = ctx; /* save context */
ci->u2.nyield = nresults; /* save number of results */
luaD_throw(L, LUA_YIELD); luaD_throw(L, LUA_YIELD);
} }
lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */
@ -769,6 +838,45 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
} }
/*
** Auxiliary structure to call 'luaF_close' in protected mode.
*/
struct CloseP {
StkId level;
int status;
};
/*
** Auxiliary function to call 'luaF_close' in protected mode.
*/
static void closepaux (lua_State *L, void *ud) {
struct CloseP *pcl = cast(struct CloseP *, ud);
luaF_close(L, pcl->level, pcl->status, 0);
}
/*
** Calls 'luaF_close' in protected mode. Return the original status
** or, in case of errors, the new status.
*/
int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status) {
CallInfo *old_ci = L->ci;
lu_byte old_allowhooks = L->allowhook;
for (;;) { /* keep closing upvalues until no more errors */
struct CloseP pcl;
pcl.level = restorestack(L, level); pcl.status = status;
status = luaD_rawrunprotected(L, &closepaux, &pcl);
if (l_likely(status == LUA_OK)) /* no more errors? */
return pcl.status;
else { /* an error occurred; restore saved state and repeat */
L->ci = old_ci;
L->allowhook = old_allowhooks;
}
}
}
/* /*
** Call the C function 'func' in protected mode, restoring basic ** Call the C function 'func' in protected mode, restoring basic
** thread information ('allowhook', etc.) and in particular ** thread information ('allowhook', etc.) and in particular
@ -782,13 +890,11 @@ 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? */
StkId oldtop = restorestack(L, old_top);
L->ci = old_ci; L->ci = old_ci;
L->allowhook = old_allowhooks; L->allowhook = old_allowhooks;
status = luaF_close(L, oldtop, status); status = luaD_closeprotected(L, old_top, status);
oldtop = restorestack(L, old_top); /* previous call may change stack */ luaD_seterrorobj(L, status, restorestack(L, old_top));
luaD_seterrorobj(L, status, oldtop);
luaD_shrinkstack(L); /* restore stack size in case of overflow */ luaD_shrinkstack(L); /* restore stack size in case of overflow */
} }
L->errfunc = old_errfunc; L->errfunc = old_errfunc;

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); }
@ -63,6 +63,7 @@ LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func);
LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef); ptrdiff_t oldtop, ptrdiff_t ef);
LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres); LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres);

View file

@ -100,115 +100,83 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
} }
static void callclose (lua_State *L, void *ud) {
UNUSED(ud);
luaD_callnoyield(L, L->top - 3, 0);
}
/* /*
** Prepare closing method plus its arguments for object 'obj' with ** Call closing method for object 'obj' with error message 'err'. The
** error message 'err'. (This function assumes EXTRA_STACK.) ** boolean 'yy' controls whether the call is yieldable.
** (This function assumes EXTRA_STACK.)
*/ */
static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
StkId top = L->top; StkId top = L->top;
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
if (ttisnil(tm)) /* no metamethod? */
return 0; /* nothing to call */
setobj2s(L, top, tm); /* will call metamethod... */ setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
L->top = top + 3; /* add function and arguments */ L->top = top + 3; /* add function and arguments */
return 1; if (yy)
luaD_call(L, top, 0);
else
luaD_callnoyield(L, top, 0);
} }
/* /*
** Raise an error with message 'msg', inserting the name of the ** Check whether object at given level has a close metamethod and raise
** local variable at position 'level' in the stack. ** an error if not.
*/ */
static void varerror (lua_State *L, StkId level, const char *msg) { static void checkclosemth (lua_State *L, StkId level) {
int idx = cast_int(level - L->ci->func); const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
if (ttisnil(tm)) { /* no metamethod? */
int idx = cast_int(level - L->ci->func); /* variable index */
const char *vname = luaG_findlocal(L, L->ci, idx, NULL); const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
if (vname == NULL) vname = "?"; if (vname == NULL) vname = "?";
luaG_runerror(L, msg, vname); luaG_runerror(L, "variable '%s' got a non-closable value", vname);
}
} }
/* /*
** Prepare and call a closing method. If status is OK, code is still ** Prepare and call a closing method.
** inside the original protected call, and so any error will be handled ** If status is CLOSEKTOP, the call to the closing method will be pushed
** there. Otherwise, a previous error already activated the original ** at the top of the stack. Otherwise, values can be pushed right after
** protected call, and so the call to the closing method must be ** the 'level' of the upvalue being closed, as everything after that
** protected here. (A status == CLOSEPROTECT behaves like a previous ** won't be used again.
** error, to also run the closing method in protected mode).
** If status is OK, the call to the closing method will be pushed
** at the top of the stack. Otherwise, values are pushed after
** the 'level' of the upvalue being closed, as everything after
** that won't be used again.
*/ */
static int callclosemth (lua_State *L, StkId level, int status) { static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
TValue *uv = s2v(level); /* value being closed */ TValue *uv = s2v(level); /* value being closed */
if (likely(status == LUA_OK)) { TValue *errobj;
if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ if (status == CLOSEKTOP)
callclose(L, NULL); /* call closing method */ errobj = &G(L)->nilvalue; /* error object is nil */
else if (!l_isfalse(uv)) /* non-closable non-false value? */ else { /* 'luaD_seterrorobj' will set top to level + 2 */
varerror(L, level, "attempt to close non-closable variable '%s'"); errobj = s2v(level + 1); /* error object goes after 'uv' */
luaD_seterrorobj(L, status, level + 1); /* set error object */
} }
else { /* must close the object in protected mode */ callclosemethod(L, uv, errobj, yy);
ptrdiff_t oldtop;
level++; /* space for error message */
oldtop = savestack(L, level + 1); /* top will be after that */
luaD_seterrorobj(L, status, level); /* set error message */
if (prepclosingmethod(L, uv, s2v(level))) { /* something to call? */
int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0);
if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */
status = newstatus; /* this will be the new error */
else {
if (newstatus != LUA_OK) /* suppressed error? */
luaE_warnerror(L, "__close metamethod");
/* leave original error (or nil) on top */
L->top = restorestack(L, oldtop);
}
}
/* else no metamethod; ignore this case and keep original error */
}
return status;
} }
/* /*
** Try to create a to-be-closed upvalue ** Maximum value for deltas in 'tbclist', dependent on the type
** (can raise a memory-allocation error) ** of delta. (This macro assumes that an 'L' is in scope where it
** is used.)
*/ */
static void trynewtbcupval (lua_State *L, void *ud) { #define MAXDELTA \
newupval(L, 1, cast(StkId, ud), &L->openupval); ((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1)
}
/* /*
** Create a to-be-closed upvalue. If there is a memory error ** Insert a variable in the list of to-be-closed variables.
** when creating the upvalue, the closing method must be called here,
** as there is no upvalue to call it later.
*/ */
void luaF_newtbcupval (lua_State *L, StkId level) { void luaF_newtbcupval (lua_State *L, StkId level) {
TValue *obj = s2v(level); lua_assert(level > L->tbclist);
lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); if (l_isfalse(s2v(level)))
if (!l_isfalse(obj)) { /* false doesn't need to be closed */ return; /* false doesn't need to be closed */
int status; checkclosemth(L, level); /* value must have a close method */
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); while (cast_uint(level - L->tbclist) > MAXDELTA) {
if (ttisnil(tm)) /* no metamethod? */ L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */
varerror(L, level, "variable '%s' got a non-closable value"); L->tbclist->tbclist.delta = 0;
status = luaD_rawrunprotected(L, trynewtbcupval, level);
if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */
lua_assert(status == LUA_ERRMEM);
luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */
/* next call must succeed, as object is closable */
prepclosingmethod(L, s2v(level), s2v(level + 1));
callclose(L, NULL); /* call closing method */
luaD_throw(L, LUA_ERRMEM); /* throw memory error */
}
} }
level->tbclist.delta = cast(unsigned short, level - L->tbclist);
L->tbclist = level;
} }
@ -220,18 +188,16 @@ void luaF_unlinkupval (UpVal *uv) {
} }
int luaF_close (lua_State *L, StkId level, int status) { /*
** Close all upvalues up to the given stack level.
*/
void luaF_closeupval (lua_State *L, StkId level) {
UpVal *uv; UpVal *uv;
while ((uv = L->openupval) != NULL && uplevel(uv) >= level) { StkId upl; /* stack index pointed by 'uv' */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
TValue *slot = &uv->u.value; /* new position for value */ TValue *slot = &uv->u.value; /* new position for value */
lua_assert(uplevel(uv) < L->top); lua_assert(uplevel(uv) < L->top);
if (uv->tbc && status != NOCLOSINGMETH) { luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
/* must run closing method, which may change the stack */
ptrdiff_t levelrel = savestack(L, level);
status = callclosemth(L, uplevel(uv), status);
level = restorestack(L, levelrel);
}
luaF_unlinkupval(uv);
setobj(L, slot, uv->v); /* move value to upvalue slot */ setobj(L, slot, uv->v); /* move value to upvalue slot */
uv->v = slot; /* now current value lives here */ uv->v = slot; /* now current value lives here */
if (!iswhite(uv)) { /* neither white nor dead? */ if (!iswhite(uv)) { /* neither white nor dead? */
@ -239,7 +205,35 @@ int luaF_close (lua_State *L, StkId level, int status) {
luaC_barrier(L, uv, slot); luaC_barrier(L, uv, slot);
} }
} }
return status; }
/*
** 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
** level.
*/
void luaF_close (lua_State *L, StkId level, int status, int yy) {
ptrdiff_t levelrel = savestack(L, level);
luaF_closeupval(L, level); /* first, close the upvalues */
while (L->tbclist >= level) { /* traverse tbc's down to that level */
StkId tbc = L->tbclist; /* get variable index */
poptbclist(L); /* remove it from list */
prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel);
}
} }

View file

@ -42,15 +42,9 @@
#define MAXMISS 10 #define MAXMISS 10
/*
** Special "status" for 'luaF_close'
*/
/* close upvalues without running their closing methods */ /* special status to close upvalues preserving the top of the stack */
#define NOCLOSINGMETH (-1) #define CLOSEKTOP (-1)
/* close upvalues running all closing methods in protected mode */
#define CLOSEPROTECT (-2)
LUAI_FUNC Proto *luaF_newproto (lua_State *L); LUAI_FUNC Proto *luaF_newproto (lua_State *L);
@ -59,7 +53,8 @@ LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nupvals);
LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
LUAI_FUNC int luaF_close (lua_State *L, StkId level, int status); LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv); LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,

View file

@ -916,7 +916,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 */
} }
@ -1575,52 +1575,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

@ -52,12 +52,6 @@ static int l_checkmode (const char *mode) {
** ======================================================= ** =======================================================
*/ */
#if !defined(l_checkmodep)
/* By default, Lua accepts only "r" or "w" as mode */
#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0')
#endif
#if !defined(l_popen) /* { */ #if !defined(l_popen) /* { */
#if defined(LUA_USE_POSIX) /* { */ #if defined(LUA_USE_POSIX) /* { */
@ -70,6 +64,12 @@ static int l_checkmode (const char *mode) {
#define l_popen(L,c,m) (_popen(c,m)) #define l_popen(L,c,m) (_popen(c,m))
#define l_pclose(L,file) (_pclose(file)) #define l_pclose(L,file) (_pclose(file))
#if !defined(l_checkmodep)
/* Windows accepts "[rw][bt]?" as valid modes */
#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && \
(m[1] == '\0' || ((m[1] == 'b' || m[1] == 't') && m[2] == '\0')))
#endif
#else /* }{ */ #else /* }{ */
/* ISO C definitions */ /* ISO C definitions */
@ -83,6 +83,12 @@ static int l_checkmode (const char *mode) {
#endif /* } */ #endif /* } */
#if !defined(l_checkmodep)
/* By default, Lua accepts only "r" or "w" as valid modes */
#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0')
#endif
/* }====================================================== */ /* }====================================================== */
@ -180,7 +186,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;
@ -255,7 +261,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));
} }
@ -303,7 +309,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;
} }
@ -430,7 +436,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 */
} }
@ -493,8 +499,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 */
@ -670,7 +676,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);
} }
@ -697,7 +704,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

@ -122,26 +122,29 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
/* /*
** creates a new string and anchors it in scanner's table so that ** Creates a new string and anchors it in scanner's table so that it
** it will not be collected until the end of the compilation ** will not be collected until the end of the compilation; by that time
** (by that time it should be anchored somewhere) ** it should be anchored somewhere. It also internalizes long strings,
** ensuring there is only one copy of each unique string. The table
** here is used as a set: the string enters as the key, while its value
** is irrelevant. We use the string itself as the value only because it
** is a TValue readly available. Later, the code generation can change
** this value.
*/ */
TString *luaX_newstring (LexState *ls, const char *str, size_t l) { TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
lua_State *L = ls->L; lua_State *L = ls->L;
TValue *o; /* entry for 'str' */
TString *ts = luaS_newlstr(L, str, l); /* create new string */ TString *ts = luaS_newlstr(L, str, l); /* create new string */
setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ const TValue *o = luaH_getstr(ls->h, ts);
o = luaH_set(L, ls->h, s2v(L->top - 1)); if (!ttisnil(o)) /* string already present? */
if (isempty(o)) { /* not in use yet? */ ts = keystrval(nodefromval(o)); /* get saved copy */
/* boolean value does not need GC barrier; else { /* not in use yet */
table is not a metatable, so it does not need to invalidate cache */ TValue *stv = s2v(L->top++); /* reserve stack space for string */
setbtvalue(o); /* t[string] = true */ setsvalue(L, stv, ts); /* temporarily anchor the string */
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
/* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L); luaC_checkGC(L);
}
else { /* string already present */
ts = keystrval(nodefromval(o)); /* re-use value previously stored */
}
L->top--; /* remove string from stack */ L->top--; /* remove string from stack */
}
return ts; return ts;
} }

View file

@ -149,22 +149,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

@ -73,7 +73,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);
@ -175,7 +175,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

@ -24,12 +24,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 (ttisnil(&g->nilvalue) && 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);
@ -83,7 +83,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 */
} }
@ -138,15 +138,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 (ttisnil(&g->nilvalue)) { /* 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 */
} }
@ -156,16 +158,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' */
@ -179,7 +178,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;
} }
@ -191,7 +190,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

@ -132,14 +132,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;
} }
@ -410,7 +412,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);
@ -523,14 +525,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 */
} }
@ -623,13 +625,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

@ -136,10 +136,19 @@ typedef struct TValue {
/* /*
** Entries in the Lua stack ** Entries in a Lua stack. Field 'tbclist' forms a list of all
** to-be-closed variables active in this stack. Dummy entries are
** used when the distance between two tbc variables does not fit
** 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 {
TValuefields;
unsigned short delta;
} tbclist;
} StackValue; } StackValue;
@ -570,10 +579,11 @@ typedef struct Proto {
#define LUA_VCCL makevariant(LUA_TFUNCTION, 2) /* C closure */ #define LUA_VCCL makevariant(LUA_TFUNCTION, 2) /* C closure */
#define ttisfunction(o) checktype(o, LUA_TFUNCTION) #define ttisfunction(o) checktype(o, LUA_TFUNCTION)
#define ttisclosure(o) ((rawtt(o) & 0x1F) == LUA_VLCL)
#define ttisLclosure(o) checktag((o), ctb(LUA_VLCL)) #define ttisLclosure(o) checktag((o), ctb(LUA_VLCL))
#define ttislcf(o) checktag((o), LUA_VLCF) #define ttislcf(o) checktag((o), LUA_VLCF)
#define ttisCclosure(o) checktag((o), ctb(LUA_VCCL)) #define ttisCclosure(o) checktag((o), ctb(LUA_VCCL))
#define ttisclosure(o) (ttisLclosure(o) || ttisCclosure(o))
#define isLfunction(o) ttisLclosure(o) #define isLfunction(o) ttisLclosure(o)

View file

@ -225,13 +225,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

@ -170,7 +170,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;
@ -208,7 +208,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);
@ -253,9 +253,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

@ -128,7 +128,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 {
@ -222,26 +222,26 @@ static Vardesc *getlocalvardesc (FuncState *fs, int vidx) {
/* /*
** Convert 'nvar', a compiler index level, to it corresponding ** Convert 'nvar', a compiler index level, to its corresponding
** stack index level. For that, search for the highest variable ** register. For that, search for the highest variable below that level
** below that level that is in the stack and uses its stack ** that is in a register and uses its register index ('ridx') plus one.
** index ('sidx').
*/ */
static int stacklevel (FuncState *fs, int nvar) { static int reglevel (FuncState *fs, int nvar) {
while (nvar-- > 0) { while (nvar-- > 0) {
Vardesc *vd = getlocalvardesc(fs, nvar); /* get variable */ Vardesc *vd = getlocalvardesc(fs, nvar); /* get previous variable */
if (vd->vd.kind != RDKCTC) /* is in the stack? */ if (vd->vd.kind != RDKCTC) /* is in a register? */
return vd->vd.sidx + 1; return vd->vd.ridx + 1;
} }
return 0; /* no variables in the stack */ return 0; /* no variables in registers */
} }
/* /*
** Return the number of variables in the stack for function 'fs' ** Return the number of variables in the register stack for the given
** function.
*/ */
int luaY_nvarstack (FuncState *fs) { int luaY_nvarstack (FuncState *fs) {
return stacklevel(fs, fs->nactvar); return reglevel(fs, fs->nactvar);
} }
@ -267,7 +267,7 @@ static void init_var (FuncState *fs, expdesc *e, int vidx) {
e->f = e->t = NO_JUMP; e->f = e->t = NO_JUMP;
e->k = VLOCAL; e->k = VLOCAL;
e->u.var.vidx = vidx; e->u.var.vidx = vidx;
e->u.var.sidx = getlocalvardesc(fs, vidx)->vd.sidx; e->u.var.ridx = getlocalvardesc(fs, vidx)->vd.ridx;
} }
@ -310,12 +310,12 @@ static void check_readonly (LexState *ls, expdesc *e) {
*/ */
static void adjustlocalvars (LexState *ls, int nvars) { static void adjustlocalvars (LexState *ls, int nvars) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
int stklevel = luaY_nvarstack(fs); int reglevel = luaY_nvarstack(fs);
int i; int i;
for (i = 0; i < nvars; i++) { for (i = 0; i < nvars; i++) {
int vidx = fs->nactvar++; int vidx = fs->nactvar++;
Vardesc *var = getlocalvardesc(fs, vidx); Vardesc *var = getlocalvardesc(fs, vidx);
var->vd.sidx = stklevel++; var->vd.ridx = reglevel++;
var->vd.pidx = registerlocalvar(ls, fs, var->vd.name); var->vd.pidx = registerlocalvar(ls, fs, var->vd.name);
} }
} }
@ -366,7 +366,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
FuncState *prev = fs->prev; FuncState *prev = fs->prev;
if (v->k == VLOCAL) { if (v->k == VLOCAL) {
up->instack = 1; up->instack = 1;
up->idx = v->u.var.sidx; up->idx = v->u.var.ridx;
up->kind = getlocalvardesc(prev, v->u.var.vidx)->vd.kind; up->kind = getlocalvardesc(prev, v->u.var.vidx)->vd.kind;
lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->vd.name)); lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->vd.name));
} }
@ -517,7 +517,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 */
@ -620,7 +620,7 @@ static void movegotosout (FuncState *fs, BlockCnt *bl) {
for (i = bl->firstgoto; i < gl->n; i++) { /* for each pending goto */ for (i = bl->firstgoto; i < gl->n; i++) { /* for each pending goto */
Labeldesc *gt = &gl->arr[i]; Labeldesc *gt = &gl->arr[i];
/* leaving a variable scope? */ /* leaving a variable scope? */
if (stacklevel(fs, gt->nactvar) > stacklevel(fs, bl->nactvar)) if (reglevel(fs, gt->nactvar) > reglevel(fs, bl->nactvar))
gt->close |= bl->upval; /* jump may need a close */ gt->close |= bl->upval; /* jump may need a close */
gt->nactvar = bl->nactvar; /* update goto level */ gt->nactvar = bl->nactvar; /* update goto level */
} }
@ -661,7 +661,7 @@ static void leaveblock (FuncState *fs) {
BlockCnt *bl = fs->bl; BlockCnt *bl = fs->bl;
LexState *ls = fs->ls; LexState *ls = fs->ls;
int hasclose = 0; int hasclose = 0;
int stklevel = stacklevel(fs, bl->nactvar); /* level outside the block */ int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
if (bl->isloop) /* fix pending breaks? */ if (bl->isloop) /* fix pending breaks? */
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0); hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
if (!hasclose && bl->previous && bl->upval) if (!hasclose && bl->previous && bl->upval)
@ -1330,13 +1330,13 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
} }
} }
else { /* table is a register */ else { /* table is a register */
if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.sidx) { if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.ridx) {
conflict = 1; /* table is the local being assigned now */ conflict = 1; /* table is the local being assigned now */
lh->v.u.ind.t = extra; /* assignment will use safe copy */ lh->v.u.ind.t = extra; /* assignment will use safe copy */
} }
/* is index the local being assigned? */ /* is index the local being assigned? */
if (lh->v.k == VINDEXED && v->k == VLOCAL && if (lh->v.k == VINDEXED && v->k == VLOCAL &&
lh->v.u.ind.idx == v->u.var.sidx) { lh->v.u.ind.idx == v->u.var.ridx) {
conflict = 1; conflict = 1;
lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */
} }
@ -1346,7 +1346,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) {
if (conflict) { if (conflict) {
/* copy upvalue/local value to a temporary (in position 'extra') */ /* copy upvalue/local value to a temporary (in position 'extra') */
if (v->k == VLOCAL) if (v->k == VLOCAL)
luaK_codeABC(fs, OP_MOVE, extra, v->u.var.sidx, 0); luaK_codeABC(fs, OP_MOVE, extra, v->u.var.ridx, 0);
else else
luaK_codeABC(fs, OP_GETUPVAL, extra, v->u.info, 0); luaK_codeABC(fs, OP_GETUPVAL, extra, v->u.info, 0);
luaK_reserveregs(fs, 1); luaK_reserveregs(fs, 1);
@ -1411,7 +1411,7 @@ static void gotostat (LexState *ls) {
newgotoentry(ls, name, line, luaK_jump(fs)); newgotoentry(ls, name, line, luaK_jump(fs));
else { /* found a label */ else { /* found a label */
/* backward jump; will be resolved here */ /* backward jump; will be resolved here */
int lblevel = stacklevel(fs, lb->nactvar); /* label level */ int lblevel = reglevel(fs, lb->nactvar); /* label level */
if (luaY_nvarstack(fs) > lblevel) /* leaving the scope of a variable? */ if (luaY_nvarstack(fs) > lblevel) /* leaving the scope of a variable? */
luaK_codeABC(fs, OP_CLOSE, lblevel, 0, 0); luaK_codeABC(fs, OP_CLOSE, lblevel, 0, 0);
/* create jump and link it to the label */ /* create jump and link it to the label */
@ -1435,7 +1435,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 */
@ -1488,7 +1488,7 @@ static void repeatstat (LexState *ls, int line) {
if (bl2.upval) { /* upvalues? */ if (bl2.upval) { /* upvalues? */
int exit = luaK_jump(fs); /* normal exit must jump over fix */ int exit = luaK_jump(fs); /* normal exit must jump over fix */
luaK_patchtohere(fs, condexit); /* repetition must close upvalues */ luaK_patchtohere(fs, condexit); /* repetition must close upvalues */
luaK_codeABC(fs, OP_CLOSE, stacklevel(fs, bl2.nactvar), 0, 0); luaK_codeABC(fs, OP_CLOSE, reglevel(fs, bl2.nactvar), 0, 0);
condexit = luaK_jump(fs); /* repeat after closing upvalues */ condexit = luaK_jump(fs); /* repeat after closing upvalues */
luaK_patchtohere(fs, exit); /* normal exit comes to here */ luaK_patchtohere(fs, exit); /* normal exit comes to here */
} }
@ -1520,7 +1520,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);
} }
@ -1708,7 +1708,7 @@ static void checktoclose (LexState *ls, int level) {
FuncState *fs = ls->fs; FuncState *fs = ls->fs;
markupval(fs, level + 1); markupval(fs, level + 1);
fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */
luaK_codeABC(fs, OP_TBC, stacklevel(fs, level), 0, 0); luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0);
} }
} }

View file

@ -35,7 +35,7 @@ typedef enum {
(string is fixed by the lexer) */ (string is fixed by the lexer) */
VNONRELOC, /* expression has its value in a fixed register; VNONRELOC, /* expression has its value in a fixed register;
info = result register */ info = result register */
VLOCAL, /* local variable; var.sidx = stack index (local register); VLOCAL, /* local variable; var.ridx = register index;
var.vidx = relative index in 'actvar.arr' */ var.vidx = relative index in 'actvar.arr' */
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
VCONST, /* compile-time <const> variable; VCONST, /* compile-time <const> variable;
@ -77,7 +77,7 @@ typedef struct expdesc {
lu_byte t; /* table (register or upvalue) */ lu_byte t; /* table (register or upvalue) */
} ind; } ind;
struct { /* for local variables */ struct { /* for local variables */
lu_byte sidx; /* index in the stack */ lu_byte ridx; /* register holding the variable */
unsigned short vidx; /* compiler index (in 'actvar.arr') */ unsigned short vidx; /* compiler index (in 'actvar.arr') */
} var; } var;
} u; } u;
@ -97,7 +97,7 @@ typedef union Vardesc {
struct { struct {
TValuefields; /* constant value (if it is a compile-time constant) */ TValuefields; /* constant value (if it is a compile-time constant) */
lu_byte kind; lu_byte kind;
lu_byte sidx; /* index of the variable in the stack */ lu_byte ridx; /* register holding the variable */
short pidx; /* index of the variable in the Proto's 'locvars' array */ short pidx; /* index of the variable in the Proto's 'locvars' array */
TString *name; /* variable name */ TString *name; /* variable name */
} vd; } vd;

View file

@ -172,7 +172,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);
} }
@ -181,6 +181,7 @@ static void stack_init (lua_State *L1, lua_State *L) {
int i; CallInfo *ci; int i; CallInfo *ci;
/* initialize stack array */ /* initialize stack array */
L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
L1->tbclist = L1->stack;
for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++)
setnilvalue(s2v(L1->stack + i)); /* erase new stack */ setnilvalue(s2v(L1->stack + i)); /* erase new stack */
L1->top = L1->stack; L1->top = L1->stack;
@ -213,24 +214,19 @@ static void freestack (lua_State *L) {
** Create registry table and its predefined values ** Create registry table and its predefined values
*/ */
static void init_registry (lua_State *L, global_State *g) { static void init_registry (lua_State *L, global_State *g) {
TValue temp;
/* create registry */ /* create registry */
Table *registry = luaH_new(L); Table *registry = luaH_new(L);
sethvalue(L, &g->l_registry, registry); sethvalue(L, &g->l_registry, registry);
luaH_resize(L, registry, LUA_RIDX_LAST, 0); luaH_resize(L, registry, LUA_RIDX_LAST, 0);
/* registry[LUA_RIDX_MAINTHREAD] = L */ /* registry[LUA_RIDX_MAINTHREAD] = L */
setthvalue(L, &temp, L); /* temp = L */ setthvalue(L, &registry->array[LUA_RIDX_MAINTHREAD - 1], L);
luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */
/* registry[LUA_RIDX_GLOBALS] = table of globals */ sethvalue(L, &registry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L));
sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */
luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp);
} }
/* /*
** open parts of the state that may cause memory-allocation errors. ** open parts of the state that may cause memory-allocation errors.
** ('g->nilvalue' being a nil value flags that the state was completely
** build.)
*/ */
static void f_luaopen (lua_State *L, void *ud) { static void f_luaopen (lua_State *L, void *ud) {
global_State *g = G(L); global_State *g = G(L);
@ -241,7 +237,7 @@ static void f_luaopen (lua_State *L, void *ud) {
luaT_init(L); luaT_init(L);
luaX_init(L); luaX_init(L);
g->gcrunning = 1; /* allow gc */ g->gcrunning = 1; /* allow gc */
setnilvalue(&g->nilvalue); setnilvalue(&g->nilvalue); /* now state is complete */
luai_userstateopen(L); luai_userstateopen(L);
} }
@ -256,6 +252,7 @@ static void preinit_thread (lua_State *L, global_State *g) {
L->ci = NULL; L->ci = NULL;
L->nci = 0; L->nci = 0;
L->twups = L; /* thread has no upvalues */ L->twups = L; /* thread has no upvalues */
L->nCcalls = 0;
L->errorJmp = NULL; L->errorJmp = NULL;
L->hook = NULL; L->hook = NULL;
L->hookmask = 0; L->hookmask = 0;
@ -271,10 +268,13 @@ static void preinit_thread (lua_State *L, global_State *g) {
static void close_state (lua_State *L) { static void close_state (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
luaF_close(L, L->stack, CLOSEPROTECT); /* close all upvalues */ if (!completestate(g)) /* closing a partially built state? */
luaC_freeallobjects(L); /* jucst collect its objects */
else { /* closing a fully built state */
luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */
luaC_freeallobjects(L); /* collect all objects */ luaC_freeallobjects(L); /* collect all objects */
if (ttisnil(&g->nilvalue)) /* closing a fully built state? */
luai_userstateclose(L); luai_userstateclose(L);
}
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
freestack(L); freestack(L);
lua_assert(gettotalbytes(g) == sizeof(LG)); lua_assert(gettotalbytes(g) == sizeof(LG));
@ -299,7 +299,6 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
setthvalue2s(L, L->top, L1); setthvalue2s(L, L->top, L1);
api_incr_top(L); api_incr_top(L);
preinit_thread(L1, g); preinit_thread(L1, g);
L1->nCcalls = 0;
L1->hookmask = L->hookmask; L1->hookmask = L->hookmask;
L1->basehookcount = L->basehookcount; L1->basehookcount = L->basehookcount;
L1->hook = L->hook; L1->hook = L->hook;
@ -316,7 +315,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
void luaE_freethread (lua_State *L, lua_State *L1) { void luaE_freethread (lua_State *L, lua_State *L1) {
LX *l = fromstate(L1); LX *l = fromstate(L1);
luaF_close(L1, L1->stack, NOCLOSINGMETH); /* close all upvalues */ luaF_closeupval(L1, L1->stack); /* close all upvalues */
lua_assert(L1->openupval == NULL); lua_assert(L1->openupval == NULL);
luai_userstatefree(L, L1); luai_userstatefree(L, L1);
freestack(L1); freestack(L1);
@ -324,23 +323,29 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
} }
int lua_resetthread (lua_State *L) { int luaE_resetthread (lua_State *L, int status) {
CallInfo *ci; CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
int status;
lua_lock(L);
L->ci = ci = &L->base_ci; /* unwind CallInfo list */
setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */ setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */
ci->func = L->stack; ci->func = L->stack;
ci->callstatus = CIST_C; ci->callstatus = CIST_C;
status = luaF_close(L, L->stack, CLOSEPROTECT); if (status == LUA_YIELD)
if (status != CLOSEPROTECT) /* real errors? */
luaD_seterrorobj(L, status, L->stack + 1);
else {
status = LUA_OK; status = LUA_OK;
status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */
luaD_seterrorobj(L, status, L->stack + 1);
else
L->top = L->stack + 1; L->top = L->stack + 1;
}
ci->top = L->top + LUA_MINSTACK; ci->top = L->top + LUA_MINSTACK;
L->status = status; L->status = cast_byte(status);
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0);
return status;
}
LUA_API int lua_resetthread (lua_State *L) {
int status;
lua_lock(L);
status = luaE_resetthread(L, L->status);
lua_unlock(L); lua_unlock(L);
return status; return status;
} }
@ -360,7 +365,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
preinit_thread(L, g); preinit_thread(L, g);
g->allgc = obj2gco(L); /* by now, only object is the main thread */ g->allgc = obj2gco(L); /* by now, only object is the main thread */
L->next = NULL; L->next = NULL;
L->nCcalls = 0;
incnny(L); /* main thread is always non yieldable */ incnny(L); /* main thread is always non yieldable */
g->frealloc = f; g->frealloc = f;
g->ud = ud; g->ud = ud;
@ -375,6 +379,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

@ -156,6 +156,18 @@ typedef struct stringtable {
/* /*
** Information about a call. ** Information about a call.
** About union 'u':
** - field 'l' is used only for Lua functions;
** - field 'c' is used only for C functions.
** About union 'u2':
** - field 'funcidx' is used only by C functions while doing a
** protected call;
** - field 'nyield' is used only while a function is "doing" an
** yield (from the yield until the next resume);
** - field 'nres' is used only while closing tbc variables when
** returning from a C function;
** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends.
*/ */
typedef struct CallInfo { typedef struct CallInfo {
StkId func; /* function index in the stack */ StkId func; /* function index in the stack */
@ -176,6 +188,7 @@ typedef struct CallInfo {
union { union {
int funcidx; /* called-function index */ int funcidx; /* called-function index */
int nyield; /* number of values yielded */ int nyield; /* number of values yielded */
int nres; /* number of values returned */
struct { /* info about transferred values (for call/return hooks) */ struct { /* info about transferred values (for call/return hooks) */
unsigned short ftransfer; /* offset of first value transferred */ unsigned short ftransfer; /* offset of first value transferred */
unsigned short ntransfer; /* number of values transferred */ unsigned short ntransfer; /* number of values transferred */
@ -193,15 +206,32 @@ typedef struct CallInfo {
#define CIST_C (1<<1) /* call is running a C function */ #define CIST_C (1<<1) /* call is running a C function */
#define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */ #define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */
#define CIST_HOOKED (1<<3) /* call is running a debug hook */ #define CIST_HOOKED (1<<3) /* call is running a debug hook */
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ #define CIST_YPCALL (1<<4) /* doing a yieldable protected call */
#define CIST_TAIL (1<<5) /* call was tail called */ #define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
#define CIST_FIN (1<<7) /* call is running a finalizer */ #define CIST_FIN (1<<7) /* call is running a finalizer */
#define CIST_TRAN (1<<8) /* 'ci' has transfer information */ #define CIST_TRAN (1<<8) /* 'ci' has transfer information */
#define CIST_CLSRET (1<<9) /* function is closing tbc variables */
/* Bits 10-12 are used for CIST_RECST (see below) */
#define CIST_RECST 10
#if defined(LUA_COMPAT_LT_LE) #if defined(LUA_COMPAT_LT_LE)
#define CIST_LEQ (1<<9) /* using __lt for __le */ #define CIST_LEQ (1<<13) /* using __lt for __le */
#endif #endif
/*
** Field CIST_RECST stores the "recover status", used to keep the error
** status while closing to-be-closed variables in coroutines, so that
** Lua can correctly resume after an yield from a __close method called
** because of an error. (Three bits are enough for error status.)
*/
#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7)
#define setcistrecst(ci,st) \
check_exp(((st) & 7) == (st), /* status must fit in three bits */ \
((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST)) \
| ((st) << CIST_RECST)))
/* active function is a Lua function */ /* active function is a Lua function */
#define isLua(ci) (!((ci)->callstatus & CIST_C)) #define isLua(ci) (!((ci)->callstatus & CIST_C))
@ -230,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 */
@ -281,6 +312,7 @@ struct lua_State {
StkId stack_last; /* end of stack (last element + 1) */ StkId stack_last; /* end of stack (last element + 1) */
StkId stack; /* stack base */ StkId stack; /* stack base */
UpVal *openupval; /* list of open upvalues in this stack */ UpVal *openupval; /* list of open upvalues in this stack */
StkId tbclist; /* list of to-be-closed variables */
GCObject *gclist; GCObject *gclist;
struct lua_State *twups; /* list of threads with open upvalues */ struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */ struct lua_longjmp *errorJmp; /* current error recover point */
@ -297,6 +329,12 @@ struct lua_State {
#define G(L) (L->l_G) #define G(L) (L->l_G)
/*
** 'g->nilvalue' being a nil value flags that the state was completely
** build.
*/
#define completestate(g) ttisnil(&g->nilvalue)
/* /*
** Union of all collectable objects (only for conversions) ** Union of all collectable objects (only for conversions)
@ -359,6 +397,7 @@ LUAI_FUNC void luaE_checkcstack (lua_State *L);
LUAI_FUNC void luaE_incCstack (lua_State *L); LUAI_FUNC void luaE_incCstack (lua_State *L);
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where); LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
LUAI_FUNC int luaE_resetthread (lua_State *L, int status);
#endif #endif

View file

@ -89,7 +89,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 */
@ -172,7 +172,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... */
@ -223,7 +223,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));
@ -259,7 +259,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

@ -152,8 +152,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;
@ -181,7 +182,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");
@ -235,7 +236,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;
@ -275,7 +276,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 */
@ -383,7 +385,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;
} }
@ -400,14 +403,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. '%]') */
@ -482,7 +485,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 {
@ -565,7 +568,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? */
@ -599,7 +602,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);
@ -699,7 +702,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;
@ -707,7 +710,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);
@ -926,7 +929,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 {
@ -1058,7 +1061,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;
} }
@ -1358,16 +1361,6 @@ struct cD {
#define MAXALIGN (offsetof(struct cD, u)) #define MAXALIGN (offsetof(struct cD, u))
/*
** Union for serializing floats
*/
typedef union Ftypes {
float f;
double d;
lua_Number n;
} Ftypes;
/* /*
** information to pack/unpack stuff ** information to pack/unpack stuff
*/ */
@ -1384,7 +1377,9 @@ typedef struct Header {
typedef enum KOption { typedef enum KOption {
Kint, /* signed integers */ Kint, /* signed integers */
Kuint, /* unsigned integers */ Kuint, /* unsigned integers */
Kfloat, /* floating-point numbers */ Kfloat, /* single-precision floating-point numbers */
Knumber, /* Lua "native" floating-point numbers */
Kdouble, /* double-precision floating-point numbers */
Kchar, /* fixed-length strings */ Kchar, /* fixed-length strings */
Kstring, /* strings with prefixed length */ Kstring, /* strings with prefixed length */
Kzstr, /* zero-terminated strings */ Kzstr, /* zero-terminated strings */
@ -1419,7 +1414,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;
@ -1453,14 +1448,14 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
case 'J': *size = sizeof(lua_Integer); return Kuint; case 'J': *size = sizeof(lua_Integer); return Kuint;
case 'T': *size = sizeof(size_t); return Kuint; case 'T': *size = sizeof(size_t); return Kuint;
case 'f': *size = sizeof(float); return Kfloat; case 'f': *size = sizeof(float); return Kfloat;
case 'd': *size = sizeof(double); return Kfloat; case 'n': *size = sizeof(lua_Number); return Knumber;
case 'n': *size = sizeof(lua_Number); return Kfloat; case 'd': *size = sizeof(double); return Kdouble;
case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint;
case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint;
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;
@ -1499,7 +1494,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);
} }
@ -1580,15 +1575,27 @@ static int str_pack (lua_State *L) {
packint(&b, (lua_Unsigned)n, h.islittle, size, 0); packint(&b, (lua_Unsigned)n, h.islittle, size, 0);
break; break;
} }
case Kfloat: { /* floating-point options */ case Kfloat: { /* C float */
Ftypes u; float f = (float)luaL_checknumber(L, arg); /* get argument */
char *buff = luaL_prepbuffsize(&b, size); char *buff = luaL_prepbuffsize(&b, sizeof(f));
lua_Number n = luaL_checknumber(L, arg); /* get argument */ /* move 'f' to final result, correcting endianness if needed */
if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
else if (size == sizeof(u.d)) u.d = (double)n; luaL_addsize(&b, size);
else u.n = n; break;
/* move 'u' to final result, correcting endianness if needed */ }
copywithendian(buff, (char *)&u, size, h.islittle); case Knumber: { /* Lua float */
lua_Number f = luaL_checknumber(L, arg); /* get argument */
char *buff = luaL_prepbuffsize(&b, sizeof(f));
/* move 'f' to final result, correcting endianness if needed */
copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
luaL_addsize(&b, size);
break;
}
case Kdouble: { /* C double */
double f = (double)luaL_checknumber(L, arg); /* get argument */
char *buff = luaL_prepbuffsize(&b, sizeof(f));
/* move 'f' to final result, correcting endianness if needed */
copywithendian(buff, (char *)&f, sizeof(f), h.islittle);
luaL_addsize(&b, size); luaL_addsize(&b, size);
break; break;
} }
@ -1679,7 +1686,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);
} }
} }
@ -1714,13 +1721,21 @@ static int str_unpack (lua_State *L) {
break; break;
} }
case Kfloat: { case Kfloat: {
Ftypes u; float f;
lua_Number num; copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
copywithendian((char *)&u, data + pos, size, h.islittle); lua_pushnumber(L, (lua_Number)f);
if (size == sizeof(u.f)) num = (lua_Number)u.f; break;
else if (size == sizeof(u.d)) num = (lua_Number)u.d; }
else num = u.n; case Knumber: {
lua_pushnumber(L, num); lua_Number f;
copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
lua_pushnumber(L, f);
break;
}
case Kdouble: {
double f;
copywithendian((char *)&f, data + pos, sizeof(f), h.islittle);
lua_pushnumber(L, (lua_Number)f);
break; break;
} }
case Kchar: { case Kchar: {

View file

@ -68,20 +68,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))
@ -135,24 +140,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);
}
} }
} }
@ -307,7 +326,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 */
@ -485,7 +504,7 @@ static void reinsert (lua_State *L, Table *ot, Table *t) {
already present in the table */ already present in the table */
TValue k; TValue k;
getnodekey(L, &k, old); getnodekey(L, &k, old);
setobjt2t(L, luaH_set(L, t, &k), gval(old)); luaH_set(L, t, &k, gval(old));
} }
} }
} }
@ -541,7 +560,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) */
} }
@ -632,10 +651,10 @@ static Node *getfreepos (Table *t) {
** put new key in its main position; otherwise (colliding node is in its main ** put new key in its main position; otherwise (colliding node is in its main
** position), new key goes to an empty position. ** position), new key goes to an empty position.
*/ */
TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { 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);
@ -644,9 +663,11 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
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))
return; /* do not insert nil values */
mp = mainpositionTV(t, key); mp = mainpositionTV(t, key);
if (!isempty(gval(mp)) || isdummy(t)) { /* main position is taken? */ if (!isempty(gval(mp)) || isdummy(t)) { /* main position is taken? */
Node *othern; Node *othern;
@ -654,7 +675,8 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
if (f == NULL) { /* cannot find a free place? */ if (f == NULL) { /* cannot find a free place? */
rehash(L, t, key); /* grow table */ rehash(L, t, key); /* grow table */
/* whatever called 'newkey' takes care of TM cache */ /* whatever called 'newkey' takes care of TM cache */
return luaH_set(L, t, key); /* insert key into grown table */ luaH_set(L, t, key, value); /* insert key into grown table */
return;
} }
lua_assert(!isdummy(t)); lua_assert(!isdummy(t));
othern = mainposition(t, keytt(mp), &keyval(mp)); othern = mainposition(t, keytt(mp), &keyval(mp));
@ -682,7 +704,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
setnodekey(L, mp, key); setnodekey(L, mp, key);
luaC_barrierback(L, obj2gco(t), key); luaC_barrierback(L, obj2gco(t), key);
lua_assert(isempty(gval(mp))); lua_assert(isempty(gval(mp)));
return gval(mp); setobj2t(L, gval(mp), value);
} }
@ -769,29 +791,40 @@ const TValue *luaH_get (Table *t, const TValue *key) {
} }
/*
** Finish a raw "set table" operation, where 'slot' is where the value
** should have been (the result of a previous "get table").
** Beware: when using this function you probably need to check a GC
** barrier and invalidate the TM cache.
*/
void luaH_finishset (lua_State *L, Table *t, const TValue *key,
const TValue *slot, TValue *value) {
if (isabstkey(slot))
luaH_newkey(L, t, key, value);
else
setobj2t(L, cast(TValue *, slot), value);
}
/* /*
** beware: when using this function you probably need to check a GC ** beware: when using this function you probably need to check a GC
** barrier and invalidate the TM cache. ** barrier and invalidate the TM cache.
*/ */
TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) {
const TValue *p = luaH_get(t, key); const TValue *slot = luaH_get(t, key);
if (!isabstkey(p)) luaH_finishset(L, t, key, slot, value);
return cast(TValue *, p);
else return luaH_newkey(L, t, key);
} }
void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) {
const TValue *p = luaH_getint(t, key); const TValue *p = luaH_getint(t, key);
TValue *cell; if (isabstkey(p)) {
if (!isabstkey(p))
cell = cast(TValue *, p);
else {
TValue k; TValue k;
setivalue(&k, key); setivalue(&k, key);
cell = luaH_newkey(L, t, &k); luaH_newkey(L, t, &k, value);
} }
setobj2t(L, cell, value); else
setobj2t(L, cast(TValue *, p), value);
} }

View file

@ -41,8 +41,12 @@ LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key); LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key,
LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); TValue *value);
LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key,
TValue *value);
LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key,
const TValue *slot, TValue *value);
LUAI_FUNC Table *luaH_new (lua_State *L); LUAI_FUNC Table *luaH_new (lua_State *L);
LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
unsigned int nhsize); unsigned int nhsize);

View file

@ -145,8 +145,8 @@ 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 %d 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);
} }
@ -196,7 +196,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);
@ -300,14 +301,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

@ -147,7 +147,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: {
@ -166,7 +166,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

@ -18,14 +18,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"
@ -348,6 +348,7 @@ LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
LUA_API void (lua_toclose) (lua_State *L, int idx); LUA_API void (lua_toclose) (lua_State *L, int idx);
LUA_API void (lua_closeslot) (lua_State *L, int idx);
/* /*
@ -491,7 +492,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

@ -16,13 +16,13 @@
** =================================================================== ** ===================================================================
** General Configuration File for Lua ** General Configuration File for Lua
** **
** Some definitions here can be changed externally, through the ** Some definitions here can be changed externally, through the compiler
** compiler (e.g., with '-D' options). Those are protected by ** (e.g., with '-D' options): They are commented out or protected
** '#if !defined' guards. However, several other definitions should ** by '#if !defined' guards. However, several other definitions
** be changed directly here, either because they affect the Lua ** should be changed directly here, either because they affect the
** ABI (by making the changes here, you ensure that all software ** Lua ABI (by making the changes here, you ensure that all software
** connected to Lua, such as C libraries, will be compiled with the ** connected to Lua, such as C libraries, will be compiled with the same
** same configuration); or because they are seldom changed. ** configuration); or because they are seldom changed.
** **
** Search for "@@" to find all configurable definitions. ** Search for "@@" to find all configurable definitions.
** =================================================================== ** ===================================================================
@ -81,26 +81,12 @@
/* /*
** {================================================================== ** {==================================================================
** Configuration for Number types. ** Configuration for Number types. These options should not be
** set externally, because any other code connected to Lua must
** use the same configuration.
** =================================================================== ** ===================================================================
*/ */
/*
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
*/
/* #define LUA_32BITS */
/*
@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
** C89 ('long' and 'double'); Windows always has '__int64', so it does
** not need to use this case.
*/
#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
#define LUA_C89_NUMBERS
#endif
/* /*
@@ LUA_INT_TYPE defines the type for Lua integers. @@ LUA_INT_TYPE defines the type for Lua integers.
@@ LUA_FLOAT_TYPE defines the type for Lua floats. @@ LUA_FLOAT_TYPE defines the type for Lua floats.
@ -121,7 +107,31 @@
#define LUA_FLOAT_DOUBLE 2 #define LUA_FLOAT_DOUBLE 2
#define LUA_FLOAT_LONGDOUBLE 3 #define LUA_FLOAT_LONGDOUBLE 3
#if defined(LUA_32BITS) /* { */
/* Default configuration ('long long' and 'double', for 64-bit Lua) */
#define LUA_INT_DEFAULT LUA_INT_LONGLONG
#define LUA_FLOAT_DEFAULT LUA_FLOAT_DOUBLE
/*
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats.
*/
#define LUA_32BITS 0
/*
@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
** C89 ('long' and 'double'); Windows always has '__int64', so it does
** not need to use this case.
*/
#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
#define LUA_C89_NUMBERS 1
#else
#define LUA_C89_NUMBERS 0
#endif
#if LUA_32BITS /* { */
/* /*
** 32-bit integers and 'float' ** 32-bit integers and 'float'
*/ */
@ -132,27 +142,22 @@
#endif #endif
#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT #define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
#elif defined(LUA_C89_NUMBERS) /* }{ */ #elif LUA_C89_NUMBERS /* }{ */
/* /*
** largest types available for C89 ('long' and 'double') ** largest types available for C89 ('long' and 'double')
*/ */
#define LUA_INT_TYPE LUA_INT_LONG #define LUA_INT_TYPE LUA_INT_LONG
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE #define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
#else /* }{ */
/* use defaults */
#define LUA_INT_TYPE LUA_INT_DEFAULT
#define LUA_FLOAT_TYPE LUA_FLOAT_DEFAULT
#endif /* } */ #endif /* } */
/*
** default configuration for 64-bit Lua ('long long' and 'double')
*/
#if !defined(LUA_INT_TYPE)
#define LUA_INT_TYPE LUA_INT_LONGLONG
#endif
#if !defined(LUA_FLOAT_TYPE)
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
#endif
/* }================================================================== */ /* }================================================================== */
@ -373,14 +378,13 @@
/* /*
** {================================================================== ** {==================================================================
** Configuration for Numbers. ** Configuration for Numbers (low-level part).
** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* ** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
** satisfy your needs. ** satisfy your needs.
** =================================================================== ** ===================================================================
*/ */
/* /*
@@ LUA_NUMBER is the floating-point type used by Lua.
@@ LUAI_UACNUMBER is the result of a 'default argument promotion' @@ LUAI_UACNUMBER is the result of a 'default argument promotion'
@@ over a floating number. @@ over a floating number.
@@ l_floatatt(x) corrects float attribute 'x' to the proper float type @@ l_floatatt(x) corrects float attribute 'x' to the proper float type
@ -473,10 +477,7 @@
/* /*
@@ LUA_INTEGER is the integer type used by Lua.
**
@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. @@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
**
@@ LUAI_UACINT is the result of a 'default argument promotion' @@ LUAI_UACINT is the result of a 'default argument promotion'
@@ over a LUA_INTEGER. @@ over a LUA_INTEGER.
@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers. @@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
@ -659,6 +660,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
/* }================================================================== */ /* }================================================================== */

View file

@ -49,10 +49,4 @@ LUAMOD_API int (luaopen_package) (lua_State *L);
LUALIB_API void (luaL_openlibs) (lua_State *L); LUALIB_API void (luaL_openlibs) (lua_State *L);
#if !defined(lua_assert)
#define lua_assert(x) ((void)0)
#endif
#endif #endif

View file

@ -235,11 +235,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");
@ -292,7 +292,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 */
} }
@ -337,10 +337,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
lua_assert(isempty(slot)); /* slot must be empty */ lua_assert(isempty(slot)); /* slot must be empty */
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
if (tm == NULL) { /* no metamethod? */ if (tm == NULL) { /* no metamethod? */
if (isabstkey(slot)) /* no previous entry? */ luaH_finishset(L, h, key, slot, val); /* set new value */
slot = luaH_newkey(L, h, key); /* create one */
/* no metamethod and (now) there is an entry with given key */
setobj2t(L, cast(TValue *, slot), val); /* set its new value */
invalidateTMcache(h); invalidateTMcache(h);
luaC_barrierback(L, obj2gco(h), val); luaC_barrierback(L, obj2gco(h), val);
return; return;
@ -349,7 +346,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 */
@ -571,8 +568,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 */
@ -654,7 +656,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;
} }
@ -698,7 +700,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;
} }
@ -714,7 +716,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 */
@ -734,7 +736,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 */
@ -845,6 +847,10 @@ void luaV_finishOp (lua_State *L) {
luaV_concat(L, total); /* concat them (may yield again) */ luaV_concat(L, total); /* concat them (may yield again) */
break; break;
} }
case OP_CLOSE: case OP_RETURN: { /* yielded closing variables */
ci->u.l.savedpc--; /* repeat instruction to close other vars. */
break;
}
default: { default: {
/* only these other opcodes can yield */ /* only these other opcodes can yield */
lua_assert(op == OP_TFORCALL || op == OP_CALL || lua_assert(op == OP_TFORCALL || op == OP_CALL ||
@ -920,7 +926,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); }
@ -949,7 +955,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); }
@ -1048,7 +1054,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); } }
/* /*
@ -1106,7 +1113,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 */ \
} \ } \
@ -1134,7 +1141,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 */
@ -1149,6 +1156,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
Instruction i; /* instruction being executed */ Instruction i; /* instruction being executed */
StkId ra; /* instruction's A register */ StkId ra; /* instruction's A register */
vmfetch(); vmfetch();
// low-level line tracing for debugging Lua
// printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
lua_assert(base == ci->func + 1); lua_assert(base == ci->func + 1);
lua_assert(base <= L->top && L->top < L->stack_last); lua_assert(base <= L->top && L->top < L->stack_last);
/* invalidate top for instructions not expecting it */ /* invalidate top for instructions not expecting it */
@ -1527,7 +1536,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_CLOSE) { vmcase(OP_CLOSE) {
Protect(luaF_close(L, ra, LUA_OK)); Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak; vmbreak;
} }
vmcase(OP_TBC) { vmcase(OP_TBC) {
@ -1632,10 +1641,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
b = cast_int(L->top - ra); b = cast_int(L->top - ra);
savepc(ci); /* several calls here can raise errors */ savepc(ci); /* several calls here can raise errors */
if (TESTARG_k(i)) { if (TESTARG_k(i)) {
/* close upvalues from current call; the compiler ensures luaF_closeupval(L, base); /* close upvalues from current call */
that there are no to-be-closed variables here, so this lua_assert(L->tbclist < base); /* no pending tbc variables */
call cannot change the stack */
luaF_close(L, base, NOCLOSINGMETH);
lua_assert(base == ci->func + 1); lua_assert(base == ci->func + 1);
} }
while (!ttisfunction(s2v(ra))) { /* not a function? */ while (!ttisfunction(s2v(ra))) { /* not a function? */
@ -1665,7 +1672,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
if (TESTARG_k(i)) { /* may there be open upvalues? */ if (TESTARG_k(i)) { /* may there be open upvalues? */
if (L->top < ci->top) if (L->top < ci->top)
L->top = ci->top; L->top = ci->top;
luaF_close(L, base, LUA_OK); luaF_close(L, base, CLOSEKTOP, 1);
updatetrap(ci); updatetrap(ci);
updatestack(ci); updatestack(ci);
} }
@ -1677,23 +1684,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... */
@ -1707,8 +1714,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 */
@ -1811,7 +1818,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))