Bring Lua to 5.4.5.

This commit is contained in:
Michael Lenaghan 2023-07-28 17:11:35 -04:00
parent f6d65c0263
commit a0e095873c
81 changed files with 1584 additions and 1038 deletions

View file

@ -9,14 +9,14 @@ PROVENANCE
https://github.com/lua/lua/ https://github.com/lua/lua/
commit 5d708c3f9cae12820e415d4f89c9eacbe2ab964b commit e15f1f2bb7a38a3c94519294d031e48508d65006
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br> Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Jan 13, 2022 at 6:15 AM EST Date: Apr 18, 2023 at 8:44 AM EDT
New release number (5.4.4) New release number (5.4.5)
luac.c needed to be sourced from: luac.c needed to be sourced from:
https://www.lua.org/ftp/lua-5.4.4.tar.gz https://www.lua.org/ftp/lua-5.4.5.tar.gz
LOCAL MODIFICATIONS LOCAL MODIFICATIONS

250
third_party/lua/lapi.c vendored
View file

@ -47,7 +47,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -80,27 +80,28 @@ const char lua_ident[] =
static TValue *index2value (lua_State *L, int idx) { static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
StkId o = ci->func + idx; StkId o = ci->func.p + idx;
api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index"); api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
if (o >= L->top) return &G(L)->nilvalue; if (o >= L->top.p) return &G(L)->nilvalue;
else return s2v(o); else return s2v(o);
} }
else if (!ispseudo(idx)) { /* negative index */ else if (!ispseudo(idx)) { /* negative index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
return s2v(L->top + idx); "invalid index");
return s2v(L->top.p + idx);
} }
else if (idx == LUA_REGISTRYINDEX) else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry; return &G(L)->l_registry;
else { /* upvalues */ else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx; idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
if (ttisCclosure(s2v(ci->func))) { /* C closure? */ if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */
CClosure *func = clCvalue(s2v(ci->func)); CClosure *func = clCvalue(s2v(ci->func.p));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1] return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue; : &G(L)->nilvalue;
} }
else { /* light C function or Lua function (through a hook)?) */ else { /* light C function or Lua function (through a hook)?) */
api_check(L, ttislcf(s2v(ci->func)), "caller not a C function"); api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function");
return &G(L)->nilvalue; /* no upvalues */ return &G(L)->nilvalue; /* no upvalues */
} }
} }
@ -114,14 +115,15 @@ static TValue *index2value (lua_State *L, int idx) {
l_sinline StkId index2stack (lua_State *L, int idx) { l_sinline StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
StkId o = ci->func + idx; StkId o = ci->func.p + idx;
api_check(L, o < L->top, "invalid index"); api_check(L, o < L->top.p, "invalid index");
return o; return o;
} }
else { /* non-positive index */ else { /* non-positive index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
"invalid index");
api_check(L, !ispseudo(idx), "invalid index"); api_check(L, !ispseudo(idx), "invalid index");
return L->top + idx; return L->top.p + idx;
} }
} }
@ -132,17 +134,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
lua_lock(L); lua_lock(L);
ci = L->ci; ci = L->ci;
api_check(L, n >= 0, "negative 'n'"); api_check(L, n >= 0, "negative 'n'");
if (L->stack_last - L->top > n) /* stack large enough? */ if (L->stack_last.p - L->top.p > n) /* stack large enough? */
res = 1; /* yes; check is OK */ res = 1; /* yes; check is OK */
else { /* no; need to grow stack */ else /* need to grow stack */
int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
res = 0; /* no */
else /* try to grow stack */
res = luaD_growstack(L, n, 0); res = luaD_growstack(L, n, 0);
} if (res && ci->top.p < L->top.p + n)
if (res && ci->top < L->top + n) ci->top.p = L->top.p + n; /* adjust frame top */
ci->top = L->top + n; /* adjust frame top */
lua_unlock(L); lua_unlock(L);
return res; return res;
} }
@ -159,11 +156,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to); lua_lock(to);
api_checknelems(from, n); api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states"); api_check(from, G(from) == G(to), "moving among independent states");
api_check(from, to->ci->top - to->top >= n, "stack overflow"); api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
from->top -= n; from->top.p -= n;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
setobjs2s(to, to->top, from->top + i); setobjs2s(to, to->top.p, from->top.p + i);
to->top++; /* stack already checked by previous 'api_check' */ to->top.p++; /* stack already checked by previous 'api_check' */
} }
lua_unlock(to); lua_unlock(to);
} }
@ -216,7 +213,7 @@ LUA_API lua_Number lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) { LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx)) return (idx > 0 || ispseudo(idx))
? idx ? idx
: cast_int(L->top - L->ci->func) + idx; : cast_int(L->top.p - L->ci->func.p) + idx;
} }
/** /**
@ -227,7 +224,7 @@ LUA_API int lua_absindex (lua_State *L, int idx) {
* particular, 0 means an empty stack. * particular, 0 means an empty stack.
*/ */
LUA_API int lua_gettop (lua_State *L) { LUA_API int lua_gettop (lua_State *L) {
return cast_int(L->top - (L->ci->func + 1)); return cast_int(L->top.p - (L->ci->func.p + 1));
} }
/** /**
@ -246,24 +243,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
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;
func = ci->func; func = ci->func.p;
if (idx >= 0) { if (idx >= 0) {
api_check(L, idx <= ci->top - (func + 1), "new top too large"); api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
diff = ((func + 1) + idx) - L->top; diff = ((func + 1) + idx) - L->top.p;
for (; diff > 0; diff--) for (; diff > 0; diff--)
setnilvalue(s2v(L->top++)); /* clear new slots */ setnilvalue(s2v(L->top.p++)); /* clear new slots */
} }
else { else {
api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); api_check(L, -(idx+1) <= (L->top.p - (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) */
} }
api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot"); api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
newtop = L->top + diff; newtop = L->top.p + diff;
if (diff < 0 && L->tbclist >= newtop) { if (diff < 0 && L->tbclist.p >= newtop) {
lua_assert(hastocloseCfunc(ci->nresults)); lua_assert(hastocloseCfunc(ci->nresults));
luaF_close(L, newtop, CLOSEKTOP, 0); newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
} }
L->top = newtop; /* correct top only after closing any upvalue */ L->top.p = newtop; /* correct top only after closing any upvalue */
lua_unlock(L); lua_unlock(L);
} }
@ -272,10 +269,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
StkId level; StkId level;
lua_lock(L); lua_lock(L);
level = index2stack(L, idx); level = index2stack(L, idx);
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level, api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
"no variable to close at given level"); "no variable to close at given level");
luaF_close(L, level, CLOSEKTOP, 0); level = luaF_close(L, level, CLOSEKTOP, 0);
level = index2stack(L, idx); /* stack may be moved */
setnilvalue(s2v(level)); setnilvalue(s2v(level));
lua_unlock(L); lua_unlock(L);
} }
@ -304,7 +300,7 @@ l_sinline void reverse (lua_State *L, StkId from, StkId to) {
LUA_API void lua_rotate (lua_State *L, int idx, int n) { LUA_API void lua_rotate (lua_State *L, int idx, int n) {
StkId p, t, m; StkId p, t, m;
lua_lock(L); lua_lock(L);
t = L->top - 1; /* end of stack segment being rotated */ t = L->top.p - 1; /* end of stack segment being rotated */
p = index2stack(L, idx); /* start of segment */ p = index2stack(L, idx); /* start of segment */
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
@ -323,7 +319,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
api_check(L, isvalid(L, to), "invalid index"); api_check(L, isvalid(L, to), "invalid index");
setobj(L, to, fr); setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */ if (isupvalue(toidx)) /* function upvalue? */
luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr); luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr);
/* LUA_REGISTRYINDEX does not need gc barrier /* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */ (collector revisits it before finishing collection) */
lua_unlock(L); lua_unlock(L);
@ -332,7 +328,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
setobj2s(L, L->top, index2value(L, idx)); setobj2s(L, L->top.p, index2value(L, idx));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -401,12 +397,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
api_checknelems(L, 2); /* all other operations expect two operands */ api_checknelems(L, 2); /* all other operations expect two operands */
else { /* for unary operations, add fake 2nd operand */ else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1); api_checknelems(L, 1);
setobjs2s(L, L->top, L->top - 1); setobjs2s(L, L->top.p, L->top.p - 1);
api_incr_top(L); api_incr_top(L);
} }
/* first operand at top - 2, second at top - 1; result go to top - 2 */ /* first operand at top - 2, second at top - 1; result go to top - 2 */
luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2); luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
L->top--; /* remove second operand */ L->top.p--; /* remove second operand */
lua_unlock(L); lua_unlock(L);
} }
@ -432,7 +428,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
size_t sz = luaO_str2num(s, s2v(L->top)); size_t sz = luaO_str2num(s, s2v(L->top.p));
if (sz != 0) if (sz != 0)
api_incr_top(L); api_incr_top(L);
return sz; return sz;
@ -589,7 +585,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
*/ */
LUA_API void lua_pushnil (lua_State *L) { LUA_API void lua_pushnil (lua_State *L) {
lua_lock(L); lua_lock(L);
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -602,7 +598,7 @@ LUA_API void lua_pushnil (lua_State *L) {
*/ */
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L); lua_lock(L);
setfltvalue(s2v(L->top), n); setfltvalue(s2v(L->top.p), n);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -617,7 +613,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
*/ */
LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
lua_lock(L); lua_lock(L);
setivalue(s2v(L->top), n); setivalue(s2v(L->top.p), n);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -632,7 +628,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts; TString *ts;
lua_lock(L); lua_lock(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top.p, ts);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
@ -654,11 +650,11 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
LUA_API const char *lua_pushstring (lua_State *L, const char *s) { LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_lock(L); lua_lock(L);
if (s == NULL) if (s == NULL)
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
else { else {
TString *ts; TString *ts;
ts = luaS_new(L, s); ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top.p, ts);
s = getstr(ts); /* internal copy's address */ s = getstr(ts); /* internal copy's address */
} }
api_incr_top(L); api_incr_top(L);
@ -746,7 +742,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L); lua_lock(L);
if (n == 0) { if (n == 0) {
setfvalue(s2v(L->top), fn); setfvalue(s2v(L->top.p), fn);
api_incr_top(L); api_incr_top(L);
} }
else { else {
@ -755,13 +751,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
api_check(L, n <= MAXUPVAL, "upvalue index too large"); api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n); cl = luaF_newCclosure(L, n);
cl->f = fn; cl->f = fn;
L->top -= n; L->top.p -= n;
while (n--) { while (n--) {
setobj2n(L, &cl->upvalue[n], s2v(L->top + n)); setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
/* does not need barrier because closure is white */ /* does not need barrier because closure is white */
lua_assert(iswhite(cl)); lua_assert(iswhite(cl));
} }
setclCvalue(L, s2v(L->top), cl); setclCvalue(L, s2v(L->top.p), cl);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
} }
@ -778,9 +774,9 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
lua_lock(L); lua_lock(L);
/* a.k.a. L->top->val.tt_ = b ? LUA_VTRUE : LUA_VFALSE; */ /* a.k.a. L->top->val.tt_ = b ? LUA_VTRUE : LUA_VFALSE; */
if (b) if (b)
setbtvalue(s2v(L->top)); setbtvalue(s2v(L->top.p));
else else
setbfvalue(s2v(L->top)); setbfvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -798,7 +794,7 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
*/ */
LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
lua_lock(L); lua_lock(L);
setpvalue(s2v(L->top), p); setpvalue(s2v(L->top.p), p);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -812,7 +808,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
*/ */
LUA_API int lua_pushthread (lua_State *L) { LUA_API int lua_pushthread (lua_State *L) {
lua_lock(L); lua_lock(L);
setthvalue(L, s2v(L->top), L); setthvalue(L, s2v(L->top.p), L);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return (G(L)->mainthread == L); return (G(L)->mainthread == L);
@ -829,16 +825,16 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot; const TValue *slot;
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, slot); setobj2s(L, L->top.p, slot);
api_incr_top(L); api_incr_top(L);
} }
else { else {
setsvalue2s(L, L->top, str); setsvalue2s(L, L->top.p, str);
api_incr_top(L); api_incr_top(L);
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot); luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
} }
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@ -865,13 +861,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
TValue *t; TValue *t;
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) { if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
setobj2s(L, L->top - 1, slot); setobj2s(L, L->top.p - 1, slot);
} }
else else
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot); luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@ -887,27 +883,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) { if (luaV_fastgeti(L, t, n, slot)) {
setobj2s(L, L->top, slot); setobj2s(L, L->top.p, slot);
} }
else { else {
TValue aux; TValue aux;
setivalue(&aux, n); setivalue(&aux, n);
luaV_finishget(L, t, &aux, L->top, slot); luaV_finishget(L, t, &aux, L->top.p, slot);
} }
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
l_sinline int finishrawget (lua_State *L, const TValue *val) { l_sinline int finishrawget (lua_State *L, const TValue *val) {
if (isempty(val)) /* avoid copying empty items to the stack */ if (isempty(val)) /* avoid copying empty items to the stack */
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
else else
setobj2s(L, L->top, val); setobj2s(L, L->top.p, val);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@ -930,8 +926,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
val = luaH_get(t, s2v(L->top - 1)); val = luaH_get(t, s2v(L->top.p - 1));
L->top--; /* remove key */ L->top.p--; /* remove key */
return finishrawget(L, val); return finishrawget(L, val);
} }
@ -978,7 +974,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t; Table *t;
lua_lock(L); lua_lock(L);
t = luaH_new(L); t = luaH_new(L);
sethvalue2s(L, L->top, t); sethvalue2s(L, L->top.p, t);
api_incr_top(L); api_incr_top(L);
if (narray > 0 || nrec > 0) if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec); luaH_resize(L, t, narray, nrec);
@ -1014,7 +1010,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
break; break;
} }
if (mt != NULL) { if (mt != NULL) {
sethvalue2s(L, L->top, mt); sethvalue2s(L, L->top.p, mt);
api_incr_top(L); api_incr_top(L);
res = 1; res = 1;
} }
@ -1041,12 +1037,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
o = index2value(L, idx); o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected"); api_check(L, ttisfulluserdata(o), "full userdata expected");
if (n <= 0 || n > uvalue(o)->nuvalue) { if (n <= 0 || n > uvalue(o)->nuvalue) {
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
t = LUA_TNONE; t = LUA_TNONE;
} }
else { else {
setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv); setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
t = ttype(s2v(L->top)); t = ttype(s2v(L->top.p));
} }
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
@ -1066,14 +1062,14 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
api_checknelems(L, 1); api_checknelems(L, 1);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
L->top--; /* pop value */ L->top.p--; /* pop value */
} }
else { else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */
api_incr_top(L); api_incr_top(L);
luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot); luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
L->top -= 2; /* pop value and key */ L->top.p -= 2; /* pop value and key */
} }
lua_unlock(L); /* lock done by caller */ lua_unlock(L); /* lock done by caller */
} }
@ -1093,12 +1089,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 2); api_checknelems(L, 2);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) { if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
} }
else else
luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot); luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
L->top -= 2; /* pop index and value */ L->top.p -= 2; /* pop index and value */
lua_unlock(L); lua_unlock(L);
} }
@ -1125,14 +1121,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1); api_checknelems(L, 1);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) { if (luaV_fastgeti(L, t, n, slot)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
} }
else { else {
TValue aux; TValue aux;
setivalue(&aux, n); setivalue(&aux, n);
luaV_finishset(L, t, &aux, s2v(L->top - 1), slot); luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
} }
L->top--; /* pop value */ L->top.p--; /* pop value */
lua_unlock(L); lua_unlock(L);
} }
@ -1142,10 +1138,10 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
lua_lock(L); lua_lock(L);
api_checknelems(L, n); api_checknelems(L, n);
t = gettable(L, idx); t = gettable(L, idx);
luaH_set(L, t, key, s2v(L->top - 1)); luaH_set(L, t, key, s2v(L->top.p - 1));
invalidateTMcache(t); invalidateTMcache(t);
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1)); luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top -= n; L->top.p -= n;
lua_unlock(L); lua_unlock(L);
} }
@ -1157,7 +1153,7 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
* metamethods). * metamethods).
*/ */
LUA_API void lua_rawset (lua_State *L, int idx) { LUA_API void lua_rawset (lua_State *L, int idx) {
aux_rawset(L, idx, s2v(L->top - 2), 2); aux_rawset(L, idx, s2v(L->top.p - 2), 2);
} }
@ -1192,9 +1188,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
luaH_setint(L, t, n, s2v(L->top - 1)); luaH_setint(L, t, n, s2v(L->top.p - 1));
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1)); luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
} }
@ -1214,11 +1210,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
obj = index2value(L, objindex); obj = index2value(L, objindex);
if (ttisnil(s2v(L->top - 1))) if (ttisnil(s2v(L->top.p - 1)))
mt = NULL; mt = NULL;
else { else {
api_check(L, ttistable(s2v(L->top - 1)), "table expected"); api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
mt = hvalue(s2v(L->top - 1)); mt = hvalue(s2v(L->top.p - 1));
} }
switch (ttype(obj)) { switch (ttype(obj)) {
case LUA_TTABLE: { case LUA_TTABLE: {
@ -1242,7 +1238,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
break; break;
} }
} }
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
return 1; return 1;
} }
@ -1265,11 +1261,11 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue))) if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */ res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
else { else {
setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1)); setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
luaC_barrierback(L, gcvalue(o), s2v(L->top - 1)); luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
res = 1; res = 1;
} }
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
return res; return res;
} }
@ -1281,7 +1277,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
#define checkresults(L,na,nr) \ #define checkresults(L,na,nr) \
api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ api_check(L, (nr) == LUA_MULTRET \
|| (L->ci->top.p - L->top.p >= (nr) - (na)), \
"results from function overflow current stack size") "results from function overflow current stack size")
@ -1294,7 +1291,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
api_checknelems(L, nargs+1); api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults); checkresults(L, nargs, nresults);
func = L->top - (nargs+1); func = L->top.p - (nargs+1);
if (k != NULL && yieldable(L)) { /* need to prepare continuation? */ if (k != NULL && yieldable(L)) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */ L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */ L->ci->u.c.ctx = ctx; /* save context */
@ -1342,7 +1339,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
api_check(L, ttisfunction(s2v(o)), "error handler must be a function"); api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
func = savestack(L, o); func = savestack(L, o);
} }
c.func = L->top - (nargs+1); /* function to be called */ c.func = L->top.p - (nargs+1); /* function to be called */
if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */ if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */ c.nresults = nresults; /* do a 'conventional' protected call */
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
@ -1377,12 +1374,12 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
luaZ_init(L, &z, reader, data); luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode); status = luaD_protectedparser(L, &z, chunkname, mode);
if (status == LUA_OK) { /* no errors? */ if (status == LUA_OK) { /* no errors? */
LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */ LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new 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 */
const TValue *gt = getGtable(L); const TValue *gt = getGtable(L);
/* 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.p, gt);
luaC_barrier(L, f->upvals[0], gt); luaC_barrier(L, f->upvals[0], gt);
} }
} }
@ -1396,7 +1393,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
TValue *o; TValue *o;
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
o = s2v(L->top - 1); o = s2v(L->top.p - 1);
if (isLfunction(o)) if (isLfunction(o))
status = luaU_dump(L, getproto(o), writer, data, strip); status = luaU_dump(L, getproto(o), writer, data, strip);
else else
@ -1529,7 +1526,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
LUA_API int lua_error (lua_State *L) { LUA_API int lua_error (lua_State *L) {
TValue *errobj; TValue *errobj;
lua_lock(L); lua_lock(L);
errobj = s2v(L->top - 1); errobj = s2v(L->top.p - 1);
api_checknelems(L, 1); api_checknelems(L, 1);
/* error object is the memory error message? */ /* error object is the memory error message? */
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg)) if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
@ -1576,12 +1573,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
more = luaH_next(L, t, L->top - 1); more = luaH_next(L, t, L->top.p - 1);
if (more) { if (more) {
api_incr_top(L); api_incr_top(L);
} }
else /* no more elements */ else /* no more elements */
L->top -= 1; /* remove key */ L->top.p -= 1; /* remove key */
lua_unlock(L); lua_unlock(L);
return more; return more;
} }
@ -1614,7 +1611,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->tbclist < o, "given index below or equal a marked one"); api_check(L, L->tbclist.p < o, "given index below or equal a marked 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 */
@ -1637,7 +1634,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
if (n > 0) if (n > 0)
luaV_concat(L, n); luaV_concat(L, n);
else { /* nothing to concatenate */ else { /* nothing to concatenate */
setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */ setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */
api_incr_top(L); api_incr_top(L);
} }
luaC_checkGC(L); luaC_checkGC(L);
@ -1656,7 +1653,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
TValue *t; TValue *t;
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
luaV_objlen(L, L->top, t); luaV_objlen(L, L->top.p, t);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -1743,7 +1740,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
lua_lock(L); lua_lock(L);
api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value"); api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
u = luaS_newudata(L, size, nuvalue); u = luaS_newudata(L, size, nuvalue);
setuvalue(L, s2v(L->top), u); setuvalue(L, s2v(L->top.p), u);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
@ -1751,6 +1748,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
} }
static const char *aux_upvalue (TValue *fi, int n, TValue **val, static const char *aux_upvalue (TValue *fi, int n, TValue **val,
GCObject **owner) { GCObject **owner) {
switch (ttypetag(fi)) { switch (ttypetag(fi)) {
@ -1768,7 +1766,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
Proto *p = f->p; Proto *p = f->p;
if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues))) if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
return NULL; /* 'n' not in [1, p->sizeupvalues] */ return NULL; /* 'n' not in [1, p->sizeupvalues] */
*val = f->upvals[n-1]->v; *val = f->upvals[n-1]->v.p;
if (owner) *owner = obj2gco(f->upvals[n - 1]); if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name; name = p->upvalues[n-1].name;
return (name == NULL) ? "(no name)" : getstr(name); return (name == NULL) ? "(no name)" : getstr(name);
@ -1794,7 +1792,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
lua_lock(L); lua_lock(L);
name = aux_upvalue(index2value(L, funcindex), n, &val, NULL); name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
if (name) { if (name) {
setobj2s(L, L->top, val); setobj2s(L, L->top.p, val);
api_incr_top(L); api_incr_top(L);
} }
lua_unlock(L); lua_unlock(L);
@ -1824,8 +1822,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
api_checknelems(L, 1); api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner); name = aux_upvalue(fi, n, &val, &owner);
if (name) { if (name) {
L->top--; L->top.p--;
setobj(L, val, s2v(L->top)); setobj(L, val, s2v(L->top.p));
luaC_barrier(L, owner, val); luaC_barrier(L, owner, val);
} }
lua_unlock(L); lua_unlock(L);

View file

@ -6,22 +6,25 @@
// clang-format off // clang-format off
/* Increments 'L->top', checking for stack overflows */ /* Increments 'L->top.p', checking for stack overflows */
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ #define api_incr_top(L) {L->top.p++; \
api_check(L, L->top.p <= L->ci->top.p, \
"stack overflow");} "stack overflow");}
/* /*
** If a call returns too many multiple returns, the callee may not have ** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro ** stack space to accommodate all results. In this case, this macro
** increases its stack space ('L->ci->top'). ** increases its stack space ('L->ci->top.p').
*/ */
#define adjustresults(L,nres) \ #define adjustresults(L,nres) \
{ if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
L->ci->top.p = L->top.p; }
/* Ensure the stack has at least 'n' elements */ /* Ensure the stack has at least 'n' elements */
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ #define api_checknelems(L,n) \
api_check(L, (n) < (L->top.p - L->ci->func.p), \
"not enough elements in the stack") "not enough elements in the stack")

View file

@ -39,7 +39,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -771,13 +771,14 @@ static void newbox (lua_State *L) {
/* /*
** Compute new size for buffer 'B', enough to accommodate extra 'sz' ** Compute new size for buffer 'B', enough to accommodate extra 'sz'
** bytes. ** bytes. (The test for "not big enough" also gets the case when the
** computation of 'newsize' overflows.)
*/ */
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) * 3; /* buffer size * 1.5 */
if (l_unlikely(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) /* not big enough? */
newsize = B->n + sz; newsize = B->n + sz;
return newsize; return newsize;
} }
@ -879,7 +880,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
** box (if existent) is not on the top of the stack. So, instead of ** box (if existent) is not on the top of the stack. So, instead of
** calling 'luaL_addlstring', it replicates the code using -2 as the ** calling 'luaL_addlstring', it replicates the code using -2 as the
** last argument to 'prepbuffsize', signaling that the box is (or will ** last argument to 'prepbuffsize', signaling that the box is (or will
** be) bellow the string being added to the buffer. (Box creation can ** be) below the string being added to the buffer. (Box creation can
** trigger an emergency GC, so we should not remove the string from the ** trigger an emergency GC, so we should not remove the string from the
** stack before we have the space guaranteed.) ** stack before we have the space guaranteed.)
*/ */
@ -1027,17 +1028,18 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
} }
static int skipBOM (LoadF *lf) { /*
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ ** Skip an optional BOM at the start of a stream. If there is an
int c; ** incomplete BOM (the first character is correct but the rest is
lf->n = 0; ** not), returns the first character anyway to force an error
do { ** (as no chunk can start with 0xEF).
c = getc(lf->f); */
if (c == EOF || c != *(const unsigned char *)p++) return c; static int skipBOM (FILE *f) {
lf->buff[lf->n++] = c; /* to be read by the parser */ int c = getc(f); /* read first character */
} while (*p != '\0'); if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
lf->n = 0; /* prefix matched; discard it */ return getc(f); /* ignore BOM and return next char */
return getc(lf->f); /* return next character */ else /* no (valid) BOM */
return c; /* return first character */
} }
@ -1048,13 +1050,13 @@ static int skipBOM (LoadF *lf) {
** first "valid" character of the file (after the optional BOM and ** first "valid" character of the file (after the optional BOM and
** a first-line comment). ** a first-line comment).
*/ */
static int skipcomment (LoadF *lf, int *cp) { static int skipcomment (FILE *f, int *cp) {
int c = *cp = skipBOM(lf); int c = *cp = skipBOM(f);
if (c == '#') { /* first line is a comment (Unix exec. file)? */ if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */ do { /* skip first line */
c = getc(lf->f); c = getc(f);
} while (c != EOF && c != '\n'); } while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */ *cp = getc(f); /* next character after comment, if present */
return 1; /* there was a comment */ return 1; /* there was a comment */
} }
else return 0; /* no comment */ else return 0; /* no comment */
@ -1091,12 +1093,16 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
lf.f = fopen(filename, "r"); lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex); if (lf.f == NULL) return errfile(L, "open", fnameindex);
} }
if (skipcomment(&lf, &c)) /* read initial portion */ lf.n = 0;
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ if (skipcomment(lf.f, &c)) /* read initial portion */
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
if (c == LUA_SIGNATURE[0]) { /* binary file? */
lf.n = 0; /* remove possible newline */
if (filename) { /* "real" file? */
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex); if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
skipcomment(&lf, &c); /* re-read initial portion */ skipcomment(lf.f, &c); /* re-read initial portion */
}
} }
if (c != EOF) if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */

View file

@ -37,7 +37,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");

View file

@ -47,7 +47,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -1372,6 +1372,35 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
} }
/*
** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) {
lua_assert(baser <= opr &&
((baser == OPR_ADD && opr <= OPR_SHR) ||
(baser == OPR_LT && opr <= OPR_LE)));
return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base));
}
/*
** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode unopr2op (UnOpr opr) {
return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) +
cast_int(OP_UNM));
}
/*
** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM)
*/
l_sinline TMS binopr2TM (BinOpr opr) {
lua_assert(OPR_ADD <= opr && opr <= OPR_SHR);
return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD));
}
/* /*
** Emit code for unary expressions that "produce values" ** Emit code for unary expressions that "produce values"
** (everything but 'not'). ** (everything but 'not').
@ -1410,12 +1439,15 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
** Emit code for binary expressions that "produce values" over ** Emit code for binary expressions that "produce values" over
** two registers. ** two registers.
*/ */
static void codebinexpval (FuncState *fs, OpCode op, static void codebinexpval (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) { expdesc *e1, expdesc *e2, int line) {
int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */ OpCode op = binopr2op(opr, OPR_ADD, OP_ADD);
int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */
/* 'e1' must be already in a register or it is a constant */
lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
e1->k == VNONRELOC || e1->k == VRELOC);
lua_assert(OP_ADD <= op && op <= OP_SHR); lua_assert(OP_ADD <= op && op <= OP_SHR);
finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr));
cast(TMS, (op - OP_ADD) + TM_ADD));
} }
@ -1431,6 +1463,18 @@ static void codebini (FuncState *fs, OpCode op,
} }
/*
** Code binary operators with K operand.
*/
static void codebinK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = binopr2TM(opr);
int v2 = e2->u.info; /* K index */
OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK);
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
}
/* Try to code a binary operator negating its second operand. /* Try to code a binary operator negating its second operand.
** For the metamethod, 2nd operand must keep its original value. ** For the metamethod, 2nd operand must keep its original value.
*/ */
@ -1458,24 +1502,27 @@ static void swapexps (expdesc *e1, expdesc *e2) {
} }
/*
** Code binary operators with no constant operand.
*/
static void codebinNoK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
if (flip)
swapexps(e1, e2); /* back to original order */
codebinexpval(fs, opr, e1, e2, line); /* use standard operators */
}
/* /*
** Code arithmetic operators ('+', '-', ...). If second operand is a ** Code arithmetic operators ('+', '-', ...). If second operand is a
** constant in the proper range, use variant opcodes with K operands. ** constant in the proper range, use variant opcodes with K operands.
*/ */
static void codearith (FuncState *fs, BinOpr opr, static void codearith (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) { expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = cast(TMS, opr + TM_ADD); if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */
if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */ codebinK(fs, opr, e1, e2, flip, line);
int v2 = e2->u.info; /* K index */ else /* 'e2' is neither an immediate nor a K operand */
OpCode op = cast(OpCode, opr + OP_ADDK); codebinNoK(fs, opr, e1, e2, flip, line);
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
}
else { /* 'e2' is neither an immediate nor a K operand */
OpCode op = cast(OpCode, opr + OP_ADD);
if (flip)
swapexps(e1, e2); /* back to original order */
codebinexpval(fs, op, e1, e2, line); /* use standard operators */
}
} }
@ -1492,35 +1539,27 @@ static void codecommutative (FuncState *fs, BinOpr op,
flip = 1; flip = 1;
} }
if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */ if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */
codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD); codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD);
else else
codearith(fs, op, e1, e2, flip, line); codearith(fs, op, e1, e2, flip, line);
} }
/* /*
** Code bitwise operations; they are all associative, so the function ** Code bitwise operations; they are all commutative, so the function
** tries to put an integer constant as the 2nd operand (a K operand). ** tries to put an integer constant as the 2nd operand (a K operand).
*/ */
static void codebitwise (FuncState *fs, BinOpr opr, static void codebitwise (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) { expdesc *e1, expdesc *e2, int line) {
int flip = 0; int flip = 0;
int v2; if (e1->k == VKINT) {
OpCode op;
if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
swapexps(e1, e2); /* 'e2' will be the constant operand */ swapexps(e1, e2); /* 'e2' will be the constant operand */
flip = 1; flip = 1;
} }
else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */ if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */
op = cast(OpCode, opr + OP_ADD); codebinK(fs, opr, e1, e2, flip, line);
codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */ else /* no constants */
return; codebinNoK(fs, opr, e1, e2, flip, line);
}
v2 = e2->u.info; /* index in K array */
op = cast(OpCode, opr + OP_ADDK);
lua_assert(ttisinteger(&fs->f->k[v2]));
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
cast(TMS, opr + TM_ADD));
} }
@ -1528,25 +1567,27 @@ static void codebitwise (FuncState *fs, BinOpr opr,
** Emit code for order comparisons. When using an immediate operand, ** Emit code for order comparisons. When using an immediate operand,
** 'isfloat' tells whether the original value was a float. ** 'isfloat' tells whether the original value was a float.
*/ */
static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int r1, r2; int r1, r2;
int im; int im;
int isfloat = 0; int isfloat = 0;
OpCode op;
if (isSCnumber(e2, &im, &isfloat)) { if (isSCnumber(e2, &im, &isfloat)) {
/* use immediate operand */ /* use immediate operand */
r1 = luaK_exp2anyreg(fs, e1); r1 = luaK_exp2anyreg(fs, e1);
r2 = im; r2 = im;
op = cast(OpCode, (op - OP_LT) + OP_LTI); op = binopr2op(opr, OPR_LT, OP_LTI);
} }
else if (isSCnumber(e1, &im, &isfloat)) { else if (isSCnumber(e1, &im, &isfloat)) {
/* transform (A < B) to (B > A) and (A <= B) to (B >= A) */ /* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
r1 = luaK_exp2anyreg(fs, e2); r1 = luaK_exp2anyreg(fs, e2);
r2 = im; r2 = im;
op = (op == OP_LT) ? OP_GTI : OP_GEI; op = binopr2op(opr, OPR_LT, OP_GTI);
} }
else { /* regular case, compare two registers */ else { /* regular case, compare two registers */
r1 = luaK_exp2anyreg(fs, e1); r1 = luaK_exp2anyreg(fs, e1);
r2 = luaK_exp2anyreg(fs, e2); r2 = luaK_exp2anyreg(fs, e2);
op = binopr2op(opr, OPR_LT, OP_LT);
} }
freeexps(fs, e1, e2); freeexps(fs, e1, e2);
e1->u.info = condjump(fs, op, r1, r2, isfloat, 1); e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
@ -1572,7 +1613,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
op = OP_EQI; op = OP_EQI;
r2 = im; /* immediate operand */ r2 = im; /* immediate operand */
} }
else if (luaK_exp2RK(fs, e2)) { /* 1st expression is constant? */ else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */
op = OP_EQK; op = OP_EQK;
r2 = e2->u.info; /* constant index */ r2 = e2->u.info; /* constant index */
} }
@ -1589,16 +1630,16 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
/* /*
** Apply prefix operation 'op' to expression 'e'. ** Apply prefix operation 'op' to expression 'e'.
*/ */
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) {
static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
luaK_dischargevars(fs, e); luaK_dischargevars(fs, e);
switch (op) { switch (opr) {
case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
if (constfolding(fs, op + LUA_OPUNM, e, &ef)) if (constfolding(fs, opr + LUA_OPUNM, e, &ef))
break; break;
/* else */ /* FALLTHROUGH */ /* else */ /* FALLTHROUGH */
case OPR_LEN: case OPR_LEN:
codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); codeunexpval(fs, unopr2op(opr), e, line);
break; break;
case OPR_NOT: codenot(fs, e); break; case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0); default: lua_assert(0);
@ -1632,7 +1673,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_SHL: case OPR_SHR: { case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL)) if (!tonumeral(v, NULL))
luaK_exp2anyreg(fs, v); luaK_exp2anyreg(fs, v);
/* else keep numeral, which may be folded with 2nd operand */ /* else keep numeral, which may be folded or used as an immediate
operand */
break; break;
} }
case OPR_EQ: case OPR_NE: { case OPR_EQ: case OPR_NE: {
@ -1727,30 +1769,27 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
/* coded as (r1 >> -I) */; /* coded as (r1 >> -I) */;
} }
else /* regular case (two registers) */ else /* regular case (two registers) */
codebinexpval(fs, OP_SHL, e1, e2, line); codebinexpval(fs, opr, e1, e2, line);
break; break;
} }
case OPR_SHR: { case OPR_SHR: {
if (isSCint(e2)) if (isSCint(e2))
codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */ codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */
else /* regular case (two registers) */ else /* regular case (two registers) */
codebinexpval(fs, OP_SHR, e1, e2, line); codebinexpval(fs, opr, e1, e2, line);
break; break;
} }
case OPR_EQ: case OPR_NE: { case OPR_EQ: case OPR_NE: {
codeeq(fs, opr, e1, e2); codeeq(fs, opr, e1, e2);
break; break;
} }
case OPR_LT: case OPR_LE: {
OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
codeorder(fs, op, e1, e2);
break;
}
case OPR_GT: case OPR_GE: { case OPR_GT: case OPR_GE: {
/* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */ /* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */
OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
swapexps(e1, e2); swapexps(e1, e2);
codeorder(fs, op, e1, e2); opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT);
} /* FALLTHROUGH */
case OPR_LT: case OPR_LE: {
codeorder(fs, opr, e1, e2);
break; break;
} }
default: lua_assert(0); default: lua_assert(0);

View file

@ -36,7 +36,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -99,7 +99,7 @@ static int luaB_auxwrap (lua_State *L) {
if (l_unlikely(r < 0)) { /* error? */ if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co); int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
stat = lua_resetthread(co); /* close its tbc variables */ stat = lua_resetthread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK); lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* move error message to the caller */ lua_xmove(co, L, 1); /* move error message to the caller */
} }
@ -195,7 +195,7 @@ static int luaB_close (lua_State *L) {
int status = auxstatus(L, co); int status = auxstatus(L, co);
switch (status) { switch (status) {
case COS_DEAD: case COS_YIELD: { case COS_DEAD: case COS_YIELD: {
status = lua_resetthread(co); status = lua_resetthread(co, L);
if (status == LUA_OK) { if (status == LUA_OK) {
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
return 1; return 1;

View file

@ -37,7 +37,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -502,3 +502,4 @@ LUAMOD_API int luaopen_debug (lua_State *L) {
luaL_newlib(L, dblib); luaL_newlib(L, dblib);
return 1; return 1;
} }

View file

@ -47,7 +47,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -203,10 +203,10 @@ static const char *upvalname (const Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) { static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
if (clLvalue(s2v(ci->func))->p->is_vararg) { if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
int nextra = ci->u.l.nextraargs; int nextra = ci->u.l.nextraargs;
if (n >= -nextra) { /* 'n' is negative */ if (n >= -nextra) { /* 'n' is negative */
*pos = ci->func - nextra - (n + 1); *pos = ci->func.p - nextra - (n + 1);
return "(vararg)"; /* generic name for any vararg */ return "(vararg)"; /* generic name for any vararg */
} }
} }
@ -215,7 +215,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
StkId base = ci->func + 1; StkId base = ci->func.p + 1;
const char *name = NULL; const char *name = NULL;
if (isLua(ci)) { if (isLua(ci)) {
if (n < 0) /* access to vararg values? */ if (n < 0) /* access to vararg values? */
@ -224,7 +224,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
} }
if (name == NULL) { /* no 'standard' name? */ if (name == NULL) { /* no 'standard' name? */
StkId limit = (ci == L->ci) ? L->top : ci->next->func; StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */ if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
/* generic name for any valid slot */ /* generic name for any valid slot */
name = isLua(ci) ? "(temporary)" : "(C temporary)"; name = isLua(ci) ? "(temporary)" : "(C temporary)";
@ -242,16 +242,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name; const char *name;
lua_lock(L); lua_lock(L);
if (ar == NULL) { /* information about non-active function? */ if (ar == NULL) { /* information about non-active function? */
if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */ if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
name = NULL; name = NULL;
else /* consider live variables at function start (parameters) */ else /* consider live variables at function start (parameters) */
name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0); name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
} }
else { /* active function; get information through 'ar' */ else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */ StkId pos = NULL; /* to avoid warnings */
name = luaG_findlocal(L, ar->i_ci, n, &pos); name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) { if (name) {
setobjs2s(L, L->top, pos); setobjs2s(L, L->top.p, pos);
api_incr_top(L); api_incr_top(L);
} }
} }
@ -266,8 +266,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
lua_lock(L); lua_lock(L);
name = luaG_findlocal(L, ar->i_ci, n, &pos); name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) { if (name) {
setobjs2s(L, pos, L->top - 1); setobjs2s(L, pos, L->top.p - 1);
L->top--; /* pop value */ L->top.p--; /* pop value */
} }
lua_unlock(L); lua_unlock(L);
return name; return name;
@ -310,7 +310,7 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) { static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) { if (noLuaClosure(f)) {
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
} }
else { else {
@ -319,7 +319,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
const Proto *p = f->l.p; const Proto *p = f->l.p;
int currentline = p->linedefined; int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */ Table *t = luaH_new(L); /* new table to store active lines */
sethvalue2s(L, L->top, t); /* push it on stack */ sethvalue2s(L, L->top.p, 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 */
if (!p->is_vararg) /* regular function? */ if (!p->is_vararg) /* regular function? */
@ -409,20 +409,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
lua_lock(L); lua_lock(L);
if (*what == '>') { if (*what == '>') {
ci = NULL; ci = NULL;
func = s2v(L->top - 1); func = s2v(L->top.p - 1);
api_check(L, ttisfunction(func), "function expected"); api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */ what++; /* skip the '>' */
L->top--; /* pop function */ L->top.p--; /* pop function */
} }
else { else {
ci = ar->i_ci; ci = ar->i_ci;
func = s2v(ci->func); func = s2v(ci->func.p);
lua_assert(ttisfunction(func)); lua_assert(ttisfunction(func));
} }
cl = ttisclosure(func) ? clvalue(func) : NULL; cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci); status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) { if (strchr(what, 'f')) {
setobj2s(L, L->top, func); setobj2s(L, L->top.p, func);
api_incr_top(L); api_incr_top(L);
} }
if (strchr(what, 'L')) if (strchr(what, 'L'))
@ -677,18 +677,19 @@ static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
/* /*
** Check whether pointer 'o' points to some value in the stack ** Check whether pointer 'o' points to some value in the stack frame of
** frame of the current function. Because 'o' may not point to a ** the current function and, if so, returns its index. Because 'o' may
** value in this stack, we cannot compare it with the region ** not point to a value in this stack, we cannot compare it with the
** boundaries (undefined behaviour in ISO C). ** region boundaries (undefined behavior in ISO C).
*/ */
static int isinstack (CallInfo *ci, const TValue *o) { static int instack (CallInfo *ci, const TValue *o) {
StkId pos; int pos;
for (pos = ci->func + 1; pos < ci->top; pos++) { StkId base = ci->func.p + 1;
if (o == s2v(pos)) for (pos = 0; base + pos < ci->top.p; pos++) {
return 1; if (o == s2v(base + pos))
return pos;
} }
return 0; /* not found */ return -1; /* not found */
} }
@ -702,7 +703,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
LClosure *c = ci_func(ci); LClosure *c = ci_func(ci);
int i; int i;
for (i = 0; i < c->nupvalues; i++) { for (i = 0; i < c->nupvalues; i++) {
if (c->upvals[i]->v == o) { if (c->upvals[i]->v.p == o) {
*name = upvalname(c->p, i); *name = upvalname(c->p, i);
return "upvalue"; return "upvalue";
} }
@ -729,9 +730,11 @@ static const char *varinfo (lua_State *L, const TValue *o) {
const char *kind = NULL; const char *kind = NULL;
if (isLua(ci)) { if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
if (!kind && isinstack(ci, o)) /* no? try a register */ if (!kind) { /* not an upvalue? */
kind = getobjname(ci_func(ci)->p, currentpc(ci), int reg = instack(ci, o); /* try a register */
cast_int(cast(StkId, o) - (ci->func + 1)), &name); if (reg >= 0) /* is 'o' a register? */
kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
}
} }
return formatvarinfo(L, kind, name); return formatvarinfo(L, kind, name);
} }
@ -828,10 +831,10 @@ l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */ if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc); StkId errfunc = restorestack(L, L->errfunc);
lua_assert(ttisfunction(s2v(errfunc))); lua_assert(ttisfunction(s2v(errfunc)));
setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */ setobjs2s(L, L->top.p - 1, errfunc); /* push function */
L->top++; /* assume EXTRA_STACK */ L->top.p++; /* assume EXTRA_STACK */
luaD_callnoyield(L, L->top - 2, 1); /* call it */ luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
} }
luaD_throw(L, LUA_ERRRUN); luaD_throw(L, LUA_ERRRUN);
} }
@ -845,8 +848,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_start(argp, fmt); va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */ msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp); va_end(argp);
if (isLua(ci)) /* if Lua function, add source:line information */ if (isLua(ci)) { /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci)); luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
L->top.p--;
}
luaG_errormsg(L); luaG_errormsg(L);
} }
@ -863,7 +869,7 @@ 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;
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */ if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
int delta = 0; /* line diference */ int delta = 0; /* line difference */
int pc = oldpc; int pc = oldpc;
for (;;) { for (;;) {
int lineinfo = p->lineinfo[++pc]; int lineinfo = p->lineinfo[++pc];
@ -890,7 +896,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc' ** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** at most causes an extra call to a line hook.) ** at most causes an extra call to a line hook.)
** This function is not "Protected" when called, so it should correct ** This function is not "Protected" when called, so it should correct
** 'L->top' before calling anything that can run the GC. ** 'L->top.p' 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;
@ -913,7 +919,7 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
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))) /* top not being used? */ if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
L->top = ci->top; /* correct top */ L->top.p = ci->top.p; /* 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) {

View file

@ -9,7 +9,7 @@
/* Active Lua function (given call info) */ /* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue(s2v((ci)->func))) #define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define resethookcount(L) (L->hookcount = L->basehookcount) #define resethookcount(L) (L->hookcount = L->basehookcount)

223
third_party/lua/ldo.c vendored
View file

@ -56,7 +56,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -130,11 +130,11 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
} }
default: { default: {
lua_assert(errorstatus(errcode)); /* real error */ lua_assert(errorstatus(errcode)); /* real error */
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */
break; break;
} }
} }
L->top = oldtop + 1; L->top.p = oldtop + 1;
} }
@ -147,7 +147,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
global_State *g = G(L); global_State *g = G(L);
errcode = luaE_resetthread(L, errcode); /* close all upvalues */ errcode = luaE_resetthread(L, errcode); /* close all upvalues */
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.p++, L->top.p - 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 */
@ -184,16 +184,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
** Stack reallocation ** Stack reallocation
** =================================================================== ** ===================================================================
*/ */
static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/*
** Change all pointers to the stack into offsets.
*/
static void relstack (lua_State *L) {
CallInfo *ci; CallInfo *ci;
UpVal *up; UpVal *up;
L->top = (L->top - oldstack) + newstack; L->top.offset = savestack(L, L->top.p);
L->tbclist = (L->tbclist - oldstack) + newstack; L->tbclist.offset = savestack(L, L->tbclist.p);
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.offset = savestack(L, uplevel(up));
for (ci = L->ci; ci != NULL; ci = ci->previous) { for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top = (ci->top - oldstack) + newstack; ci->top.offset = savestack(L, ci->top.p);
ci->func = (ci->func - oldstack) + newstack; ci->func.offset = savestack(L, ci->func.p);
}
}
/*
** Change back all offsets into pointers.
*/
static void correctstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
L->top.p = restorestack(L, L->top.offset);
L->tbclist.p = restorestack(L, L->tbclist.offset);
for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v.p = s2v(restorestack(L, up->v.offset));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top.p = restorestack(L, ci->top.offset);
ci->func.p = restorestack(L, ci->func.offset);
if (isLua(ci)) if (isLua(ci))
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */ ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
} }
@ -203,44 +225,45 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/* some space for error handling */ /* some space for error handling */
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
/* /*
** Reallocate the stack to a new size, correcting all pointers into ** Reallocate the stack to a new size, correcting all pointers into it.
** it. (There are pointers to a stack from its upvalues, from its list ** In ISO C, any pointer use after the pointer has been deallocated is
** of call infos, plus a few individual pointers.) The reallocation is ** undefined behavior. So, before the reallocation, all pointers are
** done in two steps (allocation + free) because the correction must be ** changed to offsets, and after the reallocation they are changed back
** done while both addresses (the old stack and the new one) are valid. ** to pointers. As during the reallocation the pointers are invalid, the
** (In ISO C, any pointer use after the pointer has been deallocated is ** reallocation cannot run emergency collections.
** undefined behavior.) **
** In case of allocation error, raise an error or return false according ** In case of allocation error, raise an error or return false according
** to 'raiseerror'. ** to 'raiseerror'.
*/ */
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int oldsize = stacksize(L); int oldsize = stacksize(L);
int i; int i;
StkId newstack = luaM_reallocvector(L, NULL, 0, StkId newstack;
newsize + EXTRA_STACK, StackValue); int oldgcstop = G(L)->gcstopem;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
relstack(L); /* change pointers to offsets */
G(L)->gcstopem = 1; /* stop emergency collection */
newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
newsize + EXTRA_STACK, StackValue);
G(L)->gcstopem = oldgcstop; /* restore emergency collection */
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
correctstack(L); /* change offsets back to pointers */
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 */
} }
/* number of elements to be copied to the new stack */ L->stack.p = newstack;
i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK; correctstack(L); /* change offsets back to pointers */
memcpy(newstack, L->stack, i * sizeof(StackValue)); L->stack_last.p = L->stack.p + newsize;
for (; i < newsize + EXTRA_STACK; i++) for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */ setnilvalue(s2v(newstack + i)); /* erase new segment */
correctstack(L, L->stack, newstack);
luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
L->stack = newstack;
L->stack_last = L->stack + newsize;
return 1; return 1;
} }
/* /*
** Try to grow the stack by at least 'n' elements. when 'raiseerror' ** Try to grow the stack by at least 'n' elements. When 'raiseerror'
** is true, raises any error; otherwise, return 0 in case of errors. ** is true, raises any error; otherwise, return 0 in case of errors.
*/ */
int luaD_growstack (lua_State *L, int n, int raiseerror) { int luaD_growstack (lua_State *L, int n, int raiseerror) {
@ -254,35 +277,38 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
luaD_throw(L, LUA_ERRERR); /* error inside message handler */ luaD_throw(L, LUA_ERRERR); /* error inside message handler */
return 0; /* if not 'raiseerror', just signal it */ return 0; /* if not 'raiseerror', just signal it */
} }
else { else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */
int newsize = 2 * size; /* tentative new size */ int newsize = 2 * size; /* tentative new size */
int needed = cast_int(L->top - L->stack) + n; int needed = cast_int(L->top.p - L->stack.p) + n;
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */ if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
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 (l_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 */
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror); luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
if (raiseerror) if (raiseerror)
luaG_runerror(L, "stack overflow"); luaG_runerror(L, "stack overflow");
return 0; return 0;
} }
}
}
/*
** Compute how much of the stack is being used, by computing the
** maximum top of all call frames in the stack and the current top.
*/
static int stackinuse (lua_State *L) { static int stackinuse (lua_State *L) {
CallInfo *ci; CallInfo *ci;
int res; int res;
StkId lim = L->top; StkId lim = L->top.p;
for (ci = L->ci; ci != NULL; ci = ci->previous) { for (ci = L->ci; ci != NULL; ci = ci->previous) {
if (lim < ci->top) lim = ci->top; if (lim < ci->top.p) lim = ci->top.p;
} }
lua_assert(lim <= L->stack_last); lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
res = cast_int(lim - L->stack) + 1; /* part of stack in use */ res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */
if (res < LUA_MINSTACK) if (res < LUA_MINSTACK)
res = LUA_MINSTACK; /* ensure a minimum size */ res = LUA_MINSTACK; /* ensure a minimum size */
return res; return res;
@ -300,17 +326,13 @@ static int stackinuse (lua_State *L) {
*/ */
void luaD_shrinkstack (lua_State *L) { void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L); int inuse = stackinuse(L);
int nsize = inuse * 2; /* proposed new size */ int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
int max = inuse * 3; /* maximum "reasonable" size */
if (max > LUAI_MAXSTACK) {
max = LUAI_MAXSTACK; /* respect stack limit */
if (nsize > LUAI_MAXSTACK)
nsize = LUAI_MAXSTACK;
}
/* if thread is currently not handling a stack overflow and its /* if thread is currently not handling a stack overflow and its
size is larger than maximum "reasonable" size, shrink it */ size is larger than maximum "reasonable" size, shrink it */
if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
luaD_reallocstack(L, nsize, 0); /* ok if that fails */ luaD_reallocstack(L, nsize, 0); /* ok if that fails */
}
else /* don't change stack */ else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */ condmovestack(L,{},{}); /* (change only for debugging) */
luaE_shrinkCI(L); /* shrink CI list */ luaE_shrinkCI(L); /* shrink CI list */
@ -319,7 +341,7 @@ void luaD_shrinkstack (lua_State *L) {
void luaD_inctop (lua_State *L) { void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1); luaD_checkstack(L, 1);
L->top++; L->top.p++;
} }
/* }================================================================== */ /* }================================================================== */
@ -336,8 +358,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); /* preserve original 'top' */ ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */
ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */ ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */
lua_Debug ar; lua_Debug ar;
ar.event = event; ar.event = event;
ar.currentline = line; ar.currentline = line;
@ -347,11 +369,11 @@ 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) if (isLua(ci) && L->top.p < ci->top.p)
L->top = ci->top; /* protect entire activation register */ L->top.p = ci->top.p; /* protect entire activation register */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
if (ci->top < L->top + LUA_MINSTACK) if (ci->top.p < L->top.p + LUA_MINSTACK)
ci->top = L->top + LUA_MINSTACK; ci->top.p = L->top.p + 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;
lua_unlock(L); lua_unlock(L);
@ -359,8 +381,8 @@ void luaD_hook (lua_State *L, int event, int line,
lua_lock(L); lua_lock(L);
lua_assert(!L->allowhook); lua_assert(!L->allowhook);
L->allowhook = 1; L->allowhook = 1;
ci->top = restorestack(L, ci_top); ci->top.p = restorestack(L, ci_top);
L->top = restorestack(L, top); L->top.p = restorestack(L, top);
ci->callstatus &= ~mask; ci->callstatus &= ~mask;
} }
} }
@ -391,7 +413,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
*/ */
static void rethook (lua_State *L, CallInfo *ci, int nres) { static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
StkId firstres = L->top - nres; /* index of first result */ StkId firstres = L->top.p - nres; /* index of first result */
int delta = 0; /* correction for vararg functions */ int delta = 0; /* correction for vararg functions */
int ftransfer; int ftransfer;
if (isLua(ci)) { if (isLua(ci)) {
@ -399,10 +421,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (p->is_vararg) if (p->is_vararg)
delta = ci->u.l.nextraargs + p->numparams + 1; delta = ci->u.l.nextraargs + p->numparams + 1;
} }
ci->func += delta; /* if vararg, back to virtual 'func' */ ci->func.p += delta; /* if vararg, back to virtual 'func' */
ftransfer = cast(unsigned short, firstres - ci->func); ftransfer = cast(unsigned short, firstres - ci->func.p);
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.p -= delta;
} }
if (isLua(ci = ci->previous)) if (isLua(ci = ci->previous))
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */ L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
@ -421,9 +443,9 @@ StkId luaD_tryfuncTM (lua_State *L, StkId func) {
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */ tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
if (l_unlikely(ttisnil(tm))) if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */ luaG_callerror(L, s2v(func)); /* nothing to call */
for (p = L->top; p > func; p--) /* open space for metamethod */ for (p = L->top.p; 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.p++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */ setobj2s(L, func, tm); /* metamethod is the new function to be called */
return func; return func;
} }
@ -440,28 +462,29 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
int i; int i;
switch (wanted) { /* handle typical cases separately */ switch (wanted) { /* handle typical cases separately */
case 0: /* no values needed */ case 0: /* no values needed */
L->top = res; L->top.p = res;
return; return;
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 /* at least one result */ else /* at least one result */
setobjs2s(L, res, L->top - nres); /* move it to proper place */ setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
L->top = res + 1; L->top.p = 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: /* two/more results and/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);
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */ L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
L->ci->u2.nres = nres; L->ci->u2.nres = nres;
luaF_close(L, res, CLOSEKTOP, 1); res = luaF_close(L, res, CLOSEKTOP, 1);
L->ci->callstatus &= ~CIST_CLSRET; L->ci->callstatus &= ~CIST_CLSRET;
if (L->hookmask) /* if needed, call hook after '__close's */ if (L->hookmask) { /* if needed, call hook after '__close's */
ptrdiff_t savedres = savestack(L, res);
rethook(L, L->ci, nres); rethook(L, L->ci, nres);
res = restorestack(L, savedres); /* close and hook can move stack */ res = restorestack(L, savedres); /* hook can move stack */
}
wanted = decodeNresults(wanted); wanted = decodeNresults(wanted);
if (wanted == LUA_MULTRET) if (wanted == LUA_MULTRET)
wanted = nres; /* we want all results */ wanted = nres; /* we want all results */
@ -469,14 +492,14 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
break; break;
} }
/* generic case */ /* generic case */
firstresult = L->top - nres; /* index of first result */ firstresult = L->top.p - nres; /* index of first result */
if (nres > wanted) /* extra results? */ if (nres > wanted) /* extra results? */
nres = wanted; /* don't need them */ nres = wanted; /* don't need them */
for (i = 0; i < nres; i++) /* move all results to correct place */ 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));
L->top = res + wanted; /* top points after the last result */ L->top.p = res + wanted; /* top points after the last result */
} }
@ -491,7 +514,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted))) if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
rethook(L, ci, nres); rethook(L, ci, nres);
/* move results to proper place */ /* move results to proper place */
moveresults(L, ci->func, nres, wanted); moveresults(L, ci->func.p, nres, wanted);
/* function cannot be in any of these cases when returning */ /* function cannot be in any of these cases when returning */
lua_assert(!(ci->callstatus & lua_assert(!(ci->callstatus &
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET))); (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
@ -506,10 +529,10 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
int mask, StkId top) { int mask, StkId top) {
CallInfo *ci = L->ci = next_ci(L); /* new frame */ CallInfo *ci = L->ci = next_ci(L); /* new frame */
ci->func = func; ci->func.p = func;
ci->nresults = nret; ci->nresults = nret;
ci->callstatus = mask; ci->callstatus = mask;
ci->top = top; ci->top.p = top;
return ci; return ci;
} }
@ -523,10 +546,10 @@ l_sinline int precallC (lua_State *L, StkId func, int nresults,
CallInfo *ci; CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
L->top + LUA_MINSTACK); L->top.p + LUA_MINSTACK);
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
if (l_unlikely(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.p - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
} }
lua_unlock(L); lua_unlock(L);
@ -558,17 +581,17 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int nfixparams = p->numparams; int nfixparams = p->numparams;
int i; int i;
checkstackGCp(L, fsize - delta, func); checkstackGCp(L, fsize - delta, func);
ci->func -= delta; /* restore 'func' (if vararg) */ ci->func.p -= delta; /* restore 'func' (if vararg) */
for (i = 0; i < narg1; i++) /* move down function and arguments */ for (i = 0; i < narg1; i++) /* move down function and arguments */
setobjs2s(L, ci->func + i, func + i); setobjs2s(L, ci->func.p + i, func + i);
func = ci->func; /* moved-down function */ func = ci->func.p; /* moved-down function */
for (; narg1 <= nfixparams; narg1++) for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */ setnilvalue(s2v(func + narg1)); /* complete missing arguments */
ci->top = func + 1 + fsize; /* top for new function */ ci->top.p = func + 1 + fsize; /* top for new function */
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL; ci->callstatus |= CIST_TAIL;
L->top = func + narg1; /* set top */ L->top.p = func + narg1; /* set top */
return -1; return -1;
} }
default: { /* not a function */ default: { /* not a function */
@ -601,15 +624,15 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
case LUA_VLCL: { /* Lua function */ case LUA_VLCL: { /* Lua function */
CallInfo *ci; CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p; Proto *p = clLvalue(s2v(func))->p;
int narg = cast_int(L->top - func) - 1; /* number of real arguments */ int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */
int nfixparams = p->numparams; int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */ int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func); checkstackGCp(L, fsize, func);
L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.savedpc = p->code; /* starting point */
for (; narg < nfixparams; narg++) for (; narg < nfixparams; narg++)
setnilvalue(s2v(L->top++)); /* complete missing arguments */ setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
return ci; return ci;
} }
default: { /* not a function */ default: { /* not a function */
@ -625,12 +648,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** Call a function (C or Lua) through C. 'inc' can be 1 (increment ** Call a function (C or Lua) through C. 'inc' can be 1 (increment
** number of recursive invocations in the C stack) or nyci (the same ** number of recursive invocations in the C stack) or nyci (the same
** plus increment number of non-yieldable calls). ** plus increment number of non-yieldable calls).
** This function can be called with some use of EXTRA_STACK, so it should
** check the stack before doing anything else. 'luaD_precall' already
** does that.
*/ */
l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) { l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) {
CallInfo *ci; CallInfo *ci;
L->nCcalls += inc; L->nCcalls += inc;
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
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 */
luaV_execute(L, ci); /* call it */ luaV_execute(L, ci); /* call it */
@ -678,8 +706,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
else { /* error */ else { /* error */
StkId func = restorestack(L, ci->u2.funcidx); StkId func = restorestack(L, ci->u2.funcidx);
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */ L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
luaF_close(L, func, status, 1); /* can yield or raise an error */ func = 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_seterrorobj(L, status, func);
luaD_shrinkstack(L); /* restore stack size in case of overflow */ luaD_shrinkstack(L); /* restore stack size in case of overflow */
setcistrecst(ci, LUA_OK); /* clear original status */ setcistrecst(ci, LUA_OK); /* clear original status */
@ -767,8 +794,8 @@ static CallInfo *findpcall (lua_State *L) {
** coroutine error handler and should not kill the coroutine.) ** coroutine error handler and should not kill the coroutine.)
*/ */
static int resume_error (lua_State *L, const char *msg, int narg) { static int resume_error (lua_State *L, const char *msg, int narg) {
L->top -= narg; /* remove args from the stack */ L->top.p -= narg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return LUA_ERRRUN; return LUA_ERRRUN;
@ -784,7 +811,7 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
*/ */
static void resume (lua_State *L, void *ud) { static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */ int n = *(cast(int*, ud)); /* number of arguments */
StkId firstArg = L->top - n; /* first argument */ StkId firstArg = L->top.p - n; /* first argument */
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (L->status == LUA_OK) /* starting a coroutine? */ if (L->status == LUA_OK) /* starting a coroutine? */
ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */ ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
@ -792,7 +819,7 @@ 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) */
if (isLua(ci)) { /* yielded inside a hook? */ if (isLua(ci)) { /* yielded inside a hook? */
L->top = firstArg; /* discard arguments */ L->top.p = 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 */
@ -835,7 +862,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
if (L->status == LUA_OK) { /* may be starting a coroutine */ if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */ if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs); return resume_error(L, "cannot resume non-suspended coroutine", nargs);
else if (L->top - (L->ci->func + 1) == nargs) /* no function? */ else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */
return resume_error(L, "cannot resume dead coroutine", nargs); return resume_error(L, "cannot resume dead coroutine", nargs);
} }
else if (L->status != LUA_YIELD) /* ended with errors? */ else if (L->status != LUA_YIELD) /* ended with errors? */
@ -853,11 +880,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
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' */
luaD_seterrorobj(L, status, L->top); /* push error message */ luaD_seterrorobj(L, status, L->top.p); /* push error message */
L->ci->top = L->top; L->ci->top.p = L->top.p;
} }
*nresults = (status == LUA_YIELD) ? L->ci->u2.nyield *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
: cast_int(L->top - (L->ci->func + 1)); : cast_int(L->top.p - (L->ci->func.p + 1));
lua_unlock(L); lua_unlock(L);
return status; return status;
} }
@ -1012,7 +1039,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0; p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff); luaZ_initbuffer(L, &p.buff);
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
luaZ_freebuffer(L, &p.buff); luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);

16
third_party/lua/ldo.h vendored
View file

@ -17,7 +17,7 @@
** at every check. ** at every check.
*/ */
#define luaD_checkstackaux(L,n,pre,pos) \ #define luaD_checkstackaux(L,n,pre,pos) \
if (l_unlikely(L->stack_last - L->top <= (n))) \ if (l_unlikely(L->stack_last.p - L->top.p <= (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); }
@ -26,11 +26,18 @@
#define savestack(L,p) ((char *)(p) - (char *)L->stack) #define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
#define restorestack(L,n) ((StkId)((char *)L->stack + (n))) #define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
/* macro to check stack size, preserving 'p' */ /* macro to check stack size, preserving 'p' */
#define checkstackp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \ #define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \ luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
@ -52,7 +59,8 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer); int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta); LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); 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);

View file

@ -37,7 +37,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -78,8 +78,11 @@ static void dumpByte (DumpState *D, int y) {
} }
/* dumpInt Buff Size */ /*
#define DIBS ((sizeof(size_t) * 8 / 7) + 1) ** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
** rounds up the division.)
*/
#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7)
static void dumpSize (DumpState *D, size_t x) { static void dumpSize (DumpState *D, size_t x) {
lu_byte buff[DIBS]; lu_byte buff[DIBS];

View file

@ -42,7 +42,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -73,8 +73,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
for (i = 0; i < cl->nupvalues; i++) { for (i = 0; i < cl->nupvalues; i++) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal)); GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o); UpVal *uv = gco2upv(o);
uv->v = &uv->u.value; /* make it closed */ uv->v.p = &uv->u.value; /* make it closed */
setnilvalue(uv->v); setnilvalue(uv->v.p);
cl->upvals[i] = uv; cl->upvals[i] = uv;
luaC_objbarrier(L, cl, uv); luaC_objbarrier(L, cl, uv);
} }
@ -85,12 +85,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
** Create a new upvalue at the given level, and link it to the list of ** Create a new upvalue at the given level, and link it to the list of
** open upvalues of 'L' after entry 'prev'. ** open upvalues of 'L' after entry 'prev'.
**/ **/
static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) { static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal)); GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o); UpVal *uv = gco2upv(o);
UpVal *next = *prev; UpVal *next = *prev;
uv->v = s2v(level); /* current value lives in the stack */ uv->v.p = s2v(level); /* current value lives in the stack */
uv->tbc = tbc;
uv->u.open.next = next; /* link it to list of open upvalues */ uv->u.open.next = next; /* link it to list of open upvalues */
uv->u.open.previous = prev; uv->u.open.previous = prev;
if (next) if (next)
@ -119,7 +118,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
pp = &p->u.open.next; pp = &p->u.open.next;
} }
/* not found: create a new upvalue after 'pp' */ /* not found: create a new upvalue after 'pp' */
return newupval(L, 0, level, pp); return newupval(L, level, pp);
} }
@ -129,12 +128,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
** (This function assumes EXTRA_STACK.) ** (This function assumes EXTRA_STACK.)
*/ */
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
StkId top = L->top; StkId top = L->top.p;
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
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.p = top + 3; /* add function and arguments */
if (yy) if (yy)
luaD_call(L, top, 0); luaD_call(L, top, 0);
else else
@ -149,7 +148,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
static void checkclosemth (lua_State *L, StkId level) { static void checkclosemth (lua_State *L, StkId level) {
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE); const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
if (ttisnil(tm)) { /* no metamethod? */ if (ttisnil(tm)) { /* no metamethod? */
int idx = cast_int(level - L->ci->func); /* variable index */ int idx = cast_int(level - L->ci->func.p); /* 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, "variable '%s' got a non-closable value", vname); luaG_runerror(L, "variable '%s' got a non-closable value", vname);
@ -183,23 +182,23 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
** is used.) ** is used.)
*/ */
#define MAXDELTA \ #define MAXDELTA \
((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1) ((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
/* /*
** Insert a variable in the list of to-be-closed variables. ** Insert a variable in the list of to-be-closed variables.
*/ */
void luaF_newtbcupval (lua_State *L, StkId level) { void luaF_newtbcupval (lua_State *L, StkId level) {
lua_assert(level > L->tbclist); lua_assert(level > L->tbclist.p);
if (l_isfalse(s2v(level))) if (l_isfalse(s2v(level)))
return; /* false doesn't need to be closed */ return; /* false doesn't need to be closed */
checkclosemth(L, level); /* value must have a close method */ checkclosemth(L, level); /* value must have a close method */
while (cast_uint(level - L->tbclist) > MAXDELTA) { while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */ L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
L->tbclist->tbclist.delta = 0; L->tbclist.p->tbclist.delta = 0;
} }
level->tbclist.delta = cast(unsigned short, level - L->tbclist); level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
L->tbclist = level; L->tbclist.p = level;
} }
@ -219,10 +218,10 @@ void luaF_closeupval (lua_State *L, StkId level) {
StkId upl; /* stack index pointed by 'uv' */ StkId upl; /* stack index pointed by 'uv' */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { 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.p);
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */ luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
setobj(L, slot, uv->v); /* move value to upvalue slot */ setobj(L, slot, uv->v.p); /* move value to upvalue slot */
uv->v = slot; /* now current value lives here */ uv->v.p = slot; /* now current value lives here */
if (!iswhite(uv)) { /* neither white nor dead? */ if (!iswhite(uv)) { /* neither white nor dead? */
nw2black(uv); /* closed upvalues cannot be gray */ nw2black(uv); /* closed upvalues cannot be gray */
luaC_barrier(L, uv, slot); luaC_barrier(L, uv, slot);
@ -232,31 +231,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
/* /*
** Remove firt element from the tbclist plus its dummy nodes. ** Remove first element from the tbclist plus its dummy nodes.
*/ */
static void poptbclist (lua_State *L) { static void poptbclist (lua_State *L) {
StkId tbc = L->tbclist; StkId tbc = L->tbclist.p;
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */ lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
tbc -= tbc->tbclist.delta; tbc -= tbc->tbclist.delta;
while (tbc > L->stack && tbc->tbclist.delta == 0) while (tbc > L->stack.p && tbc->tbclist.delta == 0)
tbc -= MAXDELTA; /* remove dummy nodes */ tbc -= MAXDELTA; /* remove dummy nodes */
L->tbclist = tbc; L->tbclist.p = tbc;
} }
/* /*
** Close all upvalues and to-be-closed variables up to the given stack ** Close all upvalues and to-be-closed variables up to the given stack
** level. ** level. Return restored 'level'.
*/ */
void luaF_close (lua_State *L, StkId level, int status, int yy) { StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
ptrdiff_t levelrel = savestack(L, level); ptrdiff_t levelrel = savestack(L, level);
luaF_closeupval(L, level); /* first, close the upvalues */ luaF_closeupval(L, level); /* first, close the upvalues */
while (L->tbclist >= level) { /* traverse tbc's down to that level */ while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
StkId tbc = L->tbclist; /* get variable index */ StkId tbc = L->tbclist.p; /* get variable index */
poptbclist(L); /* remove it from list */ poptbclist(L); /* remove it from list */
prepcallclosemth(L, tbc, status, yy); /* close variable */ prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel); level = restorestack(L, levelrel);
} }
return level;
} }

View file

@ -23,10 +23,10 @@
#define MAXUPVAL 255 #define MAXUPVAL 255
#define upisopen(up) ((up)->v != &(up)->u.value) #define upisopen(up) ((up)->v.p != &(up)->u.value)
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v)) #define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
/* /*
@ -48,7 +48,7 @@ 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 void luaF_closeupval (lua_State *L, StkId level); 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 StkId 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,

108
third_party/lua/lgc.c vendored
View file

@ -45,7 +45,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -275,12 +275,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
/* /*
** create a new collectable object (with given type and size) and link ** create a new collectable object (with given type, size, and offset)
** it to 'allgc' list. ** and link it to 'allgc' list.
*/ */
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
global_State *g = G(L); global_State *g = G(L);
GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
GCObject *o = cast(GCObject *, p + offset);
o->marked = luaC_white(g); o->marked = luaC_white(g);
o->tt = tt; o->tt = tt;
o->next = g->allgc; o->next = g->allgc;
@ -288,6 +289,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return o; return o;
} }
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return luaC_newobjdt(L, tt, sz, 0);
}
/* }====================================================== */ /* }====================================================== */
@ -324,7 +330,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
set2gray(uv); /* open upvalues are kept gray */ set2gray(uv); /* open upvalues are kept gray */
else else
set2black(uv); /* closed upvalues are visited here */ set2black(uv); /* closed upvalues are visited here */
markvalue(g, uv->v); /* mark its content */ markvalue(g, uv->v.p); /* mark its content */
break; break;
} }
case LUA_VUSERDATA: { case LUA_VUSERDATA: {
@ -399,7 +405,7 @@ static int remarkupvals (global_State *g) {
work++; work++;
if (!iswhite(uv)) { /* upvalue already visited? */ if (!iswhite(uv)) { /* upvalue already visited? */
lua_assert(upisopen(uv) && isgray(uv)); lua_assert(upisopen(uv) && isgray(uv));
markvalue(g, uv->v); /* mark its value */ markvalue(g, uv->v.p); /* mark its value */
} }
} }
} }
@ -643,19 +649,19 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
*/ */
static int traversethread (global_State *g, lua_State *th) { static int traversethread (global_State *g, lua_State *th) {
UpVal *uv; UpVal *uv;
StkId o = th->stack; StkId o = th->stack.p;
if (isold(th) || g->gcstate == GCSpropagate) if (isold(th) || g->gcstate == GCSpropagate)
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
if (o == NULL) if (o == NULL)
return 1; /* stack not completely built yet */ return 1; /* stack not completely built yet */
lua_assert(g->gcstate == GCSatomic || lua_assert(g->gcstate == GCSatomic ||
th->openupval == NULL || isintwups(th)); th->openupval == NULL || isintwups(th));
for (; o < th->top; o++) /* mark live elements in the stack */ for (; o < th->top.p; o++) /* mark live elements in the stack */
markvalue(g, s2v(o)); markvalue(g, s2v(o));
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markobject(g, uv); /* open upvalues cannot be collected */ markobject(g, uv); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */ if (g->gcstate == GCSatomic) { /* final traversal? */
for (; o < th->stack_last + EXTRA_STACK; o++) for (; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */ setnilvalue(s2v(o)); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */ /* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) { if (!isintwups(th) && th->openupval != NULL) {
@ -915,7 +921,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) { static void dothecall (lua_State *L, void *ud) {
UNUSED(ud); UNUSED(ud);
luaD_callnoyield(L, L->top - 2, 0); luaD_callnoyield(L, L->top.p - 2, 0);
} }
@ -932,16 +938,16 @@ static void GCTM (lua_State *L) {
int oldgcstp = g->gcstp; int oldgcstp = g->gcstp;
g->gcstp |= GCSTPGC; /* avoid GC steps */ g->gcstp |= GCSTPGC; /* avoid GC steps */
L->allowhook = 0; /* stop debug hooks during GC metamethod */ L->allowhook = 0; /* stop debug hooks during GC metamethod */
setobj2s(L, L->top++, tm); /* push finalizer... */ setobj2s(L, L->top.p++, tm); /* push finalizer... */
setobj2s(L, L->top++, &v); /* ... and its argument */ setobj2s(L, L->top.p++, &v); /* ... and its argument */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
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->gcstp = oldgcstp; /* restore state */ g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc"); luaE_warnerror(L, "__gc");
L->top--; /* pops error object */ L->top.p--; /* pops error object */
} }
} }
} }
@ -1064,7 +1070,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** ======================================================= ** =======================================================
*/ */
static void setpause (global_State *g);
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/* /*
@ -1308,6 +1332,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
} }
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/* /*
** Enter generational mode. Must go until the end of an atomic cycle ** Enter generational mode. Must go until the end of an atomic cycle
** to ensure that all objects are correctly marked and weak tables ** to ensure that all objects are correctly marked and weak tables
@ -1320,6 +1353,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
numobjs = atomic(L); /* propagates all and then do the atomic stuff */ numobjs = atomic(L); /* propagates all and then do the atomic stuff */
atomic2gen(L, g); atomic2gen(L, g);
setminordebt(g); /* set debt assuming next cycle will be minor */
return numobjs; return numobjs;
} }
@ -1365,15 +1399,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
} }
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/* /*
** Does a major collection after last collection was a "bad collection". ** Does a major collection after last collection was a "bad collection".
** **
@ -1445,8 +1470,8 @@ static void genstep (lua_State *L, global_State *g) {
lu_mem numobjs = fullgen(L, g); /* do a major collection */ lu_mem numobjs = fullgen(L, g); /* do a major collection */
if (gettotalbytes(g) < majorbase + (majorinc / 2)) { if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
/* collected at least half of memory growth since last major /* collected at least half of memory growth since last major
collection; keep doing minor collections */ collection; keep doing minor collections. */
setminordebt(g); lua_assert(g->lastatomic == 0);
} }
else { /* bad collection */ else { /* bad collection */
g->lastatomic = numobjs; /* signal that last collection was bad */ g->lastatomic = numobjs; /* signal that last collection was bad */
@ -1472,26 +1497,6 @@ static void genstep (lua_State *L, global_State *g) {
*/ */
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/* /*
** Enter first sweep phase. ** Enter first sweep phase.
** The call to 'sweeptolive' makes the pointer point to an object ** The call to 'sweeptolive' makes the pointer point to an object
@ -1699,12 +1704,15 @@ static void incstep (lua_State *L, global_State *g) {
} }
/* /*
** performs a basic GC step if collector is running ** Performs a basic GC step if collector is running. (If collector is
** not running, set a reasonable debt to avoid it being called at
** every single check.)
*/ */
void luaC_step (lua_State *L) { void luaC_step (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
lua_assert(!g->gcemergency); if (!gcrunning(g)) /* not running? */
if (gcrunning(g)) { /* running? */ luaE_setdebt(g, -2000);
else {
if(isdecGCmodegen(g)) if(isdecGCmodegen(g))
genstep(L, g); genstep(L, g);
else else

19
third_party/lua/lgc.h vendored
View file

@ -167,24 +167,27 @@
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) #define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_barrier(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrierback_(L,p) : cast_void(0))
#define luaC_objbarrier(L,p,o) ( \ #define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \ (isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_barrier(L,p,v) ( \
iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
#define luaC_objbarrierback(L,p,o) ( \
(isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
size_t offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);

View file

@ -52,7 +52,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");

View file

@ -43,7 +43,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");

View file

@ -45,7 +45,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -149,7 +149,7 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
** ensuring there is only one copy of each unique string. The table ** 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 ** 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 irrelevant. We use the string itself as the value only because it
** is a TValue readly available. Later, the code generation can change ** is a TValue readily available. Later, the code generation can change
** this value. ** this value.
*/ */
TString *luaX_newstring (LexState *ls, const char *str, size_t l) { TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
@ -159,12 +159,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
if (!ttisnil(o)) /* string already present? */ if (!ttisnil(o)) /* string already present? */
ts = keystrval(nodefromval(o)); /* get saved copy */ ts = keystrval(nodefromval(o)); /* get saved copy */
else { /* not in use yet */ else { /* not in use yet */
TValue *stv = s2v(L->top++); /* reserve stack space for string */ TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
setsvalue(L, stv, ts); /* temporarily anchor the string */ setsvalue(L, stv, ts); /* temporarily anchor the string */
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = 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 */ /* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L); luaC_checkGC(L);
L->top--; /* remove string from stack */ L->top.p--; /* remove string from stack */
} }
return ts; return ts;
} }

View file

@ -63,11 +63,24 @@ typedef signed char ls_byte;
/* /*
** conversion of pointer to unsigned integer: ** conversion of pointer to unsigned integer: this is for hashing only;
** this is for hashing only; there is no problem if the integer ** there is no problem if the integer cannot hold the whole pointer
** cannot hold the whole pointer value ** value. (In strict ISO C this may cause undefined behavior, but no
** actual machine seems to bother.)
*/ */
#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX)) #if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 199901L
#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
#define L_P2I uintptr_t
#else /* no 'intptr'? */
#define L_P2I uintmax_t /* use the largest available integer */
#endif
#else /* C89 option */
#define L_P2I size_t
#endif
#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX))

View file

@ -39,7 +39,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -289,7 +289,7 @@ static int math_type (lua_State *L) {
/* try to find an integer type with at least 64 bits */ /* try to find an integer type with at least 64 bits */
#if (ULONG_MAX >> 31 >> 31) >= 3 #if ((ULONG_MAX >> 31) >> 31) >= 3
/* 'long' has at least 64 bits */ /* 'long' has at least 64 bits */
#define Rand64 unsigned long #define Rand64 unsigned long
@ -299,9 +299,9 @@ static int math_type (lua_State *L) {
/* there is a 'long long' type (which must have at least 64 bits) */ /* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long #define Rand64 unsigned long long
#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3 #elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
/* 'lua_Integer' has at least 64 bits */ /* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned #define Rand64 lua_Unsigned
#endif #endif
@ -522,12 +522,12 @@ static lua_Number I2d (Rand64 x) {
/* convert a 'Rand64' to a 'lua_Unsigned' */ /* convert a 'Rand64' to a 'lua_Unsigned' */
static lua_Unsigned I2UInt (Rand64 x) { static lua_Unsigned I2UInt (Rand64 x) {
return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l); return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
} }
/* convert a 'lua_Unsigned' to a 'Rand64' */ /* convert a 'lua_Unsigned' to a 'Rand64' */
static Rand64 Int2I (lua_Unsigned n) { static Rand64 Int2I (lua_Unsigned n) {
return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n); return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
} }
#endif /* } */ #endif /* } */

View file

@ -41,31 +41,11 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail whenever not building initial state.
** (This fail will trigger 'tryagain' and a full GC cycle at every
** allocation.)
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (completestate(g) && ns > 0) /* frees never fail */
return NULL; /* fail */
else /* normal allocation */
return (*g->frealloc)(g->ud, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
#endif
/* /*
** About the realloc function: ** About the realloc function:
** void *frealloc (void *ud, void *ptr, size_t osize, size_t nsize); ** void *frealloc (void *ud, void *ptr, size_t osize, size_t nsize);
@ -84,6 +64,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
*/ */
/*
** Macro to call the allocation function.
*/
#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
/*
** When an allocation fails, it will try again after an emergency
** collection, except when it cannot run a collection. The GC should
** not be called while the state is not fully built, as the 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.
*/
#define cantryagain(g) (completestate(g) && !g->gcstopem)
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail except when freeing a block (frees never
** fail) and when it cannot try again; this fail will trigger 'tryagain'
** and a full GC cycle at every allocation.
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (ns > 0 && cantryagain(g))
return NULL; /* fail */
else /* normal allocation */
return callfrealloc(g, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
#endif
/* /*
@ -156,7 +173,7 @@ l_noret luaM_toobig (lua_State *L) {
void luaM_free_ (lua_State *L, void *block, size_t osize) { void luaM_free_ (lua_State *L, void *block, size_t osize) {
global_State *g = G(L); global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL)); lua_assert((osize == 0) == (block == NULL));
(*g->frealloc)(g->ud, block, osize, 0); callfrealloc(g, block, osize, 0);
g->GCdebt -= osize; g->GCdebt -= osize;
} }
@ -164,20 +181,16 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
/* /*
** In case of allocation fail, this function will do an emergency ** In case of allocation fail, this function will do an emergency
** collection to free some memory and then try the allocation again. ** collection to free some memory and then try the allocation again.
** The GC should not be called while state is not fully built, as the
** collector is not yet fully initialized. Also, it should not be called
** when 'gcstopem' is true, because then the interpreter is in the
** middle of a collection step.
*/ */
static void *tryagain (lua_State *L, void *block, static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) { size_t osize, size_t nsize) {
global_State *g = G(L); global_State *g = G(L);
if (completestate(g) && !g->gcstopem) { if (cantryagain(g)) {
WARNF("reacting to malloc() failure by running lua garbage collector..."); // [jart] WARNF("reacting to malloc() failure by running lua garbage collector..."); // [jart]
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 callfrealloc(g, block, osize, nsize); /* try again */
} }
else return NULL; /* cannot free any memory without a full state */ else return NULL; /* cannot run an emergency collection */
} }

View file

@ -38,7 +38,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -736,8 +736,13 @@ static const luaL_Reg ll_funcs[] = {
static void createsearcherstable (lua_State *L) { static void createsearcherstable (lua_State *L) {
static const lua_CFunction searchers[] = static const lua_CFunction searchers[] = {
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; searcher_preload,
searcher_Lua,
searcher_C,
searcher_Croot,
NULL
};
int i; int i;
/* create 'searchers' table */ /* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);

View file

@ -43,7 +43,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -66,7 +66,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPBOR: return intop(|, v1, v2); case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2); case LUA_OPBXOR: return intop(^, v1, v2);
case LUA_OPSHL: return luaV_shiftl(v1, v2); case LUA_OPSHL: return luaV_shiftl(v1, v2);
case LUA_OPSHR: return luaV_shiftl(v1, -v2); case LUA_OPSHR: return luaV_shiftr(v1, v2);
case LUA_OPUNM: return intop(-, 0, v1); case LUA_OPUNM: return intop(-, 0, v1);
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
default: lua_assert(0); return 0; default: lua_assert(0); return 0;
@ -409,29 +409,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
** =================================================================== ** ===================================================================
*/ */
/* size for buffer space used by 'luaO_pushvfstring' */ /*
#define BUFVFS 200 ** Size for buffer space used by 'luaO_pushvfstring'. It should be
** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
** so that 'luaG_addinfo' can work directly on the buffer.
*/
#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */ /* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS { typedef struct BuffFS {
lua_State *L; lua_State *L;
int pushed; /* number of string pieces already on the stack */ int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */ int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */ char space[BUFVFS]; /* holds last part of the result */
} BuffFS; } BuffFS;
/* /*
** Push given string to the stack, as part of the buffer, and ** Push given string to the stack, as part of the result, and
** join the partial strings in the stack into one. ** join it to previous partial result if there is one.
** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
** This call cannot invoke metamethods, as both operands must be
** strings. It can, however, raise an error if the result is too
** long. In that case, 'luaV_concat' frees the extra slot before
** raising the error.
*/ */
static void pushstr (BuffFS *buff, const char *str, size_t l) { static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L; lua_State *L = buff->L;
setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
L->top++; /* may use one extra slot */ L->top.p++; /* may use one slot from EXTRA_STACK */
buff->pushed++; if (!buff->pushed) /* no previous string on the stack? */
luaV_concat(L, buff->pushed); /* join partial results into one */ buff->pushed = 1; /* now there is one */
buff->pushed = 1; else /* join previous string with new one */
luaV_concat(L, 2);
} }
@ -477,7 +487,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
/* /*
** Add a number to the buffer. ** Add a numeral to the buffer.
*/ */
static void addnum2buff (BuffFS *buff, TValue *num) { static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR); char *numbuff = getbuff(buff, MAXNUMBER2STR);
@ -555,7 +565,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */ addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */ clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1); lua_assert(buff.pushed == 1);
return svalue(s2v(L->top - 1)); return svalue(s2v(L->top.p - 1));
} }

View file

@ -43,6 +43,8 @@ typedef union Value {
lua_CFunction f; /* light C functions */ lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */ lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */ lua_Number n; /* float numbers */
/* not used, but may avoid warnings for uninitialized value */
lu_byte ub;
} Value; } Value;
@ -146,6 +148,17 @@ typedef union StackValue {
/* index to stack elements */ /* index to stack elements */
typedef StackValue *StkId; typedef StackValue *StkId;
/*
** When reallocating the stack, change all pointers to the stack into
** proper offsets.
*/
typedef union {
StkId p; /* actual pointer */
ptrdiff_t offset; /* used while the stack is being reallocated */
} StkIdRel;
/* convert a 'StackValue' to a 'TValue' */ /* convert a 'StackValue' to a 'TValue' */
#define s2v(o) (&(o)->val) #define s2v(o) (&(o)->val)
@ -606,8 +619,10 @@ typedef struct Proto {
*/ */
typedef struct UpVal { typedef struct UpVal {
CommonHeader; CommonHeader;
lu_byte tbc; /* true if it represents a to-be-closed variable */ union {
TValue *v; /* points to stack or to its own value */ TValue *p; /* points to stack or to its own value */
ptrdiff_t offset; /* used while the stack is being reallocated */
} v;
union { union {
struct { /* (when open) */ struct { /* (when open) */
struct UpVal *next; /* linked list */ struct UpVal *next; /* linked list */

View file

@ -34,7 +34,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");

View file

@ -16,7 +16,7 @@ iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) | iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) | iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) | iAx Ax(25) | Op(7) |
isJ sJ(25) | Op(7) | isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the the written unsigned value minus K, where K is half the maximum for the

View file

@ -46,7 +46,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -59,23 +59,14 @@ asm(".include \"libc/disclaimer.inc\"");
*/ */
#if !defined(LUA_STRFTIMEOPTIONS) /* { */ #if !defined(LUA_STRFTIMEOPTIONS) /* { */
/* options for ANSI C 89 (only 1-char options) */
#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
/* options for ISO C 99 and POSIX */
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
/* options for Windows */
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#if defined(LUA_USE_WINDOWS) #if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN #define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
#elif defined(LUA_USE_C89) "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89 #elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
#else /* C99 specification */ #else /* C99 specification */
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99 #define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
#endif #endif
#endif /* } */ #endif /* } */
@ -163,12 +154,21 @@ asm(".include \"libc/disclaimer.inc\"");
/* }================================================================== */ /* }================================================================== */
#if !defined(l_system)
#if defined(LUA_USE_IOS)
/* Despite claiming to be ISO C, iOS does not implement 'system'. */
#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
#else
#define l_system(cmd) system(cmd) /* default definition */
#endif
#endif
static int os_execute (lua_State *L) { static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL); const char *cmd = luaL_optstring(L, 1, NULL);
int stat; int stat;
errno = 0; errno = 0;
stat = system(cmd); stat = l_system(cmd);
if (cmd != NULL) if (cmd != NULL)
return luaL_execresult(L, stat); return luaL_execresult(L, stat);
else { else {
@ -285,9 +285,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
res = d; res = d;
} }
else { else {
/* unsigned avoids overflow when lua_Integer has 32 bits */ if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
: (lua_Integer)INT_MIN + delta <= res))
return luaL_error(L, "field '%s' is out-of-bound", key); return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta; res -= delta;
} }

View file

@ -47,7 +47,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -490,6 +490,7 @@ static void singlevar (LexState *ls, expdesc *var) {
expdesc key; expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */ lua_assert(var->k != VVOID); /* this one must exist */
luaK_exp2anyregup(fs, var); /* but could be a constant */
codestring(&key, varname); /* key is variable name */ codestring(&key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */ luaK_indexed(fs, var, &key); /* env[varname] */
} }
@ -542,12 +543,12 @@ static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
/* /*
** Solves the goto at index 'g' to given 'label' and removes it ** Solves the goto at index 'g' to given 'label' and removes it
** from the list of pending goto's. ** from the list of pending gotos.
** If it jumps into the scope of some variable, raises an error. ** If it jumps into the scope of some variable, raises an error.
*/ */
static void solvegoto (LexState *ls, int g, Labeldesc *label) { static void solvegoto (LexState *ls, int g, Labeldesc *label) {
int i; int i;
Labellist *gl = &ls->dyd->gt; /* list of goto's */ Labellist *gl = &ls->dyd->gt; /* list of gotos */
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 (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */ if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
@ -601,7 +602,7 @@ static int newgotoentry (LexState *ls, TString *name, int line, int pc) {
/* /*
** Solves forward jumps. Check whether new label 'lb' matches any ** Solves forward jumps. Check whether new label 'lb' matches any
** pending gotos in current block and solves them. Return true ** pending gotos in current block and solves them. Return true
** if any of the goto's need to close upvalues. ** if any of the gotos need to close upvalues.
*/ */
static int solvegotos (LexState *ls, Labeldesc *lb) { static int solvegotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt; Labellist *gl = &ls->dyd->gt;
@ -622,7 +623,7 @@ static int solvegotos (LexState *ls, Labeldesc *lb) {
/* /*
** Create a new label with the given 'name' at the given 'line'. ** Create a new label with the given 'name' at the given 'line'.
** 'last' tells whether label is the last non-op statement in its ** 'last' tells whether label is the last non-op statement in its
** block. Solves all pending goto's to this new label and adds ** block. Solves all pending gotos to this new label and adds
** a close instruction if necessary. ** a close instruction if necessary.
** Returns true iff it added a close instruction. ** Returns true iff it added a close instruction.
*/ */
@ -695,19 +696,19 @@ static void leaveblock (FuncState *fs) {
LexState *ls = fs->ls; LexState *ls = fs->ls;
int hasclose = 0; int hasclose = 0;
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */ int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
if (bl->isloop) /* fix pending breaks? */ removevars(fs, bl->nactvar); /* remove block locals */
lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
if (bl->isloop) /* has to 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) /* still need a 'close'? */
luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0); luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
fs->bl = bl->previous;
removevars(fs, bl->nactvar);
lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = stklevel; /* free registers */ fs->freereg = stklevel; /* free registers */
ls->dyd->label.n = bl->firstlabel; /* remove local labels */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */
if (bl->previous) /* inner block? */ fs->bl = bl->previous; /* current block now is previous one */
movegotosout(fs, bl); /* update pending gotos to outer block */ if (bl->previous) /* was it a nested block? */
movegotosout(fs, bl); /* update pending gotos to enclosing block */
else { else {
if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
} }
} }
@ -1965,10 +1966,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LexState lexstate; LexState lexstate;
FuncState funcstate; FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue2s(L, L->top, cl); /* anchor it (to avoid being collected) */ setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L); luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */ lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue2s(L, L->top, lexstate.h); /* anchor it */ sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
luaD_inctop(L); luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L); funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p); luaC_objbarrier(L, cl, cl->p);
@ -1982,7 +1983,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */ /* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
L->top--; /* remove scanner's table */ L->top.p--; /* remove scanner's table */
return cl; /* closure is on the stack, too */ return cl; /* closure is on the stack, too */
} }

View file

@ -37,3 +37,4 @@
#endif /* } */ #endif /* } */
#endif #endif

View file

@ -51,7 +51,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");

View file

@ -47,7 +47,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -201,33 +201,33 @@ LUAI_FUNC void luaE_incCstack (lua_State *L) {
static void stack_init (lua_State *L1, lua_State *L) { 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.p = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue);
L1->tbclist = L1->stack; L1->tbclist.p = L1->stack.p;
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.p + i)); /* erase new stack */
L1->top = L1->stack; L1->top.p = L1->stack.p;
L1->stack_last = L1->stack + BASIC_STACK_SIZE; L1->stack_last.p = L1->stack.p + BASIC_STACK_SIZE;
/* initialize first ci */ /* initialize first ci */
ci = &L1->base_ci; ci = &L1->base_ci;
ci->next = ci->previous = NULL; ci->next = ci->previous = NULL;
ci->callstatus = CIST_C; ci->callstatus = CIST_C;
ci->func = L1->top; ci->func.p = L1->top.p;
ci->u.c.k = NULL; ci->u.c.k = NULL;
ci->nresults = 0; ci->nresults = 0;
setnilvalue(s2v(L1->top)); /* 'function' entry for this 'ci' */ setnilvalue(s2v(L1->top.p)); /* 'function' entry for this 'ci' */
L1->top++; L1->top.p++;
ci->top = L1->top + LUA_MINSTACK; ci->top.p = L1->top.p + LUA_MINSTACK;
L1->ci = ci; L1->ci = ci;
} }
static void freestack (lua_State *L) { static void freestack (lua_State *L) {
if (L->stack == NULL) if (L->stack.p == NULL)
return; /* stack not completely built yet */ return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */ L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L); luaE_freeCI(L);
lua_assert(L->nci == 0); lua_assert(L->nci == 0);
luaM_freearray(L, L->stack, stacksize(L) + EXTRA_STACK); /* free stack */ luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */
} }
@ -269,7 +269,7 @@ static void f_luaopen (lua_State *L, void *ud) {
*/ */
static void preinit_thread (lua_State *L, global_State *g) { static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g; G(L) = g;
L->stack = NULL; L->stack.p = NULL;
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 */
@ -315,20 +315,16 @@ static void close_state (lua_State *L) {
* Threads are subject to garbage collection, like any Lua object. * Threads are subject to garbage collection, like any Lua object.
*/ */
LUA_API lua_State *lua_newthread (lua_State *L) { LUA_API lua_State *lua_newthread (lua_State *L) {
global_State *g; global_State *g = G(L);
GCObject *o;
lua_State *L1; lua_State *L1;
lua_lock(L); lua_lock(L);
g = G(L);
luaC_checkGC(L); luaC_checkGC(L);
/* create new thread */ /* create new thread */
L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; o = luaC_newobjdt(L, LUA_TTHREAD, sizeof(LX), offsetof(LX, l));
L1->marked = luaC_white(g); L1 = gco2th(o);
L1->tt = LUA_VTHREAD;
/* link it on list 'allgc' */
L1->next = g->allgc;
g->allgc = obj2gco(L1);
/* anchor it on L stack */ /* anchor it on L stack */
setthvalue2s(L, L->top, L1); setthvalue2s(L, L->top.p, L1);
api_incr_top(L); api_incr_top(L);
preinit_thread(L1, g); preinit_thread(L1, g);
L1->hookmask = L->hookmask; L1->hookmask = L->hookmask;
@ -347,7 +343,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_closeupval(L1, L1->stack); /* close all upvalues */ luaF_closeupval(L1, L1->stack.p); /* 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);
@ -357,26 +353,27 @@ void luaE_freethread (lua_State *L, lua_State *L1) {
int luaE_resetthread (lua_State *L, int status) { int luaE_resetthread (lua_State *L, int status) {
CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */ CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */
setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */ setnilvalue(s2v(L->stack.p)); /* 'function' entry for basic 'ci' */
ci->func = L->stack; ci->func.p = L->stack.p;
ci->callstatus = CIST_C; ci->callstatus = CIST_C;
if (status == LUA_YIELD) if (status == LUA_YIELD)
status = LUA_OK; status = LUA_OK;
L->status = LUA_OK; /* so it can run __close metamethods */ L->status = LUA_OK; /* so it can run __close metamethods */
status = luaD_closeprotected(L, 1, status); status = luaD_closeprotected(L, 1, status);
if (status != LUA_OK) /* errors? */ if (status != LUA_OK) /* errors? */
luaD_seterrorobj(L, status, L->stack + 1); luaD_seterrorobj(L, status, L->stack.p + 1);
else else
L->top = L->stack + 1; L->top.p = L->stack.p + 1;
ci->top = L->top + LUA_MINSTACK; ci->top.p = L->top.p + LUA_MINSTACK;
luaD_reallocstack(L, cast_int(ci->top - L->stack), 0); luaD_reallocstack(L, cast_int(ci->top.p - L->stack.p), 0);
return status; return status;
} }
LUA_API int lua_resetthread (lua_State *L) { LUA_API int lua_resetthread (lua_State *L, lua_State *from) {
int status; int status;
lua_lock(L); lua_lock(L);
L->nCcalls = (from) ? getCcalls(from) : 0;
status = luaE_resetthread(L, L->status); status = luaE_resetthread(L, L->status);
lua_unlock(L); lua_unlock(L);
return status; return status;
@ -457,7 +454,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) {
** Generate a warning from an error message ** Generate a warning from an error message
*/ */
void luaE_warnerror (lua_State *L, const char *where) { void luaE_warnerror (lua_State *L, const char *where) {
TValue *errobj = s2v(L->top - 1); /* error object */ TValue *errobj = s2v(L->top.p - 1); /* error object */
const char *msg = (ttisstring(errobj)) const char *msg = (ttisstring(errobj))
? svalue(errobj) ? svalue(errobj)
: "error object is not a string"; : "error object is not a string";

View file

@ -1,6 +1,9 @@
#ifndef lstate_h #ifndef lstate_h
#define lstate_h #define lstate_h
/* Some header files included here need this definition */
typedef struct CallInfo CallInfo;
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "third_party/lua/lobject.h" #include "third_party/lua/lobject.h"
#include "third_party/lua/lua.h" #include "third_party/lua/lua.h"
@ -133,7 +136,7 @@ struct lua_longjmp; /* defined in ldo.c */
#define BASIC_STACK_SIZE (2*LUA_MINSTACK) #define BASIC_STACK_SIZE (2*LUA_MINSTACK)
#define stacksize(th) cast_int((th)->stack_last - (th)->stack) #define stacksize(th) cast_int((th)->stack_last.p - (th)->stack.p)
/* kinds of Garbage Collection */ /* kinds of Garbage Collection */
@ -163,9 +166,9 @@ typedef struct stringtable {
** - field 'transferinfo' is used only during call/returnhooks, ** - field 'transferinfo' is used only during call/returnhooks,
** before the function starts or after it ends. ** before the function starts or after it ends.
*/ */
typedef struct CallInfo { struct CallInfo {
StkId func; /* function index in the stack */ StkIdRel func; /* function index in the stack */
StkId top; /* top for this function */ StkIdRel top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */ struct CallInfo *previous, *next; /* dynamic call link */
union { union {
struct { /* only for Lua functions */ struct { /* only for Lua functions */
@ -190,7 +193,7 @@ typedef struct CallInfo {
} u2; } u2;
short nresults; /* expected number of results from this function */ short nresults; /* expected number of results from this function */
unsigned short callstatus; unsigned short callstatus;
} CallInfo; };
/* /*
@ -285,7 +288,7 @@ typedef struct global_State {
struct lua_State *mainthread; struct lua_State *mainthread;
TString *memerrmsg; /* message for memory-allocation errors */ TString *memerrmsg; /* message for memory-allocation errors */
TString *tmname[TM_N]; /* array with tag-method names */ TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */ struct Table *mt[LUA_NUMTYPES]; /* metatables for basic types */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
lua_WarnFunction warnf; /* warning function */ lua_WarnFunction warnf; /* warning function */
void *ud_warn; /* auxiliary data to 'warnf' */ void *ud_warn; /* auxiliary data to 'warnf' */
@ -300,13 +303,13 @@ struct lua_State {
lu_byte status; lu_byte status;
lu_byte allowhook; lu_byte allowhook;
unsigned short nci; /* number of items in 'ci' list */ unsigned short nci; /* number of items in 'ci' list */
StkId top; /* first free slot in the stack */ StkIdRel top; /* first free slot in the stack */
global_State *l_G; global_State *l_G;
CallInfo *ci; /* call info for current function */ CallInfo *ci; /* call info for current function */
StkId stack_last; /* end of stack (last element + 1) */ StkIdRel stack_last; /* end of stack (last element + 1) */
StkId stack; /* stack base */ StkIdRel 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 */ StkIdRel 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 */

View file

@ -41,7 +41,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");

View file

@ -39,7 +39,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -614,7 +614,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 (l_unlikely(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 to optimize tail recursion */
if (p != ms->p_end) { /* end of pattern? */ if (p != ms->p_end) { /* end of pattern? */
switch (*p) { switch (*p) {
case '(': { /* start capture */ case '(': { /* start capture */

View file

@ -43,7 +43,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -130,7 +130,7 @@ static const TValue absentkey = {ABSTKEYCONSTANT};
*/ */
static Node *hashint (const Table *t, lua_Integer i) { static Node *hashint (const Table *t, lua_Integer i) {
lua_Unsigned ui = l_castS2U(i); lua_Unsigned ui = l_castS2U(i);
if (ui <= (unsigned int)INT_MAX) if (ui <= cast_uint(INT_MAX))
return hashmod(t, cast_int(ui)); return hashmod(t, cast_int(ui));
else else
return hashmod(t, ui); return hashmod(t, ui);
@ -280,9 +280,11 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) {
size |= (size >> 2); size |= (size >> 2);
size |= (size >> 4); size |= (size >> 4);
size |= (size >> 8); size |= (size >> 8);
#if (UINT_MAX >> 14) > 3 /* unsigned int has more than 16 bits */
size |= (size >> 16); size |= (size >> 16);
#if (UINT_MAX >> 30) > 3 #if (UINT_MAX >> 30) > 3
size |= (size >> 32); /* unsigned int has more than 32 bits */ size |= (size >> 32); /* unsigned int has more than 32 bits */
#endif
#endif #endif
size++; size++;
lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size); lua_assert(ispow2(size) && size/2 < t->alimit && t->alimit < size);
@ -511,7 +513,7 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
luaG_runerror(L, "table overflow"); luaG_runerror(L, "table overflow");
size = twoto(lsize); size = twoto(lsize);
t->node = luaM_newvector(L, size, Node); t->node = luaM_newvector(L, size, Node);
for (i = 0; i < (int)size; i++) { for (i = 0; i < cast_int(size); i++) {
Node *n = gnode(t, i); Node *n = gnode(t, i);
gnext(n) = 0; gnext(n) = 0;
setnilkey(n); setnilkey(n);
@ -998,6 +1000,4 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainpositionTV(t, key); return mainpositionTV(t, key);
} }
int luaH_isdummy (const Table *t) { return isdummy(t); }
#endif #endif

View file

@ -54,7 +54,6 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t);
#if defined(LUA_DEBUG) #if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key); LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
LUAI_FUNC int luaH_isdummy (const Table *t);
#endif #endif

View file

@ -39,7 +39,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -117,7 +117,7 @@ static int tremove (lua_State *L) {
lua_Integer pos = luaL_optinteger(L, 2, size); lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */ if (pos != size) /* validate 'pos' if given */
/* check whether 'pos' is in [1, size + 1] */ /* check whether 'pos' is in [1, size + 1] */
luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 1, luaL_argcheck(L, (lua_Unsigned)pos - 1u <= (lua_Unsigned)size, 2,
"position out of bounds"); "position out of bounds");
lua_geti(L, 1, pos); /* result = t[pos] */ lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) { for ( ; pos < size; pos++) {

View file

@ -48,7 +48,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -62,7 +62,7 @@ asm(".include \"libc/disclaimer.inc\"");
void *l_Trick = 0; void *l_Trick = 0;
#define obj_at(L,k) s2v(L->ci->func + (k)) #define obj_at(L,k) s2v(L->ci->func.p + (k))
static int runC (lua_State *L, lua_State *L1, const char *pc); static int runC (lua_State *L, lua_State *L1, const char *pc);
@ -75,7 +75,7 @@ static void setnameval (lua_State *L, const char *name, int val) {
static void pushobject (lua_State *L, const TValue *o) { static void pushobject (lua_State *L, const TValue *o) {
setobj2s(L, L->top, o); setobj2s(L, L->top.p, o);
api_incr_top(L); api_incr_top(L);
} }
@ -437,7 +437,7 @@ static void checkLclosure (global_State *g, LClosure *cl) {
if (uv) { if (uv) {
checkobjrefN(g, clgc, uv); checkobjrefN(g, clgc, uv);
if (!upisopen(uv)) if (!upisopen(uv))
checkvalref(g, obj2gco(uv), uv->v); checkvalref(g, obj2gco(uv), uv->v.p);
} }
} }
} }
@ -446,7 +446,7 @@ static void checkLclosure (global_State *g, LClosure *cl) {
static int lua_checkpc (CallInfo *ci) { static int lua_checkpc (CallInfo *ci) {
if (!isLua(ci)) return 1; if (!isLua(ci)) return 1;
else { else {
StkId f = ci->func; StkId f = ci->func.p;
Proto *p = clLvalue(s2v(f))->p; Proto *p = clLvalue(s2v(f))->p;
return p->code <= ci->u.l.savedpc && return p->code <= ci->u.l.savedpc &&
ci->u.l.savedpc <= p->code + p->sizecode; ci->u.l.savedpc <= p->code + p->sizecode;
@ -459,19 +459,19 @@ static void checkstack (global_State *g, lua_State *L1) {
CallInfo *ci; CallInfo *ci;
UpVal *uv; UpVal *uv;
assert(!isdead(g, L1)); assert(!isdead(g, L1));
if (L1->stack == NULL) { /* incomplete thread? */ if (L1->stack.p == NULL) { /* incomplete thread? */
assert(L1->openupval == NULL && L1->ci == NULL); assert(L1->openupval == NULL && L1->ci == NULL);
return; return;
} }
for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next) for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next)
assert(upisopen(uv)); /* must be open */ assert(upisopen(uv)); /* must be open */
assert(L1->top <= L1->stack_last); assert(L1->top.p <= L1->stack_last.p);
assert(L1->tbclist <= L1->top); assert(L1->tbclist.p <= L1->top.p);
for (ci = L1->ci; ci != NULL; ci = ci->previous) { for (ci = L1->ci; ci != NULL; ci = ci->previous) {
assert(ci->top <= L1->stack_last); assert(ci->top.p <= L1->stack_last.p);
assert(lua_checkpc(ci)); assert(lua_checkpc(ci));
} }
for (o = L1->stack; o < L1->stack_last; o++) for (o = L1->stack.p; o < L1->stack_last.p; o++)
checkliveness(L1, s2v(o)); /* entire stack must have valid values */ checkliveness(L1, s2v(o)); /* entire stack must have valid values */
} }
@ -483,7 +483,7 @@ static void checkrefs (global_State *g, GCObject *o) {
break; break;
} }
case LUA_VUPVAL: { case LUA_VUPVAL: {
checkvalref(g, o, gco2upv(o)->v); checkvalref(g, o, gco2upv(o)->v.p);
break; break;
} }
case LUA_VTABLE: { case LUA_VTABLE: {
@ -551,7 +551,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead,
static lu_mem checkgraylist (global_State *g, GCObject *o) { static lu_mem checkgraylist (global_State *g, GCObject *o) {
int total = 0; /* count number of elements in the list */ int total = 0; /* count number of elements in the list */
((void)g); /* better to keep it available if we need to print an object */ cast_void(g); /* better to keep it if we need to print an object */
while (o) { while (o) {
assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2)); assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2));
assert(!testbit(o->marked, TESTBIT)); assert(!testbit(o->marked, TESTBIT));
@ -998,7 +998,7 @@ static int hash_query (lua_State *L) {
static int stacklevel (lua_State *L) { static int stacklevel (lua_State *L) {
unsigned long a = 0; unsigned long a = 0;
lua_pushinteger(L, (L->top - L->stack)); lua_pushinteger(L, (L->top.p - L->stack.p));
lua_pushinteger(L, stacksize(L)); lua_pushinteger(L, stacksize(L));
lua_pushinteger(L, L->nCcalls); lua_pushinteger(L, L->nCcalls);
lua_pushinteger(L, L->nci); lua_pushinteger(L, L->nci);
@ -1058,7 +1058,7 @@ static int string_query (lua_State *L) {
TString *ts; TString *ts;
int n = 0; int n = 0;
for (ts = tb->hash[s]; ts != NULL; ts = ts->u.hnext) { for (ts = tb->hash[s]; ts != NULL; ts = ts->u.hnext) {
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top.p, ts);
api_incr_top(L); api_incr_top(L);
n++; n++;
} }
@ -1073,7 +1073,7 @@ static int tref (lua_State *L) {
luaL_checkany(L, 1); luaL_checkany(L, 1);
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX)); lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX));
(void)level; /* to avoid warnings */ cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level+1); /* +1 for result */ lua_assert(lua_gettop(L) == level+1); /* +1 for result */
return 1; return 1;
} }
@ -1081,7 +1081,7 @@ static int tref (lua_State *L) {
static int getref (lua_State *L) { static int getref (lua_State *L) {
int level = lua_gettop(L); int level = lua_gettop(L);
lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkinteger(L, 1)); lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkinteger(L, 1));
(void)level; /* to avoid warnings */ cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level+1); lua_assert(lua_gettop(L) == level+1);
return 1; return 1;
} }
@ -1089,7 +1089,7 @@ static int getref (lua_State *L) {
static int unref (lua_State *L) { static int unref (lua_State *L) {
int level = lua_gettop(L); int level = lua_gettop(L);
luaL_unref(L, LUA_REGISTRYINDEX, cast_int(luaL_checkinteger(L, 1))); luaL_unref(L, LUA_REGISTRYINDEX, cast_int(luaL_checkinteger(L, 1)));
(void)level; /* to avoid warnings */ cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level); lua_assert(lua_gettop(L) == level);
return 0; return 0;
} }
@ -1551,7 +1551,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
lua_newthread(L1); lua_newthread(L1);
} }
else if EQ("resetthread") { else if EQ("resetthread") {
lua_pushinteger(L1, lua_resetthread(L1)); lua_pushinteger(L1, lua_resetthread(L1, L));
} }
else if EQ("newuserdata") { else if EQ("newuserdata") {
lua_newuserdata(L1, getnum); lua_newuserdata(L1, getnum);
@ -1758,7 +1758,7 @@ static struct X { int x; } x;
else if EQ("tostring") { else if EQ("tostring") {
const char *s = lua_tostring(L1, getindex); const char *s = lua_tostring(L1, getindex);
const char *s1 = lua_pushstring(L1, s); const char *s1 = lua_pushstring(L1, s);
(void)s1; /* to avoid warnings */ cast_void(s1); /* to avoid warnings */
lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0); lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0);
} }
else if EQ("Ltolstring") { else if EQ("Ltolstring") {

View file

@ -119,6 +119,13 @@ LUA_API void *debug_realloc (void *ud, void *block,
#define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; } #define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; }
/*
** This one is not compatible with tests for opcode optimizations,
** as it blocks some optimizations
#define MAXINDEXRK 0
*/
/* make stack-overflow tests run faster */ /* make stack-overflow tests run faster */
#undef LUAI_MAXSTACK #undef LUAI_MAXSTACK
#define LUAI_MAXSTACK 50000 #define LUAI_MAXSTACK 50000

40
third_party/lua/ltm.c vendored
View file

@ -43,7 +43,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -125,12 +125,12 @@ const char *luaT_objtypename (lua_State *L, const TValue *o) {
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1, void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, const TValue *p3) { const TValue *p2, const TValue *p3) {
StkId func = L->top; StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */ setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */ setobj2s(L, func + 2, p2); /* 2nd argument */
setobj2s(L, func + 3, p3); /* 3rd argument */ setobj2s(L, func + 3, p3); /* 3rd argument */
L->top = func + 4; L->top.p = func + 4;
/* metamethod may yield only when called from Lua code */ /* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci)) if (isLuacode(L->ci))
luaD_call(L, func, 0); luaD_call(L, func, 0);
@ -142,18 +142,18 @@ void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1, void luaT_callTMres (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, StkId res) { const TValue *p2, StkId res) {
ptrdiff_t result = savestack(L, res); ptrdiff_t result = savestack(L, res);
StkId func = L->top; StkId func = L->top.p;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */ setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */ setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */ setobj2s(L, func + 2, p2); /* 2nd argument */
L->top += 3; L->top.p += 3;
/* metamethod may yield only when called from Lua code */ /* metamethod may yield only when called from Lua code */
if (isLuacode(L->ci)) if (isLuacode(L->ci))
luaD_call(L, func, 1); luaD_call(L, func, 1);
else else
luaD_callnoyield(L, func, 1); luaD_callnoyield(L, func, 1);
res = restorestack(L, result); res = restorestack(L, result);
setobjs2s(L, res, --L->top); /* move result to its place */ setobjs2s(L, res, --L->top.p); /* move result to its place */
} }
@ -188,7 +188,7 @@ 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.p;
if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2,
TM_CONCAT))) TM_CONCAT)))
luaG_concaterror(L, s2v(top - 2), s2v(top - 1)); luaG_concaterror(L, s2v(top - 2), s2v(top - 1));
@ -223,15 +223,15 @@ void luaT_trybiniTM (lua_State *L, const TValue *p1, lua_Integer i2,
*/ */
int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2, int luaT_callorderTM (lua_State *L, const TValue *p1, const TValue *p2,
TMS event) { TMS event) {
if (callbinTM(L, p1, p2, L->top, event)) /* try original event */ if (callbinTM(L, p1, p2, L->top.p, event)) /* try original event */
return !l_isfalse(s2v(L->top)); return !l_isfalse(s2v(L->top.p));
#if defined(LUA_COMPAT_LT_LE) #if defined(LUA_COMPAT_LT_LE)
else if (event == TM_LE) { else if (event == TM_LE) {
/* try '!(p2 < p1)' for '(p1 <= p2)' */ /* try '!(p2 < p1)' for '(p1 <= p2)' */
L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */ L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
if (callbinTM(L, p2, p1, L->top, TM_LT)) { if (callbinTM(L, p2, p1, L->top.p, TM_LT)) {
L->ci->callstatus ^= CIST_LEQ; /* clear mark */ L->ci->callstatus ^= CIST_LEQ; /* clear mark */
return l_isfalse(s2v(L->top)); return l_isfalse(s2v(L->top.p));
} }
/* else error will remove this 'ci'; no need to clear mark */ /* else error will remove this 'ci'; no need to clear mark */
} }
@ -261,20 +261,20 @@ int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci, void luaT_adjustvarargs (lua_State *L, int nfixparams, CallInfo *ci,
const Proto *p) { const Proto *p) {
int i; int i;
int actual = cast_int(L->top - ci->func) - 1; /* number of arguments */ int actual = cast_int(L->top.p - ci->func.p) - 1; /* number of arguments */
int nextra = actual - nfixparams; /* number of extra arguments */ int nextra = actual - nfixparams; /* number of extra arguments */
ci->u.l.nextraargs = nextra; ci->u.l.nextraargs = nextra;
luaD_checkstack(L, p->maxstacksize + 1); luaD_checkstack(L, p->maxstacksize + 1);
/* copy function to the top of the stack */ /* copy function to the top of the stack */
setobjs2s(L, L->top++, ci->func); setobjs2s(L, L->top.p++, ci->func.p);
/* move fixed parameters to the top of the stack */ /* move fixed parameters to the top of the stack */
for (i = 1; i <= nfixparams; i++) { for (i = 1; i <= nfixparams; i++) {
setobjs2s(L, L->top++, ci->func + i); setobjs2s(L, L->top.p++, ci->func.p + i);
setnilvalue(s2v(ci->func + i)); /* erase original parameter (for GC) */ setnilvalue(s2v(ci->func.p + i)); /* erase original parameter (for GC) */
} }
ci->func += actual + 1; ci->func.p += actual + 1;
ci->top += actual + 1; ci->top.p += actual + 1;
lua_assert(L->top <= ci->top && ci->top <= L->stack_last); lua_assert(L->top.p <= ci->top.p && ci->top.p <= L->stack_last.p);
} }
@ -284,10 +284,10 @@ void luaT_getvarargs (lua_State *L, CallInfo *ci, StkId where, int wanted) {
if (wanted < 0) { if (wanted < 0) {
wanted = nextra; /* get all extra arguments available */ wanted = nextra; /* get all extra arguments available */
checkstackGCp(L, nextra, where); /* ensure stack space */ checkstackGCp(L, nextra, where); /* ensure stack space */
L->top = where + nextra; /* next instruction will need top */ L->top.p = where + nextra; /* next instruction will need top */
} }
for (i = 0; i < wanted && i < nextra; i++) for (i = 0; i < wanted && i < nextra; i++)
setobjs2s(L, where + i, ci->func - nextra + i); setobjs2s(L, where + i, ci->func.p - nextra + i);
for (; i < wanted; i++) /* complete required results with nil */ for (; i < wanted; i++) /* complete required results with nil */
setnilvalue(s2v(where + i)); setnilvalue(s2v(where + i));
} }

View file

@ -2,6 +2,7 @@
#define ltm_h #define ltm_h
#include "third_party/lua/lobject.h" #include "third_party/lua/lobject.h"
#include "third_party/lua/lstate.h"
#include "third_party/lua/luaconf.h" #include "third_party/lua/luaconf.h"
#include "third_party/lua/tms.h" #include "third_party/lua/tms.h"
@ -63,8 +64,8 @@ LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2,
int inv, int isfloat, TMS event); int inv, int isfloat, TMS event);
LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams,
struct CallInfo *ci, const Proto *p); CallInfo *ci, const Proto *p);
LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci,
StkId where, int wanted); StkId where, int wanted);

24
third_party/lua/lua.h vendored
View file

@ -10,14 +10,14 @@ COSMOPOLITAN_C_START_
#define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4" #define LUA_VERSION_MINOR "4"
#define LUA_VERSION_RELEASE "4" #define LUA_VERSION_RELEASE "5"
#define LUA_VERSION_NUM 504 #define LUA_VERSION_NUM 504
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4) #define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 5)
#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-2022 Lua.org, PUC-Rio" #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 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"
@ -123,6 +123,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont); typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
/*
** Type used by the debug API to collect debug information
*/
typedef struct lua_Debug lua_Debug;
/*
** Functions to be called by the debugger in specific events
*/
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
/* /*
@ -145,7 +155,7 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L); LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L); LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API int (lua_resetthread) (lua_State *L); LUA_API int (lua_resetthread) (lua_State *L, lua_State *from);
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
@ -434,12 +444,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
#define LUA_MASKLINE (1 << LUA_HOOKLINE) #define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debugger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);

View file

@ -55,7 +55,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -117,10 +117,11 @@ static void print_version (void) {
** to the script (everything after 'script') go to positive indices; ** to the script (everything after 'script') go to positive indices;
** other arguments (before the script name) go to negative indices. ** other arguments (before the script name) go to negative indices.
** If there is no script name, assume interpreter's name as base. ** If there is no script name, assume interpreter's name as base.
** (If there is no interpreter's name either, 'script' is -1, so
** table sizes are zero.)
*/ */
static void createargtable (lua_State *L, char **argv, int argc, int script) { static void createargtable (lua_State *L, char **argv, int argc, int script) {
int i, narg; int i, narg;
if (script == argc) script = 0; /* no script name? */
narg = argc - (script + 1); /* number of positive indices */ narg = argc - (script + 1); /* number of positive indices */
lua_createtable(L, narg, script + 1); lua_createtable(L, narg, script + 1);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
@ -161,10 +162,10 @@ static int dolibrary (lua_State *L, char *globname) {
} }
lua_getglobal(L, "require"); lua_getglobal(L, "require");
lua_pushstring(L, modname); lua_pushstring(L, modname);
status = docall(L, 1, 1); /* call 'require(modname)' */ status = lua_runchunk(L, 1, 1); /* call 'require(modname)' */
if (status == LUA_OK) if (status == LUA_OK)
lua_setglobal(L, globname); /* globname = require(modname) */ lua_setglobal(L, globname); /* globname = require(modname) */
return report(L, status); return lua_report(L, status);
} }
@ -208,14 +209,23 @@ static int handle_script (lua_State *L, char **argv) {
/* /*
** Traverses all arguments from 'argv', returning a mask with those ** Traverses all arguments from 'argv', returning a mask with those
** needed before running any Lua code (or an error code if it finds ** needed before running any Lua code or an error code if it finds any
** any invalid argument). 'first' returns the first not-handled argument ** invalid argument. In case of error, 'first' is the index of the bad
** (either the script name or a bad argument in case of error). ** argument. Otherwise, 'first' is -1 if there is no program name,
** 0 if there is no script name, or the index of the script name.
*/ */
static int collectargs (char **argv, int *first) { static int collectargs (char **argv, int *first) {
int args = 0; int args = 0;
int i; int i;
for (i = 1; argv[i] != NULL; i++) { if (argv[0] != NULL) { /* is there a program name? */
if (argv[0][0]) /* not empty? */
lua_progname = argv[0]; /* save it */
}
else { /* no program name */
*first = -1;
return 0;
}
for (i = 1; argv[i] != NULL; i++) { /* handle arguments */
*first = i; *first = i;
if (argv[i][0] != '-') /* not an option? */ if (argv[i][0] != '-') /* not an option? */
return args; /* stop handling options */ return args; /* stop handling options */
@ -256,7 +266,7 @@ static int collectargs (char **argv, int *first) {
return has_error; return has_error;
} }
} }
*first = i; /* no script name */ *first = 0; /* no script name */
return args; return args;
} }
@ -362,9 +372,8 @@ static int pmain (lua_State *L) {
char **argv = (char **)lua_touserdata(L, 2); char **argv = (char **)lua_touserdata(L, 2);
int script; int script;
int args = collectargs(argv, &script); int args = collectargs(argv, &script);
int optlim = (script > 0) ? script : argc; /* first argv not an option */
luaL_checkversion(L); /* check that interpreter has correct version */ luaL_checkversion(L); /* check that interpreter has correct version */
lua_progname = LUA_PROGNAME;
if (argv[0] && argv[0][0]) lua_progname = argv[0];
if (args == has_error) { /* bad arg? */ if (args == has_error) { /* bad arg? */
print_usage(argv[script]); /* 'script' has index of bad arg. */ print_usage(argv[script]); /* 'script' has index of bad arg. */
return 0; return 0;
@ -379,19 +388,21 @@ static int pmain (lua_State *L) {
luaL_requiref(L, "unix", LuaUnix, 1); luaL_requiref(L, "unix", LuaUnix, 1);
lua_pop(L, 1); lua_pop(L, 1);
createargtable(L, argv, argc, script); /* create table 'arg' */ createargtable(L, argv, argc, script); /* create table 'arg' */
lua_gc(L, LUA_GCGEN, 0, 0); /* GC in generational mode */ lua_gc(L, LUA_GCRESTART); /* start GC... */
lua_gc(L, LUA_GCGEN, 0, 0); /* ...in generational mode */
if (!(args & has_E)) { /* no option '-E'? */ if (!(args & has_E)) { /* no option '-E'? */
if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */ if (handle_luainit(L) != LUA_OK) /* run LUA_INIT */
return 0; /* error running LUA_INIT */ return 0; /* error running LUA_INIT */
} }
if (!runargs(L, argv, script)) /* execute arguments -e and -l */ if (!runargs(L, argv, optlim)) /* execute arguments -e and -l */
return 0; /* something failed */ return 0; /* something failed */
if (script < argc && /* execute main script (if there is one) */ if (script > 0) { /* execute main script (if there is one) */
handle_script(L, argv + script) != LUA_OK) if (handle_script(L, argv + script) != LUA_OK)
return 0; return 0; /* interrupt in case of error */
}
if (args & has_i) /* -i option? */ if (args & has_i) /* -i option? */
doREPL(L); /* do read-eval-print loop */ doREPL(L); /* do read-eval-print loop */
else if (script == argc && !(args & (has_e | has_v))) { /* no arguments? */ else if (script < 1 && !(args & (has_e | has_v))) { /* no active option? */
if (lua_stdin_is_tty()) { /* running in interactive mode? */ if (lua_stdin_is_tty()) { /* running in interactive mode? */
print_version(); print_version();
doREPL(L); /* do read-eval-print loop */ doREPL(L); /* do read-eval-print loop */
@ -415,6 +426,7 @@ int main (int argc, char **argv) {
lua_l_message(argv[0], "cannot create state: not enough memory"); lua_l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
lua_gc(L, LUA_GCSTOP); /* stop GC while building state */
lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */ lua_pushcfunction(L, &pmain); /* to call 'pmain' in protected mode */
lua_pushinteger(L, argc); /* 1st argument */ lua_pushinteger(L, argc); /* 1st argument */
lua_pushlightuserdata(L, argv); /* 2nd argument */ lua_pushlightuserdata(L, argv); /* 2nd argument */

View file

@ -48,7 +48,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -149,7 +149,7 @@ static int doargs(int argc, char* argv[])
return i; return i;
} }
#define FUNCTION "(function()end)();" #define FUNCTION "(function()end)();\n"
static const char* reader(lua_State* L, void* ud, size_t* size) static const char* reader(lua_State* L, void* ud, size_t* size)
{ {
@ -166,7 +166,7 @@ static const char* reader(lua_State* L, void* ud, size_t* size)
} }
} }
#define toproto(L,i) getproto(s2v(L->top+(i))) #define toproto(L,i) getproto(s2v(L->top.p+(i)))
static const Proto* combine(lua_State* L, int n) static const Proto* combine(lua_State* L, int n)
{ {
@ -183,8 +183,6 @@ static const Proto* combine(lua_State* L, int n)
f->p[i]=toproto(L,i-n-1); f->p[i]=toproto(L,i-n-1);
if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0; if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0;
} }
luaM_freearray(L,f->lineinfo,f->sizelineinfo);
f->sizelineinfo=0;
return f; return f;
} }
} }

View file

@ -71,6 +71,12 @@
#endif #endif
#if defined(LUA_USE_IOS)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN
#endif
/* /*
@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits. @@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
*/ */
@ -665,7 +671,7 @@
** CHANGE it if you need a different limit. This limit is arbitrary; ** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack ** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices). ** space (and to reserve some numbers for pseudo-indices).
** (It must fit into max(size_t)/32.) ** (It must fit into max(size_t)/32 and max(int)/2.)
*/ */
#if LUAI_IS32INT #if LUAI_IS32INT
#define LUAI_MAXSTACK 1000000 #define LUAI_MAXSTACK 1000000
@ -684,14 +690,15 @@
/* /*
@@ LUA_IDSIZE gives the maximum size for the description of the source @@ LUA_IDSIZE gives the maximum size for the description of the source
@@ of a function in debug information. ** of a function in debug information.
** CHANGE it if you want a different size. ** CHANGE it if you want a different size.
*/ */
#define LUA_IDSIZE 60 #define LUA_IDSIZE 60
/* /*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. @@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
** buffer system.
*/ */
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number))) #define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))

View file

@ -43,7 +43,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -143,10 +143,10 @@ static TString *loadStringN (LoadState *S, Proto *p) {
} }
else { /* long string */ else { /* long string */
ts = luaS_createlngstrobj(L, size); /* create string */ ts = luaS_createlngstrobj(L, size); /* create string */
setsvalue2s(L, L->top, ts); /* anchor it ('loadVector' can GC) */ setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */
luaD_inctop(L); luaD_inctop(L);
loadVector(S, getstr(ts), size); /* load directly in final place */ loadVector(S, getstr(ts), size); /* load directly in final place */
L->top--; /* pop string */ L->top.p--; /* pop string */
} }
luaC_objbarrier(L, p, ts); luaC_objbarrier(L, p, ts);
return ts; return ts;
@ -271,6 +271,8 @@ static void loadDebug (LoadState *S, Proto *f) {
f->locvars[i].endpc = loadInt(S); f->locvars[i].endpc = loadInt(S);
} }
n = loadInt(S); n = loadInt(S);
if (n != 0) /* does it have debug information? */
n = f->sizeupvalues; /* must be this many */
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
f->upvalues[i].name = loadStringN(S, f); f->upvalues[i].name = loadStringN(S, f);
} }
@ -344,7 +346,7 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
S.Z = Z; S.Z = Z;
checkHeader(&S); checkHeader(&S);
cl = luaF_newLclosure(L, loadByte(&S)); cl = luaF_newLclosure(L, loadByte(&S));
setclLvalue2s(L, L->top, cl); setclLvalue2s(L, L->top.p, cl);
luaD_inctop(L); luaD_inctop(L);
cl->p = luaF_newproto(L); cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p); luaC_objbarrier(L, cl, cl->p);

View file

@ -36,7 +36,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -45,6 +45,9 @@ asm(".include \"libc/disclaimer.inc\"");
#define MAXUTF 0x7FFFFFFFu #define MAXUTF 0x7FFFFFFFu
#define MSGInvalid "invalid UTF-8 code"
/* /*
** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits. ** Integer type for decoded UTF-8 values; MAXUTF needs 31 bits.
*/ */
@ -55,7 +58,8 @@ typedef unsigned long utfint;
#endif #endif
#define iscont(p) ((*(p) & 0xC0) == 0x80) #define iscont(c) (((c) & 0xC0) == 0x80)
#define iscontp(p) iscont(*(p))
/* from strlib */ /* from strlib */
@ -85,7 +89,7 @@ static const char *utf8_decode (const char *s, utfint *val, int strict) {
int count = 0; /* to count number of continuation bytes */ int count = 0; /* to count number of continuation bytes */
for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */ for (; c & 0x40; c <<= 1) { /* while it needs continuation bytes... */
unsigned int cc = (unsigned char)s[++count]; /* read next byte */ unsigned int cc = (unsigned char)s[++count]; /* read next byte */
if ((cc & 0xC0) != 0x80) /* not a continuation byte? */ if (!iscont(cc)) /* not a continuation byte? */
return NULL; /* invalid byte sequence */ return NULL; /* invalid byte sequence */
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */ res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
} }
@ -160,7 +164,7 @@ static int codepoint (lua_State *L) {
utfint code; utfint code;
s = utf8_decode(s, &code, !lax); s = utf8_decode(s, &code, !lax);
if (s == NULL) if (s == NULL)
return luaL_error(L, "invalid UTF-8 code"); return luaL_error(L, MSGInvalid);
lua_pushinteger(L, code); lua_pushinteger(L, code);
n++; n++;
} }
@ -210,16 +214,16 @@ static int byteoffset (lua_State *L) {
"position out of bounds"); "position out of bounds");
if (n == 0) { if (n == 0) {
/* find beginning of current byte sequence */ /* find beginning of current byte sequence */
while (posi > 0 && iscont(s + posi)) posi--; while (posi > 0 && iscontp(s + posi)) posi--;
} }
else { else {
if (iscont(s + posi)) if (iscontp(s + posi))
return luaL_error(L, "initial position is a continuation byte"); return luaL_error(L, "initial position is a continuation byte");
if (n < 0) { if (n < 0) {
while (n < 0 && posi > 0) { /* move back */ while (n < 0 && posi > 0) { /* move back */
do { /* find beginning of previous character */ do { /* find beginning of previous character */
posi--; posi--;
} while (posi > 0 && iscont(s + posi)); } while (posi > 0 && iscontp(s + posi));
n++; n++;
} }
} }
@ -228,7 +232,7 @@ static int byteoffset (lua_State *L) {
while (n > 0 && posi < (lua_Integer)len) { while (n > 0 && posi < (lua_Integer)len) {
do { /* find beginning of next character */ do { /* find beginning of next character */
posi++; posi++;
} while (iscont(s + posi)); /* (cannot pass final '\0') */ } while (iscontp(s + posi)); /* (cannot pass final '\0') */
n--; n--;
} }
} }
@ -246,15 +250,15 @@ static int iter_aux (lua_State *L, int strict) {
const char *s = luaL_checklstring(L, 1, &len); const char *s = luaL_checklstring(L, 1, &len);
lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2); lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2);
if (n < len) { if (n < len) {
while (iscont(s + n)) n++; /* skip continuation bytes */ while (iscontp(s + n)) n++; /* go to next character */
} }
if (n >= len) /* (also handles original 'n' being negative) */ if (n >= len) /* (also handles original 'n' being negative) */
return 0; /* no more codepoints */ return 0; /* no more codepoints */
else { else {
utfint code; utfint code;
const char *next = utf8_decode(s + n, &code, strict); const char *next = utf8_decode(s + n, &code, strict);
if (next == NULL) if (next == NULL || iscontp(next))
return luaL_error(L, "invalid UTF-8 code"); return luaL_error(L, MSGInvalid);
lua_pushinteger(L, n + 1); lua_pushinteger(L, n + 1);
lua_pushinteger(L, code); lua_pushinteger(L, code);
return 2; return 2;
@ -273,7 +277,8 @@ static int iter_auxlax (lua_State *L) {
static int iter_codes (lua_State *L) { static int iter_codes (lua_State *L) {
int lax = lua_toboolean(L, 2); int lax = lua_toboolean(L, 2);
luaL_checkstring(L, 1); const char *s = luaL_checkstring(L, 1);
luaL_argcheck(L, !iscontp(s), 1, MSGInvalid);
lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict); lua_pushcfunction(L, lax ? iter_auxlax : iter_auxstrict);
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
lua_pushinteger(L, 0); lua_pushinteger(L, 0);

185
third_party/lua/lvm.c vendored
View file

@ -46,7 +46,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.3 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
@ -628,8 +628,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (tm == NULL) /* no TM? */ if (tm == NULL) /* no TM? */
return 0; /* objects are different */ return 0; /* objects are different */
else { else {
luaT_callTMres(L, tm, t1, t2, L->top); /* call TM */ luaT_callTMres(L, tm, t1, t2, L->top.p); /* call TM */
return !l_isfalse(s2v(L->top)); return !l_isfalse(s2v(L->top.p));
} }
} }
@ -653,17 +653,17 @@ static void copy2buff (StkId top, int n, char *buff) {
/* /*
** Main operation for concatenation: concat 'total' values in the stack, ** Main operation for concatenation: concat 'total' values in the stack,
** from 'L->top - total' up to 'L->top - 1'. ** from 'L->top.p - total' up to 'L->top.p - 1'.
*/ */
void luaV_concat (lua_State *L, int total) { void luaV_concat (lua_State *L, int total) {
if (total == 1) if (total == 1)
return; /* "all" values already concatenated */ return; /* "all" values already concatenated */
do { do {
StkId top = L->top; StkId top = L->top.p;
int n = 2; /* number of elements handled in this pass (at least 2) */ int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) || if (!(ttisstring(s2v(top - 2)) || cvt2str(s2v(top - 2))) ||
!tostring(L, s2v(top - 1))) !tostring(L, s2v(top - 1)))
luaT_tryconcatTM(L); luaT_tryconcatTM(L); /* may invalidate 'top' */
else if (isemptystr(s2v(top - 1))) /* second operand is empty? */ else if (isemptystr(s2v(top - 1))) /* second operand is empty? */
cast_void(tostring(L, s2v(top - 2))); /* result is first operand */ cast_void(tostring(L, s2v(top - 2))); /* result is first operand */
else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */ else if (isemptystr(s2v(top - 2))) { /* first operand is empty string? */
@ -676,8 +676,10 @@ 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 (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) {
L->top.p = top - total; /* pop strings to avoid wasting stack */
luaG_runerror(L, "string length overflow"); luaG_runerror(L, "string length overflow");
}
tl += l; tl += l;
} }
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */ if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
@ -691,8 +693,8 @@ void luaV_concat (lua_State *L, int total) {
} }
setsvalue2s(L, top - n, ts); /* create result */ setsvalue2s(L, top - n, ts); /* create result */
} }
total -= n-1; /* got 'n' strings to create 1 new */ total -= n - 1; /* got 'n' strings to create one new */
L->top -= n-1; /* popped 'n' strings and pushed one */ L->top.p -= n - 1; /* popped 'n' strings and pushed one */
} while (total > 1); /* repeat until only 1 result left */ } while (total > 1); /* repeat until only 1 result left */
} }
@ -783,12 +785,10 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) {
/* number of bits in an integer */ /* number of bits in an integer */
#define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT) #define NBITS cast_int(sizeof(lua_Integer) * CHAR_BIT)
/* /*
** Shift left operation. (Shift right just negates 'y'.) ** Shift left operation. (Shift right just negates 'y'.)
*/ */
#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) {
if (y < 0) { /* shift right? */ if (y < 0) { /* shift right? */
if (y <= -NBITS) return 0; if (y <= -NBITS) return 0;
@ -828,26 +828,26 @@ static void pushclosure (lua_State *L, Proto *p, UpVal **encup, StkId base,
*/ */
void luaV_finishOp (lua_State *L) { void luaV_finishOp (lua_State *L) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
StkId base = ci->func + 1; StkId base = ci->func.p + 1;
Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */ Instruction inst = *(ci->u.l.savedpc - 1); /* interrupted instruction */
OpCode op = GET_OPCODE(inst); OpCode op = GET_OPCODE(inst);
switch (op) { /* finish its execution */ switch (op) { /* finish its execution */
case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: { case OP_MMBIN: case OP_MMBINI: case OP_MMBINK: {
setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top); setobjs2s(L, base + GETARG_A(*(ci->u.l.savedpc - 2)), --L->top.p);
break; break;
} }
case OP_UNM: case OP_BNOT: case OP_LEN: case OP_UNM: case OP_BNOT: case OP_LEN:
case OP_GETTABUP: case OP_GETTABLE: case OP_GETI: case OP_GETTABUP: case OP_GETTABLE: case OP_GETI:
case OP_GETFIELD: case OP_SELF: { case OP_GETFIELD: case OP_SELF: {
setobjs2s(L, base + GETARG_A(inst), --L->top); setobjs2s(L, base + GETARG_A(inst), --L->top.p);
break; break;
} }
case OP_LT: case OP_LE: case OP_LT: case OP_LE:
case OP_LTI: case OP_LEI: case OP_LTI: case OP_LEI:
case OP_GTI: case OP_GEI: case OP_GTI: case OP_GEI:
case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */ case OP_EQ: { /* note that 'OP_EQI'/'OP_EQK' cannot yield */
int res = !l_isfalse(s2v(L->top - 1)); int res = !l_isfalse(s2v(L->top.p - 1));
L->top--; L->top.p--;
#if defined(LUA_COMPAT_LT_LE) #if defined(LUA_COMPAT_LT_LE)
if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */ if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
ci->callstatus ^= CIST_LEQ; /* clear mark */ ci->callstatus ^= CIST_LEQ; /* clear mark */
@ -860,11 +860,11 @@ void luaV_finishOp (lua_State *L) {
break; break;
} }
case OP_CONCAT: { case OP_CONCAT: {
StkId top = L->top - 1; /* top when 'luaT_tryconcatTM' was called */ StkId top = L->top.p - 1; /* top when 'luaT_tryconcatTM' was called */
int a = GETARG_A(inst); /* first element to concatenate */ int a = GETARG_A(inst); /* first element to concatenate */
int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */ int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */
setobjs2s(L, top - 2, top); /* put TM result in proper position */ setobjs2s(L, top - 2, top); /* put TM result in proper position */
L->top = top - 1; /* top is one after last element (at top-2) */ L->top.p = top - 1; /* top is one after last element (at top-2) */
luaV_concat(L, total); /* concat them (may yield again) */ luaV_concat(L, total); /* concat them (may yield again) */
break; break;
} }
@ -876,7 +876,7 @@ void luaV_finishOp (lua_State *L) {
StkId ra = base + GETARG_A(inst); StkId ra = base + GETARG_A(inst);
/* adjust top to signal correct number of returns, in case the /* adjust top to signal correct number of returns, in case the
return is "up to top" ('isIT') */ return is "up to top" ('isIT') */
L->top = ra + ci->u2.nres; L->top.p = ra + ci->u2.nres;
/* repeat instruction to close other vars. and complete the return */ /* repeat instruction to close other vars. and complete the return */
ci->u.l.savedpc--; ci->u.l.savedpc--;
break; break;
@ -918,6 +918,7 @@ void luaV_finishOp (lua_State *L) {
** operation, 'fop' is the float operation. ** operation, 'fop' is the float operation.
*/ */
#define op_arithI(L,iop,fop) { \ #define op_arithI(L,iop,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
int imm = GETARG_sC(i); \ int imm = GETARG_sC(i); \
if (ttisinteger(v1)) { \ if (ttisinteger(v1)) { \
@ -946,6 +947,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over floats and others with register operands. ** Arithmetic operations over floats and others with register operands.
*/ */
#define op_arithf(L,fop) { \ #define op_arithf(L,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \ TValue *v2 = vRC(i); \
op_arithf_aux(L, v1, v2, fop); } op_arithf_aux(L, v1, v2, fop); }
@ -955,6 +957,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations with K operands for floats. ** Arithmetic operations with K operands for floats.
*/ */
#define op_arithfK(L,fop) { \ #define op_arithfK(L,fop) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \
op_arithf_aux(L, v1, v2, fop); } op_arithf_aux(L, v1, v2, fop); }
@ -964,6 +967,7 @@ void luaV_finishOp (lua_State *L) {
** Arithmetic operations over integers and floats. ** Arithmetic operations over integers and floats.
*/ */
#define op_arith_aux(L,v1,v2,iop,fop) { \ #define op_arith_aux(L,v1,v2,iop,fop) { \
StkId ra = RA(i); \
if (ttisinteger(v1) && ttisinteger(v2)) { \ if (ttisinteger(v1) && ttisinteger(v2)) { \
lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \ lua_Integer i1 = ivalue(v1); lua_Integer i2 = ivalue(v2); \
pc++; setivalue(s2v(ra), iop(L, i1, i2)); \ pc++; setivalue(s2v(ra), iop(L, i1, i2)); \
@ -993,6 +997,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with constant operand. ** Bitwise operations with constant operand.
*/ */
#define op_bitwiseK(L,op) { \ #define op_bitwiseK(L,op) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = KC(i); \ TValue *v2 = KC(i); \
lua_Integer i1; \ lua_Integer i1; \
@ -1006,6 +1011,7 @@ void luaV_finishOp (lua_State *L) {
** Bitwise operations with register operands. ** Bitwise operations with register operands.
*/ */
#define op_bitwise(L,op) { \ #define op_bitwise(L,op) { \
StkId ra = RA(i); \
TValue *v1 = vRB(i); \ TValue *v1 = vRB(i); \
TValue *v2 = vRC(i); \ TValue *v2 = vRC(i); \
lua_Integer i1; lua_Integer i2; \ lua_Integer i1; lua_Integer i2; \
@ -1020,6 +1026,7 @@ void luaV_finishOp (lua_State *L) {
** integers. ** integers.
*/ */
#define op_order(L,opi,opn,other) { \ #define op_order(L,opi,opn,other) { \
StkId ra = RA(i); \
int cond; \ int cond; \
TValue *rb = vRB(i); \ TValue *rb = vRB(i); \
if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \ if (ttisinteger(s2v(ra)) && ttisinteger(rb)) { \
@ -1039,6 +1046,7 @@ void luaV_finishOp (lua_State *L) {
** always small enough to have an exact representation as a float.) ** always small enough to have an exact representation as a float.)
*/ */
#define op_orderI(L,opi,opf,inv,tm) { \ #define op_orderI(L,opi,opf,inv,tm) { \
StkId ra = RA(i); \
int cond; \ int cond; \
int im = GETARG_sB(i); \ int im = GETARG_sB(i); \
if (ttisinteger(s2v(ra))) \ if (ttisinteger(s2v(ra))) \
@ -1081,7 +1089,7 @@ void luaV_finishOp (lua_State *L) {
#define updatetrap(ci) (trap = ci->u.l.trap) #define updatetrap(ci) (trap = ci->u.l.trap)
#define updatebase(ci) (base = ci->func + 1) #define updatebase(ci) (base = ci->func.p + 1)
#define updatestack(ci) \ #define updatestack(ci) \
@ -1116,7 +1124,7 @@ void luaV_finishOp (lua_State *L) {
** Whenever code can raise errors, the global 'pc' and the global ** Whenever code can raise errors, the global 'pc' and the global
** 'top' must be correct to report occasional errors. ** 'top' must be correct to report occasional errors.
*/ */
#define savestate(L,ci) (savepc(L), L->top = ci->top) #define savestate(L,ci) (savepc(L), L->top.p = ci->top.p)
/* /*
@ -1136,7 +1144,7 @@ void luaV_finishOp (lua_State *L) {
/* 'c' is the limit of live values in the stack */ /* 'c' is the limit of live values in the stack */
#define checkGC(L,c) \ #define checkGC(L,c) \
{ luaC_condGC(L, (savepc(L), L->top = (c)), \ { luaC_condGC(L, (savepc(L), L->top.p = (c)), \
updatetrap(ci)); \ updatetrap(ci)); \
luai_threadyield(L); } luai_threadyield(L); }
@ -1148,7 +1156,6 @@ void luaV_finishOp (lua_State *L) {
updatebase(ci); /* correct stack */ \ updatebase(ci); /* correct stack */ \
} \ } \
i = *(pc++); \ i = *(pc++); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
} }
#define vmdispatch(o) switch(o) #define vmdispatch(o) switch(o)
@ -1168,7 +1175,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
startfunc: startfunc:
trap = L->hookmask; trap = L->hookmask;
returning: /* trap already set */ returning: /* trap already set */
cl = clLvalue(s2v(ci->func)); cl = clLvalue(s2v(ci->func.p));
k = cl->p->k; k = cl->p->k;
pc = ci->u.l.savedpc; pc = ci->u.l.savedpc;
if (l_unlikely(trap)) { if (l_unlikely(trap)) {
@ -1180,60 +1187,68 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
} }
ci->u.l.trap = 1; /* assume trap is on, for now */ ci->u.l.trap = 1; /* assume trap is on, for now */
} }
base = ci->func + 1; base = ci->func.p + 1;
/* main loop of interpreter */ /* main loop of interpreter */
for (;;) { for (;;) {
Instruction i; /* instruction being executed */ Instruction i; /* instruction being executed */
StkId ra; /* instruction's A register */
vmfetch(); vmfetch();
#if 0 #if 0
/* low-level line tracing for debugging Lua */ /* low-level line tracing for debugging Lua */
printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p)));
#endif #endif
lua_assert(base == ci->func + 1); lua_assert(base == ci->func.p + 1);
lua_assert(base <= L->top && L->top < L->stack_last); lua_assert(base <= L->top.p && L->top.p <= L->stack_last.p);
/* invalidate top for instructions not expecting it */ /* invalidate top for instructions not expecting it */
lua_assert(isIT(i) || (cast_void(L->top = base), 1)); lua_assert(isIT(i) || (cast_void(L->top.p = base), 1));
vmdispatch (GET_OPCODE(i)) { vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) { vmcase(OP_MOVE) {
StkId ra = RA(i);
setobjs2s(L, ra, RB(i)); setobjs2s(L, ra, RB(i));
vmbreak; vmbreak;
} }
vmcase(OP_LOADI) { vmcase(OP_LOADI) {
StkId ra = RA(i);
lua_Integer b = GETARG_sBx(i); lua_Integer b = GETARG_sBx(i);
setivalue(s2v(ra), b); setivalue(s2v(ra), b);
vmbreak; vmbreak;
} }
vmcase(OP_LOADF) { vmcase(OP_LOADF) {
StkId ra = RA(i);
int b = GETARG_sBx(i); int b = GETARG_sBx(i);
setfltvalue(s2v(ra), cast_num(b)); setfltvalue(s2v(ra), cast_num(b));
vmbreak; vmbreak;
} }
vmcase(OP_LOADK) { vmcase(OP_LOADK) {
StkId ra = RA(i);
TValue *rb = k + GETARG_Bx(i); TValue *rb = k + GETARG_Bx(i);
setobj2s(L, ra, rb); setobj2s(L, ra, rb);
vmbreak; vmbreak;
} }
vmcase(OP_LOADKX) { vmcase(OP_LOADKX) {
StkId ra = RA(i);
TValue *rb; TValue *rb;
rb = k + GETARG_Ax(*pc); pc++; rb = k + GETARG_Ax(*pc); pc++;
setobj2s(L, ra, rb); setobj2s(L, ra, rb);
vmbreak; vmbreak;
} }
vmcase(OP_LOADFALSE) { vmcase(OP_LOADFALSE) {
StkId ra = RA(i);
setbfvalue(s2v(ra)); setbfvalue(s2v(ra));
vmbreak; vmbreak;
} }
vmcase(OP_LFALSESKIP) { vmcase(OP_LFALSESKIP) {
StkId ra = RA(i);
setbfvalue(s2v(ra)); setbfvalue(s2v(ra));
pc++; /* skip next instruction */ pc++; /* skip next instruction */
vmbreak; vmbreak;
} }
vmcase(OP_LOADTRUE) { vmcase(OP_LOADTRUE) {
StkId ra = RA(i);
setbtvalue(s2v(ra)); setbtvalue(s2v(ra));
vmbreak; vmbreak;
} }
vmcase(OP_LOADNIL) { vmcase(OP_LOADNIL) {
StkId ra = RA(i);
int b = GETARG_B(i); int b = GETARG_B(i);
do { do {
setnilvalue(s2v(ra++)); setnilvalue(s2v(ra++));
@ -1241,19 +1256,22 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETUPVAL) { vmcase(OP_GETUPVAL) {
StkId ra = RA(i);
int b = GETARG_B(i); int b = GETARG_B(i);
setobj2s(L, ra, cl->upvals[b]->v); setobj2s(L, ra, cl->upvals[b]->v.p);
vmbreak; vmbreak;
} }
vmcase(OP_SETUPVAL) { vmcase(OP_SETUPVAL) {
StkId ra = RA(i);
UpVal *uv = cl->upvals[GETARG_B(i)]; UpVal *uv = cl->upvals[GETARG_B(i)];
setobj(L, uv->v, s2v(ra)); setobj(L, uv->v.p, s2v(ra));
luaC_barrier(L, uv, s2v(ra)); luaC_barrier(L, uv, s2v(ra));
vmbreak; vmbreak;
} }
vmcase(OP_GETTABUP) { vmcase(OP_GETTABUP) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *upval = cl->upvals[GETARG_B(i)]->v; TValue *upval = cl->upvals[GETARG_B(i)]->v.p;
TValue *rc = KC(i); TValue *rc = KC(i);
TString *key = tsvalue(rc); /* key must be a string */ TString *key = tsvalue(rc); /* key must be a string */
if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) {
@ -1264,6 +1282,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETTABLE) { vmcase(OP_GETTABLE) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
TValue *rc = vRC(i); TValue *rc = vRC(i);
@ -1278,6 +1297,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETI) { vmcase(OP_GETI) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
int c = GETARG_C(i); int c = GETARG_C(i);
@ -1292,6 +1312,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_GETFIELD) { vmcase(OP_GETFIELD) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
TValue *rc = KC(i); TValue *rc = KC(i);
@ -1305,7 +1326,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
} }
vmcase(OP_SETTABUP) { vmcase(OP_SETTABUP) {
const TValue *slot; const TValue *slot;
TValue *upval = cl->upvals[GETARG_A(i)]->v; TValue *upval = cl->upvals[GETARG_A(i)]->v.p;
TValue *rb = KB(i); TValue *rb = KB(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
TString *key = tsvalue(rb); /* key must be a string */ TString *key = tsvalue(rb); /* key must be a string */
@ -1317,6 +1338,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SETTABLE) { vmcase(OP_SETTABLE) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); /* key (table is in 'ra') */ TValue *rb = vRB(i); /* key (table is in 'ra') */
TValue *rc = RKC(i); /* value */ TValue *rc = RKC(i); /* value */
@ -1331,6 +1353,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SETI) { vmcase(OP_SETI) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
int c = GETARG_B(i); int c = GETARG_B(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
@ -1345,6 +1368,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SETFIELD) { vmcase(OP_SETFIELD) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = KB(i); TValue *rb = KB(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
@ -1357,6 +1381,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_NEWTABLE) { vmcase(OP_NEWTABLE) {
StkId ra = RA(i);
int b = GETARG_B(i); /* log2(hash size) + 1 */ int b = GETARG_B(i); /* log2(hash size) + 1 */
int c = GETARG_C(i); /* array size */ int c = GETARG_C(i); /* array size */
Table *t; Table *t;
@ -1366,7 +1391,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
if (TESTARG_k(i)) /* non-zero extra argument? */ if (TESTARG_k(i)) /* non-zero extra argument? */
c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */ c += GETARG_Ax(*pc) * (MAXARG_C + 1); /* add it to size */
pc++; /* skip extra argument */ pc++; /* skip extra argument */
L->top = ra + 1; /* correct top in case of emergency GC */ L->top.p = ra + 1; /* correct top in case of emergency GC */
t = luaH_new(L); /* memory allocation */ t = luaH_new(L); /* memory allocation */
sethvalue2s(L, ra, t); sethvalue2s(L, ra, t);
if (b != 0 || c != 0) if (b != 0 || c != 0)
@ -1375,6 +1400,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SELF) { vmcase(OP_SELF) {
StkId ra = RA(i);
const TValue *slot; const TValue *slot;
TValue *rb = vRB(i); TValue *rb = vRB(i);
TValue *rc = RKC(i); TValue *rc = RKC(i);
@ -1404,6 +1430,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MODK) { vmcase(OP_MODK) {
savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_mod, luaV_modf); op_arithK(L, luaV_mod, luaV_modf);
vmbreak; vmbreak;
} }
@ -1416,6 +1443,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_IDIVK) { vmcase(OP_IDIVK) {
savestate(L, ci); /* in case of division by 0 */
op_arithK(L, luaV_idiv, luai_numidiv); op_arithK(L, luaV_idiv, luai_numidiv);
vmbreak; vmbreak;
} }
@ -1432,6 +1460,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SHRI) { vmcase(OP_SHRI) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
int ic = GETARG_sC(i); int ic = GETARG_sC(i);
lua_Integer ib; lua_Integer ib;
@ -1441,6 +1470,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_SHLI) { vmcase(OP_SHLI) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
int ic = GETARG_sC(i); int ic = GETARG_sC(i);
lua_Integer ib; lua_Integer ib;
@ -1462,6 +1492,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MOD) { vmcase(OP_MOD) {
savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_mod, luaV_modf); op_arith(L, luaV_mod, luaV_modf);
vmbreak; vmbreak;
} }
@ -1474,6 +1505,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_IDIV) { /* floor division */ vmcase(OP_IDIV) { /* floor division */
savestate(L, ci); /* in case of division by 0 */
op_arith(L, luaV_idiv, luai_numidiv); op_arith(L, luaV_idiv, luai_numidiv);
vmbreak; vmbreak;
} }
@ -1498,6 +1530,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MMBIN) { vmcase(OP_MMBIN) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */ Instruction pi = *(pc - 2); /* original arith. expression */
TValue *rb = vRB(i); TValue *rb = vRB(i);
TMS tm = (TMS)GETARG_C(i); TMS tm = (TMS)GETARG_C(i);
@ -1507,6 +1540,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MMBINI) { vmcase(OP_MMBINI) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */ Instruction pi = *(pc - 2); /* original arith. expression */
int imm = GETARG_sB(i); int imm = GETARG_sB(i);
TMS tm = (TMS)GETARG_C(i); TMS tm = (TMS)GETARG_C(i);
@ -1516,6 +1550,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_MMBINK) { vmcase(OP_MMBINK) {
StkId ra = RA(i);
Instruction pi = *(pc - 2); /* original arith. expression */ Instruction pi = *(pc - 2); /* original arith. expression */
TValue *imm = KB(i); TValue *imm = KB(i);
TMS tm = (TMS)GETARG_C(i); TMS tm = (TMS)GETARG_C(i);
@ -1525,6 +1560,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_UNM) { vmcase(OP_UNM) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
lua_Number nb; lua_Number nb;
if (ttisinteger(rb)) { if (ttisinteger(rb)) {
@ -1539,6 +1575,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_BNOT) { vmcase(OP_BNOT) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
lua_Integer ib; lua_Integer ib;
if (tointegerns(rb, &ib)) { if (tointegerns(rb, &ib)) {
@ -1549,6 +1586,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_NOT) { vmcase(OP_NOT) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
if (l_isfalse(rb)) if (l_isfalse(rb))
setbtvalue(s2v(ra)); setbtvalue(s2v(ra));
@ -1557,21 +1595,25 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_LEN) { vmcase(OP_LEN) {
StkId ra = RA(i);
Protect(luaV_objlen(L, ra, vRB(i))); Protect(luaV_objlen(L, ra, vRB(i)));
vmbreak; vmbreak;
} }
vmcase(OP_CONCAT) { vmcase(OP_CONCAT) {
StkId ra = RA(i);
int n = GETARG_B(i); /* number of elements to concatenate */ int n = GETARG_B(i); /* number of elements to concatenate */
L->top = ra + n; /* mark the end of concat operands */ L->top.p = ra + n; /* mark the end of concat operands */
ProtectNT(luaV_concat(L, n)); ProtectNT(luaV_concat(L, n));
checkGC(L, L->top); /* 'luaV_concat' ensures correct top */ checkGC(L, L->top.p); /* 'luaV_concat' ensures correct top */
vmbreak; vmbreak;
} }
vmcase(OP_CLOSE) { vmcase(OP_CLOSE) {
StkId ra = RA(i);
Protect(luaF_close(L, ra, LUA_OK, 1)); Protect(luaF_close(L, ra, LUA_OK, 1));
vmbreak; vmbreak;
} }
vmcase(OP_TBC) { vmcase(OP_TBC) {
StkId ra = RA(i);
/* create new to-be-closed upvalue */ /* create new to-be-closed upvalue */
halfProtect(luaF_newtbcupval(L, ra)); halfProtect(luaF_newtbcupval(L, ra));
vmbreak; vmbreak;
@ -1581,6 +1623,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_EQ) { vmcase(OP_EQ) {
StkId ra = RA(i);
int cond; int cond;
TValue *rb = vRB(i); TValue *rb = vRB(i);
Protect(cond = luaV_equalobj(L, s2v(ra), rb)); Protect(cond = luaV_equalobj(L, s2v(ra), rb));
@ -1596,6 +1639,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_EQK) { vmcase(OP_EQK) {
StkId ra = RA(i);
TValue *rb = KB(i); TValue *rb = KB(i);
/* basic types do not use '__eq'; we can use raw equality */ /* basic types do not use '__eq'; we can use raw equality */
int cond = luaV_rawequalobj(s2v(ra), rb); int cond = luaV_rawequalobj(s2v(ra), rb);
@ -1603,6 +1647,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_EQI) { vmcase(OP_EQI) {
StkId ra = RA(i);
int cond; int cond;
int im = GETARG_sB(i); int im = GETARG_sB(i);
if (ttisinteger(s2v(ra))) if (ttisinteger(s2v(ra)))
@ -1631,11 +1676,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_TEST) { vmcase(OP_TEST) {
StkId ra = RA(i);
int cond = !l_isfalse(s2v(ra)); int cond = !l_isfalse(s2v(ra));
docondjump(); docondjump();
vmbreak; vmbreak;
} }
vmcase(OP_TESTSET) { vmcase(OP_TESTSET) {
StkId ra = RA(i);
TValue *rb = vRB(i); TValue *rb = vRB(i);
if (l_isfalse(rb) == GETARG_k(i)) if (l_isfalse(rb) == GETARG_k(i))
pc++; pc++;
@ -1646,11 +1693,12 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_CALL) { vmcase(OP_CALL) {
StkId ra = RA(i);
CallInfo *newci; CallInfo *newci;
int b = GETARG_B(i); int b = GETARG_B(i);
int nresults = GETARG_C(i) - 1; int nresults = GETARG_C(i) - 1;
if (b != 0) /* fixed number of arguments? */ if (b != 0) /* fixed number of arguments? */
L->top = ra + b; /* top signals number of arguments */ L->top.p = ra + b; /* top signals number of arguments */
/* else previous instruction set top */ /* else previous instruction set top */
savepc(L); /* in case of errors */ savepc(L); /* in case of errors */
if ((newci = luaD_precall(L, ra, nresults)) == NULL) if ((newci = luaD_precall(L, ra, nresults)) == NULL)
@ -1662,54 +1710,57 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_TAILCALL) { vmcase(OP_TAILCALL) {
StkId ra = RA(i);
int b = GETARG_B(i); /* number of arguments + 1 (function) */ int b = GETARG_B(i); /* number of arguments + 1 (function) */
int n; /* number of results when calling a C function */ int n; /* number of results when calling a C function */
int nparams1 = GETARG_C(i); int nparams1 = GETARG_C(i);
/* delta is virtual 'func' - real 'func' (vararg functions) */ /* delta is virtual 'func' - real 'func' (vararg functions) */
int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0;
if (b != 0) if (b != 0)
L->top = ra + b; L->top.p = ra + b;
else /* previous instruction set top */ else /* previous instruction set top */
b = cast_int(L->top - ra); b = cast_int(L->top.p - 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)) {
luaF_closeupval(L, base); /* close upvalues from current call */ luaF_closeupval(L, base); /* close upvalues from current call */
lua_assert(L->tbclist < base); /* no pending tbc variables */ lua_assert(L->tbclist.p < base); /* no pending tbc variables */
lua_assert(base == ci->func + 1); lua_assert(base == ci->func.p + 1);
} }
if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */ if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */
goto startfunc; /* execute the callee */ goto startfunc; /* execute the callee */
else { /* C function? */ else { /* C function? */
ci->func -= delta; /* restore 'func' (if vararg) */ ci->func.p -= delta; /* restore 'func' (if vararg) */
luaD_poscall(L, ci, n); /* finish caller */ luaD_poscall(L, ci, n); /* finish caller */
updatetrap(ci); /* 'luaD_poscall' can change hooks */ updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; /* caller returns after the tail call */ goto ret; /* caller returns after the tail call */
} }
} }
vmcase(OP_RETURN) { vmcase(OP_RETURN) {
StkId ra = RA(i);
int n = GETARG_B(i) - 1; /* number of results */ int n = GETARG_B(i) - 1; /* number of results */
int nparams1 = GETARG_C(i); int nparams1 = GETARG_C(i);
if (n < 0) /* not fixed? */ if (n < 0) /* not fixed? */
n = cast_int(L->top - ra); /* get what is available */ n = cast_int(L->top.p - ra); /* get what is available */
savepc(ci); savepc(ci);
if (TESTARG_k(i)) { /* may there be open upvalues? */ if (TESTARG_k(i)) { /* may there be open upvalues? */
ci->u2.nres = n; /* save number of returns */ ci->u2.nres = n; /* save number of returns */
if (L->top < ci->top) if (L->top.p < ci->top.p)
L->top = ci->top; L->top.p = ci->top.p;
luaF_close(L, base, CLOSEKTOP, 1); luaF_close(L, base, CLOSEKTOP, 1);
updatetrap(ci); updatetrap(ci);
updatestack(ci); updatestack(ci);
} }
if (nparams1) /* vararg function? */ if (nparams1) /* vararg function? */
ci->func -= ci->u.l.nextraargs + nparams1; ci->func.p -= ci->u.l.nextraargs + nparams1;
L->top = ra + n; /* set call for 'luaD_poscall' */ L->top.p = ra + n; /* set call for 'luaD_poscall' */
luaD_poscall(L, ci, n); luaD_poscall(L, ci, n);
updatetrap(ci); /* 'luaD_poscall' can change hooks */ updatetrap(ci); /* 'luaD_poscall' can change hooks */
goto ret; goto ret;
} }
vmcase(OP_RETURN0) { vmcase(OP_RETURN0) {
if (l_unlikely(L->hookmask)) { if (l_unlikely(L->hookmask)) {
L->top = ra; StkId ra = RA(i);
L->top.p = ra;
savepc(ci); savepc(ci);
luaD_poscall(L, ci, 0); /* no hurry... */ luaD_poscall(L, ci, 0); /* no hurry... */
trap = 1; trap = 1;
@ -1717,15 +1768,16 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
else { /* do the 'poscall' here */ else { /* do the 'poscall' here */
int nres; int nres;
L->ci = ci->previous; /* back to caller */ L->ci = ci->previous; /* back to caller */
L->top = base - 1; L->top.p = base - 1;
for (nres = ci->nresults; l_unlikely(nres > 0); nres--) for (nres = ci->nresults; l_unlikely(nres > 0); nres--)
setnilvalue(s2v(L->top++)); /* all results are nil */ setnilvalue(s2v(L->top.p++)); /* all results are nil */
} }
goto ret; goto ret;
} }
vmcase(OP_RETURN1) { vmcase(OP_RETURN1) {
if (l_unlikely(L->hookmask)) { if (l_unlikely(L->hookmask)) {
L->top = ra + 1; StkId ra = RA(i);
L->top.p = ra + 1;
savepc(ci); savepc(ci);
luaD_poscall(L, ci, 1); /* no hurry... */ luaD_poscall(L, ci, 1); /* no hurry... */
trap = 1; trap = 1;
@ -1734,12 +1786,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
int nres = ci->nresults; int nres = ci->nresults;
L->ci = ci->previous; /* back to caller */ L->ci = ci->previous; /* back to caller */
if (nres == 0) if (nres == 0)
L->top = base - 1; /* asked for no results */ L->top.p = base - 1; /* asked for no results */
else { else {
StkId ra = RA(i);
setobjs2s(L, base - 1, ra); /* at least this result */ setobjs2s(L, base - 1, ra); /* at least this result */
L->top = base; L->top.p = base;
for (; l_unlikely(nres > 1); nres--) for (; l_unlikely(nres > 1); nres--)
setnilvalue(s2v(L->top++)); /* complete missing results */ setnilvalue(s2v(L->top.p++)); /* complete missing results */
} }
} }
ret: /* return from a Lua function */ ret: /* return from a Lua function */
@ -1751,6 +1804,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
} }
} }
vmcase(OP_FORLOOP) { vmcase(OP_FORLOOP) {
StkId ra = RA(i);
if (ttisinteger(s2v(ra + 2))) { /* integer loop? */ if (ttisinteger(s2v(ra + 2))) { /* integer loop? */
lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1))); lua_Unsigned count = l_castS2U(ivalue(s2v(ra + 1)));
if (count > 0) { /* still more iterations? */ if (count > 0) { /* still more iterations? */
@ -1769,12 +1823,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_FORPREP) { vmcase(OP_FORPREP) {
StkId ra = RA(i);
savestate(L, ci); /* in case of errors */ savestate(L, ci); /* in case of errors */
if (forprep(L, ra)) if (forprep(L, ra))
pc += GETARG_Bx(i) + 1; /* skip the loop */ pc += GETARG_Bx(i) + 1; /* skip the loop */
vmbreak; vmbreak;
} }
vmcase(OP_TFORPREP) { vmcase(OP_TFORPREP) {
StkId ra = RA(i);
/* create to-be-closed upvalue (if needed) */ /* create to-be-closed upvalue (if needed) */
halfProtect(luaF_newtbcupval(L, ra + 3)); halfProtect(luaF_newtbcupval(L, ra + 3));
pc += GETARG_Bx(i); pc += GETARG_Bx(i);
@ -1783,7 +1839,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
goto l_tforcall; goto l_tforcall;
} }
vmcase(OP_TFORCALL) { vmcase(OP_TFORCALL) {
l_tforcall: l_tforcall: {
StkId ra = RA(i);
/* 'ra' has the iterator function, 'ra + 1' has the state, /* 'ra' has the iterator function, 'ra + 1' has the state,
'ra + 2' has the control variable, and 'ra + 3' has the 'ra + 2' has the control variable, and 'ra + 3' has the
to-be-closed variable. The call will use the stack after to-be-closed variable. The call will use the stack after
@ -1791,29 +1848,31 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
*/ */
/* push function, state, and control variable */ /* push function, state, and control variable */
memcpy(ra + 4, ra, 3 * sizeof(*ra)); memcpy(ra + 4, ra, 3 * sizeof(*ra));
L->top = ra + 4 + 3; L->top.p = ra + 4 + 3;
ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */ ProtectNT(luaD_call(L, ra + 4, GETARG_C(i))); /* do the call */
updatestack(ci); /* stack may have changed */ updatestack(ci); /* stack may have changed */
i = *(pc++); /* go to next instruction */ i = *(pc++); /* go to next instruction */
lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i)); lua_assert(GET_OPCODE(i) == OP_TFORLOOP && ra == RA(i));
goto l_tforloop; goto l_tforloop;
} }}
vmcase(OP_TFORLOOP) { vmcase(OP_TFORLOOP) {
l_tforloop: l_tforloop: {
StkId ra = RA(i);
if (!ttisnil(s2v(ra + 4))) { /* continue loop? */ if (!ttisnil(s2v(ra + 4))) { /* continue loop? */
setobjs2s(L, ra + 2, ra + 4); /* save control variable */ setobjs2s(L, ra + 2, ra + 4); /* save control variable */
pc -= GETARG_Bx(i); /* jump back */ pc -= GETARG_Bx(i); /* jump back */
} }
vmbreak; vmbreak;
} }}
vmcase(OP_SETLIST) { vmcase(OP_SETLIST) {
StkId ra = RA(i);
int n = GETARG_B(i); int n = GETARG_B(i);
unsigned int last = GETARG_C(i); unsigned int last = GETARG_C(i);
Table *h = hvalue(s2v(ra)); Table *h = hvalue(s2v(ra));
if (n == 0) if (n == 0)
n = cast_int(L->top - ra) - 1; /* get up to the top */ n = cast_int(L->top.p - ra) - 1; /* get up to the top */
else else
L->top = ci->top; /* correct top in case of emergency GC */ L->top.p = ci->top.p; /* correct top in case of emergency GC */
last += n; last += n;
if (TESTARG_k(i)) { if (TESTARG_k(i)) {
last += GETARG_Ax(*pc) * (MAXARG_C + 1); last += GETARG_Ax(*pc) * (MAXARG_C + 1);
@ -1830,12 +1889,14 @@ void luaV_execute (lua_State *L, CallInfo *ci) {
vmbreak; vmbreak;
} }
vmcase(OP_CLOSURE) { vmcase(OP_CLOSURE) {
StkId ra = RA(i);
Proto *p = cl->p->p[GETARG_Bx(i)]; Proto *p = cl->p->p[GETARG_Bx(i)];
halfProtect(pushclosure(L, p, cl->upvals, base, ra)); halfProtect(pushclosure(L, p, cl->upvals, base, ra));
checkGC(L, ra + 1); checkGC(L, ra + 1);
vmbreak; vmbreak;
} }
vmcase(OP_VARARG) { vmcase(OP_VARARG) {
StkId ra = RA(i);
int n = GETARG_C(i) - 1; /* required results */ int n = GETARG_C(i) - 1; /* required results */
Protect(luaT_getvarargs(L, ci, ra, n)); Protect(luaT_getvarargs(L, ci, ra, n));
vmbreak; vmbreak;

View file

@ -104,6 +104,11 @@ typedef enum {
luaC_barrierback(L, gcvalue(t), v); } luaC_barrierback(L, gcvalue(t), v); }
/*
** Shift right is the same as shift left with a negative 'y'
*/
#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y))
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2); LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);

View file

@ -39,7 +39,7 @@
// clang-format off // clang-format off
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Lua 5.4.4 (MIT License)\\n\ Lua 5.4.5 (MIT License)\\n\
Copyright 19942022 Lua.org, PUC-Rio.\""); Copyright 19942022 Lua.org, PUC-Rio.\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");

View file

@ -163,6 +163,7 @@ f()
dofile('db.lua') dofile('db.lua')
assert(dofile('calls.lua') == deep and deep) assert(dofile('calls.lua') == deep and deep)
_G.deep = nil
olddofile('strings.lua') olddofile('strings.lua')
olddofile('literals.lua') olddofile('literals.lua')
dofile('tpack.lua') dofile('tpack.lua')

View file

@ -14,7 +14,7 @@ local pack = table.pack
-- standard error message for memory errors -- standard error message for memory errors
local MEMERRMSG = "not enough memory" local MEMERRMSG = "not enough memory"
function tcheck (t1, t2) local function tcheck (t1, t2)
assert(t1.n == (t2.n or #t2) + 1) assert(t1.n == (t2.n or #t2) + 1)
for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end
end end
@ -28,7 +28,7 @@ end
print('testing C API') print('testing C API')
a = T.testC("pushvalue R; return 1") local a = T.testC("pushvalue R; return 1")
assert(a == debug.getregistry()) assert(a == debug.getregistry())
@ -43,10 +43,10 @@ a = T.d2s(12458954321123.0)
assert(a == string.pack("d", 12458954321123.0)) assert(a == string.pack("d", 12458954321123.0))
assert(T.s2d(a) == 12458954321123.0) assert(T.s2d(a) == 12458954321123.0)
a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2") local a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2")
assert(a == 2 and b == 3 and not c) assert(a == 2 and b == 3 and not c)
f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2") local f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2")
a,b,c = f() a,b,c = f()
assert(a == 2 and b == 3 and not c) assert(a == 2 and b == 3 and not c)
@ -61,7 +61,7 @@ assert(a==false and b==true and c==false)
a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40) a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40)
assert(a == 40 and b == 5 and not c) assert(a == 40 and b == 5 and not c)
t = pack(T.testC("settop 5; return *", 2, 3)) local t = pack(T.testC("settop 5; return *", 2, 3))
tcheck(t, {n=4,2,3}) tcheck(t, {n=4,2,3})
t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23)) t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23))
@ -166,16 +166,17 @@ end
-- testing globals -- testing globals
_G.a = 14; _G.b = "a31" _G.AA = 14; _G.BB = "a31"
local a = {T.testC[[ local a = {T.testC[[
getglobal a; getglobal AA;
getglobal b; getglobal BB;
getglobal b; getglobal BB;
setglobal a; setglobal AA;
return * return *
]]} ]]}
assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.a == "a31") assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.AA == "a31")
_G.AA, _G.BB = nil
-- testing arith -- testing arith
assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5) assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5)
@ -199,13 +200,14 @@ a,b,c = T.testC([[pushnum 1;
pushstring 10; arith _; pushstring 10; arith _;
pushstring 5; return 3]]) pushstring 5; return 3]])
assert(a == 1 and b == -10 and c == "5") assert(a == 1 and b == -10 and c == "5")
mt = {__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end, local mt = {
__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end,
__mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end, __mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end,
__unm = function (a) return setmetatable({a[1]* 2}, mt) end} __unm = function (a) return setmetatable({a[1]* 2}, mt) end}
a,b,c = setmetatable({4}, mt), a,b,c = setmetatable({4}, mt),
setmetatable({8}, mt), setmetatable({8}, mt),
setmetatable({-3}, mt) setmetatable({-3}, mt)
x,y,z = T.testC("arith +; return 2", 10, a, b) local x,y,z = T.testC("arith +; return 2", 10, a, b)
assert(x == 10 and y[1] == 12 and z == nil) assert(x == 10 and y[1] == 12 and z == nil)
assert(T.testC("arith %; return 1", a, c)[1] == 4%-3) assert(T.testC("arith %; return 1", a, c)[1] == 4%-3)
assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] == assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] ==
@ -312,9 +314,9 @@ assert(T.testC("concat 1; return 1", "xuxu") == "xuxu")
-- testing lua_is -- testing lua_is
function B(x) return x and 1 or 0 end local function B (x) return x and 1 or 0 end
function count (x, n) local function count (x, n)
n = n or 2 n = n or 2
local prog = [[ local prog = [[
isnumber %d; isnumber %d;
@ -345,7 +347,7 @@ assert(count(nil, 15) == 100)
-- testing lua_to... -- testing lua_to...
function to (s, x, n) local function to (s, x, n)
n = n or 2 n = n or 2
return T.testC(string.format("%s %d; return 1", s, n), x) return T.testC(string.format("%s %d; return 1", s, n), x)
end end
@ -486,11 +488,12 @@ a = T.testC([[
pushvalue 3; insert -2; pcall 1 1 0; pushvalue 3; insert -2; pcall 1 1 0;
pcall 0 0 0; pcall 0 0 0;
return 1 return 1
]], "x=150", function (a) assert(a==nil); return 3 end) ]], "XX=150", function (a) assert(a==nil); return 3 end)
assert(type(a) == 'string' and x == 150) assert(type(a) == 'string' and XX == 150)
_G.XX = nil
function check3(p, ...) local function check3(p, ...)
local arg = {...} local arg = {...}
assert(#arg == 3) assert(#arg == 3)
assert(string.find(arg[3], p)) assert(string.find(arg[3], p))
@ -500,7 +503,7 @@ check3("%.", T.testC("loadfile 2; return *", "."))
check3("xxxx", T.testC("loadfile 2; return *", "xxxx")) check3("xxxx", T.testC("loadfile 2; return *", "xxxx"))
-- test errors in non protected threads -- test errors in non protected threads
function checkerrnopro (code, msg) local function checkerrnopro (code, msg)
local th = coroutine.create(function () end) -- create new thread local th = coroutine.create(function () end) -- create new thread
local stt, err = pcall(T.testC, th, code) -- run code there local stt, err = pcall(T.testC, th, code) -- run code there
assert(not stt and string.find(err, msg)) assert(not stt and string.find(err, msg))
@ -510,8 +513,9 @@ if not _soft then
collectgarbage("stop") -- avoid __gc with full stack collectgarbage("stop") -- avoid __gc with full stack
checkerrnopro("pushnum 3; call 0 0", "attempt to call") checkerrnopro("pushnum 3; call 0 0", "attempt to call")
print"testing stack overflow in unprotected thread" print"testing stack overflow in unprotected thread"
function f () f() end function F () F() end
checkerrnopro("getglobal 'f'; call 0 0;", "stack overflow") checkerrnopro("getglobal 'F'; call 0 0;", "stack overflow")
F = nil
collectgarbage("restart") collectgarbage("restart")
end end
print"+" print"+"
@ -588,7 +592,7 @@ assert(a[a] == "x")
b = setmetatable({p = a}, {}) b = setmetatable({p = a}, {})
getmetatable(b).__index = function (t, i) return t.p[i] end getmetatable(b).__index = function (t, i) return t.p[i] end
k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x") local k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x")
assert(x == 15 and k == 35) assert(x == 15 and k == 35)
k = T.testC("getfield 2 y, return 1", b) k = T.testC("getfield 2 y, return 1", b)
assert(k == 12) assert(k == 12)
@ -748,8 +752,8 @@ local i = T.ref{}
T.unref(i) T.unref(i)
assert(T.ref{} == i) assert(T.ref{} == i)
Arr = {} local Arr = {}
Lim = 100 local Lim = 100
for i=1,Lim do -- lock many objects for i=1,Lim do -- lock many objects
Arr[i] = T.ref({}) Arr[i] = T.ref({})
end end
@ -761,7 +765,7 @@ for i=1,Lim do -- unlock all them
T.unref(Arr[i]) T.unref(Arr[i])
end end
function printlocks () local function printlocks ()
local f = T.makeCfunc("gettable R; return 1") local f = T.makeCfunc("gettable R; return 1")
local n = f("n") local n = f("n")
print("n", n) print("n", n)
@ -793,8 +797,8 @@ assert(type(T.getref(a)) == 'table')
-- colect in cl the `val' of all collected userdata -- colect in cl the `val' of all collected userdata
tt = {} local tt = {}
cl = {n=0} local cl = {n=0}
A = nil; B = nil A = nil; B = nil
local F local F
F = function (x) F = function (x)
@ -817,6 +821,7 @@ F = function (x)
end end
tt.__gc = F tt.__gc = F
-- test whether udate collection frees memory in the right time -- test whether udate collection frees memory in the right time
do do
collectgarbage(); collectgarbage();
@ -853,9 +858,9 @@ end
collectgarbage("stop") collectgarbage("stop")
-- create 3 userdatas with tag `tt' -- create 3 userdatas with tag `tt'
a = T.newuserdata(0); debug.setmetatable(a, tt); na = T.udataval(a) a = T.newuserdata(0); debug.setmetatable(a, tt); local na = T.udataval(a)
b = T.newuserdata(0); debug.setmetatable(b, tt); nb = T.udataval(b) b = T.newuserdata(0); debug.setmetatable(b, tt); local nb = T.udataval(b)
c = T.newuserdata(0); debug.setmetatable(c, tt); nc = T.udataval(c) c = T.newuserdata(0); debug.setmetatable(c, tt); local nc = T.udataval(c)
-- create userdata without meta table -- create userdata without meta table
x = T.newuserdata(4) x = T.newuserdata(4)
@ -866,9 +871,9 @@ checkerr("FILE%* expected, got userdata", io.input, x)
assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil) assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil)
d=T.ref(a); local d = T.ref(a);
e=T.ref(b); local e = T.ref(b);
f=T.ref(c); local f = T.ref(c);
t = {T.getref(d), T.getref(e), T.getref(f)} t = {T.getref(d), T.getref(e), T.getref(f)}
assert(t[1] == a and t[2] == b and t[3] == c) assert(t[1] == a and t[2] == b and t[3] == c)
@ -888,7 +893,7 @@ tt=nil -- frees tt for GC
A = nil A = nil
b = nil b = nil
T.unref(d); T.unref(d);
n5 = T.newuserdata(0) local n5 = T.newuserdata(0)
debug.setmetatable(n5, {__gc=F}) debug.setmetatable(n5, {__gc=F})
n5 = T.udataval(n5) n5 = T.udataval(n5)
collectgarbage() collectgarbage()
@ -959,11 +964,11 @@ print'+'
-- testing changing hooks during hooks -- testing changing hooks during hooks
_G.t = {} _G.TT = {}
T.sethook([[ T.sethook([[
# set a line hook after 3 count hooks # set a line hook after 3 count hooks
sethook 4 0 ' sethook 4 0 '
getglobal t; getglobal TT;
pushvalue -3; append -2 pushvalue -3; append -2
pushvalue -2; append -2 pushvalue -2; append -2
']], "c", 3) ']], "c", 3)
@ -973,12 +978,13 @@ a = 1 -- count hook (set line hook)
a = 1 -- line hook a = 1 -- line hook
a = 1 -- line hook a = 1 -- line hook
debug.sethook() debug.sethook()
t = _G.t local t = _G.TT
assert(t[1] == "line") assert(t[1] == "line")
line = t[2] local line = t[2]
assert(t[3] == "line" and t[4] == line + 1) assert(t[3] == "line" and t[4] == line + 1)
assert(t[5] == "line" and t[6] == line + 2) assert(t[5] == "line" and t[6] == line + 2)
assert(t[7] == nil) assert(t[7] == nil)
_G.TT = nil
------------------------------------------------------------------------- -------------------------------------------------------------------------
@ -1003,6 +1009,7 @@ do -- testing errors during GC
collectgarbage("restart") collectgarbage("restart")
warn("@on") warn("@on")
end end
_G.A = nil
------------------------------------------------------------------------- -------------------------------------------------------------------------
-- test for userdata vals -- test for userdata vals
do do
@ -1032,8 +1039,8 @@ assert(a == 'alo' and b == '3')
T.doremote(L1, "_ERRORMESSAGE = nil") T.doremote(L1, "_ERRORMESSAGE = nil")
-- error: `sin' is not defined -- error: `sin' is not defined
a, _, b = T.doremote(L1, "return sin(1)") a, b, c = T.doremote(L1, "return sin(1)")
assert(a == nil and b == 2) -- 2 == run-time error assert(a == nil and c == 2) -- 2 == run-time error
-- error: syntax error -- error: syntax error
a, b, c = T.doremote(L1, "return a+") a, b, c = T.doremote(L1, "return a+")
@ -1204,7 +1211,7 @@ T.alloccount() -- remove limit
-- o that we get memory errors in all allocations of a given -- o that we get memory errors in all allocations of a given
-- task, until there is enough memory to complete the task without -- task, until there is enough memory to complete the task without
-- errors. -- errors.
function testbytes (s, f) local function testbytes (s, f)
collectgarbage() collectgarbage()
local M = T.totalmem() local M = T.totalmem()
local oldM = M local oldM = M
@ -1229,7 +1236,7 @@ end
-- task, until there is enough allocations to complete the task without -- task, until there is enough allocations to complete the task without
-- errors. -- errors.
function testalloc (s, f) local function testalloc (s, f)
collectgarbage() collectgarbage()
local M = 0 local M = 0
local a,b = nil local a,b = nil
@ -1296,12 +1303,12 @@ end)
-- testing threads -- testing threads
-- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1) -- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1)
mt = T.testC("rawgeti R 1; return 1") local mt = T.testC("rawgeti R 1; return 1")
assert(type(mt) == "thread" and coroutine.running() == mt) assert(type(mt) == "thread" and coroutine.running() == mt)
function expand (n,s) local function expand (n,s)
if n==0 then return "" end if n==0 then return "" end
local e = string.rep("=", n) local e = string.rep("=", n)
return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n", return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
@ -1311,9 +1318,10 @@ end
G=0; collectgarbage(); a =collectgarbage("count") G=0; collectgarbage(); a =collectgarbage("count")
load(expand(20,"G=G+1"))() load(expand(20,"G=G+1"))()
assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1) assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1)
G = nil
testamem("running code on new thread", function () testamem("running code on new thread", function ()
return T.doonnewstack("x=1") == 0 -- try to create thread return T.doonnewstack("local x=1") == 0 -- try to create thread
end) end)
@ -1327,13 +1335,13 @@ end)
local testprog = [[ local testprog = [[
local function foo () return end local function foo () return end
local t = {"x"} local t = {"x"}
a = "aaa" AA = "aaa"
for i = 1, #t do a=a..t[i] end for i = 1, #t do AA = AA .. t[i] end
return true return true
]] ]]
-- testing memory x dofile -- testing memory x dofile
_G.a = nil _G.AA = nil
local t =os.tmpname() local t =os.tmpname()
local f = assert(io.open(t, "w")) local f = assert(io.open(t, "w"))
f:write(testprog) f:write(testprog)
@ -1343,7 +1351,7 @@ testamem("dofile", function ()
return a and a() return a and a()
end) end)
assert(os.remove(t)) assert(os.remove(t))
assert(_G.a == "aaax") assert(_G.AA == "aaax")
-- other generic tests -- other generic tests
@ -1360,6 +1368,8 @@ testamem("dump/undump", function ()
return a and a() return a and a()
end) end)
_G.AA = nil
local t = os.tmpname() local t = os.tmpname()
testamem("file creation", function () testamem("file creation", function ()
local f = assert(io.open(t, 'w')) local f = assert(io.open(t, 'w'))
@ -1381,7 +1391,7 @@ testamem("constructors", function ()
end) end)
local a = 1 local a = 1
close = nil local close = nil
testamem("closure creation", function () testamem("closure creation", function ()
function close (b) function close (b)
return function (x) return b + x end return function (x) return b + x end

View file

@ -85,7 +85,7 @@ local DIR = "libs" .. dirsep
-- prepend DIR to a name and correct directory separators -- prepend DIR to a name and correct directory separators
local function D (x) local function D (x)
x = string.gsub(x, "/", dirsep) local x = string.gsub(x, "/", dirsep)
return DIR .. x return DIR .. x
end end
@ -106,7 +106,7 @@ local function createfiles (files, preextras, posextras)
end end
end end
function removefiles (files) local function removefiles (files)
for n in pairs(files) do for n in pairs(files) do
os.remove(D(n)) os.remove(D(n))
end end
@ -154,10 +154,9 @@ local try = function (p, n, r, ext)
assert(ext == x) assert(ext == x)
end end
a = require"names" local a = require"names"
assert(a[1] == "names" and a[2] == D"names.lua") assert(a[1] == "names" and a[2] == D"names.lua")
_G.a = nil
local st, msg = pcall(require, "err") local st, msg = pcall(require, "err")
assert(not st and string.find(msg, "arithmetic") and B == 15) assert(not st and string.find(msg, "arithmetic") and B == 15)
st, msg = pcall(require, "synerr") st, msg = pcall(require, "synerr")
@ -191,6 +190,7 @@ try("X", "XXxX", AA, "libs/XXxX")
removefiles(files) removefiles(files)
NAME, REQUIRED, AA, B = nil
-- testing require of sub-packages -- testing require of sub-packages
@ -223,7 +223,7 @@ assert(require"P1" == m and m.AA == 10)
removefiles(files) removefiles(files)
AA = nil
package.path = "" package.path = ""
assert(not pcall(require, "file_does_not_exist")) assert(not pcall(require, "file_does_not_exist"))
@ -305,6 +305,7 @@ else
assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1") assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
assert(string.find(ext, "libs/lib1", 1, true)) assert(string.find(ext, "libs/lib1", 1, true))
assert(fs.id(45) == 45) assert(fs.id(45) == 45)
_ENV.x, _ENV.y = nil
end end
_ENV = _G _ENV = _G
@ -338,10 +339,10 @@ print("testing assignments, logical operators, and constructors")
local res, res2 = 27 local res, res2 = 27
a, b = 1, 2+3 local a, b = 1, 2+3
assert(a==1 and b==5) assert(a==1 and b==5)
a={} a={}
function f() return 10, 11, 12 end local function f() return 10, 11, 12 end
a.x, b, a[1] = 1, 2, f() a.x, b, a[1] = 1, 2, f()
assert(a.x==1 and b==2 and a[1]==10) assert(a.x==1 and b==2 and a[1]==10)
a[f()], b, a[f()+3] = f(), a, 'x' a[f()], b, a[f()+3] = f(), a, 'x'
@ -353,15 +354,15 @@ do
local a,b,c local a,b,c
a,b = 0, f(1) a,b = 0, f(1)
assert(a == 0 and b == 1) assert(a == 0 and b == 1)
A,b = 0, f(1) a,b = 0, f(1)
assert(A == 0 and b == 1) assert(a == 0 and b == 1)
a,b,c = 0,5,f(4) a,b,c = 0,5,f(4)
assert(a==0 and b==5 and c==1) assert(a==0 and b==5 and c==1)
a,b,c = 0,5,f(0) a,b,c = 0,5,f(0)
assert(a==0 and b==5 and c==nil) assert(a==0 and b==5 and c==nil)
end end
a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6 local a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6
assert(not a and b and c and d==6) assert(not a and b and c and d==6)
d = 20 d = 20
@ -419,6 +420,7 @@ assert(not pcall(function () local a = {[nil] = 10} end))
assert(a[nil] == undef) assert(a[nil] == undef)
a = nil a = nil
local a, b, c
a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'} a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'}
a, a.x, a.y = a, a[-3] a, a.x, a.y = a, a[-3]
assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y) assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y)
@ -434,6 +436,16 @@ a.aVeryLongName012345678901234567890123456789012345678901234567890123456789 ==
10) 10)
do
-- _ENV constant
local function foo ()
local _ENV <const> = 11
X = "hi"
end
local st, msg = pcall(foo)
assert(not st and string.find(msg, "number"))
end
-- test of large float/integer indices -- test of large float/integer indices
@ -445,7 +457,7 @@ while maxint ~= (maxint + 0.0) or (maxint - 1) ~= (maxint - 1.0) do
maxint = maxint // 2 maxint = maxint // 2
end end
maxintF = maxint + 0.0 -- float version local maxintF = maxint + 0.0 -- float version
assert(maxintF == maxint and math.type(maxintF) == "float" and assert(maxintF == maxint and math.type(maxintF) == "float" and
maxintF >= 2.0^14) maxintF >= 2.0^14)

View file

@ -32,7 +32,7 @@ setmetatable(env, {
}) })
X = nil X = nil
co = coroutine.wrap(f) local co = coroutine.wrap(f)
assert(co() == 's') assert(co() == 's')
assert(co() == 'g') assert(co() == 'g')
assert(co() == 'g') assert(co() == 'g')

View file

@ -38,6 +38,18 @@ d = d << 32
assert(a | b ~ c & d == 0xF4000000 << 32) assert(a | b ~ c & d == 0xF4000000 << 32)
assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1) assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1)
do -- constant folding
local code = string.format("return -1 >> %d", math.maxinteger)
assert(load(code)() == 0)
local code = string.format("return -1 >> %d", math.mininteger)
assert(load(code)() == 0)
local code = string.format("return -1 << %d", math.maxinteger)
assert(load(code)() == 0)
local code = string.format("return -1 << %d", math.mininteger)
assert(load(code)() == 0)
end
assert(-1 >> 1 == (1 << (numbits - 1)) - 1 and 1 << 31 == 0x80000000) assert(-1 >> 1 == (1 << (numbits - 1)) - 1 and 1 << 31 == 0x80000000)
assert(-1 >> (numbits - 1) == 1) assert(-1 >> (numbits - 1) == 1)
assert(-1 >> numbits == 0 and assert(-1 >> numbits == 0 and

View file

@ -16,7 +16,7 @@ assert(type(nil) == 'nil'
and type(type) == 'function') and type(type) == 'function')
assert(type(assert) == type(print)) assert(type(assert) == type(print))
function f (x) return a:x (x) end local function f (x) return a:x (x) end
assert(type(f) == 'function') assert(type(f) == 'function')
assert(not pcall(type)) assert(not pcall(type))
@ -33,10 +33,11 @@ do
assert(fact(5) == 120) assert(fact(5) == 120)
end end
assert(fact == false) assert(fact == false)
fact = nil
-- testing declarations -- testing declarations
a = {i = 10} local a = {i = 10}
self = 20 local self = 20
function a:x (x) return x+self.i end function a:x (x) return x+self.i end
function a.y (x) return x+self end function a.y (x) return x+self end
@ -72,6 +73,8 @@ f(1,2, -- this one too
3,4) 3,4)
assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a') assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a')
t = nil -- delete 't'
function fat(x) function fat(x)
if x <= 1 then return 1 if x <= 1 then return 1
else return x*load("return fat(" .. x-1 .. ")", "")() else return x*load("return fat(" .. x-1 .. ")", "")()
@ -80,26 +83,29 @@ end
assert(load "load 'assert(fat(6)==720)' () ")() assert(load "load 'assert(fat(6)==720)' () ")()
a = load('return fat(5), 3') a = load('return fat(5), 3')
a,b = a() local a,b = a()
assert(a == 120 and b == 3) assert(a == 120 and b == 3)
fat = nil
print('+') print('+')
function err_on_n (n) local function err_on_n (n)
if n==0 then error(); exit(1); if n==0 then error(); exit(1);
else err_on_n (n-1); exit(1); else err_on_n (n-1); exit(1);
end end
end end
do do
function dummy (n) local function dummy (n)
if n > 0 then if n > 0 then
assert(not pcall(err_on_n, n)) assert(not pcall(err_on_n, n))
dummy(n-1) dummy(n-1)
end end
end end
dummy(10)
end end
dummy(10) _G.deep = nil -- "declaration" (used by 'all.lua')
function deep (n) function deep (n)
if n>0 then deep(n-1) end if n>0 then deep(n-1) end
@ -151,6 +157,16 @@ do -- tail calls x varargs
end end
do -- C-stack overflow while handling C-stack overflow
local function loop ()
assert(pcall(loop))
end
local err, msg = xpcall(loop, loop)
assert(not err and string.find(msg, "error"))
end
do -- tail calls x chain of __call do -- tail calls x chain of __call
local n = 10000 -- depth local n = 10000 -- depth
@ -199,7 +215,7 @@ assert(a == 23 and (function (x) return x*2 end)(20) == 40)
-- testing closures -- testing closures
-- fixed-point operator -- fixed-point operator
Z = function (le) local Z = function (le)
local function a (f) local function a (f)
return le(function (x) return f(f)(x) end) return le(function (x) return f(f)(x) end)
end end
@ -209,14 +225,14 @@ Z = function (le)
-- non-recursive factorial -- non-recursive factorial
F = function (f) local F = function (f)
return function (n) return function (n)
if n == 0 then return 1 if n == 0 then return 1
else return n*f(n-1) end else return n*f(n-1) end
end end
end end
fat = Z(F) local fat = Z(F)
assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(F)(4)) assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(F)(4))
@ -227,22 +243,21 @@ local function g (z)
return f(z,z+1,z+2,z+3) return f(z,z+1,z+2,z+3)
end end
f = g(10) local f = g(10)
assert(f(9, 16) == 10+11+12+13+10+9+16+10) assert(f(9, 16) == 10+11+12+13+10+9+16+10)
Z, F, f = nil
print('+') print('+')
-- testing multiple returns -- testing multiple returns
function unlpack (t, i) local function unlpack (t, i)
i = i or 1 i = i or 1
if (i <= #t) then if (i <= #t) then
return t[i], unlpack(t, i+1) return t[i], unlpack(t, i+1)
end end
end end
function equaltab (t1, t2) local function equaltab (t1, t2)
assert(#t1 == #t2) assert(#t1 == #t2)
for i = 1, #t1 do for i = 1, #t1 do
assert(t1[i] == t2[i]) assert(t1[i] == t2[i])
@ -251,8 +266,8 @@ end
local pack = function (...) return (table.pack(...)) end local pack = function (...) return (table.pack(...)) end
function f() return 1,2,30,4 end local function f() return 1,2,30,4 end
function ret2 (a,b) return a,b end local function ret2 (a,b) return a,b end
local a,b,c,d = unlpack{1,2,3} local a,b,c,d = unlpack{1,2,3}
assert(a==1 and b==2 and c==3 and d==nil) assert(a==1 and b==2 and c==3 and d==nil)
@ -281,7 +296,7 @@ table.sort({10,9,8,4,19,23,0,0}, function (a,b) return a<b end, "extra arg")
local x = "-- a comment\0\0\0\n x = 10 + \n23; \ local x = "-- a comment\0\0\0\n x = 10 + \n23; \
local a = function () x = 'hi' end; \ local a = function () x = 'hi' end; \
return '\0'" return '\0'"
function read1 (x) local function read1 (x)
local i = 0 local i = 0
return function () return function ()
collectgarbage() collectgarbage()
@ -290,7 +305,7 @@ function read1 (x)
end end
end end
function cannotload (msg, a,b) local function cannotload (msg, a,b)
assert(not a and string.find(b, msg)) assert(not a and string.find(b, msg))
end end
@ -327,11 +342,26 @@ do -- another bug (in 5.4.0)
end end
do -- another bug (since 5.2)
-- corrupted binary dump: list of upvalue names is larger than number
-- of upvalues, overflowing the array of upvalues.
local code =
"\x1b\x4c\x75\x61\x54\x00\x19\x93\x0d\x0a\x1a\x0a\x04\x08\x08\x78\x56\z
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x77\x40\x00\x86\x40\z
\x74\x65\x6d\x70\x81\x81\x01\x00\x02\x82\x48\x00\x02\x00\xc7\x00\x01\z
\x00\x80\x80\x80\x82\x00\x00\x80\x81\x82\x78\x80\x82\x81\x86\x40\x74\z
\x65\x6d\x70"
assert(load(code)) -- segfaults in previous versions
end
x = string.dump(load("x = 1; return x")) x = string.dump(load("x = 1; return x"))
a = assert(load(read1(x), nil, "b")) a = assert(load(read1(x), nil, "b"))
assert(a() == 1 and _G.x == 1) assert(a() == 1 and _G.x == 1)
cannotload("attempt to load a binary chunk", load(read1(x), nil, "t")) cannotload("attempt to load a binary chunk", load(read1(x), nil, "t"))
cannotload("attempt to load a binary chunk", load(x, nil, "t")) cannotload("attempt to load a binary chunk", load(x, nil, "t"))
_G.x = nil
assert(not pcall(string.dump, print)) -- no dump of C functions assert(not pcall(string.dump, print)) -- no dump of C functions
@ -356,7 +386,7 @@ debug.setupvalue(x, 2, _G)
assert(x() == 123) assert(x() == 123)
assert(assert(load("return XX + ...", nil, nil, {XX = 13}))(4) == 17) assert(assert(load("return XX + ...", nil, nil, {XX = 13}))(4) == 17)
XX = nil
-- test generic load with nested functions -- test generic load with nested functions
x = [[ x = [[

View file

@ -4,7 +4,7 @@
print "testing closures" print "testing closures"
local A,B = 0,{g=10} local A,B = 0,{g=10}
function f(x) local function f(x)
local a = {} local a = {}
for i=1,1000 do for i=1,1000 do
local y = 0 local y = 0
@ -89,6 +89,7 @@ assert(r == "a" and s == "b")
-- testing closures with 'for' control variable x break -- testing closures with 'for' control variable x break
local f
for i=1,3 do for i=1,3 do
f = function () return i end f = function () return i end
break break
@ -139,7 +140,7 @@ assert(b('get') == 'xuxu')
b('set', 10); assert(b('get') == 14) b('set', 10); assert(b('get') == 14)
local w local y, w
-- testing multi-level closure -- testing multi-level closure
function f(x) function f(x)
return function (y) return function (y)
@ -230,6 +231,7 @@ t()
-- test for debug manipulation of upvalues -- test for debug manipulation of upvalues
local debug = require'debug' local debug = require'debug'
local foo1, foo2, foo3
do do
local a , b, c = 3, 5, 7 local a , b, c = 3, 5, 7
foo1 = function () return a+b end; foo1 = function () return a+b end;

View file

@ -86,7 +86,7 @@ checkKlist(foo, {1, 1.0, 2, 2.0, 0, 0.0})
-- testing opcodes -- testing opcodes
-- check that 'f' opcodes match '...' -- check that 'f' opcodes match '...'
function check (f, ...) local function check (f, ...)
local arg = {...} local arg = {...}
local c = T.listcode(f) local c = T.listcode(f)
for i=1, #arg do for i=1, #arg do
@ -99,7 +99,7 @@ end
-- check that 'f' opcodes match '...' and that 'f(p) == r'. -- check that 'f' opcodes match '...' and that 'f(p) == r'.
function checkR (f, p, r, ...) local function checkR (f, p, r, ...)
local r1 = f(p) local r1 = f(p)
assert(r == r1 and math.type(r) == math.type(r1)) assert(r == r1 and math.type(r) == math.type(r1))
check(f, ...) check(f, ...)
@ -107,7 +107,7 @@ end
-- check that 'a' and 'b' has the same opcodes -- check that 'a' and 'b' has the same opcodes
function checkequal (a, b) local function checkequal (a, b)
a = T.listcode(a) a = T.listcode(a)
b = T.listcode(b) b = T.listcode(b)
assert(#a == #b) assert(#a == #b)

View file

@ -11,6 +11,7 @@ local function checkload (s, msg)
end end
-- testing semicollons -- testing semicollons
local a
do ;;; end do ;;; end
; do ; a = 3; assert(a == 3) end; ; do ; a = 3; assert(a == 3) end;
; ;
@ -49,10 +50,10 @@ assert((((nil and true) or false) and true) == false)
local a,b = 1,nil; local a,b = 1,nil;
assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75); assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75);
x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x); local x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x);
x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x); x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x);
x,y=1,2; local x, y = 1, 2;
assert((x>y) and x or y == 2); assert((x>y) and x or y == 2);
x,y=2,1; x,y=2,1;
assert((x>y) and x or y == 2); assert((x>y) and x or y == 2);
@ -77,13 +78,13 @@ do -- testing operators with diffent kinds of constants
local gab = f(o1, o2) local gab = f(o1, o2)
_ENV.XX = o1 _ENV.XX = o1
code = string.format("return XX %s %s", op, o2) local code = string.format("return XX %s %s", op, o2)
res = assert(load(code))() local res = assert(load(code))()
assert(res == gab) assert(res == gab)
_ENV.XX = o2 _ENV.XX = o2
local code = string.format("return (%s) %s XX", o1, op) code = string.format("return (%s) %s XX", o1, op)
local res = assert(load(code))() res = assert(load(code))()
assert(res == gab) assert(res == gab)
code = string.format("return (%s) %s %s", o1, op, o2) code = string.format("return (%s) %s %s", o1, op, o2)
@ -92,6 +93,7 @@ do -- testing operators with diffent kinds of constants
end end
end end
end end
_ENV.XX = nil
end end
@ -100,10 +102,35 @@ repeat until 1; repeat until true;
while false do end; while nil do end; while false do end; while nil do end;
do -- test old bug (first name could not be an `upvalue') do -- test old bug (first name could not be an `upvalue')
local a; function f(x) x={a=1}; x={x=1}; x={G=1} end local a; local function f(x) x={a=1}; x={x=1}; x={G=1} end
end end
function f (i)
do -- bug since 5.4.0
-- create code with a table using more than 256 constants
local code = {"local x = {"}
for i = 1, 257 do
code[#code + 1] = i .. ".1,"
end
code[#code + 1] = "};"
code = table.concat(code)
-- add "ret" to the end of that code and checks that
-- it produces the expected value "val"
local function check (ret, val)
local code = code .. ret
code = load(code)
assert(code() == val)
end
check("return (1 ~ (2 or 3))", 1 ~ 2)
check("return (1 | (2 or 3))", 1 | 2)
check("return (1 + (2 or 3))", 1 + 2)
check("return (1 << (2 or 3))", 1 << 2)
end
local function f (i)
if type(i) ~= 'number' then return i,'jojo'; end; if type(i) ~= 'number' then return i,'jojo'; end;
if i > 0 then return i, f(i-1); end; if i > 0 then return i, f(i-1); end;
end end
@ -129,10 +156,10 @@ end
assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil) assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil)
for i=1,1000 do break; end; for i=1,1000 do break; end;
n=100; local n=100;
i=3; local i=3;
t = {}; local t = {};
a=nil local a=nil
while not a do while not a do
a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end; a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end;
end end
@ -175,14 +202,14 @@ a={y=1}
x = {a.y} x = {a.y}
assert(x[1] == 1) assert(x[1] == 1)
function f(i) local function f (i)
while 1 do while 1 do
if i>0 then i=i-1; if i>0 then i=i-1;
else return; end; else return; end;
end; end;
end; end;
function g(i) local function g(i)
while 1 do while 1 do
if i>0 then i=i-1 if i>0 then i=i-1
else return end else return end
@ -247,7 +274,7 @@ function g (a,b,c,d,e)
if not (a>=b or c or d and e or nil) then return 0; else return 1; end; if not (a>=b or c or d and e or nil) then return 0; else return 1; end;
end end
function h (a,b,c,d,e) local function h (a,b,c,d,e)
while (a>=b or c or (d and e) or nil) do return 1; end; while (a>=b or c or (d and e) or nil) do return 1; end;
return 0; return 0;
end; end;
@ -275,7 +302,7 @@ do
assert(a==2) assert(a==2)
end end
function F(a) local function F (a)
assert(debug.getinfo(1, "n").name == 'F') assert(debug.getinfo(1, "n").name == 'F')
return a,2,3 return a,2,3
end end
@ -368,6 +395,8 @@ for n = 1, level do
if i % 60000 == 0 then print('+') end if i % 60000 == 0 then print('+') end
end end
end end
IX = nil
_G.GLOB1 = nil
------------------------------------------------------------------ ------------------------------------------------------------------
-- testing some syntax errors (chosen through 'gcov') -- testing some syntax errors (chosen through 'gcov')

View file

@ -30,7 +30,8 @@ local function eqtab (t1, t2)
end end
_G.x = nil -- declare x _G.x = nil -- declare x
function foo (a, ...) _G.f = nil -- declare f
local function foo (a, ...)
local x, y = coroutine.running() local x, y = coroutine.running()
assert(x == f and y == false) assert(x == f and y == false)
-- next call should not corrupt coroutine (but must fail, -- next call should not corrupt coroutine (but must fail,
@ -67,10 +68,11 @@ assert(coroutine.status(f) == "dead")
s, a = coroutine.resume(f, "xuxu") s, a = coroutine.resume(f, "xuxu")
assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead") assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead")
_G.f = nil
-- yields in tail calls -- yields in tail calls
local function foo (i) return coroutine.yield(i) end local function foo (i) return coroutine.yield(i) end
f = coroutine.wrap(function () local f = coroutine.wrap(function ()
for i=1,10 do for i=1,10 do
assert(foo(i) == _G.x) assert(foo(i) == _G.x)
end end
@ -79,8 +81,10 @@ end)
for i=1,10 do _G.x = i; assert(f(i) == i) end for i=1,10 do _G.x = i; assert(f(i) == i) end
_G.x = 'xuxu'; assert(f('xuxu') == 'a') _G.x = 'xuxu'; assert(f('xuxu') == 'a')
_G.x = nil
-- recursive -- recursive
function pf (n, i) local function pf (n, i)
coroutine.yield(n) coroutine.yield(n)
pf(n*i, i+1) pf(n*i, i+1)
end end
@ -93,14 +97,14 @@ for i=1,10 do
end end
-- sieve -- sieve
function gen (n) local function gen (n)
return coroutine.wrap(function () return coroutine.wrap(function ()
for i=2,n do coroutine.yield(i) end for i=2,n do coroutine.yield(i) end
end) end)
end end
function filter (p, g) local function filter (p, g)
return coroutine.wrap(function () return coroutine.wrap(function ()
while 1 do while 1 do
local n = g() local n = g()
@ -221,14 +225,14 @@ do
-- <close> versus pcall in coroutines -- <close> versus pcall in coroutines
local X = false local X = false
local Y = false local Y = false
function foo () local function foo ()
local x <close> = func2close(function (self, err) local x <close> = func2close(function (self, err)
Y = debug.getinfo(2) Y = debug.getinfo(2)
X = err X = err
end) end)
error(43) error(43)
end end
co = coroutine.create(function () return pcall(foo) end) local co = coroutine.create(function () return pcall(foo) end)
local st1, st2, err = coroutine.resume(co) local st1, st2, err = coroutine.resume(co)
assert(st1 and not st2 and err == 43) assert(st1 and not st2 and err == 43)
assert(X == 43 and Y.what == "C") assert(X == 43 and Y.what == "C")
@ -275,7 +279,7 @@ end
-- yielding across C boundaries -- yielding across C boundaries
co = coroutine.wrap(function() local co = coroutine.wrap(function()
assert(not pcall(table.sort,{1,2,3}, coroutine.yield)) assert(not pcall(table.sort,{1,2,3}, coroutine.yield))
assert(coroutine.isyieldable()) assert(coroutine.isyieldable())
coroutine.yield(20) coroutine.yield(20)
@ -303,15 +307,15 @@ local r1, r2, v = f1(nil)
assert(r1 and not r2 and v[1] == (10 + 1)*10/2) assert(r1 and not r2 and v[1] == (10 + 1)*10/2)
function f (a, b) a = coroutine.yield(a); error{a + b} end local function f (a, b) a = coroutine.yield(a); error{a + b} end
function g(x) return x[1]*2 end local function g(x) return x[1]*2 end
co = coroutine.wrap(function () co = coroutine.wrap(function ()
coroutine.yield(xpcall(f, g, 10, 20)) coroutine.yield(xpcall(f, g, 10, 20))
end) end)
assert(co() == 10) assert(co() == 10)
r, msg = co(100) local r, msg = co(100)
assert(not r and msg == 240) assert(not r and msg == 240)
@ -373,9 +377,10 @@ assert(not a and b == foo and coroutine.status(x) == "dead")
a,b = coroutine.resume(x) a,b = coroutine.resume(x)
assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead") assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead")
goo = nil
-- co-routines x for loop -- co-routines x for loop
function all (a, n, k) local function all (a, n, k)
if k == 0 then coroutine.yield(a) if k == 0 then coroutine.yield(a)
else else
for i=1,n do for i=1,n do
@ -415,7 +420,7 @@ assert(f() == 43 and f() == 53)
-- old bug: attempt to resume itself -- old bug: attempt to resume itself
function co_func (current_co) local function co_func (current_co)
assert(coroutine.running() == current_co) assert(coroutine.running() == current_co)
assert(coroutine.resume(current_co) == false) assert(coroutine.resume(current_co) == false)
coroutine.yield(10, 20) coroutine.yield(10, 20)
@ -491,15 +496,16 @@ a = nil
-- access to locals of erroneous coroutines -- access to locals of erroneous coroutines
local x = coroutine.create (function () local x = coroutine.create (function ()
local a = 10 local a = 10
_G.f = function () a=a+1; return a end _G.F = function () a=a+1; return a end
error('x') error('x')
end) end)
assert(not coroutine.resume(x)) assert(not coroutine.resume(x))
-- overwrite previous position of local `a' -- overwrite previous position of local `a'
assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1)) assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1))
assert(_G.f() == 11) assert(_G.F() == 11)
assert(_G.f() == 12) assert(_G.F() == 12)
_G.F = nil
if not T then if not T then
@ -510,7 +516,7 @@ else
local turn local turn
function fact (t, x) local function fact (t, x)
assert(turn == t) assert(turn == t)
if x == 0 then return 1 if x == 0 then return 1
else return x*fact(t, x-1) else return x*fact(t, x-1)
@ -579,6 +585,7 @@ else
_G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil) _G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil)
_G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20) _G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20)
assert(co() == 10) assert(co() == 10)
_G.X = nil
-- testing yields in count hook -- testing yields in count hook
co = coroutine.wrap(function () co = coroutine.wrap(function ()
@ -656,6 +663,8 @@ else
assert(X == 'a a a' and Y == 'OK') assert(X == 'a a a' and Y == 'OK')
X, Y = nil
-- resuming running coroutine -- resuming running coroutine
C = coroutine.create(function () C = coroutine.create(function ()
@ -701,7 +710,7 @@ else
X = function (x) coroutine.yield(x, 'BB'); return 'CC' end; X = function (x) coroutine.yield(x, 'BB'); return 'CC' end;
return 'ok']])) return 'ok']]))
t = table.pack(T.testC(state, [[ local t = table.pack(T.testC(state, [[
rawgeti R 1 # get main thread rawgeti R 1 # get main thread
pushstring 'XX' pushstring 'XX'
getglobal X # get function for body getglobal X # get function for body
@ -730,31 +739,28 @@ end
-- leaving a pending coroutine open -- leaving a pending coroutine open
_X = coroutine.wrap(function () _G.TO_SURVIVE = coroutine.wrap(function ()
local a = 10 local a = 10
local x = function () a = a+1 end local x = function () a = a+1 end
coroutine.yield() coroutine.yield()
end) end)
_X() _G.TO_SURVIVE()
if not _soft then if not _soft then
-- bug (stack overflow) -- bug (stack overflow)
local j = 2^9 local lim = 1000000 -- stack limit; assume 32-bit machine
local lim = 1000000 -- (C stack limit; assume 32-bit machine) local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1, lim + 5}
local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1}
for i = 1, #t do for i = 1, #t do
local j = t[i] local j = t[i]
co = coroutine.create(function() local co = coroutine.create(function()
local t = {} return table.unpack({}, 1, j)
for i = 1, j do t[i] = i end
return table.unpack(t)
end) end)
local r, msg = coroutine.resume(co) local r, msg = coroutine.resume(co)
assert(not r) -- must fail for unpacking larger than stack limit
assert(j < lim or not r)
end end
co = nil
end end
@ -938,7 +944,7 @@ assert(run(function ()
do local _ENV = _ENV do local _ENV = _ENV
f = function () AAA = BBB + 1; return AAA end f = function () AAA = BBB + 1; return AAA end
end end
g = new(10); g.k.BBB = 10; local g = new(10); g.k.BBB = 10;
debug.setupvalue(f, 1, g) debug.setupvalue(f, 1, g)
assert(run(f, {"idx", "nidx", "idx"}) == 11) assert(run(f, {"idx", "nidx", "idx"}) == 11)
assert(g.k.AAA == 11) assert(g.k.AAA == 11)
@ -1078,6 +1084,8 @@ assert(#a == 3 and a[1] == a[2] and a[2] == a[3] and a[3] == 34)
-- testing yields with continuations -- testing yields with continuations
local y
co = coroutine.wrap(function (...) return co = coroutine.wrap(function (...) return
T.testC([[ # initial function T.testC([[ # initial function
yieldk 1 2 yieldk 1 2
@ -1130,6 +1138,9 @@ assert(x == "YIELD" and y == 4)
assert(not pcall(co)) -- coroutine should be dead assert(not pcall(co)) -- coroutine should be dead
_G.ctx = nil
_G.status = nil
-- bug in nCcalls -- bug in nCcalls
local co = coroutine.wrap(function () local co = coroutine.wrap(function ()

View file

@ -84,6 +84,32 @@ do -- bug in 5.4.0
end end
do -- bug since 5.4.0
local count = 0
print("chain of 'coroutine.close'")
-- create N coroutines forming a list so that each one, when closed,
-- closes the previous one. (With a large enough N, previous Lua
-- versions crash in this test.)
local coro = false
for i = 1, 1000 do
local previous = coro
coro = coroutine.create(function()
local cc <close> = setmetatable({}, {__close=function()
count = count + 1
if previous then
assert(coroutine.close(previous))
end
end})
coroutine.yield() -- leaves 'cc' pending to be closed
end)
assert(coroutine.resume(coro)) -- start it and run until it yields
end
local st, msg = coroutine.close(coro)
assert(not st and string.find(msg, "C stack overflow"))
print("final count: ", count)
end
do do
print("nesting of resuming yielded coroutines") print("nesting of resuming yielded coroutines")
local count = 0 local count = 0

View file

@ -16,7 +16,7 @@ end
assert(not debug.gethook()) assert(not debug.gethook())
local testline = 19 -- line where 'test' is defined local testline = 19 -- line where 'test' is defined
function test (s, l, p) -- this must be line 19 local function test (s, l, p) -- this must be line 19
collectgarbage() -- avoid gc during trace collectgarbage() -- avoid gc during trace
local function f (event, line) local function f (event, line)
assert(event == 'line') assert(event == 'line')
@ -50,7 +50,7 @@ end
-- test file and string names truncation -- test file and string names truncation
a = "function f () end" local a = "function f () end"
local function dostring (s, x) return load(s, x)() end local function dostring (s, x) return load(s, x)() end
dostring(a) dostring(a)
assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a)) assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
@ -72,7 +72,8 @@ dostring(a, string.format("=%s", string.rep('x', 500)))
assert(string.find(debug.getinfo(f).short_src, "^x*$")) assert(string.find(debug.getinfo(f).short_src, "^x*$"))
dostring(a, "=") dostring(a, "=")
assert(debug.getinfo(f).short_src == "") assert(debug.getinfo(f).short_src == "")
a = nil; f = nil; _G.a = nil; _G.f = nil;
_G[string.rep("p", 400)] = nil
repeat repeat
@ -120,6 +121,7 @@ else
end end
]], {2,3,4,7}) ]], {2,3,4,7})
test([[ test([[
local function foo() local function foo()
end end
@ -128,6 +130,7 @@ A = 1
A = 2 A = 2
A = 3 A = 3
]], {2, 3, 2, 4, 5, 6}) ]], {2, 3, 2, 4, 5, 6})
_G.A = nil
test([[-- test([[--
@ -175,6 +178,8 @@ end
test([[for i=1,4 do a=1 end]], {1,1,1,1}) test([[for i=1,4 do a=1 end]], {1,1,1,1})
_G.a = nil
do -- testing line info/trace with large gaps in source do -- testing line info/trace with large gaps in source
@ -194,6 +199,7 @@ do -- testing line info/trace with large gaps in source
end end
end end
end end
_G.a = nil
do -- testing active lines do -- testing active lines
@ -287,7 +293,6 @@ foo(200, 3, 4)
local a = {} local a = {}
for i = 1, (_soft and 100 or 1000) do a[i] = i end for i = 1, (_soft and 100 or 1000) do a[i] = i end
foo(table.unpack(a)) foo(table.unpack(a))
a = nil
@ -307,13 +312,14 @@ do -- test hook presence in debug info
debug.sethook() debug.sethook()
assert(count == 4) assert(count == 4)
end end
_ENV.a = nil
-- hook table has weak keys -- hook table has weak keys
assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k') assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k')
a = {}; L = nil a = {}; local L = nil
local glob = 1 local glob = 1
local oldglob = glob local oldglob = glob
debug.sethook(function (e,l) debug.sethook(function (e,l)
@ -354,7 +360,7 @@ function foo()
end; foo() -- set L end; foo() -- set L
-- check line counting inside strings and empty lines -- check line counting inside strings and empty lines
_ = 'alo\ local _ = 'alo\
alo' .. [[ alo' .. [[
]] ]]
@ -403,6 +409,7 @@ function g(a,b) return (a+1) + f() end
assert(g(0,0) == 30) assert(g(0,0) == 30)
_G.f, _G.g = nil
debug.sethook(nil); debug.sethook(nil);
assert(not debug.gethook()) assert(not debug.gethook())
@ -446,7 +453,7 @@ local function collectlocals (level)
end end
X = nil local X = nil
a = {} a = {}
function a:f (a, b, ...) local arg = {...}; local c = 13 end function a:f (a, b, ...) local arg = {...}; local c = 13 end
debug.sethook(function (e) debug.sethook(function (e)
@ -469,6 +476,7 @@ a:f(1,2,3,4,5)
assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil) assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil)
assert(XX == 12) assert(XX == 12)
assert(not debug.gethook()) assert(not debug.gethook())
_G.XX = nil
-- testing access to local variables in return hook (bug in 5.2) -- testing access to local variables in return hook (bug in 5.2)
@ -593,6 +601,7 @@ end
debug.sethook() debug.sethook()
local g, g1
-- tests for tail calls -- tests for tail calls
local function f (x) local function f (x)
@ -638,7 +647,7 @@ h(false)
debug.sethook() debug.sethook()
assert(b == 2) -- two tail calls assert(b == 2) -- two tail calls
lim = _soft and 3000 or 30000 local lim = _soft and 3000 or 30000
local function foo (x) local function foo (x)
if x==0 then if x==0 then
assert(debug.getinfo(2).what == "main") assert(debug.getinfo(2).what == "main")
@ -940,7 +949,7 @@ end
print("testing debug functions on chunk without debug info") print("testing debug functions on chunk without debug info")
prog = [[-- program to be loaded without debug information (strip) local prog = [[-- program to be loaded without debug information (strip)
local debug = require'debug' local debug = require'debug'
local a = 12 -- a local variable local a = 12 -- a local variable

View file

@ -114,12 +114,14 @@ checkmessage("a = {} | 1", "bitwise operation")
checkmessage("a = {} < 1", "attempt to compare") checkmessage("a = {} < 1", "attempt to compare")
checkmessage("a = {} <= 1", "attempt to compare") checkmessage("a = {} <= 1", "attempt to compare")
checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'") checkmessage("aaa=1; bbbb=2; aaa=math.sin(3)+bbbb(3)", "global 'bbbb'")
checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'") checkmessage("aaa={}; do local aaa=1 end aaa:bbbb(3)", "method 'bbbb'")
checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'") checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'")) assert(not string.find(doit"aaa={13}; local bbbb=1; aaa[bbbb](3)", "'bbbb'"))
checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number") checkmessage("aaa={13}; local bbbb=1; aaa[bbbb](3)", "number")
checkmessage("a=(1)..{}", "a table value") checkmessage("aaa=(1)..{}", "a table value")
_G.aaa, _G.bbbb = nil
-- calls -- calls
checkmessage("local a; a(13)", "local 'a'") checkmessage("local a; a(13)", "local 'a'")
@ -134,12 +136,13 @@ checkmessage([[
-- tail calls -- tail calls
checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'") checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'")
checkmessage("a={}; do local a=1 end; return a:bbbb(3)", "method 'bbbb'") checkmessage("aaa={}; do local aaa=1 end; return aaa:bbbb(3)", "method 'bbbb'")
checkmessage("a = #print", "length of a function value") checkmessage("aaa = #print", "length of a function value")
checkmessage("a = #3", "length of a number value") checkmessage("aaa = #3", "length of a number value")
_G.aaa = nil
aaa = nil
checkmessage("aaa.bbb:ddd(9)", "global 'aaa'") checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'") checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'") checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
@ -152,15 +155,16 @@ checkmessage("local a,b,cc; (function () a.x = 1 end)()", "upvalue 'a'")
checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'") checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'")
checkmessage("b=1; local aaa={}; x=aaa+b", "local 'aaa'") checkmessage("BB=1; local aaa={}; x=aaa+BB", "local 'aaa'")
checkmessage("aaa={}; x=3.3/aaa", "global 'aaa'") checkmessage("aaa={}; x=3.3/aaa", "global 'aaa'")
checkmessage("aaa=2; b=nil;x=aaa*b", "global 'b'") checkmessage("aaa=2; BB=nil;x=aaa*BB", "global 'BB'")
checkmessage("aaa={}; x=-aaa", "global 'aaa'") checkmessage("aaa={}; x=-aaa", "global 'aaa'")
-- short circuit -- short circuit
checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)", checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = math.sin(1) and bbbb(3)",
"local 'bbbb'")
checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = bbbb(1) or aaa(3)",
"local 'bbbb'") "local 'bbbb'")
checkmessage("a=1; local a,bbbb=2,3; a = bbbb(1) or a(3)", "local 'bbbb'")
checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'") checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'")
checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value") checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value")
assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'")) assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
@ -187,8 +191,8 @@ checkmessage("return ~-3e40", "has no integer representation")
checkmessage("return ~-3.009", "has no integer representation") checkmessage("return ~-3.009", "has no integer representation")
checkmessage("return 3.009 & 1", "has no integer representation") checkmessage("return 3.009 & 1", "has no integer representation")
checkmessage("return 34 >> {}", "table value") checkmessage("return 34 >> {}", "table value")
checkmessage("a = 24 // 0", "divide by zero") checkmessage("aaa = 24 // 0", "divide by zero")
checkmessage("a = 1 % 0", "'n%0'") checkmessage("aaa = 1 % 0", "'n%0'")
-- type error for an object which is neither in an upvalue nor a register. -- type error for an object which is neither in an upvalue nor a register.
@ -269,13 +273,13 @@ end
-- tests for field accesses after RK limit -- tests for field accesses after RK limit
local t = {} local t = {}
for i = 1, 1000 do for i = 1, 1000 do
t[i] = "a = x" .. i t[i] = "aaa = x" .. i
end end
local s = table.concat(t, "; ") local s = table.concat(t, "; ")
t = nil t = nil
checkmessage(s.."; a = bbb + 1", "global 'bbb'") checkmessage(s.."; aaa = bbb + 1", "global 'bbb'")
checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'") checkmessage("local _ENV=_ENV;"..s.."; aaa = bbb + 1", "global 'bbb'")
checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'") checkmessage(s.."; local t = {}; aaa = t.bbb + 1", "field 'bbb'")
checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'")
checkmessage([[aaa=9 checkmessage([[aaa=9
@ -324,14 +328,17 @@ main()
]], "global 'NoSuchName'") ]], "global 'NoSuchName'")
print'+' print'+'
a = {}; setmetatable(a, {__index = string}) aaa = {}; setmetatable(aaa, {__index = string})
checkmessage("a:sub()", "bad self") checkmessage("aaa:sub()", "bad self")
checkmessage("string.sub('a', {})", "#2") checkmessage("string.sub('a', {})", "#2")
checkmessage("('a'):sub{}", "#1") checkmessage("('a'):sub{}", "#1")
checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'") checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'")
checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'") checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'")
_G.aaa = nil
-- tests for errors in coroutines -- tests for errors in coroutines
local function f (n) local function f (n)
@ -349,7 +356,7 @@ checkerr("yield across", f)
-- testing size of 'source' info; size of buffer for that info is -- testing size of 'source' info; size of buffer for that info is
-- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'. -- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'.
idsize = 60 - 1 local idsize = 60 - 1
local function checksize (source) local function checksize (source)
-- syntax error -- syntax error
local _, msg = load("x", source) local _, msg = load("x", source)
@ -411,13 +418,14 @@ x
local p = [[ local p = [[
function g() f() end function g() f() end
function f(x) error('a', X) end function f(x) error('a', XX) end
g() g()
]] ]]
X=3;lineerror((p), 3) XX=3;lineerror((p), 3)
X=0;lineerror((p), false) XX=0;lineerror((p), false)
X=1;lineerror((p), 2) XX=1;lineerror((p), 2)
X=2;lineerror((p), 1) XX=2;lineerror((p), 1)
_G.XX, _G.g, _G.f = nil
lineerror([[ lineerror([[
@ -436,6 +444,14 @@ if not b then
end end
end]], 5) end]], 5)
-- bug in 5.4.0
lineerror([[
local a = 0
local b = 1
local c = b % a
]], 3)
do do
-- Force a negative estimate for base line. Error in instruction 2 -- Force a negative estimate for base line. Error in instruction 2
-- (after VARARGPREP, GETGLOBAL), with first absolute line information -- (after VARARGPREP, GETGLOBAL), with first absolute line information
@ -449,11 +465,11 @@ if not _soft then
-- several tests that exaust the Lua stack -- several tests that exaust the Lua stack
collectgarbage() collectgarbage()
print"testing stack overflow" print"testing stack overflow"
C = 0 local C = 0
-- get line where stack overflow will happen -- get line where stack overflow will happen
local l = debug.getinfo(1, "l").currentline + 1 local l = debug.getinfo(1, "l").currentline + 1
local function auxy () C=C+1; auxy() end -- produce a stack overflow local function auxy () C=C+1; auxy() end -- produce a stack overflow
function y () function YY ()
collectgarbage("stop") -- avoid running finalizers without stack space collectgarbage("stop") -- avoid running finalizers without stack space
auxy() auxy()
collectgarbage("restart") collectgarbage("restart")
@ -465,9 +481,11 @@ if not _soft then
return (string.find(m, "stack overflow")) return (string.find(m, "stack overflow"))
end end
-- repeated stack overflows (to check stack recovery) -- repeated stack overflows (to check stack recovery)
assert(checkstackmessage(doit('y()'))) assert(checkstackmessage(doit('YY()')))
assert(checkstackmessage(doit('y()'))) assert(checkstackmessage(doit('YY()')))
assert(checkstackmessage(doit('y()'))) assert(checkstackmessage(doit('YY()')))
_G.YY = nil
-- error lines in stack overflow -- error lines in stack overflow
@ -561,7 +579,7 @@ do
end end
-- xpcall with arguments -- xpcall with arguments
a, b, c = xpcall(string.find, error, "alo", "al") local a, b, c = xpcall(string.find, error, "alo", "al")
assert(a and b == 1 and c == 2) assert(a and b == 1 and c == 2)
a, b, c = xpcall(string.find, function (x) return {} end, true, "al") a, b, c = xpcall(string.find, function (x) return {} end, true, "al")
assert(not a and type(b) == "table" and c == nil) assert(not a and type(b) == "table" and c == nil)
@ -581,11 +599,12 @@ checksyntax("a\1a = 1", "", "<\\1>", 1)
-- test 255 as first char in a chunk -- test 255 as first char in a chunk
checksyntax("\255a = 1", "", "<\\255>", 1) checksyntax("\255a = 1", "", "<\\255>", 1)
doit('I = load("a=9+"); a=3') doit('I = load("a=9+"); aaa=3')
assert(a==3 and not I) assert(_G.aaa==3 and not _G.I)
_G.I,_G.aaa = nil
print('+') print('+')
lim = 1000 local lim = 1000
if _soft then lim = 100 end if _soft then lim = 100 end
for i=1,lim do for i=1,lim do
doit('a = ') doit('a = ')

View file

@ -420,6 +420,9 @@ assert(i == 3 and x[1] == 3 and x[3] == 5)
assert(_G.X == 20) assert(_G.X == 20)
_G.X, _G.B = nil
print'+' print'+'
local _g = _G local _g = _G

View file

@ -507,15 +507,17 @@ load((io.lines(file, 1)))()
assert(_G.X == 4) assert(_G.X == 4)
load((io.lines(file, 3)))() load((io.lines(file, 3)))()
assert(_G.X == 8) assert(_G.X == 8)
_G.X = nil
print('+') print('+')
local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'" local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'"
io.output(file) io.output(file)
assert(io.write(string.format("x2 = %q\n-- comment without ending EOS", x1))) assert(io.write(string.format("X2 = %q\n-- comment without ending EOS", x1)))
io.close() io.close()
assert(loadfile(file))() assert(loadfile(file))()
assert(x1 == x2) assert(x1 == _G.X2)
_G.X2 = nil
print('+') print('+')
assert(os.remove(file)) assert(os.remove(file))
assert(not os.remove(file)) assert(not os.remove(file))
@ -834,8 +836,17 @@ checkerr("missing", os.time, {hour = 12}) -- missing date
if string.packsize("i") == 4 then -- 4-byte ints if string.packsize("i") == 4 then -- 4-byte ints
checkerr("field 'year' is out-of-bound", os.time, checkerr("field 'year' is out-of-bound", os.time,
{year = -(1 << 31) + 1899, month = 1, day = 1}) {year = -(1 << 31) + 1899, month = 1, day = 1})
checkerr("field 'year' is out-of-bound", os.time,
{year = -(1 << 31), month = 1, day = 1})
if math.maxinteger > 2^31 then -- larger lua_integer?
checkerr("field 'year' is out-of-bound", os.time,
{year = (1 << 31) + 1900, month = 1, day = 1})
end
end end
if not _port then if not _port then
-- test Posix-specific modifiers -- test Posix-specific modifiers
assert(type(os.date("%Ex")) == 'string') assert(type(os.date("%Ex")) == 'string')

View file

@ -125,7 +125,7 @@ do
end end
a:test() a:test()
_G.temp = nil
end end
@ -134,7 +134,7 @@ do local f = function () end end
print("functions with errors") print("functions with errors")
prog = [[ local prog = [[
do do
a = 10; a = 10;
function foo(x,y) function foo(x,y)
@ -153,22 +153,25 @@ do
end end
end end
end end
rawset(_G, "a", nil)
_G.x = nil
do
foo = nil foo = nil
print('long strings') print('long strings')
x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789" local x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
assert(string.len(x)==80) assert(string.len(x)==80)
s = '' local s = ''
k = math.min(300, (math.maxinteger // 80) // 2) local k = math.min(300, (math.maxinteger // 80) // 2)
for n = 1, k do s = s..x; j=tostring(n) end for n = 1, k do s = s..x; local j=tostring(n) end
assert(string.len(s) == k*80) assert(string.len(s) == k*80)
s = string.sub(s, 1, 10000) s = string.sub(s, 1, 10000)
s, i = string.gsub(s, '(%d%d%d%d)', '') local s, i = string.gsub(s, '(%d%d%d%d)', '')
assert(i==10000 // 4) assert(i==10000 // 4)
s = nil
x = nil
assert(_G["while"] == 234) assert(_G["while"] == 234)
_G["while"] = nil
end
-- --
@ -227,8 +230,8 @@ end
print("clearing tables") print("clearing tables")
lim = 15 local lim = 15
a = {} local a = {}
-- fill a with `collectable' indices -- fill a with `collectable' indices
for i=1,lim do a[{}] = i end for i=1,lim do a[{}] = i end
b = {} b = {}
@ -552,6 +555,7 @@ do
for i=1,1000 do _ENV.a = {} end -- no collection during the loop for i=1,1000 do _ENV.a = {} end -- no collection during the loop
until gcinfo() > 2 * x until gcinfo() > 2 * x
collectgarbage"restart" collectgarbage"restart"
_ENV.a = nil
end end

View file

@ -11,17 +11,17 @@ CFLAGS = -Wall -std=gnu99 -O2 -I$(LUA_DIR) -fPIC -shared
all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so
touch all touch all
lib1.so: lib1.c $(LUA_DIR)/luaconf.h lib1.so: lib1.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib1.so lib1.c $(CC) $(CFLAGS) -o lib1.so lib1.c
lib11.so: lib11.c $(LUA_DIR)/luaconf.h lib11.so: lib11.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib11.so lib11.c $(CC) $(CFLAGS) -o lib11.so lib11.c
lib2.so: lib2.c $(LUA_DIR)/luaconf.h lib2.so: lib2.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib2.so lib2.c $(CC) $(CFLAGS) -o lib2.so lib2.c
lib21.so: lib21.c $(LUA_DIR)/luaconf.h lib21.so: lib21.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib21.so lib21.c $(CC) $(CFLAGS) -o lib21.so lib21.c
lib2-v2.so: lib21.c $(LUA_DIR)/luaconf.h lib2-v2.so: lib21.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib2-v2.so lib22.c $(CC) $(CFLAGS) -o lib2-v2.so lib22.c

View file

@ -10,6 +10,7 @@ local function dostring (x) return assert(load(x), "")() end
dostring("x \v\f = \t\r 'a\0a' \v\f\f") dostring("x \v\f = \t\r 'a\0a' \v\f\f")
assert(x == 'a\0a' and string.len(x) == 3) assert(x == 'a\0a' and string.len(x) == 3)
_G.x = nil
-- escape sequences -- escape sequences
assert('\n\"\'\\' == [[ assert('\n\"\'\\' == [[
@ -129,16 +130,16 @@ end
-- long variable names -- long variable names
var1 = string.rep('a', 15000) .. '1' local var1 = string.rep('a', 15000) .. '1'
var2 = string.rep('a', 15000) .. '2' local var2 = string.rep('a', 15000) .. '2'
prog = string.format([[ local prog = string.format([[
%s = 5 %s = 5
%s = %s + 1 %s = %s + 1
return function () return %s - %s end return function () return %s - %s end
]], var1, var2, var1, var1, var2) ]], var1, var2, var1, var1, var2)
local f = dostring(prog) local f = dostring(prog)
assert(_G[var1] == 5 and _G[var2] == 6 and f() == -1) assert(_G[var1] == 5 and _G[var2] == 6 and f() == -1)
var1, var2, f = nil _G[var1], _G[var2] = nil
print('+') print('+')
-- escapes -- -- escapes --
@ -150,13 +151,13 @@ assert([[
$debug]] == "\n $debug") $debug]] == "\n $debug")
assert([[ [ ]] ~= [[ ] ]]) assert([[ [ ]] ~= [[ ] ]])
-- long strings -- -- long strings --
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789" local b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
assert(string.len(b) == 960) assert(string.len(b) == 960)
prog = [=[ prog = [=[
print('+') print('+')
a1 = [["this is a 'string' with several 'quotes'"]] local a1 = [["this is a 'string' with several 'quotes'"]]
a2 = "'quotes'" local a2 = "'quotes'"
assert(string.find(a1, a2) == 34) assert(string.find(a1, a2) == 34)
print('+') print('+')
@ -164,12 +165,13 @@ print('+')
a1 = [==[temp = [[an arbitrary value]]; ]==] a1 = [==[temp = [[an arbitrary value]]; ]==]
assert(load(a1))() assert(load(a1))()
assert(temp == 'an arbitrary value') assert(temp == 'an arbitrary value')
_G.temp = nil
-- long strings -- -- long strings --
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789" local b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
assert(string.len(b) == 960) assert(string.len(b) == 960)
print('+') print('+')
a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789 local a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789 00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789 00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789 00123456789012345678901234567890123456789123456789012345678901234567890123456789
@ -199,13 +201,11 @@ x = 1
]=] ]=]
print('+') print('+')
x = nil _G.x = nil
dostring(prog) dostring(prog)
assert(x) assert(x)
_G.x = nil
prog = nil
a = nil
b = nil
do -- reuse of long strings do -- reuse of long strings
@ -234,8 +234,8 @@ end
-- testing line ends -- testing line ends
prog = [[ prog = [[
a = 1 -- a comment local a = 1 -- a comment
b = 2 local b = 2
x = [=[ x = [=[
@ -252,10 +252,11 @@ for _, n in pairs{"\n", "\r", "\n\r", "\r\n"} do
assert(dostring(prog) == nn) assert(dostring(prog) == nn)
assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n") assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n")
end end
_G.x, _G.y = nil
-- testing comments and strings with long brackets -- testing comments and strings with long brackets
a = [==[]=]==] local a = [==[]=]==]
assert(a == "]=") assert(a == "]=")
a = [==[[===[[=[]]=][====[]]===]===]==] a = [==[[===[[=[]]=][====[]]===]===]==]

View file

@ -37,7 +37,7 @@ end
f = nil f = nil
local f local f
x = 1 local x = 1
a = nil a = nil
load('local a = {}')() load('local a = {}')()
@ -152,7 +152,7 @@ local dummy
local _ENV = (function (...) return ... end)(_G, dummy) -- { local _ENV = (function (...) return ... end)(_G, dummy) -- {
do local _ENV = {assert=assert}; assert(true) end do local _ENV = {assert=assert}; assert(true) end
mt = {_G = _G} local mt = {_G = _G}
local foo,x local foo,x
A = false -- "declare" A A = false -- "declare" A
do local _ENV = mt do local _ENV = mt
@ -174,6 +174,8 @@ do local _ENV = {assert=assert, A=10};
end end
assert(x==20) assert(x==20)
A = nil
do -- constants do -- constants
local a<const>, b, c<const> = 10, 20, 30 local a<const>, b, c<const> = 10, 20, 30
@ -360,6 +362,26 @@ do
end end
do
-- bug in 5.4.4: 'break' may generate wrong 'close' instruction when
-- leaving a loop block.
local closed = false
local o1 = setmetatable({}, {__close=function() closed = true end})
local function test()
for k, v in next, {}, nil, o1 do
local function f() return k end -- create an upvalue
break
end
assert(closed)
end
test()
end
do print("testing errors in __close") do print("testing errors in __close")
-- original error is in __close -- original error is in __close
@ -592,6 +614,28 @@ end
if rawget(_G, "T") then if rawget(_G, "T") then
do
-- bug in 5.4.3
-- 'lua_settop' may use a pointer to stack invalidated by 'luaF_close'
-- reduce stack size
collectgarbage(); collectgarbage(); collectgarbage()
-- force a stack reallocation
local function loop (n)
if n < 400 then loop(n + 1) end
end
-- close metamethod will reallocate the stack
local o = setmetatable({}, {__close = function () loop(0) end})
local script = [[toclose 2; settop 1; return 1]]
assert(T.testC(script, o) == script)
end
-- memory error inside closing function -- memory error inside closing function
local function foo () local function foo ()
local y <close> = func2close(function () T.alloccount() end) local y <close> = func2close(function () T.alloccount() end)
@ -669,7 +713,7 @@ if rawget(_G, "T") then
collectgarbage(); collectgarbage() collectgarbage(); collectgarbage()
m = T.totalmem() local m = T.totalmem()
collectgarbage("stop") collectgarbage("stop")
-- error in the first buffer allocation -- error in the first buffer allocation

View file

@ -94,6 +94,33 @@ RUN('echo "print(10)\nprint(2)\n" | lua > %s', out)
checkout("10\n2\n") checkout("10\n2\n")
-- testing BOM
prepfile("\xEF\xBB\xBF")
RUN('lua %s > %s', prog, out)
checkout("")
prepfile("\xEF\xBB\xBFprint(3)")
RUN('lua %s > %s', prog, out)
checkout("3\n")
prepfile("\xEF\xBB\xBF# comment!!\nprint(3)")
RUN('lua %s > %s', prog, out)
checkout("3\n")
-- bad BOMs
prepfile("\xEF")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
prepfile("\xEF\xBB")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
prepfile("\xEFprint(3)")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
prepfile("\xEF\xBBprint(3)")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
-- test option '-' -- test option '-'
RUN('echo "print(arg[1])" | lua - -h > %s', out) RUN('echo "print(arg[1])" | lua - -h > %s', out)
checkout("-h\n") checkout("-h\n")
@ -312,7 +339,7 @@ prepfile("a = [[b\nc\nd\ne]]\n=a")
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
checkprogout("b\nc\nd\ne\n\n") checkprogout("b\nc\nd\ne\n\n")
prompt = "alo" local prompt = "alo"
prepfile[[ -- prepfile[[ --
a = 2 a = 2
]] ]]
@ -372,7 +399,7 @@ NoRun("error object is a table value", [[lua %s]], prog)
-- chunk broken in many lines -- chunk broken in many lines
s = [=[ -- local s = [=[ --
function f ( x ) function f ( x )
local a = [[ local a = [[
xuxu xuxu
@ -394,12 +421,10 @@ checkprogout("101\n13\t22\n\n")
prepfile[[#comment in 1st line without \n at the end]] prepfile[[#comment in 1st line without \n at the end]]
RUN('lua %s', prog) RUN('lua %s', prog)
prepfile[[#test line number when file starts with comment line -- first-line comment with binary file
debug = require"debug" prepfile("#comment\n" .. string.dump(load("print(3)")))
print(debug.getinfo(1).currentline)
]]
RUN('lua %s > %s', prog, out) RUN('lua %s > %s', prog, out)
checkprogout('3\n') checkout('3\n')
-- close Lua with an open file -- close Lua with an open file
prepfile(string.format([[io.output(%q); io.write('alo')]], out)) prepfile(string.format([[io.output(%q); io.write('alo')]], out))

View file

@ -50,7 +50,7 @@ end
local msgf2i = "number.* has no integer representation" local msgf2i = "number.* has no integer representation"
-- float equality -- float equality
function eq (a,b,limit) local function eq (a,b,limit)
if not limit then if not limit then
if floatbits >= 50 then limit = 1E-11 if floatbits >= 50 then limit = 1E-11
else limit = 1E-5 else limit = 1E-5
@ -62,7 +62,7 @@ end
-- equality with types -- equality with types
function eqT (a,b) local function eqT (a,b)
return a == b and math.type(a) == math.type(b) return a == b and math.type(a) == math.type(b)
end end
@ -83,7 +83,7 @@ end
do do
local x = -1 local x = -1
local mz = 0/x -- minus zero local mz = 0/x -- minus zero
t = {[0] = 10, 20, 30, 40, 50} local t = {[0] = 10, 20, 30, 40, 50}
assert(t[mz] == t[0] and t[-0] == t[0]) assert(t[mz] == t[0] and t[-0] == t[0])
end end

View file

@ -9,6 +9,16 @@ local function checkerror (msg, f, ...)
end end
local function check (t, na, nh)
if not T then return end
local a, h = T.querytab(t)
if a ~= na or h ~= nh then
print(na, nh, a, h)
assert(nil)
end
end
local a = {} local a = {}
-- make sure table has lots of space in hash part -- make sure table has lots of space in hash part
@ -20,6 +30,25 @@ for i=1,100 do
assert(#a == i) assert(#a == i)
end end
do -- rehash moving elements from array to hash
local a = {}
for i = 1, 100 do a[i] = i end
check(a, 128, 0)
for i = 5, 95 do a[i] = nil end
check(a, 128, 0)
a.x = 1 -- force a re-hash
check(a, 4, 8)
for i = 1, 4 do assert(a[i] == i) end
for i = 5, 95 do assert(a[i] == nil) end
for i = 96, 100 do assert(a[i] == i) end
assert(a.x == 1)
end
-- testing ipairs -- testing ipairs
local x = 0 local x = 0
for k,v in ipairs{10,20,30;x=12} do for k,v in ipairs{10,20,30;x=12} do
@ -65,15 +94,6 @@ local function mp2 (n) -- minimum power of 2 >= n
end end
local function check (t, na, nh)
local a, h = T.querytab(t)
if a ~= na or h ~= nh then
print(na, nh, a, h)
assert(nil)
end
end
-- testing C library sizes -- testing C library sizes
do do
local s = 0 local s = 0
@ -169,7 +189,7 @@ end
-- size tests for vararg -- size tests for vararg
lim = 35 lim = 35
function foo (n, ...) local function foo (n, ...)
local arg = {...} local arg = {...}
check(arg, n, 0) check(arg, n, 0)
assert(select('#', ...) == n) assert(select('#', ...) == n)

View file

@ -9,12 +9,12 @@ local function checkerror (msg, f, ...)
end end
function f(s, p) local function f (s, p)
local i,e = string.find(s, p) local i,e = string.find(s, p)
if i then return string.sub(s, i, e) end if i then return string.sub(s, i, e) end
end end
a,b = string.find('', '') -- empty patterns are tricky local a,b = string.find('', '') -- empty patterns are tricky
assert(a == 1 and b == 0); assert(a == 1 and b == 0);
a,b = string.find('alo', '') a,b = string.find('alo', '')
assert(a == 1 and b == 0) assert(a == 1 and b == 0)
@ -88,7 +88,7 @@ assert(f("alo alo", "%C+") == "alo alo")
print('+') print('+')
function f1(s, p) local function f1 (s, p)
p = string.gsub(p, "%%([0-9])", function (s) p = string.gsub(p, "%%([0-9])", function (s)
return "%" .. (tonumber(s)+1) return "%" .. (tonumber(s)+1)
end) end)
@ -113,7 +113,7 @@ local abc = string.char(range(0, 127)) .. string.char(range(128, 255));
assert(string.len(abc) == 256) assert(string.len(abc) == 256)
function strset (p) local function strset (p)
local res = {s=''} local res = {s=''}
string.gsub(abc, p, function (c) res.s = res.s .. c end) string.gsub(abc, p, function (c) res.s = res.s .. c end)
return res.s return res.s
@ -147,7 +147,7 @@ assert(string.gsub('ülo ülo', 'ü', 'x') == 'xlo xlo')
assert(string.gsub('alo úlo ', ' +$', '') == 'alo úlo') -- trim assert(string.gsub('alo úlo ', ' +$', '') == 'alo úlo') -- trim
assert(string.gsub(' alo alo ', '^%s*(.-)%s*$', '%1') == 'alo alo') -- double trim assert(string.gsub(' alo alo ', '^%s*(.-)%s*$', '%1') == 'alo alo') -- double trim
assert(string.gsub('alo alo \n 123\n ', '%s+', ' ') == 'alo alo 123 ') assert(string.gsub('alo alo \n 123\n ', '%s+', ' ') == 'alo alo 123 ')
t = "abç d" local t = "abç d"
a, b = string.gsub(t, '(.)', '%1@') a, b = string.gsub(t, '(.)', '%1@')
assert('@'..a == string.gsub(t, '', '@') and b == 5) assert('@'..a == string.gsub(t, '', '@') and b == 5)
a, b = string.gsub('abçd', '(.)', '%0@', 2) a, b = string.gsub('abçd', '(.)', '%0@', 2)
@ -184,6 +184,7 @@ do
local function setglobal (n,v) rawset(_G, n, v) end local function setglobal (n,v) rawset(_G, n, v) end
string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal) string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal)
assert(_G.a=="roberto" and _G.roberto=="a") assert(_G.a=="roberto" and _G.roberto=="a")
_G.a = nil; _G.roberto = nil
end end
function f(a,b) return string.gsub(a,'.',b) end function f(a,b) return string.gsub(a,'.',b) end
@ -195,20 +196,21 @@ assert(string.gsub("alo $a='x'$ novamente $return a$",
"$([^$]*)%$", "$([^$]*)%$",
dostring) == "alo novamente x") dostring) == "alo novamente x")
x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$", local x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$",
"$([^$]*)%$", dostring) "$([^$]*)%$", dostring)
assert(x == ' assim vai para ALO') assert(x == ' assim vai para ALO')
_G.a, _G.x = nil
t = {} local t = {}
s = 'a alo jose joao' local s = 'a alo jose joao'
r = string.gsub(s, '()(%w+)()', function (a,w,b) local r = string.gsub(s, '()(%w+)()', function (a,w,b)
assert(string.len(w) == b-a); assert(string.len(w) == b-a);
t[a] = b-a; t[a] = b-a;
end) end)
assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4) assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4)
function isbalanced (s) local function isbalanced (s)
return not string.find(string.gsub(s, "%b()", ""), "[()]") return not string.find(string.gsub(s, "%b()", ""), "[()]")
end end
@ -251,7 +253,7 @@ if not _soft then
end end
-- recursive nest of gsubs -- recursive nest of gsubs
function rev (s) local function rev (s)
return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end) return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end)
end end

View file

@ -20,7 +20,7 @@ end
checkerror("wrong number of arguments", table.insert, {}, 2, 3, 4) checkerror("wrong number of arguments", table.insert, {}, 2, 3, 4)
local x,y,z,a,n local x,y,z,a,n
a = {}; lim = _soft and 200 or 2000 a = {}; local lim = _soft and 200 or 2000
for i=1, lim do a[i]=i end for i=1, lim do a[i]=i end
assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim) assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim)
x = unpack(a) x = unpack(a)
@ -222,7 +222,7 @@ a = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
table.sort(a) table.sort(a)
check(a) check(a)
function perm (s, n) local function perm (s, n)
n = n or #s n = n or #s
if n == 1 then if n == 1 then
local t = {unpack(s)} local t = {unpack(s)}
@ -248,7 +248,7 @@ perm{1,2,3,3,5}
perm{1,2,3,4,5,6} perm{1,2,3,4,5,6}
perm{2,2,3,3,5,6} perm{2,2,3,3,5,6}
function timesort (a, n, func, msg, pre) local function timesort (a, n, func, msg, pre)
local x = os.clock() local x = os.clock()
table.sort(a, func) table.sort(a, func)
x = (os.clock() - x) * 1000 x = (os.clock() - x) * 1000
@ -257,7 +257,7 @@ function timesort (a, n, func, msg, pre)
check(a, func) check(a, func)
end end
limit = 50000 local limit = 50000
if _soft then limit = 5000 end if _soft then limit = 5000 end
a = {} a = {}
@ -274,7 +274,7 @@ for i=1,limit do
a[i] = math.random() a[i] = math.random()
end end
x = os.clock(); i=0 local x = os.clock(); local i = 0
table.sort(a, function(x,y) i=i+1; return y<x end) table.sort(a, function(x,y) i=i+1; return y<x end)
x = (os.clock() - x) * 1000 x = (os.clock() - x) * 1000
print(string.format("Invert-sorting other %d elements in %.2f msec., with %i comparisons", print(string.format("Invert-sorting other %d elements in %.2f msec., with %i comparisons",
@ -289,18 +289,19 @@ timesort(a, limit, function(x,y) return nil end, "equal")
for i,v in pairs(a) do assert(v == false) end for i,v in pairs(a) do assert(v == false) end
A = {"álo", "\0first :-)", "alo", "then this one", "45", "and a new"} AA = {"álo", "\0first :-)", "alo", "then this one", "45", "and a new"}
table.sort(A) table.sort(AA)
check(A) check(AA)
table.sort(A, function (x, y) table.sort(AA, function (x, y)
load(string.format("A[%q] = ''", x), "")() load(string.format("AA[%q] = ''", x), "")()
collectgarbage() collectgarbage()
return x<y return x<y
end) end)
_G.AA = nil
tt = {__lt = function (a,b) return a.val < b.val end} local tt = {__lt = function (a,b) return a.val < b.val end}
a = {} a = {}
for i=1,10 do a[i] = {val=math.random(100)}; setmetatable(a[i], tt); end for i=1,10 do a[i] = {val=math.random(100)}; setmetatable(a[i], tt); end
table.sort(a) table.sort(a)

View file

@ -52,7 +52,7 @@ assert(("\000123456789"):sub(8) == "789")
-- testing string.find -- testing string.find
assert(string.find("123456789", "345") == 3) assert(string.find("123456789", "345") == 3)
a,b = string.find("123456789", "345") local a,b = string.find("123456789", "345")
assert(string.sub("123456789", a, b) == "345") assert(string.sub("123456789", a, b) == "345")
assert(string.find("1234567890123456789", "345", 3) == 3) assert(string.find("1234567890123456789", "345", 3) == 3)
assert(string.find("1234567890123456789", "345", 4) == 13) assert(string.find("1234567890123456789", "345", 4) == 13)
@ -192,7 +192,7 @@ do -- tests for '%p' format
end end
end end
x = '"ílo"\n\\' local x = '"ílo"\n\\'
assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\') assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\')
assert(string.format('%q', "\0") == [["\0"]]) assert(string.format('%q', "\0") == [["\0"]])
assert(load(string.format('return %q', x))() == x) assert(load(string.format('return %q', x))() == x)
@ -346,13 +346,18 @@ assert(string.format("%013i", -100) == "-000000000100")
assert(string.format("%2.5d", -100) == "-00100") assert(string.format("%2.5d", -100) == "-00100")
assert(string.format("%.u", 0) == "") assert(string.format("%.u", 0) == "")
assert(string.format("%+#014.0f", 100) == "+000000000100.") assert(string.format("%+#014.0f", 100) == "+000000000100.")
assert(string.format("% 1.0E", 100) == " 1E+02")
assert(string.format("%-16c", 97) == "a ") assert(string.format("%-16c", 97) == "a ")
assert(string.format("%+.3G", 1.5) == "+1.5") assert(string.format("%+.3G", 1.5) == "+1.5")
assert(string.format("% .1g", 2^10) == " 1e+03")
assert(string.format("%.0s", "alo") == "") assert(string.format("%.0s", "alo") == "")
assert(string.format("%.s", "alo") == "") assert(string.format("%.s", "alo") == "")
-- ISO C89 says that "The exponent always contains at least two digits",
-- but unlike ISO C99 it does not ensure that it contains "only as many
-- more digits as necessary".
assert(string.match(string.format("% 1.0E", 100), "^ 1E%+0+2$"))
assert(string.match(string.format("% .1g", 2^10), "^ 1e%+0+3$"))
-- errors in format -- errors in format
local function check (fmt, msg) local function check (fmt, msg)
@ -447,7 +452,7 @@ end
do do
local f = string.gmatch("1 2 3 4 5", "%d+") local f = string.gmatch("1 2 3 4 5", "%d+")
assert(f() == "1") assert(f() == "1")
co = coroutine.wrap(f) local co = coroutine.wrap(f)
assert(co() == "2") assert(co() == "2")
end end

View file

@ -35,7 +35,7 @@ print("\talignment: " .. align)
-- check errors in arguments -- check errors in arguments
function checkerror (msg, f, ...) local function checkerror (msg, f, ...)
local status, err = pcall(f, ...) local status, err = pcall(f, ...)
-- print(status, err, msg) -- print(status, err, msg)
assert(not status and string.find(err, msg)) assert(not status and string.find(err, msg))

View file

@ -97,9 +97,15 @@ do -- error indication in utf8.len
assert(not a and b == p) assert(not a and b == p)
end end
check("abc\xE3def", 4) check("abc\xE3def", 4)
check("汉字\x80", #("汉字") + 1)
check("\xF4\x9F\xBF", 1) check("\xF4\x9F\xBF", 1)
check("\xF4\x9F\xBF\xBF", 1) check("\xF4\x9F\xBF\xBF", 1)
-- spurious continuation bytes
check("汉字\x80", #("汉字") + 1)
check("\x80hello", 1)
check("hel\x80lo", 4)
check("汉字\xBF", #("汉字") + 1)
check("\xBFhello", 1)
check("hel\xBFlo", 4)
end end
-- errors in utf8.codes -- errors in utf8.codes
@ -112,12 +118,16 @@ do
end end
errorcodes("ab\xff") errorcodes("ab\xff")
errorcodes("\u{110000}") errorcodes("\u{110000}")
errorcodes("in\x80valid")
errorcodes("\xbfinvalid")
errorcodes("αλφ\xBFα")
-- calling interation function with invalid arguments -- calling interation function with invalid arguments
local f = utf8.codes("") local f = utf8.codes("")
assert(f("", 2) == nil) assert(f("", 2) == nil)
assert(f("", -1) == nil) assert(f("", -1) == nil)
assert(f("", math.mininteger) == nil) assert(f("", math.mininteger) == nil)
end end
-- error in initial position for offset -- error in initial position for offset
@ -220,7 +230,7 @@ do
check(s, {0x10000, 0x1FFFFF}, true) check(s, {0x10000, 0x1FFFFF}, true)
end end
x = "日本語a-4\0éó" local x = "日本語a-4\0éó"
check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243}) check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243})

View file

@ -3,13 +3,13 @@
print('testing vararg') print('testing vararg')
function f(a, ...) local function f (a, ...)
local x = {n = select('#', ...), ...} local x = {n = select('#', ...), ...}
for i = 1, x.n do assert(a[i] == x[i]) end for i = 1, x.n do assert(a[i] == x[i]) end
return x.n return x.n
end end
function c12 (...) local function c12 (...)
assert(arg == _G.arg) -- no local 'arg' assert(arg == _G.arg) -- no local 'arg'
local x = {...}; x.n = #x local x = {...}; x.n = #x
local res = (x.n==2 and x[1] == 1 and x[2] == 2) local res = (x.n==2 and x[1] == 1 and x[2] == 2)
@ -17,7 +17,7 @@ function c12 (...)
return res, 2 return res, 2
end end
function vararg (...) return {n = select('#', ...), ...} end local function vararg (...) return {n = select('#', ...), ...} end
local call = function (f, args) return f(table.unpack(args, 1, args.n)) end local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
@ -29,7 +29,7 @@ assert(vararg().n == 0)
assert(vararg(nil, nil).n == 2) assert(vararg(nil, nil).n == 2)
assert(c12(1,2)==55) assert(c12(1,2)==55)
a,b = assert(call(c12, {1,2})) local a,b = assert(call(c12, {1,2}))
assert(a == 55 and b == 2) assert(a == 55 and b == 2)
a = call(c12, {1,2;n=2}) a = call(c12, {1,2;n=2})
assert(a == 55 and b == 2) assert(a == 55 and b == 2)
@ -49,7 +49,7 @@ function t:f (...) local arg = {...}; return self[...]+#arg end
assert(t:f(1,4) == 3 and t:f(2) == 11) assert(t:f(1,4) == 3 and t:f(2) == 11)
print('+') print('+')
lim = 20 local lim = 20
local i, a = 1, {} local i, a = 1, {}
while i <= lim do a[i] = i+0.3; i=i+1 end while i <= lim do a[i] = i+0.3; i=i+1 end
@ -59,7 +59,7 @@ function f(a, b, c, d, ...)
more[lim-4] == lim+0.3 and not more[lim-3]) more[lim-4] == lim+0.3 and not more[lim-3])
end end
function g(a,b,c) local function g (a,b,c)
assert(a == 1.3 and b == 2.3 and c == 3.3) assert(a == 1.3 and b == 2.3 and c == 3.3)
end end
@ -76,7 +76,7 @@ print("+")
-- new-style varargs -- new-style varargs
function oneless (a, ...) return ... end local function oneless (a, ...) return ... end
function f (n, a, ...) function f (n, a, ...)
local b local b
@ -99,8 +99,8 @@ assert(a==nil and b==nil and c==nil and d==nil and e==nil)
-- varargs for main chunks -- varargs for main chunks
f = load[[ return {...} ]] local f = load[[ return {...} ]]
x = f(2,3) local x = f(2,3)
assert(x[1] == 2 and x[2] == 3 and x[3] == undef) assert(x[1] == 2 and x[2] == 3 and x[3] == undef)

View file

@ -52,7 +52,7 @@ if _soft then return 10 end
print "testing large programs (>64k)" print "testing large programs (>64k)"
-- template to create a very big test file -- template to create a very big test file
prog = [[$ local prog = [[$
local a,b local a,b
@ -85,7 +85,7 @@ function b:xxx (a,b) return a+b end
assert(b:xxx(10, 12) == 22) -- pushself with non-constant index assert(b:xxx(10, 12) == 22) -- pushself with non-constant index
b["xxx"] = undef b["xxx"] = undef
s = 0; n=0 local s = 0; local n=0
for a,b in pairs(b) do s=s+b; n=n+1 end for a,b in pairs(b) do s=s+b; n=n+1 end
-- with 32-bit floats, exact value of 's' depends on summation order -- with 32-bit floats, exact value of 's' depends on summation order
assert(81800000.0 < s and s < 81860000 and n == 70001) assert(81800000.0 < s and s < 81860000 and n == 70001)
@ -93,7 +93,7 @@ assert(81800000.0 < s and s < 81860000 and n == 70001)
a = nil; b = nil a = nil; b = nil
print'+' print'+'
function f(x) b=x end local function f(x) b=x end
a = f{$3$} or 10 a = f{$3$} or 10
@ -118,7 +118,7 @@ local function sig (x)
return (x % 2 == 0) and '' or '-' return (x % 2 == 0) and '' or '-'
end end
F = { local F = {
function () -- $1$ function () -- $1$
for i=10,50009 do for i=10,50009 do
io.write('a', i, ' = ', sig(i), 5+((i-10)/2), ',\n') io.write('a', i, ' = ', sig(i), 5+((i-10)/2), ',\n')
@ -138,14 +138,14 @@ function () -- $3$
end, end,
} }
file = os.tmpname() local file = os.tmpname()
io.output(file) io.output(file)
for s in string.gmatch(prog, "$([^$]+)") do for s in string.gmatch(prog, "$([^$]+)") do
local n = tonumber(s) local n = tonumber(s)
if not n then io.write(s) else F[n]() end if not n then io.write(s) else F[n]() end
end end
io.close() io.close()
result = dofile(file) local result = dofile(file)
assert(os.remove(file)) assert(os.remove(file))
print'OK' print'OK'
return result return result