aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile60
-rw-r--r--src/lapi.c266
-rw-r--r--src/lapi.h6
-rw-r--r--src/lauxlib.c161
-rw-r--r--src/lauxlib.h14
-rw-r--r--src/lbaselib.c54
-rw-r--r--src/lbitlib.c51
-rw-r--r--src/lcode.c709
-rw-r--r--src/lcode.h5
-rw-r--r--src/lcorolib.c4
-rw-r--r--src/ldblib.c21
-rw-r--r--src/ldebug.c131
-rw-r--r--src/ldebug.h7
-rw-r--r--src/ldo.c287
-rw-r--r--src/ldo.h26
-rw-r--r--src/ldump.c9
-rw-r--r--src/lfunc.h9
-rw-r--r--src/lgc.c111
-rw-r--r--src/lgc.h41
-rw-r--r--src/linit.c6
-rw-r--r--src/liolib.c70
-rw-r--r--src/llex.c63
-rw-r--r--src/llex.h3
-rw-r--r--src/llimits.h131
-rw-r--r--src/lmathlib.c22
-rw-r--r--src/lmem.c11
-rw-r--r--src/loadlib.c176
-rw-r--r--src/lobject.c149
-rw-r--r--src/lobject.h117
-rw-r--r--src/lopcodes.h4
-rw-r--r--src/loslib.c233
-rw-r--r--src/lparser.c55
-rw-r--r--src/lparser.h53
-rw-r--r--src/lstate.c37
-rw-r--r--src/lstate.h34
-rw-r--r--src/lstring.c112
-rw-r--r--src/lstring.h7
-rw-r--r--src/lstrlib.c352
-rw-r--r--src/ltable.c233
-rw-r--r--src/ltable.h19
-rw-r--r--src/ltablib.c381
-rw-r--r--src/ltm.c40
-rw-r--r--src/ltm.h5
-rw-r--r--src/lua.c59
-rw-r--r--src/lua.h19
-rw-r--r--src/luac.c6
-rw-r--r--src/luaconf.h292
-rw-r--r--src/lualib.h5
-rw-r--r--src/lundump.c22
-rw-r--r--src/lundump.h5
-rw-r--r--src/lutf8lib.c15
-rw-r--r--src/lvm.c510
-rw-r--r--src/lvm.h69
-rw-r--r--src/lzio.c12
-rw-r--r--src/lzio.h3
55 files changed, 3333 insertions, 1969 deletions
diff --git a/src/Makefile b/src/Makefile
index 2e7a4120cef2..d71c75c87322 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -130,68 +130,68 @@ solaris:
# DO NOT DELETE
lapi.o: lapi.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
- lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
- ltable.h lundump.h lvm.h
+ lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lstring.h \
+ ltable.h lundump.h lvm.h
lauxlib.o: lauxlib.c lprefix.h lua.h luaconf.h lauxlib.h
lbaselib.o: lbaselib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lbitlib.o: lbitlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lcode.o: lcode.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
- llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
- ldo.h lgc.h lstring.h ltable.h lvm.h
+ llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
+ ldo.h lgc.h lstring.h ltable.h lvm.h
lcorolib.o: lcorolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lctype.o: lctype.c lprefix.h lctype.h lua.h luaconf.h llimits.h
ldblib.o: ldblib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ldebug.o: ldebug.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
- lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
- ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
+ lobject.h ltm.h lzio.h lmem.h lcode.h llex.h lopcodes.h lparser.h \
+ ldebug.h ldo.h lfunc.h lstring.h lgc.h ltable.h lvm.h
ldo.o: ldo.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
- lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
- lparser.h lstring.h ltable.h lundump.h lvm.h
+ lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h lopcodes.h \
+ lparser.h lstring.h ltable.h lundump.h lvm.h
ldump.o: ldump.c lprefix.h lua.h luaconf.h lobject.h llimits.h lstate.h \
- ltm.h lzio.h lmem.h lundump.h
+ ltm.h lzio.h lmem.h lundump.h
lfunc.o: lfunc.c lprefix.h lua.h luaconf.h lfunc.h lobject.h llimits.h \
- lgc.h lstate.h ltm.h lzio.h lmem.h
+ lgc.h lstate.h ltm.h lzio.h lmem.h
lgc.o: lgc.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
- llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
+ llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lstring.h ltable.h
linit.o: linit.c lprefix.h lua.h luaconf.h lualib.h lauxlib.h
liolib.o: liolib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
-llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldo.h \
- lobject.h lstate.h ltm.h lzio.h lmem.h lgc.h llex.h lparser.h lstring.h \
- ltable.h
+llex.o: llex.c lprefix.h lua.h luaconf.h lctype.h llimits.h ldebug.h \
+ lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lgc.h llex.h lparser.h \
+ lstring.h ltable.h
lmathlib.o: lmathlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lmem.o: lmem.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
- llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
+ llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h
loadlib.o: loadlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lobject.o: lobject.c lprefix.h lua.h luaconf.h lctype.h llimits.h \
- ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
- lvm.h
+ ldebug.h lstate.h lobject.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h \
+ lvm.h
lopcodes.o: lopcodes.c lprefix.h lopcodes.h llimits.h lua.h luaconf.h
loslib.o: loslib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lparser.o: lparser.c lprefix.h lua.h luaconf.h lcode.h llex.h lobject.h \
- llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
- ldo.h lfunc.h lstring.h lgc.h ltable.h
+ llimits.h lzio.h lmem.h lopcodes.h lparser.h ldebug.h lstate.h ltm.h \
+ ldo.h lfunc.h lstring.h lgc.h ltable.h
lstate.o: lstate.c lprefix.h lua.h luaconf.h lapi.h llimits.h lstate.h \
- lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \
- lstring.h ltable.h
+ lobject.h ltm.h lzio.h lmem.h ldebug.h ldo.h lfunc.h lgc.h llex.h \
+ lstring.h ltable.h
lstring.o: lstring.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
- lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
+ lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h
lstrlib.o: lstrlib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ltable.o: ltable.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
- llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
+ llimits.h ltm.h lzio.h lmem.h ldo.h lgc.h lstring.h ltable.h lvm.h
ltablib.o: ltablib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
ltm.o: ltm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
- llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h ltable.h lvm.h
+ llimits.h ltm.h lzio.h lmem.h ldo.h lstring.h lgc.h ltable.h lvm.h
lua.o: lua.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
luac.o: luac.c lprefix.h lua.h luaconf.h lauxlib.h lobject.h llimits.h \
- lstate.h ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
+ lstate.h ltm.h lzio.h lmem.h lundump.h ldebug.h lopcodes.h
lundump.o: lundump.c lprefix.h lua.h luaconf.h ldebug.h lstate.h \
- lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
- lundump.h
+ lobject.h llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lstring.h lgc.h \
+ lundump.h
lutf8lib.o: lutf8lib.c lprefix.h lua.h luaconf.h lauxlib.h lualib.h
lvm.o: lvm.c lprefix.h lua.h luaconf.h ldebug.h lstate.h lobject.h \
- llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \
- ltable.h lvm.h
+ llimits.h ltm.h lzio.h lmem.h ldo.h lfunc.h lgc.h lopcodes.h lstring.h \
+ ltable.h lvm.h
lzio.o: lzio.c lprefix.h lua.h luaconf.h llimits.h lmem.h lstate.h \
- lobject.h ltm.h lzio.h
+ lobject.h ltm.h lzio.h
# (end of Makefile)
diff --git a/src/lapi.c b/src/lapi.c
index fbfafa304ff8..c9455a5d8cd5 100644
--- a/src/lapi.c
+++ b/src/lapi.c
@@ -1,5 +1,5 @@
/*
-** $Id: lapi.c,v 2.244 2014/12/26 14:43:45 roberto Exp $
+** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $
** Lua API
** See Copyright Notice in lua.h
*/
@@ -51,29 +51,29 @@ const char lua_ident[] =
/* test for valid but not pseudo index */
#define isstackindex(i, o) (isvalid(o) && !ispseudo(i))
-#define api_checkvalidindex(o) api_check(isvalid(o), "invalid index")
+#define api_checkvalidindex(l,o) api_check(l, isvalid(o), "invalid index")
-#define api_checkstackindex(i, o) \
- api_check(isstackindex(i, o), "index not in the stack")
+#define api_checkstackindex(l, i, o) \
+ api_check(l, isstackindex(i, o), "index not in the stack")
static TValue *index2addr (lua_State *L, int idx) {
CallInfo *ci = L->ci;
if (idx > 0) {
TValue *o = ci->func + idx;
- api_check(idx <= ci->top - (ci->func + 1), "unacceptable index");
+ api_check(L, idx <= ci->top - (ci->func + 1), "unacceptable index");
if (o >= L->top) return NONVALIDVALUE;
else return o;
}
else if (!ispseudo(idx)) { /* negative index */
- api_check(idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
+ api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index");
return L->top + idx;
}
else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry;
else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx;
- api_check(idx <= MAXUPVAL + 1, "upvalue index too large");
+ api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
if (ttislcf(ci->func)) /* light C function? */
return NONVALIDVALUE; /* it has no upvalues */
else {
@@ -98,7 +98,7 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
int res;
CallInfo *ci = L->ci;
lua_lock(L);
- api_check(n >= 0, "negative 'n'");
+ api_check(L, n >= 0, "negative 'n'");
if (L->stack_last - L->top > n) /* stack large enough? */
res = 1; /* yes; check is OK */
else { /* no; need to grow stack */
@@ -120,11 +120,12 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
if (from == to) return;
lua_lock(to);
api_checknelems(from, n);
- api_check(G(from) == G(to), "moving among independent states");
- api_check(to->ci->top - to->top >= n, "not enough elements to move");
+ api_check(from, G(from) == G(to), "moving among independent states");
+ api_check(from, to->ci->top - to->top >= n, "stack overflow");
from->top -= n;
for (i = 0; i < n; i++) {
- setobj2s(to, to->top++, from->top + i);
+ setobj2s(to, to->top, from->top + i);
+ to->top++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
}
@@ -159,7 +160,7 @@ LUA_API const lua_Number *lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx))
? idx
- : cast_int(L->top - L->ci->func + idx);
+ : cast_int(L->top - L->ci->func) + idx;
}
@@ -172,13 +173,13 @@ LUA_API void lua_settop (lua_State *L, int idx) {
StkId func = L->ci->func;
lua_lock(L);
if (idx >= 0) {
- api_check(idx <= L->stack_last - (func + 1), "new top too large");
+ api_check(L, idx <= L->stack_last - (func + 1), "new top too large");
while (L->top < (func + 1) + idx)
setnilvalue(L->top++);
L->top = (func + 1) + idx;
}
else {
- api_check(-(idx+1) <= (L->top - (func + 1)), "invalid new top");
+ api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top");
L->top += idx+1; /* 'subtract' index (index is negative) */
}
lua_unlock(L);
@@ -208,8 +209,8 @@ LUA_API void lua_rotate (lua_State *L, int idx, int n) {
lua_lock(L);
t = L->top - 1; /* end of stack segment being rotated */
p = index2addr(L, idx); /* start of segment */
- api_checkstackindex(idx, p);
- api_check((n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
+ api_checkstackindex(L, idx, p);
+ api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
reverse(L, p, m); /* reverse the prefix with length 'n' */
reverse(L, m + 1, t); /* reverse the suffix */
@@ -223,7 +224,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
lua_lock(L);
fr = index2addr(L, fromidx);
to = index2addr(L, toidx);
- api_checkvalidindex(to);
+ api_checkvalidindex(L, to);
setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */
luaC_barrier(L, clCvalue(L->ci->func), fr);
@@ -255,7 +256,7 @@ LUA_API int lua_type (lua_State *L, int idx) {
LUA_API const char *lua_typename (lua_State *L, int t) {
UNUSED(L);
- api_check(LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag");
+ api_check(L, LUA_TNONE <= t && t < LUA_NUMTAGS, "invalid tag");
return ttypename(t);
}
@@ -305,7 +306,7 @@ LUA_API void lua_arith (lua_State *L, int op) {
else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1);
setobjs2s(L, L->top, L->top - 1);
- L->top++;
+ api_incr_top(L);
}
/* first operand at top - 2, second at top - 1; result go to top - 2 */
luaO_arith(L, op, L->top - 2, L->top - 1, L->top - 2);
@@ -325,7 +326,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
case LUA_OPEQ: i = luaV_equalobj(L, o1, o2); break;
case LUA_OPLT: i = luaV_lessthan(L, o1, o2); break;
case LUA_OPLE: i = luaV_lessequal(L, o1, o2); break;
- default: api_check(0, "invalid option");
+ default: api_check(L, 0, "invalid option");
}
}
lua_unlock(L);
@@ -377,20 +378,22 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
return NULL;
}
lua_lock(L); /* 'luaO_tostring' may create a new string */
+ luaO_tostring(L, o);
luaC_checkGC(L);
o = index2addr(L, idx); /* previous call may reallocate the stack */
- luaO_tostring(L, o);
lua_unlock(L);
}
- if (len != NULL) *len = tsvalue(o)->len;
+ if (len != NULL)
+ *len = vslen(o);
return svalue(o);
}
LUA_API size_t lua_rawlen (lua_State *L, int idx) {
StkId o = index2addr(L, idx);
- switch (ttnov(o)) {
- case LUA_TSTRING: return tsvalue(o)->len;
+ switch (ttype(o)) {
+ case LUA_TSHRSTR: return tsvalue(o)->shrlen;
+ case LUA_TLNGSTR: return tsvalue(o)->u.lnglen;
case LUA_TUSERDATA: return uvalue(o)->len;
case LUA_TTABLE: return luaH_getn(hvalue(o));
default: return 0;
@@ -431,9 +434,8 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
case LUA_TCCL: return clCvalue(o);
case LUA_TLCF: return cast(void *, cast(size_t, fvalue(o)));
case LUA_TTHREAD: return thvalue(o);
- case LUA_TUSERDATA:
- case LUA_TLIGHTUSERDATA:
- return lua_touserdata(L, idx);
+ case LUA_TUSERDATA: return getudatamem(uvalue(o));
+ case LUA_TLIGHTUSERDATA: return pvalue(o);
default: return NULL;
}
}
@@ -469,33 +471,37 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
}
+/*
+** Pushes on the stack a string with given length. Avoid using 's' when
+** 'len' == 0 (as 's' can be NULL in that case), due to later use of
+** 'memcmp' and 'memcpy'.
+*/
LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts;
lua_lock(L);
- luaC_checkGC(L);
- ts = luaS_newlstr(L, s, len);
+ ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts);
api_incr_top(L);
+ luaC_checkGC(L);
lua_unlock(L);
return getstr(ts);
}
LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
- if (s == NULL) {
- lua_pushnil(L);
- return NULL;
- }
+ lua_lock(L);
+ if (s == NULL)
+ setnilvalue(L->top);
else {
TString *ts;
- lua_lock(L);
- luaC_checkGC(L);
ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts);
- api_incr_top(L);
- lua_unlock(L);
- return getstr(ts);
+ s = getstr(ts); /* internal copy's address */
}
+ api_incr_top(L);
+ luaC_checkGC(L);
+ lua_unlock(L);
+ return s;
}
@@ -503,8 +509,8 @@ LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
va_list argp) {
const char *ret;
lua_lock(L);
- luaC_checkGC(L);
ret = luaO_pushvfstring(L, fmt, argp);
+ luaC_checkGC(L);
lua_unlock(L);
return ret;
}
@@ -514,10 +520,10 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
const char *ret;
va_list argp;
lua_lock(L);
- luaC_checkGC(L);
va_start(argp, fmt);
ret = luaO_pushvfstring(L, fmt, argp);
va_end(argp);
+ luaC_checkGC(L);
lua_unlock(L);
return ret;
}
@@ -531,8 +537,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
else {
CClosure *cl;
api_checknelems(L, n);
- api_check(n <= MAXUPVAL, "upvalue index too large");
- luaC_checkGC(L);
+ api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n);
cl->f = fn;
L->top -= n;
@@ -543,6 +548,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
setclCvalue(L, L->top, cl);
}
api_incr_top(L);
+ luaC_checkGC(L);
lua_unlock(L);
}
@@ -578,15 +584,27 @@ LUA_API int lua_pushthread (lua_State *L) {
*/
+static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
+ const TValue *slot;
+ TString *str = luaS_new(L, k);
+ if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
+ setobj2s(L, L->top, slot);
+ api_incr_top(L);
+ }
+ else {
+ setsvalue2s(L, L->top, str);
+ api_incr_top(L);
+ luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
+ }
+ lua_unlock(L);
+ return ttnov(L->top - 1);
+}
+
+
LUA_API int lua_getglobal (lua_State *L, const char *name) {
Table *reg = hvalue(&G(L)->l_registry);
- const TValue *gt; /* global table */
lua_lock(L);
- gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
- setsvalue2s(L, L->top++, luaS_new(L, name));
- luaV_gettable(L, gt, L->top - 1, L->top - 1);
- lua_unlock(L);
- return ttnov(L->top - 1);
+ return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
}
@@ -601,24 +619,25 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
LUA_API int lua_getfield (lua_State *L, int idx, const char *k) {
- StkId t;
lua_lock(L);
- t = index2addr(L, idx);
- setsvalue2s(L, L->top, luaS_new(L, k));
- api_incr_top(L);
- luaV_gettable(L, t, L->top - 1, L->top - 1);
- lua_unlock(L);
- return ttnov(L->top - 1);
+ return auxgetstr(L, index2addr(L, idx), k);
}
LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
StkId t;
+ const TValue *slot;
lua_lock(L);
t = index2addr(L, idx);
- setivalue(L->top, n);
- api_incr_top(L);
- luaV_gettable(L, t, L->top - 1, L->top - 1);
+ if (luaV_fastget(L, t, n, slot, luaH_getint)) {
+ setobj2s(L, L->top, slot);
+ api_incr_top(L);
+ }
+ else {
+ setivalue(L->top, n);
+ api_incr_top(L);
+ luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
+ }
lua_unlock(L);
return ttnov(L->top - 1);
}
@@ -628,7 +647,7 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
- api_check(ttistable(t), "table expected");
+ api_check(L, ttistable(t), "table expected");
setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
lua_unlock(L);
return ttnov(L->top - 1);
@@ -639,7 +658,7 @@ LUA_API int lua_rawgeti (lua_State *L, int idx, lua_Integer n) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
- api_check(ttistable(t), "table expected");
+ api_check(L, ttistable(t), "table expected");
setobj2s(L, L->top, luaH_getint(hvalue(t), n));
api_incr_top(L);
lua_unlock(L);
@@ -652,7 +671,7 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
TValue k;
lua_lock(L);
t = index2addr(L, idx);
- api_check(ttistable(t), "table expected");
+ api_check(L, ttistable(t), "table expected");
setpvalue(&k, cast(void *, p));
setobj2s(L, L->top, luaH_get(hvalue(t), &k));
api_incr_top(L);
@@ -664,12 +683,12 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
- luaC_checkGC(L);
t = luaH_new(L);
sethvalue(L, L->top, t);
api_incr_top(L);
if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec);
+ luaC_checkGC(L);
lua_unlock(L);
}
@@ -705,7 +724,7 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
StkId o;
lua_lock(L);
o = index2addr(L, idx);
- api_check(ttisfulluserdata(o), "full userdata expected");
+ api_check(L, ttisfulluserdata(o), "full userdata expected");
getuservalue(L, uvalue(o), L->top);
api_incr_top(L);
lua_unlock(L);
@@ -717,17 +736,29 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
** set functions (stack -> Lua)
*/
+/*
+** t[k] = value at the top of the stack (where 'k' is a string)
+*/
+static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
+ const TValue *slot;
+ TString *str = luaS_new(L, k);
+ api_checknelems(L, 1);
+ if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
+ L->top--; /* pop value */
+ else {
+ setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
+ api_incr_top(L);
+ luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
+ L->top -= 2; /* pop value and key */
+ }
+ lua_unlock(L); /* lock done by caller */
+}
+
LUA_API void lua_setglobal (lua_State *L, const char *name) {
Table *reg = hvalue(&G(L)->l_registry);
- const TValue *gt; /* global table */
- lua_lock(L);
- api_checknelems(L, 1);
- gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
- setsvalue2s(L, L->top++, luaS_new(L, name));
- luaV_settable(L, gt, L->top - 1, L->top - 2);
- L->top -= 2; /* pop value and key */
- lua_unlock(L);
+ lua_lock(L); /* unlock done in 'auxsetstr' */
+ auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
}
@@ -743,40 +774,40 @@ LUA_API void lua_settable (lua_State *L, int idx) {
LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
- StkId t;
- lua_lock(L);
- api_checknelems(L, 1);
- t = index2addr(L, idx);
- setsvalue2s(L, L->top++, luaS_new(L, k));
- luaV_settable(L, t, L->top - 1, L->top - 2);
- L->top -= 2; /* pop value and key */
- lua_unlock(L);
+ lua_lock(L); /* unlock done in 'auxsetstr' */
+ auxsetstr(L, index2addr(L, idx), k);
}
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
StkId t;
+ const TValue *slot;
lua_lock(L);
api_checknelems(L, 1);
t = index2addr(L, idx);
- setivalue(L->top++, n);
- luaV_settable(L, t, L->top - 1, L->top - 2);
- L->top -= 2; /* pop value and key */
+ if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
+ L->top--; /* pop value */
+ else {
+ setivalue(L->top, n);
+ api_incr_top(L);
+ luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
+ L->top -= 2; /* pop value and key */
+ }
lua_unlock(L);
}
LUA_API void lua_rawset (lua_State *L, int idx) {
StkId o;
- Table *t;
+ TValue *slot;
lua_lock(L);
api_checknelems(L, 2);
o = index2addr(L, idx);
- api_check(ttistable(o), "table expected");
- t = hvalue(o);
- setobj2t(L, luaH_set(L, t, L->top-2), L->top-1);
- invalidateTMcache(t);
- luaC_barrierback(L, t, L->top-1);
+ api_check(L, ttistable(o), "table expected");
+ slot = luaH_set(L, hvalue(o), L->top - 2);
+ setobj2t(L, slot, L->top - 1);
+ invalidateTMcache(hvalue(o));
+ luaC_barrierback(L, hvalue(o), L->top-1);
L->top -= 2;
lua_unlock(L);
}
@@ -784,14 +815,12 @@ LUA_API void lua_rawset (lua_State *L, int idx) {
LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
StkId o;
- Table *t;
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
- api_check(ttistable(o), "table expected");
- t = hvalue(o);
- luaH_setint(L, t, n, L->top - 1);
- luaC_barrierback(L, t, L->top-1);
+ api_check(L, ttistable(o), "table expected");
+ luaH_setint(L, hvalue(o), n, L->top - 1);
+ luaC_barrierback(L, hvalue(o), L->top-1);
L->top--;
lua_unlock(L);
}
@@ -799,16 +828,15 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
StkId o;
- Table *t;
- TValue k;
+ TValue k, *slot;
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
- api_check(ttistable(o), "table expected");
- t = hvalue(o);
+ api_check(L, ttistable(o), "table expected");
setpvalue(&k, cast(void *, p));
- setobj2t(L, luaH_set(L, t, &k), L->top - 1);
- luaC_barrierback(L, t, L->top - 1);
+ slot = luaH_set(L, hvalue(o), &k);
+ setobj2t(L, slot, L->top - 1);
+ luaC_barrierback(L, hvalue(o), L->top - 1);
L->top--;
lua_unlock(L);
}
@@ -823,7 +851,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
if (ttisnil(L->top - 1))
mt = NULL;
else {
- api_check(ttistable(L->top - 1), "table expected");
+ api_check(L, ttistable(L->top - 1), "table expected");
mt = hvalue(L->top - 1);
}
switch (ttnov(obj)) {
@@ -859,7 +887,7 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
- api_check(ttisfulluserdata(o), "full userdata expected");
+ api_check(L, ttisfulluserdata(o), "full userdata expected");
setuservalue(L, uvalue(o), L->top - 1);
luaC_barrier(L, gcvalue(o), L->top - 1);
L->top--;
@@ -873,7 +901,7 @@ LUA_API void lua_setuservalue (lua_State *L, int idx) {
#define checkresults(L,na,nr) \
- api_check((nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
+ api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \
"results from function overflow current stack size")
@@ -881,19 +909,19 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
lua_KContext ctx, lua_KFunction k) {
StkId func;
lua_lock(L);
- api_check(k == NULL || !isLua(L->ci),
+ api_check(L, k == NULL || !isLua(L->ci),
"cannot use continuations inside hooks");
api_checknelems(L, nargs+1);
- api_check(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);
func = L->top - (nargs+1);
if (k != NULL && L->nny == 0) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */
- luaD_call(L, func, nresults, 1); /* do the call */
+ luaD_call(L, func, nresults); /* do the call */
}
else /* no continuation or no yieldable */
- luaD_call(L, func, nresults, 0); /* just do the call */
+ luaD_callnoyield(L, func, nresults); /* just do the call */
adjustresults(L, nresults);
lua_unlock(L);
}
@@ -911,7 +939,7 @@ struct CallS { /* data to 'f_call' */
static void f_call (lua_State *L, void *ud) {
struct CallS *c = cast(struct CallS *, ud);
- luaD_call(L, c->func, c->nresults, 0);
+ luaD_callnoyield(L, c->func, c->nresults);
}
@@ -922,16 +950,16 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
int status;
ptrdiff_t func;
lua_lock(L);
- api_check(k == NULL || !isLua(L->ci),
+ api_check(L, k == NULL || !isLua(L->ci),
"cannot use continuations inside hooks");
api_checknelems(L, nargs+1);
- api_check(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);
if (errfunc == 0)
func = 0;
else {
StkId o = index2addr(L, errfunc);
- api_checkstackindex(errfunc, o);
+ api_checkstackindex(L, errfunc, o);
func = savestack(L, o);
}
c.func = L->top - (nargs+1); /* function to be called */
@@ -949,7 +977,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
L->errfunc = func;
setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */
ci->callstatus |= CIST_YPCALL; /* function can do error recovery */
- luaD_call(L, c.func, nresults, 1); /* do the call */
+ luaD_call(L, c.func, nresults); /* do the call */
ci->callstatus &= ~CIST_YPCALL;
L->errfunc = ci->u.c.old_errfunc;
status = LUA_OK; /* if it is here, there were no errors */
@@ -1038,7 +1066,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
}
case LUA_GCSTEP: {
l_mem debt = 1; /* =1 to signal that it did an actual step */
- int oldrunning = g->gcrunning;
+ lu_byte oldrunning = g->gcrunning;
g->gcrunning = 1; /* allow GC to run */
if (data == 0) {
luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */
@@ -1096,7 +1124,7 @@ LUA_API int lua_next (lua_State *L, int idx) {
int more;
lua_lock(L);
t = index2addr(L, idx);
- api_check(ttistable(t), "table expected");
+ api_check(L, ttistable(t), "table expected");
more = luaH_next(L, hvalue(t), L->top - 1);
if (more) {
api_incr_top(L);
@@ -1112,7 +1140,6 @@ LUA_API void lua_concat (lua_State *L, int n) {
lua_lock(L);
api_checknelems(L, n);
if (n >= 2) {
- luaC_checkGC(L);
luaV_concat(L, n);
}
else if (n == 0) { /* push empty string */
@@ -1120,6 +1147,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
api_incr_top(L);
}
/* else n == 1; nothing to do */
+ luaC_checkGC(L);
lua_unlock(L);
}
@@ -1155,10 +1183,10 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
Udata *u;
lua_lock(L);
- luaC_checkGC(L);
u = luaS_newudata(L, size);
setuvalue(L, L->top, u);
api_incr_top(L);
+ luaC_checkGC(L);
lua_unlock(L);
return getudatamem(u);
}
@@ -1228,9 +1256,9 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
LClosure *f;
StkId fi = index2addr(L, fidx);
- api_check(ttisLclosure(fi), "Lua function expected");
+ api_check(L, ttisLclosure(fi), "Lua function expected");
f = clLvalue(fi);
- api_check((1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
+ api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
if (pf) *pf = f;
return &f->upvals[n - 1]; /* get its upvalue pointer */
}
@@ -1244,11 +1272,11 @@ LUA_API void *lua_upvalueid (lua_State *L, int fidx, int n) {
}
case LUA_TCCL: { /* C closure */
CClosure *f = clCvalue(fi);
- api_check(1 <= n && n <= f->nupvalues, "invalid upvalue index");
+ api_check(L, 1 <= n && n <= f->nupvalues, "invalid upvalue index");
return &f->upvalue[n - 1];
}
default: {
- api_check(0, "closure expected");
+ api_check(L, 0, "closure expected");
return NULL;
}
}
diff --git a/src/lapi.h b/src/lapi.h
index 092f5e974cb1..6d36dee3fb78 100644
--- a/src/lapi.h
+++ b/src/lapi.h
@@ -1,5 +1,5 @@
/*
-** $Id: lapi.h,v 2.8 2014/07/15 21:26:50 roberto Exp $
+** $Id: lapi.h,v 2.9 2015/03/06 19:49:50 roberto Exp $
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/
@@ -11,13 +11,13 @@
#include "llimits.h"
#include "lstate.h"
-#define api_incr_top(L) {L->top++; api_check(L->top <= L->ci->top, \
+#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
"stack overflow");}
#define adjustresults(L,nres) \
{ if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
-#define api_checknelems(L,n) api_check((n) < (L->top - L->ci->func), \
+#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
"not enough elements in the stack")
diff --git a/src/lauxlib.c b/src/lauxlib.c
index 1c41d6a8eaf4..f7a383663e19 100644
--- a/src/lauxlib.c
+++ b/src/lauxlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.c,v 1.279 2014/12/14 18:32:26 roberto Exp $
+** $Id: lauxlib.c,v 1.289 2016/12/20 18:37:00 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -17,7 +17,8 @@
#include <string.h>
-/* This file uses only the official API of Lua.
+/*
+** This file uses only the official API of Lua.
** Any function declared here could be written as an application function.
*/
@@ -33,8 +34,8 @@
*/
-#define LEVELS1 12 /* size of the first part of the stack */
-#define LEVELS2 10 /* size of the second part of the stack */
+#define LEVELS1 10 /* size of the first part of the stack */
+#define LEVELS2 11 /* size of the second part of the stack */
@@ -68,12 +69,11 @@ static int findfield (lua_State *L, int objidx, int level) {
/*
** Search for a name for a function in all loaded modules
-** (registry._LOADED).
*/
static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
int top = lua_gettop(L);
lua_getinfo(L, "f", ar); /* push function */
- lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+ lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
if (findfield(L, top + 1, 2)) {
const char *name = lua_tostring(L, -1);
if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */
@@ -107,7 +107,7 @@ static void pushfuncname (lua_State *L, lua_Debug *ar) {
}
-static int countlevels (lua_State *L) {
+static int lastlevel (lua_State *L) {
lua_Debug ar;
int li = 1, le = 1;
/* find an upper bound */
@@ -126,14 +126,16 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
const char *msg, int level) {
lua_Debug ar;
int top = lua_gettop(L);
- int numlevels = countlevels(L1);
- int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
- if (msg) lua_pushfstring(L, "%s\n", msg);
+ int last = lastlevel(L1);
+ int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1;
+ if (msg)
+ lua_pushfstring(L, "%s\n", msg);
+ luaL_checkstack(L, 10, NULL);
lua_pushliteral(L, "stack traceback:");
while (lua_getstack(L1, level++, &ar)) {
- if (level == mark) { /* too many levels? */
+ if (n1-- == 0) { /* too many levels? */
lua_pushliteral(L, "\n\t..."); /* add a '...' */
- level = numlevels - LEVELS2; /* and skip to last ones */
+ level = last - LEVELS2 + 1; /* and skip to last ones */
}
else {
lua_getinfo(L1, "Slnt", &ar);
@@ -196,6 +198,10 @@ static void tag_error (lua_State *L, int arg, int tag) {
}
+/*
+** The use of 'lua_pushfstring' ensures this function does not
+** need reserved stack space when called.
+*/
LUALIB_API void luaL_where (lua_State *L, int level) {
lua_Debug ar;
if (lua_getstack(L, level, &ar)) { /* check function at level */
@@ -205,10 +211,15 @@ LUALIB_API void luaL_where (lua_State *L, int level) {
return;
}
}
- lua_pushliteral(L, ""); /* else, no information available... */
+ lua_pushfstring(L, ""); /* else, no information available... */
}
+/*
+** Again, the use of 'lua_pushvfstring' ensures this function does
+** not need reserved stack space when called. (At worst, it generates
+** an error with "stack overflow" instead of the given message.)
+*/
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
@@ -286,10 +297,10 @@ LUALIB_API int luaL_execresult (lua_State *L, int stat) {
*/
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
- if (luaL_getmetatable(L, tname)) /* name already in use? */
+ if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */
return 0; /* leave previous value on top, but return 0 */
lua_pop(L, 1);
- lua_newtable(L); /* create metatable */
+ lua_createtable(L, 0, 2); /* create metatable */
lua_pushstring(L, tname);
lua_setfield(L, -2, "__name"); /* metatable.__name = tname */
lua_pushvalue(L, -1);
@@ -347,10 +358,15 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
}
+/*
+** Ensures the stack has at least 'space' extra slots, raising an error
+** if it cannot fulfill the request. (The error handling needs a few
+** extra slots to format the error message. In case of an error without
+** this extra space, Lua will generate the same 'stack overflow' error,
+** but without 'msg'.)
+*/
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
- /* keep some extra space to run error routines, if needed */
- const int extra = LUA_MINSTACK;
- if (!lua_checkstack(L, space + extra)) {
+ if (!lua_checkstack(L, space)) {
if (msg)
luaL_error(L, "stack overflow (%s)", msg);
else
@@ -435,6 +451,47 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg,
** =======================================================
*/
+/* userdata to box arbitrary data */
+typedef struct UBox {
+ void *box;
+ size_t bsize;
+} UBox;
+
+
+static void *resizebox (lua_State *L, int idx, size_t newsize) {
+ void *ud;
+ lua_Alloc allocf = lua_getallocf(L, &ud);
+ UBox *box = (UBox *)lua_touserdata(L, idx);
+ void *temp = allocf(ud, box->box, box->bsize, newsize);
+ if (temp == NULL && newsize > 0) { /* allocation error? */
+ resizebox(L, idx, 0); /* free buffer */
+ luaL_error(L, "not enough memory for buffer allocation");
+ }
+ box->box = temp;
+ box->bsize = newsize;
+ return temp;
+}
+
+
+static int boxgc (lua_State *L) {
+ resizebox(L, 1, 0);
+ return 0;
+}
+
+
+static void *newbox (lua_State *L, size_t newsize) {
+ UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox));
+ box->box = NULL;
+ box->bsize = 0;
+ if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */
+ lua_pushcfunction(L, boxgc);
+ lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */
+ }
+ lua_setmetatable(L, -2);
+ return resizebox(L, -1, newsize);
+}
+
+
/*
** check whether buffer is using a userdata on the stack as a temporary
** buffer
@@ -455,11 +512,12 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
if (newsize < B->n || newsize - B->n < sz)
luaL_error(L, "buffer too large");
/* create larger buffer */
- newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));
- /* move content to new buffer */
- memcpy(newbuff, B->b, B->n * sizeof(char));
if (buffonstack(B))
- lua_remove(L, -2); /* remove old buffer */
+ newbuff = (char *)resizebox(L, -1, newsize);
+ else { /* no buffer yet */
+ newbuff = (char *)newbox(L, newsize);
+ memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */
+ }
B->b = newbuff;
B->size = newsize;
}
@@ -468,9 +526,11 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
- char *b = luaL_prepbuffsize(B, l);
- memcpy(b, s, l * sizeof(char));
- luaL_addsize(B, l);
+ if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */
+ char *b = luaL_prepbuffsize(B, l);
+ memcpy(b, s, l * sizeof(char));
+ luaL_addsize(B, l);
+ }
}
@@ -482,8 +542,10 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
lua_State *L = B->L;
lua_pushlstring(L, B->b, B->n);
- if (buffonstack(B))
- lua_remove(L, -2); /* remove old buffer */
+ if (buffonstack(B)) {
+ resizebox(L, -2, 0); /* delete old buffer */
+ lua_remove(L, -2); /* remove its header from the stack */
+ }
}
@@ -605,7 +667,7 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
static int skipBOM (LoadF *lf) {
- const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */
+ const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
int c;
lf->n = 0;
do {
@@ -630,7 +692,7 @@ static int skipcomment (LoadF *lf, int *cp) {
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
c = getc(lf->f);
- } while (c != EOF && c != '\n') ;
+ } while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */
return 1; /* there was a comment */
}
@@ -746,13 +808,17 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
- if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */
+ if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */
+ if (!lua_isstring(L, -1))
+ luaL_error(L, "'__tostring' must return a string");
+ }
+ else {
switch (lua_type(L, idx)) {
case LUA_TNUMBER: {
if (lua_isinteger(L, idx))
- lua_pushfstring(L, "%I", lua_tointeger(L, idx));
+ lua_pushfstring(L, "%I", (LUAI_UACINT)lua_tointeger(L, idx));
else
- lua_pushfstring(L, "%f", lua_tonumber(L, idx));
+ lua_pushfstring(L, "%f", (LUAI_UACNUMBER)lua_tonumber(L, idx));
break;
}
case LUA_TSTRING:
@@ -764,10 +830,15 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
case LUA_TNIL:
lua_pushliteral(L, "nil");
break;
- default:
- lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
- lua_topointer(L, idx));
+ default: {
+ int tt = luaL_getmetafield(L, idx, "__name"); /* try name */
+ const char *kind = (tt == LUA_TSTRING) ? lua_tostring(L, -1) :
+ luaL_typename(L, idx);
+ lua_pushfstring(L, "%s: %p", kind, lua_topointer(L, idx));
+ if (tt != LUA_TNIL)
+ lua_remove(L, -2); /* remove '__name' */
break;
+ }
}
}
return lua_tolstring(L, -1, len);
@@ -819,23 +890,23 @@ static int libsize (const luaL_Reg *l) {
/*
** Find or create a module table with a given name. The function
-** first looks at the _LOADED table and, if that fails, try a
+** first looks at the LOADED table and, if that fails, try a
** global variable with that name. In any case, leaves on the stack
** the module table.
*/
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
int sizehint) {
- luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */
- if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */
+ luaL_findtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE, 1);
+ if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no LOADED[modname]? */
lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
lua_pushglobaltable(L);
if (luaL_findtable(L, 0, modname, sizehint) != NULL)
luaL_error(L, "name conflict for module '%s'", modname);
lua_pushvalue(L, -1);
- lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */
+ lua_setfield(L, -3, modname); /* LOADED[modname] = new table */
}
- lua_remove(L, -2); /* remove _LOADED table */
+ lua_remove(L, -2); /* remove LOADED table */
}
@@ -899,17 +970,17 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
*/
LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
lua_CFunction openf, int glb) {
- luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
- lua_getfield(L, -1, modname); /* _LOADED[modname] */
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
+ lua_getfield(L, -1, modname); /* LOADED[modname] */
if (!lua_toboolean(L, -1)) { /* package not already loaded? */
lua_pop(L, 1); /* remove field */
lua_pushcfunction(L, openf);
lua_pushstring(L, modname); /* argument to open function */
lua_call(L, 1, 1); /* call 'openf' to open module */
lua_pushvalue(L, -1); /* make copy of module (call result) */
- lua_setfield(L, -3, modname); /* _LOADED[modname] = module */
+ lua_setfield(L, -3, modname); /* LOADED[modname] = module */
}
- lua_remove(L, -2); /* remove _LOADED table */
+ lua_remove(L, -2); /* remove LOADED table */
if (glb) {
lua_pushvalue(L, -1); /* copy of module */
lua_setglobal(L, modname); /* _G[modname] = module */
@@ -967,6 +1038,6 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
luaL_error(L, "multiple Lua VMs detected");
else if (*v != ver)
luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
- ver, *v);
+ (LUAI_UACNUMBER)ver, (LUAI_UACNUMBER)*v);
}
diff --git a/src/lauxlib.h b/src/lauxlib.h
index 0bac2467ec61..9a2e66aa0670 100644
--- a/src/lauxlib.h
+++ b/src/lauxlib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lauxlib.h,v 1.128 2014/10/29 16:11:17 roberto Exp $
+** $Id: lauxlib.h,v 1.131 2016/12/06 14:54:31 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -16,10 +16,18 @@
-/* extra error code for 'luaL_load' */
+/* extra error code for 'luaL_loadfilex' */
#define LUA_ERRFILE (LUA_ERRERR+1)
+/* key, in the registry, for table of loaded modules */
+#define LUA_LOADED_TABLE "_LOADED"
+
+
+/* key, in the registry, for table of preloaded loaders */
+#define LUA_PRELOAD_TABLE "_PRELOAD"
+
+
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
@@ -65,7 +73,7 @@ LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
-/* pre-defined references */
+/* predefined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
diff --git a/src/lbaselib.c b/src/lbaselib.c
index a2403952f028..08523e6e7540 100644
--- a/src/lbaselib.c
+++ b/src/lbaselib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lbaselib.c,v 1.309 2014/12/10 12:26:42 roberto Exp $
+** $Id: lbaselib.c,v 1.314 2016/09/05 19:06:34 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
@@ -55,7 +55,7 @@ static const char *b_str2int (const char *s, int base, lua_Integer *pn) {
return NULL;
do {
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
- : toupper((unsigned char)*s) - 'A' + 10;
+ : (toupper((unsigned char)*s) - 'A') + 10;
if (digit >= base) return NULL; /* invalid numeral */
n = n * base + digit;
s++;
@@ -86,8 +86,8 @@ static int luaB_tonumber (lua_State *L) {
const char *s;
lua_Integer n = 0; /* to avoid warnings */
lua_Integer base = luaL_checkinteger(L, 2);
- luaL_checktype(L, 1, LUA_TSTRING); /* before 'luaL_checklstring'! */
- s = luaL_checklstring(L, 1, &l);
+ luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
+ s = lua_tolstring(L, 1, &l);
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
if (b_str2int(s, (int)base, &n) == s + l) {
lua_pushinteger(L, n);
@@ -102,8 +102,8 @@ static int luaB_tonumber (lua_State *L) {
static int luaB_error (lua_State *L) {
int level = (int)luaL_optinteger(L, 2, 1);
lua_settop(L, 1);
- if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
- luaL_where(L, level);
+ if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
+ luaL_where(L, level); /* add extra information */
lua_pushvalue(L, 1);
lua_concat(L, 2);
}
@@ -198,20 +198,18 @@ static int luaB_collectgarbage (lua_State *L) {
}
-/*
-** This function has all type names as upvalues, to maximize performance.
-*/
static int luaB_type (lua_State *L) {
- luaL_checkany(L, 1);
- lua_pushvalue(L, lua_upvalueindex(lua_type(L, 1) + 1));
+ int t = lua_type(L, 1);
+ luaL_argcheck(L, t != LUA_TNONE, 1, "value expected");
+ lua_pushstring(L, lua_typename(L, t));
return 1;
}
static int pairsmeta (lua_State *L, const char *method, int iszero,
lua_CFunction iter) {
+ luaL_checkany(L, 1);
if (luaL_getmetafield(L, 1, method) == LUA_TNIL) { /* no metamethod? */
- luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */
lua_pushcfunction(L, iter); /* will return generator, */
lua_pushvalue(L, 1); /* state, */
if (iszero) lua_pushinteger(L, 0); /* and initial value */
@@ -243,18 +241,7 @@ static int luaB_pairs (lua_State *L) {
/*
-** Traversal function for 'ipairs' for raw tables
-*/
-static int ipairsaux_raw (lua_State *L) {
- lua_Integer i = luaL_checkinteger(L, 2) + 1;
- luaL_checktype(L, 1, LUA_TTABLE);
- lua_pushinteger(L, i);
- return (lua_rawgeti(L, 1, i) == LUA_TNIL) ? 1 : 2;
-}
-
-
-/*
-** Traversal function for 'ipairs' for tables with metamethods
+** Traversal function for 'ipairs'
*/
static int ipairsaux (lua_State *L) {
lua_Integer i = luaL_checkinteger(L, 2) + 1;
@@ -264,18 +251,15 @@ static int ipairsaux (lua_State *L) {
/*
-** This function will use either 'ipairsaux' or 'ipairsaux_raw' to
-** traverse a table, depending on whether the table has metamethods
-** that can affect the traversal.
+** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
+** (The given "table" may not be a table.)
*/
static int luaB_ipairs (lua_State *L) {
- lua_CFunction iter = (luaL_getmetafield(L, 1, "__index") != LUA_TNIL)
- ? ipairsaux : ipairsaux_raw;
#if defined(LUA_COMPAT_IPAIRS)
- return pairsmeta(L, "__ipairs", 1, iter);
+ return pairsmeta(L, "__ipairs", 1, ipairsaux);
#else
luaL_checkany(L, 1);
- lua_pushcfunction(L, iter); /* iteration function */
+ lua_pushcfunction(L, ipairsaux); /* iteration function */
lua_pushvalue(L, 1); /* state */
lua_pushinteger(L, 0); /* initial value */
return 3;
@@ -490,9 +474,9 @@ static const luaL_Reg base_funcs[] = {
{"setmetatable", luaB_setmetatable},
{"tonumber", luaB_tonumber},
{"tostring", luaB_tostring},
+ {"type", luaB_type},
{"xpcall", luaB_xpcall},
/* placeholders */
- {"type", NULL},
{"_G", NULL},
{"_VERSION", NULL},
{NULL, NULL}
@@ -500,7 +484,6 @@ static const luaL_Reg base_funcs[] = {
LUAMOD_API int luaopen_base (lua_State *L) {
- int i;
/* open lib into global table */
lua_pushglobaltable(L);
luaL_setfuncs(L, base_funcs, 0);
@@ -510,11 +493,6 @@ LUAMOD_API int luaopen_base (lua_State *L) {
/* set global _VERSION */
lua_pushliteral(L, LUA_VERSION);
lua_setfield(L, -2, "_VERSION");
- /* set function 'type' with proper upvalues */
- for (i = 0; i < LUA_NUMTAGS; i++) /* push all type names as upvalues */
- lua_pushstring(L, lua_typename(L, i));
- lua_pushcclosure(L, luaB_type, LUA_NUMTAGS);
- lua_setfield(L, -2, "type");
return 1;
}
diff --git a/src/lbitlib.c b/src/lbitlib.c
index 15d5f0cdfc40..1cb1d5b93238 100644
--- a/src/lbitlib.c
+++ b/src/lbitlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lbitlib.c,v 1.28 2014/11/02 19:19:04 roberto Exp $
+** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/
@@ -19,6 +19,10 @@
#if defined(LUA_COMPAT_BITLIB) /* { */
+#define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
+#define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i))
+
+
/* number of bits to consider in a number */
#if !defined(LUA_NBITS)
#define LUA_NBITS 32
@@ -46,14 +50,14 @@ static lua_Unsigned andaux (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = ~(lua_Unsigned)0;
for (i = 1; i <= n; i++)
- r &= luaL_checkunsigned(L, i);
+ r &= checkunsigned(L, i);
return trim(r);
}
static int b_and (lua_State *L) {
lua_Unsigned r = andaux(L);
- lua_pushunsigned(L, r);
+ pushunsigned(L, r);
return 1;
}
@@ -69,8 +73,8 @@ static int b_or (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = 0;
for (i = 1; i <= n; i++)
- r |= luaL_checkunsigned(L, i);
- lua_pushunsigned(L, trim(r));
+ r |= checkunsigned(L, i);
+ pushunsigned(L, trim(r));
return 1;
}
@@ -79,15 +83,15 @@ static int b_xor (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = 0;
for (i = 1; i <= n; i++)
- r ^= luaL_checkunsigned(L, i);
- lua_pushunsigned(L, trim(r));
+ r ^= checkunsigned(L, i);
+ pushunsigned(L, trim(r));
return 1;
}
static int b_not (lua_State *L) {
- lua_Unsigned r = ~luaL_checkunsigned(L, 1);
- lua_pushunsigned(L, trim(r));
+ lua_Unsigned r = ~checkunsigned(L, 1);
+ pushunsigned(L, trim(r));
return 1;
}
@@ -104,23 +108,23 @@ static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) {
else r <<= i;
r = trim(r);
}
- lua_pushunsigned(L, r);
+ pushunsigned(L, r);
return 1;
}
static int b_lshift (lua_State *L) {
- return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkinteger(L, 2));
+ return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2));
}
static int b_rshift (lua_State *L) {
- return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkinteger(L, 2));
+ return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2));
}
static int b_arshift (lua_State *L) {
- lua_Unsigned r = luaL_checkunsigned(L, 1);
+ lua_Unsigned r = checkunsigned(L, 1);
lua_Integer i = luaL_checkinteger(L, 2);
if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1))))
return b_shift(L, r, -i);
@@ -128,19 +132,19 @@ static int b_arshift (lua_State *L) {
if (i >= LUA_NBITS) r = ALLONES;
else
r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */
- lua_pushunsigned(L, r);
+ pushunsigned(L, r);
return 1;
}
}
static int b_rot (lua_State *L, lua_Integer d) {
- lua_Unsigned r = luaL_checkunsigned(L, 1);
+ lua_Unsigned r = checkunsigned(L, 1);
int i = d & (LUA_NBITS - 1); /* i = d % NBITS */
r = trim(r);
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
r = (r << i) | (r >> (LUA_NBITS - i));
- lua_pushunsigned(L, trim(r));
+ pushunsigned(L, trim(r));
return 1;
}
@@ -175,23 +179,22 @@ static int fieldargs (lua_State *L, int farg, int *width) {
static int b_extract (lua_State *L) {
int w;
- lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
+ lua_Unsigned r = trim(checkunsigned(L, 1));
int f = fieldargs(L, 2, &w);
r = (r >> f) & mask(w);
- lua_pushunsigned(L, r);
+ pushunsigned(L, r);
return 1;
}
static int b_replace (lua_State *L) {
int w;
- lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
- lua_Unsigned v = luaL_checkunsigned(L, 2);
+ lua_Unsigned r = trim(checkunsigned(L, 1));
+ lua_Unsigned v = trim(checkunsigned(L, 2));
int f = fieldargs(L, 3, &w);
- int m = mask(w);
- v &= m; /* erase bits outside given width */
- r = (r & ~(m << f)) | (v << f);
- lua_pushunsigned(L, r);
+ lua_Unsigned m = mask(w);
+ r = (r & ~(m << f)) | ((v & m) << f);
+ pushunsigned(L, r);
return 1;
}
diff --git a/src/lcode.c b/src/lcode.c
index 5e34624bf462..0bb414262e3c 100644
--- a/src/lcode.c
+++ b/src/lcode.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.c,v 2.99 2014/12/29 16:49:25 roberto Exp $
+** $Id: lcode.c,v 2.112 2016/12/22 13:08:50 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -29,15 +29,19 @@
#include "lvm.h"
-/* Maximum number of registers in a Lua function */
-#define MAXREGS 250
+/* Maximum number of registers in a Lua function (must fit in 8 bits) */
+#define MAXREGS 255
#define hasjumps(e) ((e)->t != (e)->f)
-static int tonumeral(expdesc *e, TValue *v) {
- if (e->t != NO_JUMP || e->f != NO_JUMP)
+/*
+** If expression is a numeric constant, fills 'v' with its value
+** and returns 1. Otherwise, returns 0.
+*/
+static int tonumeral(const expdesc *e, TValue *v) {
+ if (hasjumps(e))
return 0; /* not a numeral */
switch (e->k) {
case VKINT:
@@ -51,13 +55,19 @@ static int tonumeral(expdesc *e, TValue *v) {
}
+/*
+** Create a OP_LOADNIL instruction, but try to optimize: if the previous
+** instruction is also OP_LOADNIL and ranges are compatible, adjust
+** range of previous instruction instead of emitting a new one. (For
+** instance, 'local a; local b' will generate a single opcode.)
+*/
void luaK_nil (FuncState *fs, int from, int n) {
Instruction *previous;
int l = from + n - 1; /* last register to set nil */
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
previous = &fs->f->code[fs->pc-1];
- if (GET_OPCODE(*previous) == OP_LOADNIL) {
- int pfrom = GETARG_A(*previous);
+ if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */
+ int pfrom = GETARG_A(*previous); /* get previous range */
int pl = pfrom + GETARG_B(*previous);
if ((pfrom <= from && from <= pl + 1) ||
(from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
@@ -73,37 +83,84 @@ void luaK_nil (FuncState *fs, int from, int n) {
}
+/*
+** Gets the destination address of a jump instruction. Used to traverse
+** a list of jumps.
+*/
+static int getjump (FuncState *fs, int pc) {
+ int offset = GETARG_sBx(fs->f->code[pc]);
+ if (offset == NO_JUMP) /* point to itself represents end of list */
+ return NO_JUMP; /* end of list */
+ else
+ return (pc+1)+offset; /* turn offset into absolute position */
+}
+
+
+/*
+** Fix jump instruction at position 'pc' to jump to 'dest'.
+** (Jump addresses are relative in Lua)
+*/
+static void fixjump (FuncState *fs, int pc, int dest) {
+ Instruction *jmp = &fs->f->code[pc];
+ int offset = dest - (pc + 1);
+ lua_assert(dest != NO_JUMP);
+ if (abs(offset) > MAXARG_sBx)
+ luaX_syntaxerror(fs->ls, "control structure too long");
+ SETARG_sBx(*jmp, offset);
+}
+
+
+/*
+** Concatenate jump-list 'l2' into jump-list 'l1'
+*/
+void luaK_concat (FuncState *fs, int *l1, int l2) {
+ if (l2 == NO_JUMP) return; /* nothing to concatenate? */
+ else if (*l1 == NO_JUMP) /* no original list? */
+ *l1 = l2; /* 'l1' points to 'l2' */
+ else {
+ int list = *l1;
+ int next;
+ while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
+ list = next;
+ fixjump(fs, list, l2); /* last element links to 'l2' */
+ }
+}
+
+
+/*
+** Create a jump instruction and return its position, so its destination
+** can be fixed later (with 'fixjump'). If there are jumps to
+** this position (kept in 'jpc'), link them all together so that
+** 'patchlistaux' will fix all them directly to the final destination.
+*/
int luaK_jump (FuncState *fs) {
int jpc = fs->jpc; /* save list of jumps to here */
int j;
- fs->jpc = NO_JUMP;
+ fs->jpc = NO_JUMP; /* no more jumps to here */
j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
luaK_concat(fs, &j, jpc); /* keep them on hold */
return j;
}
+/*
+** Code a 'return' instruction
+*/
void luaK_ret (FuncState *fs, int first, int nret) {
luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
}
+/*
+** Code a "conditional jump", that is, a test or comparison opcode
+** followed by a jump. Return jump position.
+*/
static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
luaK_codeABC(fs, op, A, B, C);
return luaK_jump(fs);
}
-static void fixjump (FuncState *fs, int pc, int dest) {
- Instruction *jmp = &fs->f->code[pc];
- int offset = dest-(pc+1);
- lua_assert(dest != NO_JUMP);
- if (abs(offset) > MAXARG_sBx)
- luaX_syntaxerror(fs->ls, "control structure too long");
- SETARG_sBx(*jmp, offset);
-}
-
-
/*
** returns current 'pc' and marks it as a jump target (to avoid wrong
** optimizations with consecutive instructions not in the same basic block).
@@ -114,15 +171,11 @@ int luaK_getlabel (FuncState *fs) {
}
-static int getjump (FuncState *fs, int pc) {
- int offset = GETARG_sBx(fs->f->code[pc]);
- if (offset == NO_JUMP) /* point to itself represents end of list */
- return NO_JUMP; /* end of list */
- else
- return (pc+1)+offset; /* turn offset into absolute position */
-}
-
-
+/*
+** Returns the position of the instruction "controlling" a given
+** jump (that is, its condition), or the jump itself if it is
+** unconditional.
+*/
static Instruction *getjumpcontrol (FuncState *fs, int pc) {
Instruction *pi = &fs->f->code[pc];
if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
@@ -133,37 +186,41 @@ static Instruction *getjumpcontrol (FuncState *fs, int pc) {
/*
-** check whether list has any jump that do not produce a value
-** (or produce an inverted value)
+** Patch destination register for a TESTSET instruction.
+** If instruction in position 'node' is not a TESTSET, return 0 ("fails").
+** Otherwise, if 'reg' is not 'NO_REG', set it as the destination
+** register. Otherwise, change instruction to a simple 'TEST' (produces
+** no register value)
*/
-static int need_value (FuncState *fs, int list) {
- for (; list != NO_JUMP; list = getjump(fs, list)) {
- Instruction i = *getjumpcontrol(fs, list);
- if (GET_OPCODE(i) != OP_TESTSET) return 1;
- }
- return 0; /* not found */
-}
-
-
static int patchtestreg (FuncState *fs, int node, int reg) {
Instruction *i = getjumpcontrol(fs, node);
if (GET_OPCODE(*i) != OP_TESTSET)
return 0; /* cannot patch other instructions */
if (reg != NO_REG && reg != GETARG_B(*i))
SETARG_A(*i, reg);
- else /* no register to put value or register already has the value */
+ else {
+ /* no register to put value or register already has the value;
+ change instruction to simple test */
*i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
-
+ }
return 1;
}
+/*
+** Traverse a list of tests ensuring no one produces a value
+*/
static void removevalues (FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list))
patchtestreg(fs, list, NO_REG);
}
+/*
+** Traverse a list of tests, patching their destination address and
+** registers: tests producing values jump to 'vtarget' (and put their
+** values in 'reg'), other tests jump to 'dtarget'.
+*/
static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
int dtarget) {
while (list != NO_JUMP) {
@@ -177,15 +234,35 @@ static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
}
+/*
+** Ensure all pending jumps to current position are fixed (jumping
+** to current position with no values) and reset list of pending
+** jumps
+*/
static void dischargejpc (FuncState *fs) {
patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
fs->jpc = NO_JUMP;
}
+/*
+** Add elements in 'list' to list of pending jumps to "here"
+** (current position)
+*/
+void luaK_patchtohere (FuncState *fs, int list) {
+ luaK_getlabel(fs); /* mark "here" as a jump target */
+ luaK_concat(fs, &fs->jpc, list);
+}
+
+
+/*
+** Path all jumps in 'list' to jump to 'target'.
+** (The assert means that we cannot fix a jump to a forward address
+** because we only know addresses once code is generated.)
+*/
void luaK_patchlist (FuncState *fs, int list, int target) {
- if (target == fs->pc)
- luaK_patchtohere(fs, list);
+ if (target == fs->pc) /* 'target' is current position? */
+ luaK_patchtohere(fs, list); /* add list to pending jumps */
else {
lua_assert(target < fs->pc);
patchlistaux(fs, list, target, NO_REG, target);
@@ -193,39 +270,26 @@ void luaK_patchlist (FuncState *fs, int list, int target) {
}
+/*
+** Path all jumps in 'list' to close upvalues up to given 'level'
+** (The assertion checks that jumps either were closing nothing
+** or were closing higher levels, from inner blocks.)
+*/
void luaK_patchclose (FuncState *fs, int list, int level) {
level++; /* argument is +1 to reserve 0 as non-op */
- while (list != NO_JUMP) {
- int next = getjump(fs, list);
+ for (; list != NO_JUMP; list = getjump(fs, list)) {
lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
(GETARG_A(fs->f->code[list]) == 0 ||
GETARG_A(fs->f->code[list]) >= level));
SETARG_A(fs->f->code[list], level);
- list = next;
- }
-}
-
-
-void luaK_patchtohere (FuncState *fs, int list) {
- luaK_getlabel(fs);
- luaK_concat(fs, &fs->jpc, list);
-}
-
-
-void luaK_concat (FuncState *fs, int *l1, int l2) {
- if (l2 == NO_JUMP) return;
- else if (*l1 == NO_JUMP)
- *l1 = l2;
- else {
- int list = *l1;
- int next;
- while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
- list = next;
- fixjump(fs, list, l2);
}
}
+/*
+** Emit instruction 'i', checking for array sizes and saving also its
+** line information. Return 'i' position.
+*/
static int luaK_code (FuncState *fs, Instruction i) {
Proto *f = fs->f;
dischargejpc(fs); /* 'pc' will change */
@@ -241,6 +305,10 @@ static int luaK_code (FuncState *fs, Instruction i) {
}
+/*
+** Format and emit an 'iABC' instruction. (Assertions check consistency
+** of parameters versus opcode.)
+*/
int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
lua_assert(getOpMode(o) == iABC);
lua_assert(getBMode(o) != OpArgN || b == 0);
@@ -250,6 +318,9 @@ int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
}
+/*
+** Format and emit an 'iABx' instruction.
+*/
int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
lua_assert(getCMode(o) == OpArgN);
@@ -258,12 +329,20 @@ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
}
+/*
+** Emit an "extra argument" instruction (format 'iAx')
+*/
static int codeextraarg (FuncState *fs, int a) {
lua_assert(a <= MAXARG_Ax);
return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
}
+/*
+** Emit a "load constant" instruction, using either 'OP_LOADK'
+** (if constant index 'k' fits in 18 bits) or an 'OP_LOADKX'
+** instruction with "extra argument".
+*/
int luaK_codek (FuncState *fs, int reg, int k) {
if (k <= MAXARG_Bx)
return luaK_codeABx(fs, OP_LOADK, reg, k);
@@ -275,22 +354,35 @@ int luaK_codek (FuncState *fs, int reg, int k) {
}
+/*
+** Check register-stack level, keeping track of its maximum size
+** in field 'maxstacksize'
+*/
void luaK_checkstack (FuncState *fs, int n) {
int newstack = fs->freereg + n;
if (newstack > fs->f->maxstacksize) {
if (newstack >= MAXREGS)
- luaX_syntaxerror(fs->ls, "function or expression too complex");
+ luaX_syntaxerror(fs->ls,
+ "function or expression needs too many registers");
fs->f->maxstacksize = cast_byte(newstack);
}
}
+/*
+** Reserve 'n' registers in register stack
+*/
void luaK_reserveregs (FuncState *fs, int n) {
luaK_checkstack(fs, n);
fs->freereg += n;
}
+/*
+** Free register 'reg', if it is neither a constant index nor
+** a local variable.
+)
+*/
static void freereg (FuncState *fs, int reg) {
if (!ISK(reg) && reg >= fs->nactvar) {
fs->freereg--;
@@ -299,6 +391,9 @@ static void freereg (FuncState *fs, int reg) {
}
+/*
+** Free register used by expression 'e' (if any)
+*/
static void freeexp (FuncState *fs, expdesc *e) {
if (e->k == VNONRELOC)
freereg(fs, e->u.info);
@@ -306,8 +401,29 @@ static void freeexp (FuncState *fs, expdesc *e) {
/*
+** Free registers used by expressions 'e1' and 'e2' (if any) in proper
+** order.
+*/
+static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) {
+ int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1;
+ int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1;
+ if (r1 > r2) {
+ freereg(fs, r1);
+ freereg(fs, r2);
+ }
+ else {
+ freereg(fs, r2);
+ freereg(fs, r1);
+ }
+}
+
+
+/*
+** Add constant 'v' to prototype's list of constants (field 'k').
** Use scanner's table to cache position of constants in constant list
-** and try to reuse constants
+** and try to reuse constants. Because some values should not be used
+** as keys (nil cannot be a key, integer keys can collapse with float
+** keys), the caller must provide a useful 'key' for indexing the cache.
*/
static int addk (FuncState *fs, TValue *key, TValue *v) {
lua_State *L = fs->ls->L;
@@ -336,17 +452,21 @@ static int addk (FuncState *fs, TValue *key, TValue *v) {
}
+/*
+** Add a string to list of constants and return its index.
+*/
int luaK_stringK (FuncState *fs, TString *s) {
TValue o;
setsvalue(fs->ls->L, &o, s);
- return addk(fs, &o, &o);
+ return addk(fs, &o, &o); /* use string itself as key */
}
/*
-** Integers use userdata as keys to avoid collision with floats with same
-** value; conversion to 'void*' used only for hashing, no "precision"
-** problems
+** Add an integer to list of constants and return its index.
+** Integers use userdata as keys to avoid collision with floats with
+** same value; conversion to 'void*' is used only for hashing, so there
+** are no "precision" problems.
*/
int luaK_intK (FuncState *fs, lua_Integer n) {
TValue k, o;
@@ -355,21 +475,29 @@ int luaK_intK (FuncState *fs, lua_Integer n) {
return addk(fs, &k, &o);
}
-
+/*
+** Add a float to list of constants and return its index.
+*/
static int luaK_numberK (FuncState *fs, lua_Number r) {
TValue o;
setfltvalue(&o, r);
- return addk(fs, &o, &o);
+ return addk(fs, &o, &o); /* use number itself as key */
}
+/*
+** Add a boolean to list of constants and return its index.
+*/
static int boolK (FuncState *fs, int b) {
TValue o;
setbvalue(&o, b);
- return addk(fs, &o, &o);
+ return addk(fs, &o, &o); /* use boolean itself as key */
}
+/*
+** Add nil to list of constants and return its index.
+*/
static int nilK (FuncState *fs) {
TValue k, v;
setnilvalue(&v);
@@ -379,54 +507,79 @@ static int nilK (FuncState *fs) {
}
+/*
+** Fix an expression to return the number of results 'nresults'.
+** Either 'e' is a multi-ret expression (function call or vararg)
+** or 'nresults' is LUA_MULTRET (as any expression can satisfy that).
+*/
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
if (e->k == VCALL) { /* expression is an open function call? */
- SETARG_C(getcode(fs, e), nresults+1);
+ SETARG_C(getinstruction(fs, e), nresults + 1);
}
else if (e->k == VVARARG) {
- SETARG_B(getcode(fs, e), nresults+1);
- SETARG_A(getcode(fs, e), fs->freereg);
+ Instruction *pc = &getinstruction(fs, e);
+ SETARG_B(*pc, nresults + 1);
+ SETARG_A(*pc, fs->freereg);
luaK_reserveregs(fs, 1);
}
+ else lua_assert(nresults == LUA_MULTRET);
}
+/*
+** Fix an expression to return one result.
+** If expression is not a multi-ret expression (function call or
+** vararg), it already returns one result, so nothing needs to be done.
+** Function calls become VNONRELOC expressions (as its result comes
+** fixed in the base register of the call), while vararg expressions
+** become VRELOCABLE (as OP_VARARG puts its results where it wants).
+** (Calls are created returning one result, so that does not need
+** to be fixed.)
+*/
void luaK_setoneret (FuncState *fs, expdesc *e) {
if (e->k == VCALL) { /* expression is an open function call? */
- e->k = VNONRELOC;
- e->u.info = GETARG_A(getcode(fs, e));
+ /* already returns 1 value */
+ lua_assert(GETARG_C(getinstruction(fs, e)) == 2);
+ e->k = VNONRELOC; /* result has fixed position */
+ e->u.info = GETARG_A(getinstruction(fs, e));
}
else if (e->k == VVARARG) {
- SETARG_B(getcode(fs, e), 2);
+ SETARG_B(getinstruction(fs, e), 2);
e->k = VRELOCABLE; /* can relocate its simple result */
}
}
+/*
+** Ensure that expression 'e' is not a variable.
+*/
void luaK_dischargevars (FuncState *fs, expdesc *e) {
switch (e->k) {
- case VLOCAL: {
- e->k = VNONRELOC;
+ case VLOCAL: { /* already in a register */
+ e->k = VNONRELOC; /* becomes a non-relocatable value */
break;
}
- case VUPVAL: {
+ case VUPVAL: { /* move value to some (pending) register */
e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
e->k = VRELOCABLE;
break;
}
case VINDEXED: {
- OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */
+ OpCode op;
freereg(fs, e->u.ind.idx);
- if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */
+ if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */
freereg(fs, e->u.ind.t);
op = OP_GETTABLE;
}
+ else {
+ lua_assert(e->u.ind.vt == VUPVAL);
+ op = OP_GETTABUP; /* 't' is in an upvalue */
+ }
e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
e->k = VRELOCABLE;
break;
}
- case VVARARG:
- case VCALL: {
+ case VVARARG: case VCALL: {
luaK_setoneret(fs, e);
break;
}
@@ -435,12 +588,10 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) {
}
-static int code_label (FuncState *fs, int A, int b, int jump) {
- luaK_getlabel(fs); /* those instructions may be jump targets */
- return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
-}
-
-
+/*
+** Ensures expression value is in register 'reg' (and therefore
+** 'e' will become a non-relocatable expression).
+*/
static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
luaK_dischargevars(fs, e);
switch (e->k) {
@@ -465,8 +616,8 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
break;
}
case VRELOCABLE: {
- Instruction *pc = &getcode(fs, e);
- SETARG_A(*pc, reg);
+ Instruction *pc = &getinstruction(fs, e);
+ SETARG_A(*pc, reg); /* instruction will put result in 'reg' */
break;
}
case VNONRELOC: {
@@ -475,7 +626,7 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
break;
}
default: {
- lua_assert(e->k == VVOID || e->k == VJMP);
+ lua_assert(e->k == VJMP);
return; /* nothing to do... */
}
}
@@ -484,17 +635,46 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
}
+/*
+** Ensures expression value is in any register.
+*/
static void discharge2anyreg (FuncState *fs, expdesc *e) {
- if (e->k != VNONRELOC) {
- luaK_reserveregs(fs, 1);
- discharge2reg(fs, e, fs->freereg-1);
+ if (e->k != VNONRELOC) { /* no fixed register yet? */
+ luaK_reserveregs(fs, 1); /* get a register */
+ discharge2reg(fs, e, fs->freereg-1); /* put value there */
}
}
+static int code_loadbool (FuncState *fs, int A, int b, int jump) {
+ luaK_getlabel(fs); /* those instructions may be jump targets */
+ return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
+}
+
+
+/*
+** check whether list has any jump that do not produce a value
+** or produce an inverted value
+*/
+static int need_value (FuncState *fs, int list) {
+ for (; list != NO_JUMP; list = getjump(fs, list)) {
+ Instruction i = *getjumpcontrol(fs, list);
+ if (GET_OPCODE(i) != OP_TESTSET) return 1;
+ }
+ return 0; /* not found */
+}
+
+
+/*
+** Ensures final expression result (including results from its jump
+** lists) is in register 'reg'.
+** If expression has jumps, need to patch these jumps either to
+** its final position or to "load" instructions (for those tests
+** that do not produce values).
+*/
static void exp2reg (FuncState *fs, expdesc *e, int reg) {
discharge2reg(fs, e, reg);
- if (e->k == VJMP)
+ if (e->k == VJMP) /* expression itself is a test? */
luaK_concat(fs, &e->t, e->u.info); /* put this jump in 't' list */
if (hasjumps(e)) {
int final; /* position after whole expression */
@@ -502,8 +682,8 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) {
int p_t = NO_JUMP; /* position of an eventual LOAD true */
if (need_value(fs, e->t) || need_value(fs, e->f)) {
int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
- p_f = code_label(fs, reg, 0, 1);
- p_t = code_label(fs, reg, 1, 0);
+ p_f = code_loadbool(fs, reg, 0, 1);
+ p_t = code_loadbool(fs, reg, 1, 0);
luaK_patchtohere(fs, fj);
}
final = luaK_getlabel(fs);
@@ -516,6 +696,10 @@ static void exp2reg (FuncState *fs, expdesc *e, int reg) {
}
+/*
+** Ensures final expression result (including results from its jump
+** lists) is in next available register.
+*/
void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
freeexp(fs, e);
@@ -524,26 +708,39 @@ void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
}
+/*
+** Ensures final expression result (including results from its jump
+** lists) is in some (any) register and return that register.
+*/
int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
- if (e->k == VNONRELOC) {
- if (!hasjumps(e)) return e->u.info; /* exp is already in a register */
+ if (e->k == VNONRELOC) { /* expression already has a register? */
+ if (!hasjumps(e)) /* no jumps? */
+ return e->u.info; /* result is already in a register */
if (e->u.info >= fs->nactvar) { /* reg. is not a local? */
- exp2reg(fs, e, e->u.info); /* put value on it */
+ exp2reg(fs, e, e->u.info); /* put final result in it */
return e->u.info;
}
}
- luaK_exp2nextreg(fs, e); /* default */
+ luaK_exp2nextreg(fs, e); /* otherwise, use next available register */
return e->u.info;
}
+/*
+** Ensures final expression result is either in a register or in an
+** upvalue.
+*/
void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
if (e->k != VUPVAL || hasjumps(e))
luaK_exp2anyreg(fs, e);
}
+/*
+** Ensures final expression result is either in a register or it is
+** a constant.
+*/
void luaK_exp2val (FuncState *fs, expdesc *e) {
if (hasjumps(e))
luaK_exp2anyreg(fs, e);
@@ -552,35 +749,26 @@ void luaK_exp2val (FuncState *fs, expdesc *e) {
}
+/*
+** Ensures final expression result is in a valid R/K index
+** (that is, it is either in a register or in 'k' with an index
+** in the range of R/K indices).
+** Returns R/K index.
+*/
int luaK_exp2RK (FuncState *fs, expdesc *e) {
luaK_exp2val(fs, e);
- switch (e->k) {
- case VTRUE:
- case VFALSE:
- case VNIL: {
- if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */
- e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE));
- e->k = VK;
- return RKASK(e->u.info);
- }
- else break;
- }
- case VKINT: {
- e->u.info = luaK_intK(fs, e->u.ival);
- e->k = VK;
- goto vk;
- }
- case VKFLT: {
- e->u.info = luaK_numberK(fs, e->u.nval);
- e->k = VK;
- /* go through */
- }
- case VK: {
+ switch (e->k) { /* move constants to 'k' */
+ case VTRUE: e->u.info = boolK(fs, 1); goto vk;
+ case VFALSE: e->u.info = boolK(fs, 0); goto vk;
+ case VNIL: e->u.info = nilK(fs); goto vk;
+ case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk;
+ case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk;
+ case VK:
vk:
+ e->k = VK;
if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */
return RKASK(e->u.info);
else break;
- }
default: break;
}
/* not a constant in the right range: put it in a register */
@@ -588,11 +776,14 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) {
}
+/*
+** Generate code to store result of expression 'ex' into variable 'var'.
+*/
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
switch (var->k) {
case VLOCAL: {
freeexp(fs, ex);
- exp2reg(fs, ex, var->u.info);
+ exp2reg(fs, ex, var->u.info); /* compute 'ex' into proper place */
return;
}
case VUPVAL: {
@@ -606,29 +797,32 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
break;
}
- default: {
- lua_assert(0); /* invalid var kind to store */
- break;
- }
+ default: lua_assert(0); /* invalid var kind to store */
}
freeexp(fs, ex);
}
+/*
+** Emit SELF instruction (convert expression 'e' into 'e:key(e,').
+*/
void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
int ereg;
luaK_exp2anyreg(fs, e);
ereg = e->u.info; /* register where 'e' was placed */
freeexp(fs, e);
e->u.info = fs->freereg; /* base register for op_self */
- e->k = VNONRELOC;
+ e->k = VNONRELOC; /* self expression has a fixed register */
luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */
luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key));
freeexp(fs, key);
}
-static void invertjump (FuncState *fs, expdesc *e) {
+/*
+** Negate condition 'e' (where 'e' is a comparison).
+*/
+static void negatecondition (FuncState *fs, expdesc *e) {
Instruction *pc = getjumpcontrol(fs, e->u.info);
lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
GET_OPCODE(*pc) != OP_TEST);
@@ -636,9 +830,15 @@ static void invertjump (FuncState *fs, expdesc *e) {
}
+/*
+** Emit instruction to jump if 'e' is 'cond' (that is, if 'cond'
+** is true, code will jump if 'e' is true.) Return jump position.
+** Optimize when 'e' is 'not' something, inverting the condition
+** and removing the 'not'.
+*/
static int jumponcond (FuncState *fs, expdesc *e, int cond) {
if (e->k == VRELOCABLE) {
- Instruction ie = getcode(fs, e);
+ Instruction ie = getinstruction(fs, e);
if (GET_OPCODE(ie) == OP_NOT) {
fs->pc--; /* remove previous OP_NOT */
return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
@@ -651,13 +851,16 @@ static int jumponcond (FuncState *fs, expdesc *e, int cond) {
}
+/*
+** Emit code to go through if 'e' is true, jump otherwise.
+*/
void luaK_goiftrue (FuncState *fs, expdesc *e) {
- int pc; /* pc of last jump */
+ int pc; /* pc of new jump */
luaK_dischargevars(fs, e);
switch (e->k) {
- case VJMP: {
- invertjump(fs, e);
- pc = e->u.info;
+ case VJMP: { /* condition? */
+ negatecondition(fs, e); /* jump when it is false */
+ pc = e->u.info; /* save jump position */
break;
}
case VK: case VKFLT: case VKINT: case VTRUE: {
@@ -665,22 +868,25 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
break;
}
default: {
- pc = jumponcond(fs, e, 0);
+ pc = jumponcond(fs, e, 0); /* jump when false */
break;
}
}
- luaK_concat(fs, &e->f, pc); /* insert last jump in 'f' list */
- luaK_patchtohere(fs, e->t);
+ luaK_concat(fs, &e->f, pc); /* insert new jump in false list */
+ luaK_patchtohere(fs, e->t); /* true list jumps to here (to go through) */
e->t = NO_JUMP;
}
+/*
+** Emit code to go through if 'e' is false, jump otherwise.
+*/
void luaK_goiffalse (FuncState *fs, expdesc *e) {
- int pc; /* pc of last jump */
+ int pc; /* pc of new jump */
luaK_dischargevars(fs, e);
switch (e->k) {
case VJMP: {
- pc = e->u.info;
+ pc = e->u.info; /* already jump if true */
break;
}
case VNIL: case VFALSE: {
@@ -688,29 +894,32 @@ void luaK_goiffalse (FuncState *fs, expdesc *e) {
break;
}
default: {
- pc = jumponcond(fs, e, 1);
+ pc = jumponcond(fs, e, 1); /* jump if true */
break;
}
}
- luaK_concat(fs, &e->t, pc); /* insert last jump in 't' list */
- luaK_patchtohere(fs, e->f);
+ luaK_concat(fs, &e->t, pc); /* insert new jump in 't' list */
+ luaK_patchtohere(fs, e->f); /* false list jumps to here (to go through) */
e->f = NO_JUMP;
}
+/*
+** Code 'not e', doing constant folding.
+*/
static void codenot (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
switch (e->k) {
case VNIL: case VFALSE: {
- e->k = VTRUE;
+ e->k = VTRUE; /* true == not nil == not false */
break;
}
case VK: case VKFLT: case VKINT: case VTRUE: {
- e->k = VFALSE;
+ e->k = VFALSE; /* false == not "x" == not 0.5 == not 1 == not true */
break;
}
case VJMP: {
- invertjump(fs, e);
+ negatecondition(fs, e);
break;
}
case VRELOCABLE:
@@ -721,30 +930,32 @@ static void codenot (FuncState *fs, expdesc *e) {
e->k = VRELOCABLE;
break;
}
- default: {
- lua_assert(0); /* cannot happen */
- break;
- }
+ default: lua_assert(0); /* cannot happen */
}
/* interchange true and false lists */
{ int temp = e->f; e->f = e->t; e->t = temp; }
- removevalues(fs, e->f);
+ removevalues(fs, e->f); /* values are useless when negated */
removevalues(fs, e->t);
}
+/*
+** Create expression 't[k]'. 't' must have its final result already in a
+** register or upvalue.
+*/
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
- lua_assert(!hasjumps(t));
- t->u.ind.t = t->u.info;
- t->u.ind.idx = luaK_exp2RK(fs, k);
- t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL
- : check_exp(vkisinreg(t->k), VLOCAL);
+ lua_assert(!hasjumps(t) && (vkisinreg(t->k) || t->k == VUPVAL));
+ t->u.ind.t = t->u.info; /* register or upvalue index */
+ t->u.ind.idx = luaK_exp2RK(fs, k); /* R/K index for key */
+ t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL : VLOCAL;
t->k = VINDEXED;
}
/*
-** return false if folding can raise an error
+** Return false if folding can raise an error.
+** Bitwise operations need operands convertible to integers; division
+** operations cannot have 0 as divisor.
*/
static int validop (int op, TValue *v1, TValue *v2) {
switch (op) {
@@ -761,9 +972,11 @@ static int validop (int op, TValue *v1, TValue *v2) {
/*
-** Try to "constant-fold" an operation; return 1 iff successful
+** Try to "constant-fold" an operation; return 1 iff successful.
+** (In this case, 'e1' has the final result.)
*/
-static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
+static int constfolding (FuncState *fs, int op, expdesc *e1,
+ const expdesc *e2) {
TValue v1, v2, res;
if (!tonumeral(e1, &v1) || !tonumeral(e2, &v2) || !validop(op, &v1, &v2))
return 0; /* non-numeric operands or not safe to fold */
@@ -772,7 +985,7 @@ static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
e1->k = VKINT;
e1->u.ival = ivalue(&res);
}
- else { /* folds neither NaN nor 0.0 (to avoid collapsing with -0.0) */
+ else { /* folds neither NaN nor 0.0 (to avoid problems with -0.0) */
lua_Number n = fltvalue(&res);
if (luai_numisnan(n) || n == 0)
return 0;
@@ -784,81 +997,100 @@ static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) {
/*
-** Code for binary and unary expressions that "produce values"
-** (arithmetic operations, bitwise operations, concat, length). First
-** try to do constant folding (only for numeric [arithmetic and
-** bitwise] operations, which is what 'lua_arith' accepts).
+** Emit code for unary expressions that "produce values"
+** (everything but 'not').
+** Expression to produce final result will be encoded in 'e'.
+*/
+static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) {
+ int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */
+ freeexp(fs, e);
+ e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */
+ e->k = VRELOCABLE; /* all those operations are relocatable */
+ luaK_fixline(fs, line);
+}
+
+
+/*
+** Emit code for binary expressions that "produce values"
+** (everything but logical operators 'and'/'or' and comparison
+** operators).
** Expression to produce final result will be encoded in 'e1'.
+** Because 'luaK_exp2RK' can free registers, its calls must be
+** in "stack order" (that is, first on 'e2', which may have more
+** recent registers to be released).
*/
-static void codeexpval (FuncState *fs, OpCode op,
- expdesc *e1, expdesc *e2, int line) {
- lua_assert(op >= OP_ADD);
- if (op <= OP_BNOT && constfolding(fs, op - OP_ADD + LUA_OPADD, e1, e2))
- return; /* result has been folded */
- else {
- int o1, o2;
- /* move operands to registers (if needed) */
- if (op == OP_UNM || op == OP_BNOT || op == OP_LEN) { /* unary op? */
- o2 = 0; /* no second expression */
- o1 = luaK_exp2anyreg(fs, e1); /* cannot operate on constants */
- }
- else { /* regular case (binary operators) */
- o2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */
- o1 = luaK_exp2RK(fs, e1);
- }
- if (o1 > o2) { /* free registers in proper order */
- freeexp(fs, e1);
- freeexp(fs, e2);
- }
- else {
- freeexp(fs, e2);
- freeexp(fs, e1);
- }
- e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); /* generate opcode */
- e1->k = VRELOCABLE; /* all those operations are relocable */
- luaK_fixline(fs, line);
- }
+static void codebinexpval (FuncState *fs, OpCode op,
+ expdesc *e1, expdesc *e2, int line) {
+ int rk2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */
+ int rk1 = luaK_exp2RK(fs, e1);
+ freeexps(fs, e1, e2);
+ e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */
+ e1->k = VRELOCABLE; /* all those operations are relocatable */
+ luaK_fixline(fs, line);
}
-static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
- expdesc *e2) {
- int o1 = luaK_exp2RK(fs, e1);
- int o2 = luaK_exp2RK(fs, e2);
- freeexp(fs, e2);
- freeexp(fs, e1);
- if (cond == 0 && op != OP_EQ) {
- int temp; /* exchange args to replace by '<' or '<=' */
- temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
- cond = 1;
+/*
+** Emit code for comparisons.
+** 'e1' was already put in R/K form by 'luaK_infix'.
+*/
+static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
+ int rk1 = (e1->k == VK) ? RKASK(e1->u.info)
+ : check_exp(e1->k == VNONRELOC, e1->u.info);
+ int rk2 = luaK_exp2RK(fs, e2);
+ freeexps(fs, e1, e2);
+ switch (opr) {
+ case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */
+ e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2);
+ break;
+ }
+ case OPR_GT: case OPR_GE: {
+ /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */
+ OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
+ e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */
+ break;
+ }
+ default: { /* '==', '<', '<=' use their own opcodes */
+ OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
+ e1->u.info = condjump(fs, op, 1, rk1, rk2);
+ break;
+ }
}
- e1->u.info = condjump(fs, op, cond, o1, o2);
e1->k = VJMP;
}
+/*
+** Aplly prefix operation 'op' to expression 'e'.
+*/
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
- expdesc e2;
- e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0;
+ static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
switch (op) {
- case OPR_MINUS: case OPR_BNOT: case OPR_LEN: {
- codeexpval(fs, cast(OpCode, (op - OPR_MINUS) + OP_UNM), e, &e2, line);
+ case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
+ if (constfolding(fs, op + LUA_OPUNM, e, &ef))
+ break;
+ /* FALLTHROUGH */
+ case OPR_LEN:
+ codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line);
break;
- }
case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0);
}
}
+/*
+** Process 1st operand 'v' of binary operation 'op' before reading
+** 2nd operand.
+*/
void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
switch (op) {
case OPR_AND: {
- luaK_goiftrue(fs, v);
+ luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */
break;
}
case OPR_OR: {
- luaK_goiffalse(fs, v);
+ luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */
break;
}
case OPR_CONCAT: {
@@ -870,7 +1102,9 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_MOD: case OPR_POW:
case OPR_BAND: case OPR_BOR: case OPR_BXOR:
case OPR_SHL: case OPR_SHR: {
- if (!tonumeral(v, NULL)) luaK_exp2RK(fs, v);
+ if (!tonumeral(v, NULL))
+ luaK_exp2RK(fs, v);
+ /* else keep numeral, which may be folded with 2nd operand */
break;
}
default: {
@@ -881,18 +1115,24 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
}
+/*
+** Finalize code for binary operation, after reading 2nd operand.
+** For '(a .. b .. c)' (which is '(a .. (b .. c))', because
+** concatenation is right associative), merge second CONCAT into first
+** one.
+*/
void luaK_posfix (FuncState *fs, BinOpr op,
expdesc *e1, expdesc *e2, int line) {
switch (op) {
case OPR_AND: {
- lua_assert(e1->t == NO_JUMP); /* list must be closed */
+ lua_assert(e1->t == NO_JUMP); /* list closed by 'luK_infix' */
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->f, e1->f);
*e1 = *e2;
break;
}
case OPR_OR: {
- lua_assert(e1->f == NO_JUMP); /* list must be closed */
+ lua_assert(e1->f == NO_JUMP); /* list closed by 'luK_infix' */
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->t, e1->t);
*e1 = *e2;
@@ -900,15 +1140,16 @@ void luaK_posfix (FuncState *fs, BinOpr op,
}
case OPR_CONCAT: {
luaK_exp2val(fs, e2);
- if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
- lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1);
+ if (e2->k == VRELOCABLE &&
+ GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) {
+ lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1);
freeexp(fs, e1);
- SETARG_B(getcode(fs, e2), e1->u.info);
+ SETARG_B(getinstruction(fs, e2), e1->u.info);
e1->k = VRELOCABLE; e1->u.info = e2->u.info;
}
else {
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
- codeexpval(fs, OP_CONCAT, e1, e2, line);
+ codebinexpval(fs, OP_CONCAT, e1, e2, line);
}
break;
}
@@ -916,15 +1157,13 @@ void luaK_posfix (FuncState *fs, BinOpr op,
case OPR_IDIV: case OPR_MOD: case OPR_POW:
case OPR_BAND: case OPR_BOR: case OPR_BXOR:
case OPR_SHL: case OPR_SHR: {
- codeexpval(fs, cast(OpCode, (op - OPR_ADD) + OP_ADD), e1, e2, line);
- break;
- }
- case OPR_EQ: case OPR_LT: case OPR_LE: {
- codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2);
+ if (!constfolding(fs, op + LUA_OPADD, e1, e2))
+ codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line);
break;
}
+ case OPR_EQ: case OPR_LT: case OPR_LE:
case OPR_NE: case OPR_GT: case OPR_GE: {
- codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2);
+ codecomp(fs, op, e1, e2);
break;
}
default: lua_assert(0);
@@ -932,15 +1171,25 @@ void luaK_posfix (FuncState *fs, BinOpr op,
}
+/*
+** Change line information associated with current position.
+*/
void luaK_fixline (FuncState *fs, int line) {
fs->f->lineinfo[fs->pc - 1] = line;
}
+/*
+** Emit a SETLIST instruction.
+** 'base' is register that keeps table;
+** 'nelems' is #table plus those to be stored now;
+** 'tostore' is number of values (in registers 'base + 1',...) to add to
+** table (or LUA_MULTRET to add up to stack top).
+*/
void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
int b = (tostore == LUA_MULTRET) ? 0 : tostore;
- lua_assert(tostore != 0);
+ lua_assert(tostore != 0 && tostore <= LFIELDS_PER_FLUSH);
if (c <= MAXARG_C)
luaK_codeABC(fs, OP_SETLIST, base, b, c);
else if (c <= MAXARG_Ax) {
diff --git a/src/lcode.h b/src/lcode.h
index 43ab86db77b0..cd306d573aef 100644
--- a/src/lcode.h
+++ b/src/lcode.h
@@ -1,5 +1,5 @@
/*
-** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $
+** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -40,7 +40,8 @@ typedef enum BinOpr {
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
-#define getcode(fs,e) ((fs)->f->code[(e)->u.info])
+/* get (pointer to) instruction of given 'expdesc' */
+#define getinstruction(fs,e) ((fs)->f->code[(e)->u.info])
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
diff --git a/src/lcorolib.c b/src/lcorolib.c
index 0c0b7fa6b31c..2303429e7bb3 100644
--- a/src/lcorolib.c
+++ b/src/lcorolib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $
+** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $
** Coroutine Library
** See Copyright Notice in lua.h
*/
@@ -75,7 +75,7 @@ static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L));
if (r < 0) {
- if (lua_isstring(L, -1)) { /* error object is a string? */
+ if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */
lua_insert(L, -2);
lua_concat(L, 2);
diff --git a/src/ldblib.c b/src/ldblib.c
index 24a11b53ee32..786f6cd95d7e 100644
--- a/src/ldblib.c
+++ b/src/ldblib.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldblib.c,v 1.148 2015/01/02 12:52:22 roberto Exp $
+** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
@@ -27,6 +27,17 @@
static const int HOOKKEY = 0;
+/*
+** If L1 != L, L1 can be in any state, and therefore there are no
+** guarantees about its stack space; any push in L1 must be
+** checked.
+*/
+static void checkstack (lua_State *L, lua_State *L1, int n) {
+ if (L != L1 && !lua_checkstack(L1, n))
+ luaL_error(L, "stack overflow");
+}
+
+
static int db_getregistry (lua_State *L) {
lua_pushvalue(L, LUA_REGISTRYINDEX);
return 1;
@@ -127,12 +138,16 @@ static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
/*
** Calls 'lua_getinfo' and collects all results in a new table.
+** L1 needs stack space for an optional input (function) plus
+** two optional outputs (function and line table) from function
+** 'lua_getinfo'.
*/
static int db_getinfo (lua_State *L) {
lua_Debug ar;
int arg;
lua_State *L1 = getthread(L, &arg);
const char *options = luaL_optstring(L, arg+2, "flnStu");
+ checkstack(L, L1, 3);
if (lua_isfunction(L, arg + 1)) { /* info about a function? */
options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */
lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */
@@ -190,6 +205,7 @@ static int db_getlocal (lua_State *L) {
int level = (int)luaL_checkinteger(L, arg + 1);
if (!lua_getstack(L1, level, &ar)) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
+ checkstack(L, L1, 1);
name = lua_getlocal(L1, &ar, nvar);
if (name) {
lua_xmove(L1, L, 1); /* move local value */
@@ -216,6 +232,7 @@ static int db_setlocal (lua_State *L) {
return luaL_argerror(L, arg+1, "level out of range");
luaL_checkany(L, arg+3);
lua_settop(L, arg+3);
+ checkstack(L, L1, 1);
lua_xmove(L, L1, 1);
name = lua_setlocal(L1, &ar, nvar);
if (name == NULL)
@@ -350,6 +367,7 @@ static int db_sethook (lua_State *L) {
lua_pushvalue(L, -1);
lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
}
+ checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1); /* key (thread) */
lua_pushvalue(L, arg + 1); /* value (hook function) */
lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */
@@ -370,6 +388,7 @@ static int db_gethook (lua_State *L) {
lua_pushliteral(L, "external hook");
else { /* hook table must exist */
lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
+ checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1);
lua_rawget(L, -2); /* 1st result = hooktable[L1] */
lua_remove(L, -2); /* remove hook table */
diff --git a/src/ldebug.c b/src/ldebug.c
index 6986bf0f6098..239affb76c52 100644
--- a/src/ldebug.c
+++ b/src/ldebug.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.c,v 2.110 2015/01/02 12:52:22 roberto Exp $
+** $Id: ldebug.c,v 2.121 2016/10/19 12:32:10 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -34,7 +34,12 @@
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)
-static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
+/* Active Lua function (given call info) */
+#define ci_func(ci) (clLvalue((ci)->func))
+
+
+static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
+ const char **name);
static int currentpc (CallInfo *ci) {
@@ -49,7 +54,29 @@ static int currentline (CallInfo *ci) {
/*
-** this function can be called asynchronous (e.g. during a signal)
+** If function yielded, its 'func' can be in the 'extra' field. The
+** next function restores 'func' to its correct value for debugging
+** purposes. (It exchanges 'func' and 'extra'; so, when called again,
+** after debugging, it also "re-restores" ** 'func' to its altered value.
+*/
+static void swapextra (lua_State *L) {
+ if (L->status == LUA_YIELD) {
+ CallInfo *ci = L->ci; /* get function that yielded */
+ StkId temp = ci->func; /* exchange its 'func' and 'extra' values */
+ ci->func = restorestack(L, ci->extra);
+ ci->extra = savestack(L, temp);
+ }
+}
+
+
+/*
+** This function can be called asynchronously (e.g. during a signal).
+** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
+** 'resethookcount') are for debug only, and it is no problem if they
+** get arbitrary values (causes at most one wrong hook call). 'hookmask'
+** is an atomic value. We assume that pointers are atomic too (e.g., gcc
+** ensures that for all platforms where it runs). Moreover, 'hook' is
+** always checked before being called (see 'luaD_hook').
*/
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
if (func == NULL || mask == 0) { /* turn off hooks? */
@@ -106,7 +133,7 @@ static const char *upvalname (Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
int nparams = clLvalue(ci->func)->p->numparams;
- if (n >= ci->u.l.base - ci->func - nparams)
+ if (n >= cast_int(ci->u.l.base - ci->func) - nparams)
return NULL; /* no such vararg */
else {
*pos = ci->func + nparams + n;
@@ -144,6 +171,7 @@ static const char *findlocal (lua_State *L, CallInfo *ci, int n,
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name;
lua_lock(L);
+ swapextra(L);
if (ar == NULL) { /* information about non-active function? */
if (!isLfunction(L->top - 1)) /* not a Lua function? */
name = NULL;
@@ -151,26 +179,30 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);
}
else { /* active function; get information through 'ar' */
- StkId pos = 0; /* to avoid warnings */
+ StkId pos = NULL; /* to avoid warnings */
name = findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobj2s(L, L->top, pos);
api_incr_top(L);
}
}
+ swapextra(L);
lua_unlock(L);
return name;
}
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
- StkId pos = 0; /* to avoid warnings */
- const char *name = findlocal(L, ar->i_ci, n, &pos);
+ StkId pos = NULL; /* to avoid warnings */
+ const char *name;
lua_lock(L);
+ swapextra(L);
+ name = findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobjs2s(L, pos, L->top - 1);
L->top--; /* pop value */
}
+ swapextra(L);
lua_unlock(L);
return name;
}
@@ -213,6 +245,20 @@ static void collectvalidlines (lua_State *L, Closure *f) {
}
+static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
+ if (ci == NULL) /* no 'ci'? */
+ return NULL; /* no info */
+ else if (ci->callstatus & CIST_FIN) { /* is this a finalizer? */
+ *name = "__gc";
+ return "metamethod"; /* report it as such */
+ }
+ /* calling function is a known Lua function? */
+ else if (!(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
+ return funcnamefromcode(L, ci->previous, name);
+ else return NULL; /* no way to find a name */
+}
+
+
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
Closure *f, CallInfo *ci) {
int status = 1;
@@ -243,11 +289,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
break;
}
case 'n': {
- /* calling function is a known Lua function? */
- if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
- ar->namewhat = getfuncname(L, ci->previous, &ar->name);
- else
- ar->namewhat = NULL;
+ ar->namewhat = getfuncname(L, ci, &ar->name);
if (ar->namewhat == NULL) {
ar->namewhat = ""; /* not found */
ar->name = NULL;
@@ -270,10 +312,11 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
CallInfo *ci;
StkId func;
lua_lock(L);
+ swapextra(L);
if (*what == '>') {
ci = NULL;
func = L->top - 1;
- api_check(ttisfunction(func), "function expected");
+ api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
L->top--; /* pop function */
}
@@ -288,6 +331,7 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
setobjs2s(L, L->top, func);
api_incr_top(L);
}
+ swapextra(L); /* correct before option 'L', which can raise a mem. error */
if (strchr(what, 'L'))
collectvalidlines(L, cl);
lua_unlock(L);
@@ -438,8 +482,15 @@ static const char *getobjname (Proto *p, int lastpc, int reg,
}
-static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
- TMS tm = (TMS)0; /* to avoid warnings */
+/*
+** Try to find a name for a function based on the code that called it.
+** (Only works when function was called by a Lua function.)
+** Returns what the name is (e.g., "for iterator", "method",
+** "metamethod") and sets '*name' to point to the name.
+*/
+static const char *funcnamefromcode (lua_State *L, CallInfo *ci,
+ const char **name) {
+ TMS tm = (TMS)0; /* (initial value avoids warnings) */
Proto *p = ci_func(ci)->p; /* calling function */
int pc = currentpc(ci); /* calling instruction index */
Instruction i = p->code[pc]; /* calling instruction */
@@ -449,13 +500,13 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
}
switch (GET_OPCODE(i)) {
case OP_CALL:
- case OP_TAILCALL: /* get function name */
- return getobjname(p, pc, GETARG_A(i), name);
+ case OP_TAILCALL:
+ return getobjname(p, pc, GETARG_A(i), name); /* get function name */
case OP_TFORCALL: { /* for iterator */
*name = "for iterator";
return "for iterator";
}
- /* all other instructions can call only through metamethods */
+ /* other instructions can do calls through metamethods */
case OP_SELF: case OP_GETTABUP: case OP_GETTABLE:
tm = TM_INDEX;
break;
@@ -476,7 +527,8 @@ static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
case OP_EQ: tm = TM_EQ; break;
case OP_LT: tm = TM_LT; break;
case OP_LE: tm = TM_LE; break;
- default: lua_assert(0); /* other instructions cannot call a function */
+ default:
+ return NULL; /* cannot find a reasonable name */
}
*name = getstr(G(L)->tmname[tm]);
return "metamethod";
@@ -531,7 +583,7 @@ static const char *varinfo (lua_State *L, const TValue *o) {
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
- const char *t = objtypename(o);
+ const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
}
@@ -563,28 +615,25 @@ l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
- const char *t1 = objtypename(p1);
- const char *t2 = objtypename(p2);
- if (t1 == t2)
+ const char *t1 = luaT_objtypename(L, p1);
+ const char *t2 = luaT_objtypename(L, p2);
+ if (strcmp(t1, t2) == 0)
luaG_runerror(L, "attempt to compare two %s values", t1);
else
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
}
-static void addinfo (lua_State *L, const char *msg) {
- CallInfo *ci = L->ci;
- if (isLua(ci)) { /* is Lua code? */
- char buff[LUA_IDSIZE]; /* add file:line information */
- int line = currentline(ci);
- TString *src = ci_func(ci)->p->source;
- if (src)
- luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
- else { /* no source available; use "?" instead */
- buff[0] = '?'; buff[1] = '\0';
- }
- luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
+/* add src:line information to 'msg' */
+const char *luaG_addinfo (lua_State *L, const char *msg, TString *src,
+ int line) {
+ char buff[LUA_IDSIZE];
+ if (src)
+ luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
+ else { /* no source available; use "?" instead */
+ buff[0] = '?'; buff[1] = '\0';
}
+ return luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
}
@@ -594,17 +643,21 @@ l_noret luaG_errormsg (lua_State *L) {
setobjs2s(L, L->top, L->top - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */
L->top++; /* assume EXTRA_STACK */
- luaD_call(L, L->top - 2, 1, 0); /* call it */
+ luaD_callnoyield(L, L->top - 2, 1); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
+ CallInfo *ci = L->ci;
+ const char *msg;
va_list argp;
va_start(argp, fmt);
- addinfo(L, luaO_pushvfstring(L, fmt, argp));
+ msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp);
+ if (isLua(ci)) /* if Lua function, add source:line information */
+ luaG_addinfo(L, msg, ci_func(ci)->p->source, currentline(ci));
luaG_errormsg(L);
}
@@ -612,9 +665,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
void luaG_traceexec (lua_State *L) {
CallInfo *ci = L->ci;
lu_byte mask = L->hookmask;
- int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0);
+ int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
if (counthook)
resethookcount(L); /* reset count */
+ else if (!(mask & LUA_MASKLINE))
+ return; /* no line hook and count != 0; nothing to be done */
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
return; /* do not call hook again (VM yielded, so it did not move) */
diff --git a/src/ldebug.h b/src/ldebug.h
index 0d8966ca9a61..0e31546b1b4b 100644
--- a/src/ldebug.h
+++ b/src/ldebug.h
@@ -1,5 +1,5 @@
/*
-** $Id: ldebug.h,v 2.12 2014/11/10 14:46:05 roberto Exp $
+** $Id: ldebug.h,v 2.14 2015/05/22 17:45:56 roberto Exp $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
@@ -17,9 +17,6 @@
#define resethookcount(L) (L->hookcount = L->basehookcount)
-/* Active Lua function (given call info) */
-#define ci_func(ci) (clLvalue((ci)->func))
-
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
const char *opname);
@@ -33,6 +30,8 @@ LUAI_FUNC l_noret luaG_tointerror (lua_State *L, const TValue *p1,
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
+LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg,
+ TString *src, int line);
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
LUAI_FUNC void luaG_traceexec (lua_State *L);
diff --git a/src/ldo.c b/src/ldo.c
index 6159e51da2d4..90b695fb04c7 100644
--- a/src/ldo.c
+++ b/src/ldo.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.c,v 2.135 2014/11/11 17:13:39 roberto Exp $
+** $Id: ldo.c,v 2.157 2016/12/13 15:52:21 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -150,6 +150,11 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
/* }====================================================== */
+/*
+** {==================================================================
+** Stack reallocation
+** ===================================================================
+*/
static void correctstack (lua_State *L, TValue *oldstack) {
CallInfo *ci;
UpVal *up;
@@ -206,9 +211,9 @@ static int stackinuse (lua_State *L) {
CallInfo *ci;
StkId lim = L->top;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
- lua_assert(ci->top <= L->stack_last);
if (lim < ci->top) lim = ci->top;
}
+ lua_assert(lim <= L->stack_last);
return cast_int(lim - L->stack) + 1; /* part of stack in use */
}
@@ -216,22 +221,38 @@ static int stackinuse (lua_State *L) {
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
- if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
- if (L->stacksize > LUAI_MAXSTACK) /* was handling stack overflow? */
+ if (goodsize > LUAI_MAXSTACK)
+ goodsize = LUAI_MAXSTACK; /* respect stack limit */
+ if (L->stacksize > LUAI_MAXSTACK) /* had been handling stack overflow? */
luaE_freeCI(L); /* free all CIs (list grew because of an error) */
else
luaE_shrinkCI(L); /* shrink list */
- if (inuse > LUAI_MAXSTACK || /* still handling stack overflow? */
- goodsize >= L->stacksize) /* would grow instead of shrink? */
- condmovestack(L); /* don't change stack (change only for debugging) */
- else
- luaD_reallocstack(L, goodsize); /* shrink it */
+ /* if thread is currently not handling a stack overflow and its
+ good size is smaller than current size, shrink its stack */
+ if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
+ goodsize < L->stacksize)
+ luaD_reallocstack(L, goodsize);
+ else /* don't change stack */
+ condmovestack(L,{},{}); /* (change only for debugging) */
+}
+
+
+void luaD_inctop (lua_State *L) {
+ luaD_checkstack(L, 1);
+ L->top++;
}
+/* }================================================================== */
+
+/*
+** Call a hook for the given event. Make sure there is a hook to be
+** called. (Both 'L->hook' and 'L->hookmask', which triggers this
+** function, can be changed asynchronously by signals.)
+*/
void luaD_hook (lua_State *L, int event, int line) {
lua_Hook hook = L->hook;
- if (hook && L->allowhook) {
+ if (hook && L->allowhook) { /* make sure there is a hook */
CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top);
ptrdiff_t ci_top = savestack(L, ci->top);
@@ -273,15 +294,15 @@ static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
int i;
int nfixargs = p->numparams;
StkId base, fixed;
- lua_assert(actual >= nfixargs);
/* move fixed parameters to final position */
- luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */
fixed = L->top - actual; /* first fixed argument */
base = L->top; /* final position of first argument */
- for (i=0; i<nfixargs; i++) {
+ for (i = 0; i < nfixargs && i < actual; i++) {
setobjs2s(L, L->top++, fixed + i);
- setnilvalue(fixed + i);
+ setnilvalue(fixed + i); /* erase original copy (for GC) */
}
+ for (; i < nfixargs; i++)
+ setnilvalue(L->top++); /* complete missing arguments */
return base;
}
@@ -304,74 +325,145 @@ static void tryfuncTM (lua_State *L, StkId func) {
}
+/*
+** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'.
+** Handle most typical cases (zero results for commands, one result for
+** expressions, multiple results for tail calls/single parameters)
+** separated.
+*/
+static int moveresults (lua_State *L, const TValue *firstResult, StkId res,
+ int nres, int wanted) {
+ switch (wanted) { /* handle typical cases separately */
+ case 0: break; /* nothing to move */
+ case 1: { /* one result needed */
+ if (nres == 0) /* no results? */
+ firstResult = luaO_nilobject; /* adjust with nil */
+ setobjs2s(L, res, firstResult); /* move it to proper place */
+ break;
+ }
+ case LUA_MULTRET: {
+ int i;
+ for (i = 0; i < nres; i++) /* move all results to correct place */
+ setobjs2s(L, res + i, firstResult + i);
+ L->top = res + nres;
+ return 0; /* wanted == LUA_MULTRET */
+ }
+ default: {
+ int i;
+ if (wanted <= nres) { /* enough results? */
+ for (i = 0; i < wanted; i++) /* move wanted results to correct place */
+ setobjs2s(L, res + i, firstResult + i);
+ }
+ else { /* not enough results; use all of them plus nils */
+ for (i = 0; i < nres; i++) /* move all results to correct place */
+ setobjs2s(L, res + i, firstResult + i);
+ for (; i < wanted; i++) /* complete wanted number of results */
+ setnilvalue(res + i);
+ }
+ break;
+ }
+ }
+ L->top = res + wanted; /* top points after the last result */
+ return 1;
+}
+
+
+/*
+** Finishes a function call: calls hook if necessary, removes CallInfo,
+** moves current number of results to proper place; returns 0 iff call
+** wanted multiple (variable number of) results.
+*/
+int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
+ StkId res;
+ int wanted = ci->nresults;
+ if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
+ if (L->hookmask & LUA_MASKRET) {
+ ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
+ luaD_hook(L, LUA_HOOKRET, -1);
+ firstResult = restorestack(L, fr);
+ }
+ L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
+ }
+ res = ci->func; /* res == final position of 1st result */
+ L->ci = ci->previous; /* back to caller */
+ /* move results to proper place */
+ return moveresults(L, firstResult, res, nres, wanted);
+}
+
+
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
+/* macro to check stack size, preserving 'p' */
+#define checkstackp(L,n,p) \
+ luaD_checkstackaux(L, n, \
+ ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
+ luaC_checkGC(L), /* stack grow uses memory */ \
+ p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
+
+
/*
-** returns true if function has been executed (C function)
+** Prepares a function call: checks the stack, creates a new CallInfo
+** entry, fills in the relevant information, calls hook if needed.
+** If function is a C function, does the call, too. (Otherwise, leave
+** the execution ('luaV_execute') to the caller, to allow stackless
+** calls.) Returns true iff function has been executed (C function).
*/
int luaD_precall (lua_State *L, StkId func, int nresults) {
lua_CFunction f;
CallInfo *ci;
- int n; /* number of arguments (Lua) or returns (C) */
- ptrdiff_t funcr = savestack(L, func);
switch (ttype(func)) {
+ case LUA_TCCL: /* C closure */
+ f = clCvalue(func)->f;
+ goto Cfunc;
case LUA_TLCF: /* light C function */
f = fvalue(func);
- goto Cfunc;
- case LUA_TCCL: { /* C closure */
- f = clCvalue(func)->f;
- Cfunc:
- luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
+ Cfunc: {
+ int n; /* number of returns */
+ checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
- ci->func = restorestack(L, funcr);
+ ci->func = func;
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
ci->callstatus = 0;
- luaC_checkGC(L); /* stack grow uses memory */
if (L->hookmask & LUA_MASKCALL)
luaD_hook(L, LUA_HOOKCALL, -1);
lua_unlock(L);
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
- luaD_poscall(L, L->top - n);
+ luaD_poscall(L, ci, L->top - n, n);
return 1;
}
case LUA_TLCL: { /* Lua function: prepare its call */
StkId base;
Proto *p = clLvalue(func)->p;
- n = cast_int(L->top - func) - 1; /* number of real arguments */
- luaD_checkstack(L, p->maxstacksize);
- for (; n < p->numparams; n++)
- setnilvalue(L->top++); /* complete missing arguments */
- if (!p->is_vararg) {
- func = restorestack(L, funcr);
- base = func + 1;
- }
- else {
+ int n = cast_int(L->top - func) - 1; /* number of real arguments */
+ int fsize = p->maxstacksize; /* frame size */
+ checkstackp(L, fsize, func);
+ if (p->is_vararg)
base = adjust_varargs(L, p, n);
- func = restorestack(L, funcr); /* previous call can change stack */
+ else { /* non vararg function */
+ for (; n < p->numparams; n++)
+ setnilvalue(L->top++); /* complete missing arguments */
+ base = func + 1;
}
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = func;
ci->u.l.base = base;
- ci->top = base + p->maxstacksize;
+ L->top = ci->top = base + fsize;
lua_assert(ci->top <= L->stack_last);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus = CIST_LUA;
- L->top = ci->top;
- luaC_checkGC(L); /* stack grow uses memory */
if (L->hookmask & LUA_MASKCALL)
callhook(L, ci);
return 0;
}
default: { /* not a function */
- luaD_checkstack(L, 1); /* ensure space for metamethod */
- func = restorestack(L, funcr); /* previous call may change stack */
+ checkstackp(L, 1, func); /* ensure space for metamethod */
tryfuncTM(L, func); /* try to get '__call' metamethod */
return luaD_precall(L, func, nresults); /* now it must be a function */
}
@@ -379,28 +471,18 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
}
-int luaD_poscall (lua_State *L, StkId firstResult) {
- StkId res;
- int wanted, i;
- CallInfo *ci = L->ci;
- if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
- if (L->hookmask & LUA_MASKRET) {
- ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
- luaD_hook(L, LUA_HOOKRET, -1);
- firstResult = restorestack(L, fr);
- }
- L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
- }
- res = ci->func; /* res == final position of 1st result */
- wanted = ci->nresults;
- L->ci = ci = ci->previous; /* back to caller */
- /* move results to correct place */
- for (i = wanted; i != 0 && firstResult < L->top; i--)
- setobjs2s(L, res++, firstResult++);
- while (i-- > 0)
- setnilvalue(res++);
- L->top = res;
- return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */
+/*
+** Check appropriate error for stack overflow ("regular" overflow or
+** overflow while handling stack overflow). If 'nCalls' is larger than
+** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but
+** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to
+** allow overflow handling to work)
+*/
+static void stackerror (lua_State *L) {
+ if (L->nCcalls == LUAI_MAXCCALLS)
+ luaG_runerror(L, "C stack overflow");
+ else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
+ luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
}
@@ -410,22 +492,26 @@ int luaD_poscall (lua_State *L, StkId firstResult) {
** When returns, all the results are on the stack, starting at the original
** function position.
*/
-void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
- if (++L->nCcalls >= LUAI_MAXCCALLS) {
- if (L->nCcalls == LUAI_MAXCCALLS)
- luaG_runerror(L, "C stack overflow");
- else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
- luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
- }
- if (!allowyield) L->nny++;
+void luaD_call (lua_State *L, StkId func, int nResults) {
+ if (++L->nCcalls >= LUAI_MAXCCALLS)
+ stackerror(L);
if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
luaV_execute(L); /* call it */
- if (!allowyield) L->nny--;
L->nCcalls--;
}
/*
+** Similar to 'luaD_call', but does not allow yields during the call
+*/
+void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
+ L->nny++;
+ luaD_call(L, func, nResults);
+ L->nny--;
+}
+
+
+/*
** Completes the execution of an interrupted C function, calling its
** continuation function.
*/
@@ -437,19 +523,17 @@ static void finishCcall (lua_State *L, int status) {
/* error status can only happen in a protected call */
lua_assert((ci->callstatus & CIST_YPCALL) || status == LUA_YIELD);
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
- ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */
- L->errfunc = ci->u.c.old_errfunc;
+ ci->callstatus &= ~CIST_YPCALL; /* continuation is also inside it */
+ L->errfunc = ci->u.c.old_errfunc; /* with the same error function */
}
/* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already
handled */
adjustresults(L, ci->nresults);
- /* call continuation function */
lua_unlock(L);
- n = (*ci->u.c.k)(L, status, ci->u.c.ctx);
+ n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */
lua_lock(L);
api_checknelems(L, n);
- /* finish 'luaD_precall' */
- luaD_poscall(L, L->top - n);
+ luaD_poscall(L, ci, L->top - n, n); /* finish 'luaD_precall' */
}
@@ -512,15 +596,16 @@ static int recover (lua_State *L, int status) {
/*
-** signal an error in the call to 'resume', not in the execution of the
-** coroutine itself. (Such errors should not be handled by any coroutine
-** error handler and should not kill the coroutine.)
+** Signal an error in the call to 'lua_resume', not in the execution
+** of the coroutine itself. (Such errors should not be handled by any
+** coroutine error handler and should not kill the coroutine.)
*/
-static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
- L->top = firstArg; /* remove args from the stack */
+static int resume_error (lua_State *L, const char *msg, int narg) {
+ L->top -= narg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
api_incr_top(L);
- luaD_throw(L, -1); /* jump back to 'lua_resume' */
+ lua_unlock(L);
+ return LUA_ERRRUN;
}
@@ -532,51 +617,51 @@ static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
** coroutine.
*/
static void resume (lua_State *L, void *ud) {
- int nCcalls = L->nCcalls;
- StkId firstArg = cast(StkId, ud);
+ int n = *(cast(int*, ud)); /* number of arguments */
+ StkId firstArg = L->top - n; /* first argument */
CallInfo *ci = L->ci;
- if (nCcalls >= LUAI_MAXCCALLS)
- resume_error(L, "C stack overflow", firstArg);
- if (L->status == LUA_OK) { /* may be starting a coroutine */
- if (ci != &L->base_ci) /* not in base level? */
- resume_error(L, "cannot resume non-suspended coroutine", firstArg);
- /* coroutine is in base level; start running it */
+ if (L->status == LUA_OK) { /* starting a coroutine? */
if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
luaV_execute(L); /* call it */
}
- else if (L->status != LUA_YIELD)
- resume_error(L, "cannot resume dead coroutine", firstArg);
else { /* resuming from previous yield */
+ lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */
ci->func = restorestack(L, ci->extra);
if (isLua(ci)) /* yielded inside a hook? */
luaV_execute(L); /* just continue running Lua code */
else { /* 'common' yield */
if (ci->u.c.k != NULL) { /* does it have a continuation function? */
- int n;
lua_unlock(L);
n = (*ci->u.c.k)(L, LUA_YIELD, ci->u.c.ctx); /* call continuation */
lua_lock(L);
api_checknelems(L, n);
firstArg = L->top - n; /* yield results come from continuation */
}
- luaD_poscall(L, firstArg); /* finish 'luaD_precall' */
+ luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */
}
unroll(L, NULL); /* run continuation */
}
- lua_assert(nCcalls == L->nCcalls);
}
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
int status;
- int oldnny = L->nny; /* save "number of non-yieldable" calls */
+ unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */
lua_lock(L);
- luai_userstateresume(L, nargs);
+ if (L->status == LUA_OK) { /* may be starting a coroutine */
+ if (L->ci != &L->base_ci) /* not in base level? */
+ return resume_error(L, "cannot resume non-suspended coroutine", nargs);
+ }
+ else if (L->status != LUA_YIELD)
+ return resume_error(L, "cannot resume dead coroutine", nargs);
L->nCcalls = (from) ? from->nCcalls + 1 : 1;
+ if (L->nCcalls >= LUAI_MAXCCALLS)
+ return resume_error(L, "C stack overflow", nargs);
+ luai_userstateresume(L, nargs);
L->nny = 0; /* allow yields */
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
- status = luaD_rawrunprotected(L, resume, L->top - nargs);
+ status = luaD_rawrunprotected(L, resume, &nargs);
if (status == -1) /* error calling 'lua_resume'? */
status = LUA_ERRRUN;
else { /* continue running after recoverable errors */
@@ -619,7 +704,7 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx,
L->status = LUA_YIELD;
ci->extra = savestack(L, ci->func); /* save current 'func' */
if (isLua(ci)) { /* inside a hook? */
- api_check(k == NULL, "hooks cannot continue after yielding");
+ api_check(L, k == NULL, "hooks cannot continue after yielding");
}
else {
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
@@ -684,7 +769,7 @@ static void f_parser (lua_State *L, void *ud) {
int c = zgetc(p->z); /* read first character */
if (c == LUA_SIGNATURE[0]) {
checkmode(L, p->mode, "binary");
- cl = luaU_undump(L, p->z, &p->buff, p->name);
+ cl = luaU_undump(L, p->z, p->name);
}
else {
checkmode(L, p->mode, "text");
diff --git a/src/ldo.h b/src/ldo.h
index 05745c8ad8d5..4f5d51c3c704 100644
--- a/src/ldo.h
+++ b/src/ldo.h
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.h,v 2.21 2014/10/25 11:50:46 roberto Exp $
+** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -13,11 +13,21 @@
#include "lzio.h"
-#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \
- luaD_growstack(L, n); else condmovestack(L);
+/*
+** Macro to check stack size and grow stack if needed. Parameters
+** 'pre'/'pos' allow the macro to preserve a pointer into the
+** stack across reallocations, doing the work only when needed.
+** 'condmovestack' is used in heavy tests to force a stack reallocation
+** at every check.
+*/
+#define luaD_checkstackaux(L,n,pre,pos) \
+ if (L->stack_last - L->top <= (n)) \
+ { pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); }
+
+/* In general, 'pre'/'pos' are empty (nothing to save) */
+#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
-#define incr_top(L) {L->top++; luaD_checkstack(L,0);}
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
@@ -30,14 +40,16 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode);
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line);
LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
-LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults,
- int allowyield);
+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 int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef);
-LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
+LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult,
+ int nres);
LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
+LUAI_FUNC void luaD_inctop (lua_State *L);
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
diff --git a/src/ldump.c b/src/ldump.c
index b6c7114f5d9f..016e300822f2 100644
--- a/src/ldump.c
+++ b/src/ldump.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldump.c,v 2.34 2014/11/02 19:19:04 roberto Exp $
+** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -38,7 +38,7 @@ typedef struct {
static void DumpBlock (const void *b, size_t size, DumpState *D) {
- if (D->status == 0) {
+ if (D->status == 0 && size > 0) {
lua_unlock(D->L);
D->status = (*D->writer)(D->L, b, size, D->data);
lua_lock(D->L);
@@ -74,14 +74,15 @@ static void DumpString (const TString *s, DumpState *D) {
if (s == NULL)
DumpByte(0, D);
else {
- size_t size = s->len + 1; /* include trailing '\0' */
+ size_t size = tsslen(s) + 1; /* include trailing '\0' */
+ const char *str = getstr(s);
if (size < 0xFF)
DumpByte(cast_int(size), D);
else {
DumpByte(0xFF, D);
DumpVar(size, D);
}
- DumpVector(getstr(s), size - 1, D); /* no need to save '\0' */
+ DumpVector(str, size - 1, D); /* no need to save '\0' */
}
}
diff --git a/src/lfunc.h b/src/lfunc.h
index 256d3cf90bd2..2eeb0d5a4898 100644
--- a/src/lfunc.h
+++ b/src/lfunc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lfunc.h,v 2.14 2014/06/19 18:27:20 roberto Exp $
+** $Id: lfunc.h,v 2.15 2015/01/13 15:49:11 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
@@ -23,6 +23,13 @@
/*
+** maximum number of upvalues in a closure (both C and Lua). (Value
+** must fit in a VM register.)
+*/
+#define MAXUPVAL 255
+
+
+/*
** Upvalues for Lua closures
*/
struct UpVal {
diff --git a/src/lgc.c b/src/lgc.c
index 8b95fb67da03..ba2c19e14e94 100644
--- a/src/lgc.c
+++ b/src/lgc.c
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.c,v 2.201 2014/12/20 13:58:15 roberto Exp $
+** $Id: lgc.c,v 2.215 2016/12/22 13:08:50 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -83,8 +83,13 @@
#define markvalue(g,o) { checkconsistency(o); \
if (valiswhite(o)) reallymarkobject(g,gcvalue(o)); }
-#define markobject(g,t) \
- { if ((t) && iswhite(t)) reallymarkobject(g, obj2gco(t)); }
+#define markobject(g,t) { if (iswhite(t)) reallymarkobject(g, obj2gco(t)); }
+
+/*
+** mark an object that can be NULL (either because it is really optional,
+** or it was stripped as debug info, or inside an uncompleted structure)
+*/
+#define markobjectN(g,t) { if (t) markobject(g,t); }
static void reallymarkobject (global_State *g, GCObject *o);
@@ -109,8 +114,13 @@ static void reallymarkobject (global_State *g, GCObject *o);
/*
-** if key is not marked, mark its entry as dead (therefore removing it
-** from the table)
+** If key is not marked, mark its entry as dead. This allows key to be
+** collected, but keeps its entry in the table. A dead node is needed
+** when Lua looks up for a key (it may be part of a chain) and when
+** traversing a weak table (key might be removed from the table during
+** traversal). Other places never manipulate dead keys, because its
+** associated nil value is enough to signal that the entry is logically
+** empty.
*/
static void removeentry (Node *n) {
lua_assert(ttisnil(gval(n)));
@@ -226,15 +236,19 @@ static void reallymarkobject (global_State *g, GCObject *o) {
reentry:
white2gray(o);
switch (o->tt) {
- case LUA_TSHRSTR:
+ case LUA_TSHRSTR: {
+ gray2black(o);
+ g->GCmemtrav += sizelstring(gco2ts(o)->shrlen);
+ break;
+ }
case LUA_TLNGSTR: {
gray2black(o);
- g->GCmemtrav += sizestring(gco2ts(o));
+ g->GCmemtrav += sizelstring(gco2ts(o)->u.lnglen);
break;
}
case LUA_TUSERDATA: {
TValue uvalue;
- markobject(g, gco2u(o)->metatable); /* mark its metatable */
+ markobjectN(g, gco2u(o)->metatable); /* mark its metatable */
gray2black(o);
g->GCmemtrav += sizeudata(gco2u(o));
getuservalue(g->mainthread, gco2u(o), &uvalue);
@@ -275,7 +289,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
static void markmt (global_State *g) {
int i;
for (i=0; i < LUA_NUMTAGS; i++)
- markobject(g, g->mt[i]);
+ markobjectN(g, g->mt[i]);
}
@@ -437,7 +451,7 @@ static void traversestrongtable (global_State *g, Table *h) {
static lu_mem traversetable (global_State *g, Table *h) {
const char *weakkey, *weakvalue;
const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
- markobject(g, h->metatable);
+ markobjectN(g, h->metatable);
if (mode && ttisstring(mode) && /* is there a weak mode? */
((weakkey = strchr(svalue(mode), 'k')),
(weakvalue = strchr(svalue(mode), 'v')),
@@ -453,23 +467,28 @@ static lu_mem traversetable (global_State *g, Table *h) {
else /* not weak */
traversestrongtable(g, h);
return sizeof(Table) + sizeof(TValue) * h->sizearray +
- sizeof(Node) * cast(size_t, sizenode(h));
+ sizeof(Node) * cast(size_t, allocsizenode(h));
}
+/*
+** Traverse a prototype. (While a prototype is being build, its
+** arrays can be larger than needed; the extra slots are filled with
+** NULL, so the use of 'markobjectN')
+*/
static int traverseproto (global_State *g, Proto *f) {
int i;
if (f->cache && iswhite(f->cache))
f->cache = NULL; /* allow cache to be collected */
- markobject(g, f->source);
+ markobjectN(g, f->source);
for (i = 0; i < f->sizek; i++) /* mark literals */
markvalue(g, &f->k[i]);
for (i = 0; i < f->sizeupvalues; i++) /* mark upvalue names */
- markobject(g, f->upvalues[i].name);
+ markobjectN(g, f->upvalues[i].name);
for (i = 0; i < f->sizep; i++) /* mark nested protos */
- markobject(g, f->p[i]);
+ markobjectN(g, f->p[i]);
for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
- markobject(g, f->locvars[i].varname);
+ markobjectN(g, f->locvars[i].varname);
return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
sizeof(Proto *) * f->sizep +
sizeof(TValue) * f->sizek +
@@ -494,7 +513,7 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
*/
static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
int i;
- markobject(g, cl->p); /* mark its prototype */
+ markobjectN(g, cl->p); /* mark its prototype */
for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */
UpVal *uv = cl->upvals[i];
if (uv != NULL) {
@@ -520,7 +539,7 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
StkId lim = th->stack + th->stacksize; /* real end of stack */
for (; o < lim; o++) /* clear not-marked stack slice */
setnilvalue(o);
- /* 'remarkupvals' may have removed thread from 'twups' list */
+ /* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
th->twups = g->twups; /* link it back to the list */
g->twups = th;
@@ -528,7 +547,8 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
}
else if (g->gckind != KGC_EMERGENCY)
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
- return (sizeof(lua_State) + sizeof(TValue) * th->stacksize);
+ return (sizeof(lua_State) + sizeof(TValue) * th->stacksize +
+ sizeof(CallInfo) * th->nci);
}
@@ -689,9 +709,10 @@ static void freeobj (lua_State *L, GCObject *o) {
case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break;
case LUA_TSHRSTR:
luaS_remove(L, gco2ts(o)); /* remove it from hash table */
- /* go through */
+ luaM_freemem(L, o, sizelstring(gco2ts(o)->shrlen));
+ break;
case LUA_TLNGSTR: {
- luaM_freemem(L, o, sizestring(gco2ts(o)));
+ luaM_freemem(L, o, sizelstring(gco2ts(o)->u.lnglen));
break;
}
default: lua_assert(0);
@@ -733,14 +754,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
/*
** sweep a list until a live object (or end of list)
*/
-static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
+static GCObject **sweeptolive (lua_State *L, GCObject **p) {
GCObject **old = p;
- int i = 0;
do {
- i++;
p = sweeplist(L, p, 1);
} while (p == old);
- if (n) *n += i;
return p;
}
@@ -754,12 +772,11 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
*/
/*
-** If possible, free concatenation buffer and shrink string table
+** If possible, shrink string table
*/
static void checkSizes (lua_State *L, global_State *g) {
if (g->gckind != KGC_EMERGENCY) {
l_mem olddebt = g->GCdebt;
- luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */
if (g->strt.nuse < g->strt.size / 4) /* string table too big? */
luaS_resize(L, g->strt.size / 2); /* shrink it a little */
g->GCestimate += g->GCdebt - olddebt; /* update estimate */
@@ -782,7 +799,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) {
UNUSED(ud);
- luaD_call(L, L->top - 2, 0, 0);
+ luaD_callnoyield(L, L->top - 2, 0);
}
@@ -801,7 +818,9 @@ static void GCTM (lua_State *L, int propagateerrors) {
setobj2s(L, L->top, tm); /* push finalizer... */
setobj2s(L, L->top + 1, &v); /* ... and its argument */
L->top += 2; /* and (next line) call the finalizer */
+ L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0);
+ L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */
g->gcrunning = running; /* restore state */
if (status != LUA_OK && propagateerrors) { /* error while running __gc? */
@@ -836,10 +855,10 @@ static int runafewfinalizers (lua_State *L) {
/*
** call all pending finalizers
*/
-static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
+static void callallpendingfinalizers (lua_State *L) {
global_State *g = G(L);
while (g->tobefnz)
- GCTM(L, propagateerrors);
+ GCTM(L, 0);
}
@@ -889,7 +908,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
if (issweepphase(g)) {
makewhite(g, o); /* "sweep" object 'o' */
if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
- g->sweepgc = sweeptolive(L, g->sweepgc, NULL); /* change 'sweepgc' */
+ g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
}
/* search for pointer pointing to 'o' */
for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
@@ -931,19 +950,16 @@ static void setpause (global_State *g) {
/*
** Enter first sweep phase.
-** The call to 'sweeptolive' makes pointer point to an object inside
-** the list (instead of to the header), so that the real sweep do not
-** need to skip objects created between "now" and the start of the real
-** sweep.
-** Returns how many objects it swept.
+** The call to 'sweeplist' tries to make pointer point to an object
+** inside the list (instead of to the header), so that the real sweep do
+** not need to skip objects created between "now" and the start of the
+** real sweep.
*/
-static int entersweep (lua_State *L) {
+static void entersweep (lua_State *L) {
global_State *g = G(L);
- int n = 0;
g->gcstate = GCSswpallgc;
lua_assert(g->sweepgc == NULL);
- g->sweepgc = sweeptolive(L, &g->allgc, &n);
- return n;
+ g->sweepgc = sweeplist(L, &g->allgc, 1);
}
@@ -951,7 +967,7 @@ void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L);
separatetobefnz(g, 1); /* separate all objects with finalizers */
lua_assert(g->finobj == NULL);
- callallpendingfinalizers(L, 0);
+ callallpendingfinalizers(L);
lua_assert(g->tobefnz == NULL);
g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
g->gckind = KGC_NORMAL;
@@ -1002,6 +1018,7 @@ static l_mem atomic (lua_State *L) {
/* clear values from resurrected weak tables */
clearvalues(g, g->weak, origweak);
clearvalues(g, g->allweak, origall);
+ luaS_clearcache(g);
g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */
work += g->GCmemtrav; /* complete counting */
return work; /* estimate of memory marked by 'atomic' */
@@ -1043,12 +1060,11 @@ static lu_mem singlestep (lua_State *L) {
}
case GCSatomic: {
lu_mem work;
- int sw;
propagateall(g); /* make sure gray list is empty */
work = atomic(L); /* work is what was traversed by 'atomic' */
- sw = entersweep(L);
+ entersweep(L);
g->GCestimate = gettotalbytes(g); /* first estimate */;
- return work + sw * GCSWEEPCOST;
+ return work;
}
case GCSswpallgc: { /* sweep "regular" objects */
return sweepstep(L, g, GCSswpfinobj, &g->finobj);
@@ -1098,9 +1114,12 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
static l_mem getdebt (global_State *g) {
l_mem debt = g->GCdebt;
int stepmul = g->gcstepmul;
- debt = (debt / STEPMULADJ) + 1;
- debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
- return debt;
+ if (debt <= 0) return 0; /* minimal debt */
+ else {
+ debt = (debt / STEPMULADJ) + 1;
+ debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
+ return debt;
+ }
}
/*
diff --git a/src/lgc.h b/src/lgc.h
index 0eedf84204a3..aed3e18a5f04 100644
--- a/src/lgc.h
+++ b/src/lgc.h
@@ -1,5 +1,5 @@
/*
-** $Id: lgc.h,v 2.86 2014/10/25 11:50:46 roberto Exp $
+** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -101,26 +101,35 @@
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
-#define luaC_condGC(L,c) \
- {if (G(L)->GCdebt > 0) {c;}; condchangemem(L);}
-#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);)
+/*
+** Does one step of collection when debt becomes positive. 'pre'/'pos'
+** allows some adjustments to be done only when needed. macro
+** 'condchangemem' is used only for heavy tests (forcing a full
+** GC cycle on every opportunity)
+*/
+#define luaC_condGC(L,pre,pos) \
+ { if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \
+ condchangemem(L,pre,pos); }
+
+/* more often than not, 'pre'/'pos' are empty */
+#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
-#define luaC_barrier(L,p,v) { \
- if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
- luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
+#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) { \
- if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
- luaC_barrierback_(L,p); }
+#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) { \
- if (isblack(p) && iswhite(o)) \
- luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
+#define luaC_objbarrier(L,p,o) ( \
+ (isblack(p) && iswhite(o)) ? \
+ luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
-#define luaC_upvalbarrier(L,uv) \
- { if (iscollectable((uv)->v) && !upisopen(uv)) \
- luaC_upvalbarrier_(L,uv); }
+#define luaC_upvalbarrier(L,uv) ( \
+ (iscollectable((uv)->v) && !upisopen(uv)) ? \
+ luaC_upvalbarrier_(L,uv) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
diff --git a/src/linit.c b/src/linit.c
index 8ce94ccb3554..afcaf98b24bd 100644
--- a/src/linit.c
+++ b/src/linit.c
@@ -1,5 +1,5 @@
/*
-** $Id: linit.c,v 1.38 2015/01/05 13:48:33 roberto Exp $
+** $Id: linit.c,v 1.39 2016/12/04 20:17:24 roberto Exp $
** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/
@@ -18,10 +18,10 @@
** open the library, which is already linked to the application.
** For that, do the following code:
**
-** luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
+** luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
** lua_pushcfunction(L, luaopen_modname);
** lua_setfield(L, -2, modname);
-** lua_pop(L, 1); // remove _PRELOAD table
+** lua_pop(L, 1); // remove PRELOAD table
*/
#include "lprefix.h"
diff --git a/src/liolib.c b/src/liolib.c
index 4dea39684a3b..156840358d0e 100644
--- a/src/liolib.c
+++ b/src/liolib.c
@@ -1,5 +1,5 @@
/*
-** $Id: liolib.c,v 2.142 2015/01/02 12:50:28 roberto Exp $
+** $Id: liolib.c,v 2.151 2016/12/20 18:37:00 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@@ -23,18 +23,25 @@
#include "lualib.h"
-#if !defined(l_checkmode)
+
/*
-** Check whether 'mode' matches '[rwa]%+?b?'.
** Change this macro to accept other modes for 'fopen' besides
** the standard ones.
*/
-#define l_checkmode(mode) \
- (*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
- (*mode != '+' || ++mode) && /* skip if char is '+' */ \
- (*mode != 'b' || ++mode) && /* skip if char is 'b' */ \
- (*mode == '\0'))
+#if !defined(l_checkmode)
+
+/* accepted extensions to 'mode' in 'fopen' */
+#if !defined(L_MODEEXT)
+#define L_MODEEXT "b"
+#endif
+
+/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */
+static int l_checkmode (const char *mode) {
+ return (*mode != '\0' && strchr("rwa", *(mode++)) != NULL &&
+ (*mode != '+' || (++mode, 1)) && /* skip if char is '+' */
+ (strspn(mode, L_MODEEXT) == strlen(mode))); /* check extensions */
+}
#endif
@@ -176,7 +183,7 @@ static FILE *tofile (lua_State *L) {
/*
** When creating file handles, always creates a 'closed' file handle
** before opening the actual file; so, if there is a memory error, the
-** file is not left opened.
+** handle is in a consistent state.
*/
static LStream *newprefile (lua_State *L) {
LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));
@@ -318,8 +325,15 @@ static int io_output (lua_State *L) {
static int io_readline (lua_State *L);
+/*
+** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit
+** in the limit for upvalues of a closure)
+*/
+#define MAXARGLINE 250
+
static void aux_lines (lua_State *L, int toclose) {
int n = lua_gettop(L) - 1; /* number of arguments to read */
+ luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments");
lua_pushinteger(L, n); /* number of arguments to read */
lua_pushboolean(L, toclose); /* close/not close file when finished */
lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */
@@ -362,14 +376,17 @@ static int io_lines (lua_State *L) {
/* maximum length of a numeral */
-#define MAXRN 200
+#if !defined (L_MAXLENNUM)
+#define L_MAXLENNUM 200
+#endif
+
/* auxiliary structure used by 'read_number' */
typedef struct {
FILE *f; /* file being read */
int c; /* current character (look ahead) */
int n; /* number of elements in buffer 'buff' */
- char buff[MAXRN + 1]; /* +1 for ending '\0' */
+ char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */
} RN;
@@ -377,7 +394,7 @@ typedef struct {
** Add current char to buffer (if not out of space) and read next one
*/
static int nextc (RN *rn) {
- if (rn->n >= MAXRN) { /* buffer overflow? */
+ if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */
rn->buff[0] = '\0'; /* invalidate result */
return 0; /* fail */
}
@@ -390,10 +407,10 @@ static int nextc (RN *rn) {
/*
-** Accept current char if it is in 'set' (of size 1 or 2)
+** Accept current char if it is in 'set' (of size 2)
*/
static int test2 (RN *rn, const char *set) {
- if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0'))
+ if (rn->c == set[0] || rn->c == set[1])
return nextc(rn);
else return 0;
}
@@ -410,12 +427,6 @@ static int readdigits (RN *rn, int hex) {
}
-/* access to locale "radix character" (decimal point) */
-#if !defined(l_getlocaledecpoint)
-#define l_getlocaledecpoint() (localeconv()->decimal_point[0])
-#endif
-
-
/*
** Read a number: first reads a valid prefix of a numeral into a buffer.
** Then it calls 'lua_stringtonumber' to check whether the format is
@@ -425,13 +436,14 @@ static int read_number (lua_State *L, FILE *f) {
RN rn;
int count = 0;
int hex = 0;
- char decp[2] = ".";
+ char decp[2];
rn.f = f; rn.n = 0;
- decp[0] = l_getlocaledecpoint(); /* get decimal point from locale */
+ decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */
+ decp[1] = '.'; /* always accept a dot */
l_lockfile(rn.f);
do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
test2(&rn, "-+"); /* optional signal */
- if (test2(&rn, "0")) {
+ if (test2(&rn, "00")) {
if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
else count = 1; /* count initial '0' as a valid digit */
}
@@ -457,7 +469,7 @@ static int read_number (lua_State *L, FILE *f) {
static int test_eof (lua_State *L, FILE *f) {
int c = getc(f);
ungetc(c, f); /* no-op when c == EOF */
- lua_pushlstring(L, NULL, 0);
+ lua_pushliteral(L, "");
return (c != EOF);
}
@@ -467,7 +479,7 @@ static int read_line (lua_State *L, FILE *f, int chop) {
int c = '\0';
luaL_buffinit(L, &b);
while (c != EOF && c != '\n') { /* repeat until end of line */
- char *buff = luaL_prepbuffer(&b); /* pre-allocate buffer */
+ char *buff = luaL_prepbuffer(&b); /* preallocate buffer */
int i = 0;
l_lockfile(f); /* no memory errors can happen inside the lock */
while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
@@ -488,7 +500,7 @@ static void read_all (lua_State *L, FILE *f) {
luaL_Buffer b;
luaL_buffinit(L, &b);
do { /* read file in chunks of LUAL_BUFFERSIZE bytes */
- char *p = luaL_prepbuffsize(&b, LUAL_BUFFERSIZE);
+ char *p = luaL_prepbuffer(&b);
nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f);
luaL_addsize(&b, nr);
} while (nr == LUAL_BUFFERSIZE);
@@ -607,8 +619,10 @@ static int g_write (lua_State *L, FILE *f, int arg) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
int len = lua_isinteger(L, arg)
- ? fprintf(f, LUA_INTEGER_FMT, lua_tointeger(L, arg))
- : fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg));
+ ? fprintf(f, LUA_INTEGER_FMT,
+ (LUAI_UACINT)lua_tointeger(L, arg))
+ : fprintf(f, LUA_NUMBER_FMT,
+ (LUAI_UACNUMBER)lua_tonumber(L, arg));
status = status && (len > 0);
}
else {
diff --git a/src/llex.c b/src/llex.c
index 6e4a457ad635..70328273f7a9 100644
--- a/src/llex.c
+++ b/src/llex.c
@@ -1,5 +1,5 @@
/*
-** $Id: llex.c,v 2.89 2014/11/14 16:06:09 roberto Exp $
+** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -16,6 +16,7 @@
#include "lua.h"
#include "lctype.h"
+#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "llex.h"
@@ -68,7 +69,7 @@ static void save (LexState *ls, int c) {
void luaX_init (lua_State *L) {
int i;
- TString *e = luaS_new(L, LUA_ENV); /* create env name */
+ TString *e = luaS_newliteral(L, LUA_ENV); /* create env name */
luaC_fix(L, obj2gco(e)); /* never collect this name */
for (i=0; i<NUM_RESERVED; i++) {
TString *ts = luaS_new(L, luaX_tokens[i]);
@@ -106,9 +107,7 @@ static const char *txtToken (LexState *ls, int token) {
static l_noret lexerror (LexState *ls, const char *msg, int token) {
- char buff[LUA_IDSIZE];
- luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE);
- msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
+ msg = luaG_addinfo(ls->L, msg, ls->source, ls->linenumber);
if (token)
luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token));
luaD_throw(ls->L, LUA_ERRSYNTAX);
@@ -163,7 +162,6 @@ static void inclinenumber (LexState *ls) {
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
int firstchar) {
ls->t.token = 0;
- ls->decpoint = '.';
ls->L = L;
ls->current = firstchar;
ls->lookahead.token = TK_EOS; /* no look-ahead token */
@@ -172,7 +170,7 @@ void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
ls->linenumber = 1;
ls->lastline = 1;
ls->source = source;
- ls->envn = luaS_new(L, LUA_ENV); /* get env name */
+ ls->envn = luaS_newliteral(L, LUA_ENV); /* get env name */
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
}
@@ -208,42 +206,6 @@ static int check_next2 (LexState *ls, const char *set) {
}
-/*
-** change all characters 'from' in buffer to 'to'
-*/
-static void buffreplace (LexState *ls, char from, char to) {
- if (from != to) {
- size_t n = luaZ_bufflen(ls->buff);
- char *p = luaZ_buffer(ls->buff);
- while (n--)
- if (p[n] == from) p[n] = to;
- }
-}
-
-
-#if !defined(l_getlocaledecpoint)
-#define l_getlocaledecpoint() (localeconv()->decimal_point[0])
-#endif
-
-
-#define buff2num(b,o) (luaO_str2num(luaZ_buffer(b), o) != 0)
-
-/*
-** in case of format error, try to change decimal point separator to
-** the one defined in the current locale and check again
-*/
-static void trydecpoint (LexState *ls, TValue *o) {
- char old = ls->decpoint;
- ls->decpoint = l_getlocaledecpoint();
- buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
- if (!buff2num(ls->buff, o)) {
- /* format error with correct decimal point: no more options */
- buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
- lexerror(ls, "malformed number", TK_FLT);
- }
-}
-
-
/* LUA_NUMBER */
/*
** this function is quite liberal in what it accepts, as 'luaO_str2num'
@@ -267,9 +229,8 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
else break;
}
save(ls, '\0');
- buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
- if (!buff2num(ls->buff, &obj)) /* format error? */
- trydecpoint(ls, &obj); /* try to update decimal point separator */
+ if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */
+ lexerror(ls, "malformed number", TK_FLT);
if (ttisinteger(&obj)) {
seminfo->i = ivalue(&obj);
return TK_INT;
@@ -283,8 +244,9 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
/*
-** skip a sequence '[=*[' or ']=*]' and return its number of '='s or
-** -1 if sequence is malformed
+** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return
+** its number of '='s; otherwise, return a negative number (-1 iff there
+** are no '='s after initial bracket)
*/
static int skip_sep (LexState *ls) {
int count = 0;
@@ -501,8 +463,9 @@ static int llex (LexState *ls, SemInfo *seminfo) {
read_long_string(ls, seminfo, sep);
return TK_STRING;
}
- else if (sep == -1) return '[';
- else lexerror(ls, "invalid long string delimiter", TK_STRING);
+ else if (sep != -1) /* '[=...' missing second bracket */
+ lexerror(ls, "invalid long string delimiter", TK_STRING);
+ return '[';
}
case '=': {
next(ls);
diff --git a/src/llex.h b/src/llex.h
index afb40b56228f..2363d87e40ea 100644
--- a/src/llex.h
+++ b/src/llex.h
@@ -1,5 +1,5 @@
/*
-** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp $
+** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -69,7 +69,6 @@ typedef struct LexState {
struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */
TString *envn; /* environment variable name */
- char decpoint; /* locale decimal point */
} LexState;
diff --git a/src/llimits.h b/src/llimits.h
index 8f71a6ffb951..f21377fef981 100644
--- a/src/llimits.h
+++ b/src/llimits.h
@@ -1,5 +1,5 @@
/*
-** $Id: llimits.h,v 1.125 2014/12/19 13:30:23 roberto Exp $
+** $Id: llimits.h,v 1.141 2015/11/19 19:16:22 roberto Exp $
** Limits, basic types, and some other 'installation-dependent' definitions
** See Copyright Notice in lua.h
*/
@@ -52,11 +52,11 @@ typedef unsigned char lu_byte;
/*
-** conversion of pointer to integer:
+** conversion of pointer to unsigned integer:
** this is for hashing only; there is no problem if the integer
** cannot hold the whole pointer value
*/
-#define point2int(p) ((unsigned int)((size_t)(p) & UINT_MAX))
+#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX))
@@ -64,7 +64,13 @@ typedef unsigned char lu_byte;
#if defined(LUAI_USER_ALIGNMENT_T)
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
#else
-typedef union { double u; void *s; lua_Integer i; long l; } L_Umaxalign;
+typedef union {
+ lua_Number n;
+ double u;
+ void *s;
+ lua_Integer i;
+ long l;
+} L_Umaxalign;
#endif
@@ -78,7 +84,7 @@ typedef LUAI_UACINT l_uacInt;
#if defined(lua_assert)
#define check_exp(c,e) (lua_assert(c), (e))
/* to avoid problems with conditions too long */
-#define lua_longassert(c) { if (!(c)) lua_assert(0); }
+#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0))
#else
#define lua_assert(c) ((void)0)
#define check_exp(c,e) (e)
@@ -88,22 +94,20 @@ typedef LUAI_UACINT l_uacInt;
/*
** assertion for checking API calls
*/
-#if defined(LUA_USE_APICHECK)
-#include <assert.h>
-#define luai_apicheck(e) assert(e)
-#else
-#define luai_apicheck(e) lua_assert(e)
+#if !defined(luai_apicheck)
+#define luai_apicheck(l,e) lua_assert(e)
#endif
-
-#define api_check(e,msg) luai_apicheck((e) && msg)
+#define api_check(l,e,msg) luai_apicheck(l,(e) && msg)
+/* macro to avoid warnings about unused variables */
#if !defined(UNUSED)
-#define UNUSED(x) ((void)(x)) /* to avoid warnings */
+#define UNUSED(x) ((void)(x))
#endif
+/* type casts (a macro highlights casts in the code) */
#define cast(t, exp) ((t)(exp))
#define cast_void(i) cast(void, (i))
@@ -149,11 +153,6 @@ typedef LUAI_UACINT l_uacInt;
#define LUAI_MAXCCALLS 200
#endif
-/*
-** maximum number of upvalues in a closure (both C and Lua). (Value
-** must fit in an unsigned char.)
-*/
-#define MAXUPVAL UCHAR_MAX
/*
@@ -168,10 +167,36 @@ typedef unsigned long Instruction;
+/*
+** Maximum length for short strings, that is, strings that are
+** internalized. (Cannot be smaller than reserved words or tags for
+** metamethods, as these strings must be internalized;
+** #("function") = 8, #("__newindex") = 10.)
+*/
+#if !defined(LUAI_MAXSHORTLEN)
+#define LUAI_MAXSHORTLEN 40
+#endif
+
-/* minimum size for the string table (must be power of 2) */
+/*
+** Initial size for the string table (must be power of 2).
+** The Lua core alone registers ~50 strings (reserved words +
+** metaevent keys + a few others). Libraries would typically add
+** a few dozens more.
+*/
#if !defined(MINSTRTABSIZE)
-#define MINSTRTABSIZE 64 /* minimum size for "predefined" strings */
+#define MINSTRTABSIZE 128
+#endif
+
+
+/*
+** Size of cache for strings in the API. 'N' is the number of
+** sets (better be a prime) and "M" is the size of each set (M == 1
+** makes a direct cache.)
+*/
+#if !defined(STRCACHE_N)
+#define STRCACHE_N 53
+#define STRCACHE_M 2
#endif
@@ -181,11 +206,19 @@ typedef unsigned long Instruction;
#endif
+/*
+** macros that are executed whenever program enters the Lua core
+** ('lua_lock') and leaves the core ('lua_unlock')
+*/
#if !defined(lua_lock)
#define lua_lock(L) ((void) 0)
#define lua_unlock(L) ((void) 0)
#endif
+/*
+** macro executed during Lua functions at points where the
+** function can yield.
+*/
#if !defined(luai_threadyield)
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
#endif
@@ -223,20 +256,68 @@ typedef unsigned long Instruction;
/*
+** The luai_num* macros define the primitive operations over numbers.
+*/
+
+/* floor division (defined as 'floor(a/b)') */
+#if !defined(luai_numidiv)
+#define luai_numidiv(L,a,b) ((void)L, l_floor(luai_numdiv(L,a,b)))
+#endif
+
+/* float division */
+#if !defined(luai_numdiv)
+#define luai_numdiv(L,a,b) ((a)/(b))
+#endif
+
+/*
+** modulo: defined as 'a - floor(a/b)*b'; this definition gives NaN when
+** 'b' is huge, but the result should be 'a'. 'fmod' gives the result of
+** 'a - trunc(a/b)*b', and therefore must be corrected when 'trunc(a/b)
+** ~= floor(a/b)'. That happens when the division has a non-integer
+** negative result, which is equivalent to the test below.
+*/
+#if !defined(luai_nummod)
+#define luai_nummod(L,a,b,m) \
+ { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); }
+#endif
+
+/* exponentiation */
+#if !defined(luai_numpow)
+#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b))
+#endif
+
+/* the others are quite standard operations */
+#if !defined(luai_numadd)
+#define luai_numadd(L,a,b) ((a)+(b))
+#define luai_numsub(L,a,b) ((a)-(b))
+#define luai_nummul(L,a,b) ((a)*(b))
+#define luai_numunm(L,a) (-(a))
+#define luai_numeq(a,b) ((a)==(b))
+#define luai_numlt(a,b) ((a)<(b))
+#define luai_numle(a,b) ((a)<=(b))
+#define luai_numisnan(a) (!luai_numeq((a), (a)))
+#endif
+
+
+
+
+
+/*
** macro to control inclusion of some hard tests on stack reallocation
*/
#if !defined(HARDSTACKTESTS)
-#define condmovestack(L) ((void)0)
+#define condmovestack(L,pre,pos) ((void)0)
#else
/* realloc stack keeping its size */
-#define condmovestack(L) luaD_reallocstack((L), (L)->stacksize)
+#define condmovestack(L,pre,pos) \
+ { int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; }
#endif
#if !defined(HARDMEMTESTS)
-#define condchangemem(L) condmovestack(L)
+#define condchangemem(L,pre,pos) ((void)0)
#else
-#define condchangemem(L) \
- ((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1)))
+#define condchangemem(L,pre,pos) \
+ { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } }
#endif
#endif
diff --git a/src/lmathlib.c b/src/lmathlib.c
index 002c508bc465..b7f8baee076c 100644
--- a/src/lmathlib.c
+++ b/src/lmathlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lmathlib.c,v 1.114 2014/12/27 20:32:26 roberto Exp $
+** $Id: lmathlib.c,v 1.119 2016/12/22 13:08:50 roberto Exp $
** Standard mathematical library
** See Copyright Notice in lua.h
*/
@@ -39,7 +39,7 @@
static int math_abs (lua_State *L) {
if (lua_isinteger(L, 1)) {
lua_Integer n = lua_tointeger(L, 1);
- if (n < 0) n = (lua_Integer)(0u - n);
+ if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n);
lua_pushinteger(L, n);
}
else
@@ -183,8 +183,14 @@ static int math_log (lua_State *L) {
res = l_mathop(log)(x);
else {
lua_Number base = luaL_checknumber(L, 2);
- if (base == 10.0) res = l_mathop(log10)(x);
- else res = l_mathop(log)(x)/l_mathop(log)(base);
+#if !defined(LUA_USE_C89)
+ if (base == l_mathop(2.0))
+ res = l_mathop(log2)(x); else
+#endif
+ if (base == l_mathop(10.0))
+ res = l_mathop(log10)(x);
+ else
+ res = l_mathop(log)(x)/l_mathop(log)(base);
}
lua_pushnumber(L, res);
return 1;
@@ -259,7 +265,7 @@ static int math_random (lua_State *L) {
default: return luaL_error(L, "wrong number of arguments");
}
/* random integer in the interval [low, up] */
- luaL_argcheck(L, low <= up, 1, "interval is empty");
+ luaL_argcheck(L, low <= up, 1, "interval is empty");
luaL_argcheck(L, low >= 0 || up <= LUA_MAXINTEGER + low, 1,
"interval too large");
r *= (double)(up - low) + 1.0;
@@ -270,7 +276,7 @@ static int math_random (lua_State *L) {
static int math_randomseed (lua_State *L) {
l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1));
- (void)rand(); /* discard first value to avoid undesirable correlations */
+ (void)l_rand(); /* discard first value to avoid undesirable correlations */
return 0;
}
@@ -278,9 +284,9 @@ static int math_randomseed (lua_State *L) {
static int math_type (lua_State *L) {
if (lua_type(L, 1) == LUA_TNUMBER) {
if (lua_isinteger(L, 1))
- lua_pushliteral(L, "integer");
+ lua_pushliteral(L, "integer");
else
- lua_pushliteral(L, "float");
+ lua_pushliteral(L, "float");
}
else {
luaL_checkany(L, 1);
diff --git a/src/lmem.c b/src/lmem.c
index 4feaf036c726..0a0476cc7739 100644
--- a/src/lmem.c
+++ b/src/lmem.c
@@ -1,5 +1,5 @@
/*
-** $Id: lmem.c,v 1.89 2014/11/02 19:33:33 roberto Exp $
+** $Id: lmem.c,v 1.91 2015/03/06 19:45:54 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
@@ -85,10 +85,11 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
#endif
newblock = (*g->frealloc)(g->ud, block, osize, nsize);
if (newblock == NULL && nsize > 0) {
- api_check( nsize > realosize,
- "realloc cannot fail when shrinking a block");
- luaC_fullgc(L, 1); /* try to free some memory... */
- newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
+ lua_assert(nsize > realosize); /* cannot fail when shrinking a block */
+ if (g->version) { /* is state fully built? */
+ luaC_fullgc(L, 1); /* try to free some memory... */
+ newblock = (*g->frealloc)(g->ud, block, osize, nsize); /* try again */
+ }
if (newblock == NULL)
luaD_throw(L, LUA_ERRMEM);
}
diff --git a/src/loadlib.c b/src/loadlib.c
index 7f8d99029866..4791e748b160 100644
--- a/src/loadlib.c
+++ b/src/loadlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loadlib.c,v 1.124 2015/01/05 13:51:39 roberto Exp $
+** $Id: loadlib.c,v 1.130 2017/01/12 17:14:26 roberto Exp $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@@ -14,6 +14,7 @@
#include "lprefix.h"
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -24,40 +25,9 @@
/*
-** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
-** variables that Lua check to set its paths.
-*/
-#if !defined(LUA_PATH_VAR)
-#define LUA_PATH_VAR "LUA_PATH"
-#endif
-
-#if !defined(LUA_CPATH_VAR)
-#define LUA_CPATH_VAR "LUA_CPATH"
-#endif
-
-#define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
-
-#define LUA_PATHVARVERSION LUA_PATH_VAR LUA_PATHSUFFIX
-#define LUA_CPATHVARVERSION LUA_CPATH_VAR LUA_PATHSUFFIX
-
-/*
-** LUA_PATH_SEP is the character that separates templates in a path.
-** LUA_PATH_MARK is the string that marks the substitution points in a
-** template.
-** LUA_EXEC_DIR in a Windows path is replaced by the executable's
-** directory.
** LUA_IGMARK is a mark to ignore all before it when building the
** luaopen_ function name.
*/
-#if !defined (LUA_PATH_SEP)
-#define LUA_PATH_SEP ";"
-#endif
-#if !defined (LUA_PATH_MARK)
-#define LUA_PATH_MARK "?"
-#endif
-#if !defined (LUA_EXEC_DIR)
-#define LUA_EXEC_DIR "!"
-#endif
#if !defined (LUA_IGMARK)
#define LUA_IGMARK "-"
#endif
@@ -93,7 +63,8 @@ static const int CLIBS = 0;
#define LIB_FAIL "open"
-#define setprogdir(L) ((void)0)
+
+#define setprogdir(L) ((void)0)
/*
@@ -136,8 +107,8 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym);
#include <dlfcn.h>
/*
-** Macro to covert pointer to void* to pointer to function. This cast
-** is undefined according to ISO C, but POSIX assumes that it must work.
+** Macro to convert pointer-to-void* to pointer-to-function. This cast
+** is undefined according to ISO C, but POSIX assumes that it works.
** (The '__extension__' in gnu compilers is only to avoid warnings.)
*/
#if defined(__GNUC__)
@@ -178,7 +149,6 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
#include <windows.h>
-#undef setprogdir
/*
** optional flags for LoadLibraryEx
@@ -188,21 +158,30 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
#endif
+#undef setprogdir
+
+
+/*
+** Replace in the path (on the top of the stack) any occurrence
+** of LUA_EXEC_DIR with the executable's path.
+*/
static void setprogdir (lua_State *L) {
char buff[MAX_PATH + 1];
char *lb;
DWORD nsize = sizeof(buff)/sizeof(char);
- DWORD n = GetModuleFileNameA(NULL, buff, nsize);
+ DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL)
luaL_error(L, "unable to get ModuleFileName");
else {
- *lb = '\0';
+ *lb = '\0'; /* cut name on the last '\\' to get the path */
luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff);
lua_remove(L, -2); /* remove original string */
}
}
+
+
static void pusherror (lua_State *L) {
int error = GetLastError();
char buffer[128];
@@ -272,6 +251,67 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) {
/*
+** {==================================================================
+** Set Paths
+** ===================================================================
+*/
+
+/*
+** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment
+** variables that Lua check to set its paths.
+*/
+#if !defined(LUA_PATH_VAR)
+#define LUA_PATH_VAR "LUA_PATH"
+#endif
+
+#if !defined(LUA_CPATH_VAR)
+#define LUA_CPATH_VAR "LUA_CPATH"
+#endif
+
+
+#define AUXMARK "\1" /* auxiliary mark */
+
+
+/*
+** return registry.LUA_NOENV as a boolean
+*/
+static int noenv (lua_State *L) {
+ int b;
+ lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
+ b = lua_toboolean(L, -1);
+ lua_pop(L, 1); /* remove value */
+ return b;
+}
+
+
+/*
+** Set a path
+*/
+static void setpath (lua_State *L, const char *fieldname,
+ const char *envname,
+ const char *dft) {
+ const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX);
+ const char *path = getenv(nver); /* use versioned name */
+ if (path == NULL) /* no environment variable? */
+ path = getenv(envname); /* try unversioned name */
+ if (path == NULL || noenv(L)) /* no environment variable? */
+ lua_pushstring(L, dft); /* use default */
+ else {
+ /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
+ path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
+ LUA_PATH_SEP AUXMARK LUA_PATH_SEP);
+ luaL_gsub(L, path, AUXMARK, dft);
+ lua_remove(L, -2); /* remove result from 1st 'gsub' */
+ }
+ setprogdir(L);
+ lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */
+ lua_pop(L, 1); /* pop versioned variable name */
+}
+
+/* }================================================================== */
+
+
+/*
** return registry.CLIBS[path]
*/
static void *checkclib (lua_State *L, const char *path) {
@@ -519,7 +559,7 @@ static int searcher_Croot (lua_State *L) {
static int searcher_preload (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
- lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD");
+ lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
return 1;
@@ -556,9 +596,9 @@ static void findloader (lua_State *L, const char *name) {
static int ll_require (lua_State *L) {
const char *name = luaL_checkstring(L, 1);
- lua_settop(L, 1); /* _LOADED table will be at index 2 */
- lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
- lua_getfield(L, 2, name); /* _LOADED[name] */
+ lua_settop(L, 1); /* LOADED table will be at index 2 */
+ lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
+ lua_getfield(L, 2, name); /* LOADED[name] */
if (lua_toboolean(L, -1)) /* is it there? */
return 1; /* package is already loaded */
/* else must load package */
@@ -568,11 +608,11 @@ static int ll_require (lua_State *L) {
lua_insert(L, -2); /* name is 1st argument (before search data) */
lua_call(L, 2, 1); /* run loader to load module */
if (!lua_isnil(L, -1)) /* non-nil return? */
- lua_setfield(L, 2, name); /* _LOADED[name] = returned value */
+ lua_setfield(L, 2, name); /* LOADED[name] = returned value */
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
lua_pushboolean(L, 1); /* use true as result */
lua_pushvalue(L, -1); /* extra copy to be returned */
- lua_setfield(L, 2, name); /* _LOADED[name] = true */
+ lua_setfield(L, 2, name); /* LOADED[name] = true */
}
return 1;
}
@@ -665,41 +705,6 @@ static int ll_seeall (lua_State *L) {
-/* auxiliary mark (for internal use) */
-#define AUXMARK "\1"
-
-
-/*
-** return registry.LUA_NOENV as a boolean
-*/
-static int noenv (lua_State *L) {
- int b;
- lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
- b = lua_toboolean(L, -1);
- lua_pop(L, 1); /* remove value */
- return b;
-}
-
-
-static void setpath (lua_State *L, const char *fieldname, const char *envname1,
- const char *envname2, const char *def) {
- const char *path = getenv(envname1);
- if (path == NULL) /* no environment variable? */
- path = getenv(envname2); /* try alternative name */
- if (path == NULL || noenv(L)) /* no environment variable? */
- lua_pushstring(L, def); /* use default */
- else {
- /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
- path = luaL_gsub(L, path, LUA_PATH_SEP LUA_PATH_SEP,
- LUA_PATH_SEP AUXMARK LUA_PATH_SEP);
- luaL_gsub(L, path, AUXMARK, def);
- lua_remove(L, -2);
- }
- setprogdir(L);
- lua_setfield(L, -2, fieldname);
-}
-
-
static const luaL_Reg pk_funcs[] = {
{"loadlib", ll_loadlib},
{"searchpath", ll_searchpath},
@@ -731,7 +736,7 @@ static void createsearcherstable (lua_State *L) {
int i;
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
- /* fill it with pre-defined searchers */
+ /* fill it with predefined searchers */
for (i=0; searchers[i] != NULL; i++) {
lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */
lua_pushcclosure(L, searchers[i], 1);
@@ -763,19 +768,18 @@ LUAMOD_API int luaopen_package (lua_State *L) {
createclibstable(L);
luaL_newlib(L, pk_funcs); /* create 'package' table */
createsearcherstable(L);
- /* set field 'path' */
- setpath(L, "path", LUA_PATHVARVERSION, LUA_PATH_VAR, LUA_PATH_DEFAULT);
- /* set field 'cpath' */
- setpath(L, "cpath", LUA_CPATHVARVERSION, LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
+ /* set paths */
+ setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT);
+ setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);
/* store config information */
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"
LUA_EXEC_DIR "\n" LUA_IGMARK "\n");
lua_setfield(L, -2, "config");
/* set field 'loaded' */
- luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
lua_setfield(L, -2, "loaded");
/* set field 'preload' */
- luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
+ luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
lua_setfield(L, -2, "preload");
lua_pushglobaltable(L);
lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */
diff --git a/src/lobject.c b/src/lobject.c
index 6a24aff95d9a..2da76899a27e 100644
--- a/src/lobject.c
+++ b/src/lobject.c
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.c,v 2.101 2014/12/26 14:43:45 roberto Exp $
+** $Id: lobject.c,v 2.113 2016/12/22 13:08:50 roberto Exp $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@@ -10,6 +10,8 @@
#include "lprefix.h"
+#include <locale.h>
+#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -39,8 +41,12 @@ LUAI_DDEF const TValue luaO_nilobject_ = {NILCONSTANT};
int luaO_int2fb (unsigned int x) {
int e = 0; /* exponent */
if (x < 8) return x;
- while (x >= 0x10) {
- x = (x+1) >> 1;
+ while (x >= (8 << 4)) { /* coarse steps */
+ x = (x + 0xf) >> 4; /* x = ceil(x / 16) */
+ e += 4;
+ }
+ while (x >= (8 << 1)) { /* fine steps */
+ x = (x + 1) >> 1; /* x = ceil(x / 2) */
e++;
}
return ((e+1) << 3) | (cast_int(x) - 8);
@@ -49,14 +55,15 @@ int luaO_int2fb (unsigned int x) {
/* converts back */
int luaO_fb2int (int x) {
- int e = (x >> 3) & 0x1f;
- if (e == 0) return x;
- else return ((x & 7) + 8) << (e - 1);
+ return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1);
}
+/*
+** Computes ceil(log2(x))
+*/
int luaO_ceillog2 (unsigned int x) {
- static const lu_byte log_2[256] = {
+ static const lu_byte log_2[256] = { /* log_2[i] = ceil(log2(i - 1)) */
0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
@@ -149,13 +156,13 @@ void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2,
}
/* could not perform raw operation; try metamethod */
lua_assert(L != NULL); /* should not fail when folding (compile time) */
- luaT_trybinTM(L, p1, p2, res, cast(TMS, op - LUA_OPADD + TM_ADD));
+ luaT_trybinTM(L, p1, p2, res, cast(TMS, (op - LUA_OPADD) + TM_ADD));
}
int luaO_hexavalue (int c) {
if (lisdigit(c)) return c - '0';
- else return ltolower(c) - 'a' + 10;
+ else return (ltolower(c) - 'a') + 10;
}
@@ -172,9 +179,8 @@ static int isneg (const char **s) {
** Lua's implementation for 'lua_strx2number'
** ===================================================================
*/
-#if !defined(lua_strx2number)
-#include <math.h>
+#if !defined(lua_strx2number)
/* maximum number of significant digits to read (to avoid overflows
even with single floats) */
@@ -185,21 +191,22 @@ static int isneg (const char **s) {
** C99 specification for 'strtod'
*/
static lua_Number lua_strx2number (const char *s, char **endptr) {
+ int dot = lua_getlocaledecpoint();
lua_Number r = 0.0; /* result (accumulator) */
int sigdig = 0; /* number of significant digits */
int nosigdig = 0; /* number of non-significant digits */
int e = 0; /* exponent correction */
int neg; /* 1 if number is negative */
- int dot = 0; /* true after seen a dot */
+ int hasdot = 0; /* true after seen a dot */
*endptr = cast(char *, s); /* nothing is valid yet */
while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */
neg = isneg(&s); /* check signal */
if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */
return 0.0; /* invalid format (no '0x') */
for (s += 2; ; s++) { /* skip '0x' and read numeral */
- if (*s == '.') {
- if (dot) break; /* second dot? stop loop */
- else dot = 1;
+ if (*s == dot) {
+ if (hasdot) break; /* second dot? stop loop */
+ else hasdot = 1;
}
else if (lisxdigit(cast_uchar(*s))) {
if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */
@@ -207,7 +214,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */
r = (r * cast_num(16.0)) + luaO_hexavalue(*s);
else e++; /* too many digits; ignore, but still count for exponent */
- if (dot) e--; /* decimal digit? correct exponent */
+ if (hasdot) e--; /* decimal digit? correct exponent */
}
else break; /* neither a dot nor a digit */
}
@@ -236,20 +243,59 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
/* }====================================================== */
-static const char *l_str2d (const char *s, lua_Number *result) {
+/* maximum length of a numeral */
+#if !defined (L_MAXLENNUM)
+#define L_MAXLENNUM 200
+#endif
+
+static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
char *endptr;
- if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */
+ *result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */
+ : lua_str2number(s, &endptr);
+ if (endptr == s) return NULL; /* nothing recognized? */
+ while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */
+ return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */
+}
+
+
+/*
+** Convert string 's' to a Lua number (put in 'result'). Return NULL
+** on fail or the address of the ending '\0' on success.
+** 'pmode' points to (and 'mode' contains) special things in the string:
+** - 'x'/'X' means an hexadecimal numeral
+** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)
+** - '.' just optimizes the search for the common case (nothing special)
+** This function accepts both the current locale or a dot as the radix
+** mark. If the convertion fails, it may mean number has a dot but
+** locale accepts something else. In that case, the code copies 's'
+** to a buffer (because 's' is read-only), changes the dot to the
+** current locale radix mark, and tries to convert again.
+*/
+static const char *l_str2d (const char *s, lua_Number *result) {
+ const char *endptr;
+ const char *pmode = strpbrk(s, ".xXnN");
+ int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
+ if (mode == 'n') /* reject 'inf' and 'nan' */
return NULL;
- else if (strpbrk(s, "xX")) /* hex? */
- *result = lua_strx2number(s, &endptr);
- else
- *result = lua_str2number(s, &endptr);
- if (endptr == s) return 0; /* nothing recognized */
- while (lisspace(cast_uchar(*endptr))) endptr++;
- return (*endptr == '\0' ? endptr : NULL); /* OK if no trailing characters */
+ endptr = l_str2dloc(s, result, mode); /* try to convert */
+ if (endptr == NULL) { /* failed? may be a different locale */
+ char buff[L_MAXLENNUM + 1];
+ const char *pdot = strchr(s, '.');
+ if (strlen(s) > L_MAXLENNUM || pdot == NULL)
+ return NULL; /* string too long or no dot; fail */
+ strcpy(buff, s); /* copy string to buffer */
+ buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */
+ endptr = l_str2dloc(buff, result, mode); /* try again */
+ if (endptr != NULL)
+ endptr = s + (endptr - buff); /* make relative to 's' */
+ }
+ return endptr;
}
+#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10)
+#define MAXLASTD cast_int(LUA_MAXINTEGER % 10)
+
static const char *l_str2int (const char *s, lua_Integer *result) {
lua_Unsigned a = 0;
int empty = 1;
@@ -266,7 +312,10 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
}
else { /* decimal */
for (; lisdigit(cast_uchar(*s)); s++) {
- a = a * 10 + *s - '0';
+ int d = *s - '0';
+ if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
+ return NULL; /* do not accept it (as integer) */
+ a = a * 10 + d;
empty = 0;
}
}
@@ -290,7 +339,7 @@ size_t luaO_str2num (const char *s, TValue *o) {
}
else
return 0; /* conversion failed */
- return (e - s + 1); /* success; return string size */
+ return (e - s) + 1; /* success; return string size */
}
@@ -324,12 +373,12 @@ void luaO_tostring (lua_State *L, StkId obj) {
size_t len;
lua_assert(ttisnumber(obj));
if (ttisinteger(obj))
- len = lua_integer2str(buff, ivalue(obj));
+ len = lua_integer2str(buff, sizeof(buff), ivalue(obj));
else {
- len = lua_number2str(buff, fltvalue(obj));
+ len = lua_number2str(buff, sizeof(buff), fltvalue(obj));
#if !defined(LUA_COMPAT_FLOATSTRING)
if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */
- buff[len++] = '.';
+ buff[len++] = lua_getlocaledecpoint();
buff[len++] = '0'; /* adds '.0' to result */
}
#endif
@@ -339,27 +388,29 @@ void luaO_tostring (lua_State *L, StkId obj) {
static void pushstr (lua_State *L, const char *str, size_t l) {
- setsvalue2s(L, L->top++, luaS_newlstr(L, str, l));
+ setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
+ luaD_inctop(L);
}
-/* this function handles only '%d', '%c', '%f', '%p', and '%s'
- conventional formats, plus Lua-specific '%I' and '%U' */
+/*
+** this function handles only '%d', '%c', '%f', '%p', and '%s'
+ conventional formats, plus Lua-specific '%I' and '%U'
+*/
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
int n = 0;
for (;;) {
const char *e = strchr(fmt, '%');
if (e == NULL) break;
- luaD_checkstack(L, 2); /* fmt + item */
pushstr(L, fmt, e - fmt);
switch (*(e+1)) {
- case 's': {
+ case 's': { /* zero-terminated string */
const char *s = va_arg(argp, char *);
if (s == NULL) s = "(null)";
pushstr(L, s, strlen(s));
break;
}
- case 'c': {
+ case 'c': { /* an 'int' as a character */
char buff = cast(char, va_arg(argp, int));
if (lisprint(cast_uchar(buff)))
pushstr(L, &buff, 1);
@@ -367,28 +418,28 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
luaO_pushfstring(L, "<\\%d>", cast_uchar(buff));
break;
}
- case 'd': {
- setivalue(L->top++, va_arg(argp, int));
- luaO_tostring(L, L->top - 1);
- break;
+ case 'd': { /* an 'int' */
+ setivalue(L->top, va_arg(argp, int));
+ goto top2str;
}
- case 'I': {
- setivalue(L->top++, cast(lua_Integer, va_arg(argp, l_uacInt)));
- luaO_tostring(L, L->top - 1);
- break;
+ case 'I': { /* a 'lua_Integer' */
+ setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt)));
+ goto top2str;
}
- case 'f': {
- setfltvalue(L->top++, cast_num(va_arg(argp, l_uacNumber)));
+ case 'f': { /* a 'lua_Number' */
+ setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
+ top2str: /* convert the top element to a string */
+ luaD_inctop(L);
luaO_tostring(L, L->top - 1);
break;
}
- case 'p': {
+ case 'p': { /* a pointer */
char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */
- int l = sprintf(buff, "%p", va_arg(argp, void *));
+ int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *));
pushstr(L, buff, l);
break;
}
- case 'U': {
+ case 'U': { /* an 'int' as a UTF-8 sequence */
char buff[UTF8BUFFSZ];
int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));
pushstr(L, buff + UTF8BUFFSZ - l, l);
diff --git a/src/lobject.h b/src/lobject.h
index d7d0ebf31b05..3c042289492b 100644
--- a/src/lobject.h
+++ b/src/lobject.h
@@ -1,5 +1,5 @@
/*
-** $Id: lobject.h,v 2.106 2015/01/05 13:52:37 roberto Exp $
+** $Id: lobject.h,v 2.117 2016/08/01 19:51:24 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@@ -19,8 +19,8 @@
/*
** Extra tags for non-values
*/
-#define LUA_TPROTO LUA_NUMTAGS
-#define LUA_TDEADKEY (LUA_NUMTAGS+1)
+#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */
+#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */
/*
** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
@@ -35,8 +35,6 @@
** bit 6: whether value is collectable
*/
-#define VARBITS (3 << 4)
-
/*
** LUA_TFUNCTION variants:
@@ -90,22 +88,32 @@ struct GCObject {
-/*
-** Union of all Lua values
-*/
-typedef union Value Value;
-
-
-
/*
** Tagged Values. This is the basic representation of values in Lua,
** an actual value plus a tag with its type.
*/
+/*
+** Union of all Lua values
+*/
+typedef union Value {
+ GCObject *gc; /* collectable objects */
+ void *p; /* light userdata */
+ int b; /* booleans */
+ lua_CFunction f; /* light C functions */
+ lua_Integer i; /* integer numbers */
+ lua_Number n; /* float numbers */
+} Value;
+
+
#define TValuefields Value value_; int tt_
-typedef struct lua_TValue TValue;
+
+typedef struct lua_TValue {
+ TValuefields;
+} TValue;
+
/* macro defining a nil value */
@@ -179,9 +187,9 @@ typedef struct lua_TValue TValue;
/* Macros for internal tests */
#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt)
-#define checkliveness(g,obj) \
+#define checkliveness(L,obj) \
lua_longassert(!iscollectable(obj) || \
- (righttt(obj) && !isdead(g,gcvalue(obj))))
+ (righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))
/* Macros to set values */
@@ -190,9 +198,15 @@ typedef struct lua_TValue TValue;
#define setfltvalue(obj,x) \
{ TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); }
+#define chgfltvalue(obj,x) \
+ { TValue *io=(obj); lua_assert(ttisfloat(io)); val_(io).n=(x); }
+
#define setivalue(obj,x) \
{ TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); }
+#define chgivalue(obj,x) \
+ { TValue *io=(obj); lua_assert(ttisinteger(io)); val_(io).i=(x); }
+
#define setnilvalue(obj) settt_(obj, LUA_TNIL)
#define setfvalue(obj,x) \
@@ -211,32 +225,32 @@ typedef struct lua_TValue TValue;
#define setsvalue(L,obj,x) \
{ TValue *io = (obj); TString *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define setuvalue(L,obj,x) \
{ TValue *io = (obj); Udata *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define setthvalue(L,obj,x) \
{ TValue *io = (obj); lua_State *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define setclLvalue(L,obj,x) \
{ TValue *io = (obj); LClosure *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define setclCvalue(L,obj,x) \
{ TValue *io = (obj); CClosure *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define sethvalue(L,obj,x) \
{ TValue *io = (obj); Table *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
- checkliveness(G(L),io); }
+ checkliveness(L,io); }
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
@@ -244,7 +258,7 @@ typedef struct lua_TValue TValue;
#define setobj(L,obj1,obj2) \
{ TValue *io1=(obj1); *io1 = *(obj2); \
- (void)L; checkliveness(G(L),io1); }
+ (void)L; checkliveness(L,io1); }
/*
@@ -260,12 +274,13 @@ typedef struct lua_TValue TValue;
#define setptvalue2s setptvalue
/* from table to same table */
#define setobjt2t setobj
-/* to table */
-#define setobj2t setobj
/* to new object */
#define setobj2n setobj
#define setsvalue2n setsvalue
+/* to table (define it as an expression to be used in macros) */
+#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1)))
+
@@ -276,21 +291,6 @@ typedef struct lua_TValue TValue;
*/
-union Value {
- GCObject *gc; /* collectable objects */
- void *p; /* light userdata */
- int b; /* booleans */
- lua_CFunction f; /* light C functions */
- lua_Integer i; /* integer numbers */
- lua_Number n; /* float numbers */
-};
-
-
-struct lua_TValue {
- TValuefields;
-};
-
-
typedef TValue *StkId; /* index to stack elements */
@@ -303,9 +303,12 @@ typedef TValue *StkId; /* index to stack elements */
typedef struct TString {
CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
+ lu_byte shrlen; /* length for short strings */
unsigned int hash;
- size_t len; /* number of characters in string */
- struct TString *hnext; /* linked list for hash table */
+ union {
+ size_t lnglen; /* length for long strings */
+ struct TString *hnext; /* linked list for hash table */
+ } u;
} TString;
@@ -322,13 +325,19 @@ typedef union UTString {
** Get the actual string (array of bytes) from a 'TString'.
** (Access to 'extra' ensures that value is really a 'TString'.)
*/
-#define getaddrstr(ts) (cast(char *, (ts)) + sizeof(UTString))
#define getstr(ts) \
- check_exp(sizeof((ts)->extra), cast(const char*, getaddrstr(ts)))
+ check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString))
+
/* get the actual string (array of bytes) from a Lua value */
#define svalue(o) getstr(tsvalue(o))
+/* get string length from 'TString *s' */
+#define tsslen(s) ((s)->tt == LUA_TSHRSTR ? (s)->shrlen : (s)->u.lnglen)
+
+/* get string length from 'TValue *o' */
+#define vslen(o) tsslen(tsvalue(o))
+
/*
** Header for userdata; memory area follows the end of this structure
@@ -361,14 +370,14 @@ typedef union UUdata {
#define setuservalue(L,u,o) \
{ const TValue *io=(o); Udata *iu = (u); \
- iu->user_ = io->value_; iu->ttuv_ = io->tt_; \
- checkliveness(G(L),io); }
+ iu->user_ = io->value_; iu->ttuv_ = rttype(io); \
+ checkliveness(L,io); }
#define getuservalue(L,u,o) \
{ TValue *io=(o); const Udata *iu = (u); \
- io->value_ = iu->user_; io->tt_ = iu->ttuv_; \
- checkliveness(G(L),io); }
+ io->value_ = iu->user_; settt_(io, iu->ttuv_); \
+ checkliveness(L,io); }
/*
@@ -376,7 +385,7 @@ typedef union UUdata {
*/
typedef struct Upvaldesc {
TString *name; /* upvalue name (for debug information) */
- lu_byte instack; /* whether it is in stack */
+ lu_byte instack; /* whether it is in stack (register) */
lu_byte idx; /* index of upvalue (in stack or in outer function's list) */
} Upvaldesc;
@@ -399,22 +408,22 @@ typedef struct Proto {
CommonHeader;
lu_byte numparams; /* number of fixed parameters */
lu_byte is_vararg;
- lu_byte maxstacksize; /* maximum stack used by this function */
+ lu_byte maxstacksize; /* number of registers needed by this function */
int sizeupvalues; /* size of 'upvalues' */
int sizek; /* size of 'k' */
int sizecode;
int sizelineinfo;
int sizep; /* size of 'p' */
int sizelocvars;
- int linedefined;
- int lastlinedefined;
+ int linedefined; /* debug information */
+ int lastlinedefined; /* debug information */
TValue *k; /* constants used by the function */
- Instruction *code;
+ Instruction *code; /* opcodes */
struct Proto **p; /* functions defined inside the function */
int *lineinfo; /* map from opcodes to source lines (debug information) */
LocVar *locvars; /* information about local variables (debug information) */
Upvaldesc *upvalues; /* upvalue information */
- struct LClosure *cache; /* last created closure with this prototype */
+ struct LClosure *cache; /* last-created closure with this prototype */
TString *source; /* used for debug information */
GCObject *gclist;
} Proto;
@@ -476,7 +485,7 @@ typedef union TKey {
#define setnodekey(L,key,obj) \
{ TKey *k_=(key); const TValue *io_=(obj); \
k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \
- (void)L; checkliveness(G(L),io_); }
+ (void)L; checkliveness(L,io_); }
typedef struct Node {
diff --git a/src/lopcodes.h b/src/lopcodes.h
index 864b8e4bb5d4..bbc4b61968aa 100644
--- a/src/lopcodes.h
+++ b/src/lopcodes.h
@@ -1,5 +1,5 @@
/*
-** $Id: lopcodes.h,v 1.148 2014/10/25 11:50:46 roberto Exp $
+** $Id: lopcodes.h,v 1.149 2016/07/19 17:12:21 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -139,7 +139,9 @@ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
/* gets the index of the constant */
#define INDEXK(r) ((int)(r) & ~BITRK)
+#if !defined(MAXINDEXRK) /* (for debugging only) */
#define MAXINDEXRK (BITRK - 1)
+#endif
/* code a constant index as a RK value */
#define RKASK(x) ((x) | BITRK)
diff --git a/src/loslib.c b/src/loslib.c
index 20359b24747c..5a94eb9068d5 100644
--- a/src/loslib.c
+++ b/src/loslib.c
@@ -1,5 +1,5 @@
/*
-** $Id: loslib.c,v 1.54 2014/12/26 14:46:07 roberto Exp $
+** $Id: loslib.c,v 1.65 2016/07/18 17:58:58 roberto Exp $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
@@ -22,23 +22,42 @@
#include "lualib.h"
-#if !defined(LUA_STRFTIMEOPTIONS) /* { */
/*
-** list of valid conversion specifiers for the 'strftime' function
+** {==================================================================
+** List of valid conversion specifiers for the 'strftime' function;
+** options are grouped by length; group of length 2 start with '||'.
+** ===================================================================
*/
+#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_C89)
-#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
+#if defined(LUA_USE_WINDOWS)
+#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
+#elif defined(LUA_USE_C89)
+#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
#else /* C99 specification */
-#define LUA_STRFTIMEOPTIONS \
- { "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \
- "E", "cCxXyY", \
- "O", "deHImMSuUVwWy" }
+#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
#endif
#endif /* } */
+/* }================================================================== */
+/*
+** {==================================================================
+** Configuration for time-related stuff
+** ===================================================================
+*/
#if !defined(l_time_t) /* { */
/*
@@ -46,17 +65,48 @@
*/
#define l_timet lua_Integer
#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t))
-#define l_checktime(L,a) ((time_t)luaL_checkinteger(L,a))
+
+static time_t l_checktime (lua_State *L, int arg) {
+ lua_Integer t = luaL_checkinteger(L, arg);
+ luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
+ return (time_t)t;
+}
#endif /* } */
+#if !defined(l_gmtime) /* { */
+/*
+** By default, Lua uses gmtime/localtime, except when POSIX is available,
+** where it uses gmtime_r/localtime_r
+*/
+
+#if defined(LUA_USE_POSIX) /* { */
+
+#define l_gmtime(t,r) gmtime_r(t,r)
+#define l_localtime(t,r) localtime_r(t,r)
+
+#else /* }{ */
+
+/* ISO C definitions */
+#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t))
+#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t))
+
+#endif /* } */
+
+#endif /* } */
+
+/* }================================================================== */
+
-#if !defined(lua_tmpnam) /* { */
/*
-** By default, Lua uses tmpnam except when POSIX is available, where it
-** uses mkstemp.
+** {==================================================================
+** Configuration for 'tmpnam':
+** By default, Lua uses tmpnam except when POSIX is available, where
+** it uses mkstemp.
+** ===================================================================
*/
+#if !defined(lua_tmpnam) /* { */
#if defined(LUA_USE_POSIX) /* { */
@@ -83,31 +133,10 @@
#endif /* } */
#endif /* } */
+/* }================================================================== */
-#if !defined(l_gmtime) /* { */
-/*
-** By default, Lua uses gmtime/localtime, except when POSIX is available,
-** where it uses gmtime_r/localtime_r
-*/
-
-#if defined(LUA_USE_POSIX) /* { */
-
-#define l_gmtime(t,r) gmtime_r(t,r)
-#define l_localtime(t,r) localtime_r(t,r)
-
-#else /* }{ */
-
-/* ISO C definitions */
-#define l_gmtime(t,r) ((void)(r)->tm_sec, gmtime(t))
-#define l_localtime(t,r) ((void)(r)->tm_sec, localtime(t))
-
-#endif /* } */
-
-#endif /* } */
-
-
static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL);
@@ -177,6 +206,23 @@ static void setboolfield (lua_State *L, const char *key, int value) {
lua_setfield(L, -2, key);
}
+
+/*
+** Set all fields from structure 'tm' in the table on top of the stack
+*/
+static void setallfields (lua_State *L, struct tm *stm) {
+ setfield(L, "sec", stm->tm_sec);
+ setfield(L, "min", stm->tm_min);
+ setfield(L, "hour", stm->tm_hour);
+ setfield(L, "day", stm->tm_mday);
+ setfield(L, "month", stm->tm_mon + 1);
+ setfield(L, "year", stm->tm_year + 1900);
+ setfield(L, "wday", stm->tm_wday + 1);
+ setfield(L, "yday", stm->tm_yday + 1);
+ setboolfield(L, "isdst", stm->tm_isdst);
+}
+
+
static int getboolfield (lua_State *L, const char *key) {
int res;
res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
@@ -185,36 +231,43 @@ static int getboolfield (lua_State *L, const char *key) {
}
-static int getfield (lua_State *L, const char *key, int d) {
- int res, isnum;
- lua_getfield(L, -1, key);
- res = (int)lua_tointegerx(L, -1, &isnum);
- if (!isnum) {
- if (d < 0)
+/* maximum value for date fields (to avoid arithmetic overflows with 'int') */
+#if !defined(L_MAXDATEFIELD)
+#define L_MAXDATEFIELD (INT_MAX / 2)
+#endif
+
+static int getfield (lua_State *L, const char *key, int d, int delta) {
+ int isnum;
+ int t = lua_getfield(L, -1, key); /* get field and its type */
+ lua_Integer res = lua_tointegerx(L, -1, &isnum);
+ if (!isnum) { /* field is not an integer? */
+ if (t != LUA_TNIL) /* some other value? */
+ return luaL_error(L, "field '%s' is not an integer", key);
+ else if (d < 0) /* absent field; no default? */
return luaL_error(L, "field '%s' missing in date table", key);
res = d;
}
+ else {
+ if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
+ return luaL_error(L, "field '%s' is out-of-bound", key);
+ res -= delta;
+ }
lua_pop(L, 1);
- return res;
+ return (int)res;
}
-static const char *checkoption (lua_State *L, const char *conv, char *buff) {
- static const char *const options[] = LUA_STRFTIMEOPTIONS;
- unsigned int i;
- for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) {
- if (*conv != '\0' && strchr(options[i], *conv) != NULL) {
- buff[1] = *conv;
- if (*options[i + 1] == '\0') { /* one-char conversion specifier? */
- buff[2] = '\0'; /* end buffer */
- return conv + 1;
- }
- else if (*(conv + 1) != '\0' &&
- strchr(options[i + 1], *(conv + 1)) != NULL) {
- buff[2] = *(conv + 1); /* valid two-char conversion specifier */
- buff[3] = '\0'; /* end buffer */
- return conv + 2;
- }
+static const char *checkoption (lua_State *L, const char *conv,
+ ptrdiff_t convlen, char *buff) {
+ const char *option = LUA_STRFTIMEOPTIONS;
+ int oplen = 1; /* length of options being checked */
+ for (; *option != '\0' && oplen <= convlen; option += oplen) {
+ if (*option == '|') /* next block? */
+ oplen++; /* will check options with next length (+1) */
+ else if (memcmp(conv, option, oplen) == 0) { /* match? */
+ memcpy(buff, conv, oplen); /* copy valid option to buffer */
+ buff[oplen] = '\0';
+ return conv + oplen; /* return next item */
}
}
luaL_argerror(L, 1,
@@ -223,9 +276,15 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) {
}
+/* maximum size for an individual 'strftime' item */
+#define SIZETIMEFMT 250
+
+
static int os_date (lua_State *L) {
- const char *s = luaL_optstring(L, 1, "%c");
+ size_t slen;
+ const char *s = luaL_optlstring(L, 1, "%c", &slen);
time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
+ const char *se = s + slen; /* 's' end */
struct tm tmr, *stm;
if (*s == '!') { /* UTC? */
stm = l_gmtime(&t, &tmr);
@@ -234,33 +293,26 @@ static int os_date (lua_State *L) {
else
stm = l_localtime(&t, &tmr);
if (stm == NULL) /* invalid date? */
- lua_pushnil(L);
- else if (strcmp(s, "*t") == 0) {
+ luaL_error(L, "time result cannot be represented in this installation");
+ if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */
- setfield(L, "sec", stm->tm_sec);
- setfield(L, "min", stm->tm_min);
- setfield(L, "hour", stm->tm_hour);
- setfield(L, "day", stm->tm_mday);
- setfield(L, "month", stm->tm_mon+1);
- setfield(L, "year", stm->tm_year+1900);
- setfield(L, "wday", stm->tm_wday+1);
- setfield(L, "yday", stm->tm_yday+1);
- setboolfield(L, "isdst", stm->tm_isdst);
+ setallfields(L, stm);
}
else {
- char cc[4];
+ char cc[4]; /* buffer for individual conversion specifiers */
luaL_Buffer b;
cc[0] = '%';
luaL_buffinit(L, &b);
- while (*s) {
- if (*s != '%') /* no conversion specifier? */
+ while (s < se) {
+ if (*s != '%') /* not a conversion specifier? */
luaL_addchar(&b, *s++);
else {
size_t reslen;
- char buff[200]; /* should be big enough for any conversion result */
- s = checkoption(L, s + 1, cc);
- reslen = strftime(buff, sizeof(buff), cc, stm);
- luaL_addlstring(&b, buff, reslen);
+ char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
+ s++; /* skip '%' */
+ s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */
+ reslen = strftime(buff, SIZETIMEFMT, cc, stm);
+ luaL_addsize(&b, reslen);
}
}
luaL_pushresult(&b);
@@ -277,28 +329,27 @@ static int os_time (lua_State *L) {
struct tm ts;
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); /* make sure table is at the top */
- ts.tm_sec = getfield(L, "sec", 0);
- ts.tm_min = getfield(L, "min", 0);
- ts.tm_hour = getfield(L, "hour", 12);
- ts.tm_mday = getfield(L, "day", -1);
- ts.tm_mon = getfield(L, "month", -1) - 1;
- ts.tm_year = getfield(L, "year", -1) - 1900;
+ ts.tm_sec = getfield(L, "sec", 0, 0);
+ ts.tm_min = getfield(L, "min", 0, 0);
+ ts.tm_hour = getfield(L, "hour", 12, 0);
+ ts.tm_mday = getfield(L, "day", -1, 0);
+ ts.tm_mon = getfield(L, "month", -1, 1);
+ ts.tm_year = getfield(L, "year", -1, 1900);
ts.tm_isdst = getboolfield(L, "isdst");
t = mktime(&ts);
+ setallfields(L, &ts); /* update fields with normalized values */
}
- if (t != (time_t)(l_timet)t)
- luaL_error(L, "time result cannot be represented in this Lua instalation");
- else if (t == (time_t)(-1))
- lua_pushnil(L);
- else
- l_pushtime(L, t);
+ if (t != (time_t)(l_timet)t || t == (time_t)(-1))
+ luaL_error(L, "time result cannot be represented in this installation");
+ l_pushtime(L, t);
return 1;
}
static int os_difftime (lua_State *L) {
- double res = difftime((l_checktime(L, 1)), (l_checktime(L, 2)));
- lua_pushnumber(L, (lua_Number)res);
+ time_t t1 = l_checktime(L, 1);
+ time_t t2 = l_checktime(L, 2);
+ lua_pushnumber(L, (lua_Number)difftime(t1, t2));
return 1;
}
diff --git a/src/lparser.c b/src/lparser.c
index 9a54dfc98d70..cd4512d4d417 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.c,v 2.147 2014/12/27 20:31:43 roberto Exp $
+** $Id: lparser.c,v 2.155 2016/08/01 19:51:24 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -164,7 +164,8 @@ static int registerlocalvar (LexState *ls, TString *varname) {
int oldsize = f->sizelocvars;
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
LocVar, SHRT_MAX, "local variables");
- while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
+ while (oldsize < f->sizelocvars)
+ f->locvars[oldsize++].varname = NULL;
f->locvars[fs->nlocvars].varname = varname;
luaC_objbarrier(ls->L, f, varname);
return fs->nlocvars++;
@@ -230,7 +231,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
Upvaldesc, MAXUPVAL, "upvalues");
- while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
+ while (oldsize < f->sizeupvalues)
+ f->upvalues[oldsize++].name = NULL;
f->upvalues[fs->nups].instack = (v->k == VLOCAL);
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
f->upvalues[fs->nups].name = name;
@@ -255,7 +257,8 @@ static int searchvar (FuncState *fs, TString *n) {
*/
static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl;
- while (bl->nactvar > level) bl = bl->previous;
+ while (bl->nactvar > level)
+ bl = bl->previous;
bl->upval = 1;
}
@@ -264,27 +267,26 @@ static void markupval (FuncState *fs, int level) {
Find variable with given name 'n'. If it is an upvalue, add this
upvalue into all intermediate functions.
*/
-static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
+static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) /* no more levels? */
- return VVOID; /* default is global */
+ init_exp(var, VVOID, 0); /* default is global */
else {
int v = searchvar(fs, n); /* look up locals at current level */
if (v >= 0) { /* found? */
init_exp(var, VLOCAL, v); /* variable is local */
if (!base)
markupval(fs, v); /* local will be used as an upval */
- return VLOCAL;
}
else { /* not found as local at current level; try upvalues */
int idx = searchupvalue(fs, n); /* try existing upvalues */
if (idx < 0) { /* not found? */
- if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */
- return VVOID; /* not found; is a global */
+ singlevaraux(fs->prev, n, var, 0); /* try upper levels */
+ if (var->k == VVOID) /* not found? */
+ return; /* it is a global */
/* else was LOCAL or UPVAL */
idx = newupvalue(fs, n, var); /* will be a new upvalue */
}
- init_exp(var, VUPVAL, idx);
- return VUPVAL;
+ init_exp(var, VUPVAL, idx); /* new or old upvalue */
}
}
}
@@ -293,10 +295,11 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls);
FuncState *fs = ls->fs;
- if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
+ singlevaraux(fs, varname, var, 1);
+ if (var->k == VVOID) { /* global name? */
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
- lua_assert(var->k == VLOCAL || var->k == VUPVAL);
+ lua_assert(var->k != VVOID); /* this one must exist */
codestring(ls, &key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@@ -320,6 +323,8 @@ static void adjust_assign (LexState *ls, int nvars, int nexps, expdesc *e) {
luaK_nil(fs, reg, extra);
}
}
+ if (nexps > nvars)
+ ls->fs->freereg -= nexps - nvars; /* remove extra values */
}
@@ -499,7 +504,8 @@ static Proto *addprototype (LexState *ls) {
if (fs->np >= f->sizep) {
int oldsize = f->sizep;
luaM_growvector(L, f->p, fs->np, f->sizep, Proto *, MAXARG_Bx, "functions");
- while (oldsize < f->sizep) f->p[oldsize++] = NULL;
+ while (oldsize < f->sizep)
+ f->p[oldsize++] = NULL;
}
f->p[fs->np++] = clp = luaF_newproto(L);
luaC_objbarrier(L, f, clp);
@@ -760,7 +766,7 @@ static void parlist (LexState *ls) {
}
case TK_DOTS: { /* param -> '...' */
luaX_next(ls);
- f->is_vararg = 1;
+ f->is_vararg = 1; /* declared vararg */
break;
}
default: luaX_syntaxerror(ls, "<name> or '...' expected");
@@ -1155,11 +1161,8 @@ static void assignment (LexState *ls, struct LHS_assign *lh, int nvars) {
int nexps;
checknext(ls, '=');
nexps = explist(ls, &e);
- if (nexps != nvars) {
+ if (nexps != nvars)
adjust_assign(ls, nvars, nexps, &e);
- if (nexps > nvars)
- ls->fs->freereg -= nexps - nvars; /* remove extra values */
- }
else {
luaK_setoneret(ls->fs, &e); /* close last expression */
luaK_storevar(ls->fs, &lh->v, &e);
@@ -1225,7 +1228,7 @@ static void labelstat (LexState *ls, TString *label, int line) {
checkrepeated(fs, ll, label); /* check for repeated labels */
checknext(ls, TK_DBCOLON); /* skip double colon */
/* create new entry for this label */
- l = newlabelentry(ls, ll, label, line, fs->pc);
+ l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
skipnoopstat(ls); /* skip other no-op statements */
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
@@ -1493,7 +1496,7 @@ static void exprstat (LexState *ls) {
}
else { /* stat -> func */
check_condition(ls, v.v.k == VCALL, "syntax error");
- SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
+ SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */
}
}
@@ -1510,8 +1513,8 @@ static void retstat (LexState *ls) {
if (hasmultret(e.k)) {
luaK_setmultret(fs, &e);
if (e.k == VCALL && nret == 1) { /* tail call? */
- SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
- lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
+ SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
+ lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
}
first = fs->nactvar;
nret = LUA_MULTRET; /* return all values */
@@ -1610,7 +1613,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
BlockCnt bl;
expdesc v;
open_func(ls, fs, &bl);
- fs->f->is_vararg = 1; /* main function is always vararg */
+ fs->f->is_vararg = 1; /* main function is always declared vararg */
init_exp(&v, VLOCAL, 0); /* create and... */
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
luaX_next(ls); /* read first token */
@@ -1626,10 +1629,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */
- incr_top(L);
+ luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue(L, L->top, lexstate.h); /* anchor it */
- incr_top(L);
+ luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L);
funcstate.f->source = luaS_new(L, name); /* create and anchor TString */
lua_assert(iswhite(funcstate.f)); /* do not need barrier here */
diff --git a/src/lparser.h b/src/lparser.h
index 62c50cac7cc8..02e9b03aebcb 100644
--- a/src/lparser.h
+++ b/src/lparser.h
@@ -1,5 +1,5 @@
/*
-** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $
+** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -13,25 +13,38 @@
/*
-** Expression descriptor
+** Expression and variable descriptor.
+** Code generation for variables and expressions can be delayed to allow
+** optimizations; An 'expdesc' structure describes a potentially-delayed
+** variable/expression. It has a description of its "main" value plus a
+** list of conditional jumps that can also produce its value (generated
+** by short-circuit operators 'and'/'or').
*/
+/* kinds of variables/expressions */
typedef enum {
- VVOID, /* no value */
- VNIL,
- VTRUE,
- VFALSE,
- VK, /* info = index of constant in 'k' */
- VKFLT, /* nval = numerical float value */
- VKINT, /* nval = numerical integer value */
- VNONRELOC, /* info = result register */
- VLOCAL, /* info = local register */
- VUPVAL, /* info = index of upvalue in 'upvalues' */
- VINDEXED, /* t = table register/upvalue; idx = index R/K */
- VJMP, /* info = instruction pc */
- VRELOCABLE, /* info = instruction pc */
- VCALL, /* info = instruction pc */
- VVARARG /* info = instruction pc */
+ VVOID, /* when 'expdesc' describes the last expression a list,
+ this kind means an empty list (so, no expression) */
+ VNIL, /* constant nil */
+ VTRUE, /* constant true */
+ VFALSE, /* constant false */
+ VK, /* constant in 'k'; info = index of constant in 'k' */
+ VKFLT, /* floating constant; nval = numerical float value */
+ VKINT, /* integer constant; nval = numerical integer value */
+ VNONRELOC, /* expression has its value in a fixed register;
+ info = result register */
+ VLOCAL, /* local variable; info = local register */
+ VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
+ VINDEXED, /* indexed variable;
+ ind.vt = whether 't' is register or upvalue;
+ ind.t = table register or upvalue;
+ ind.idx = key's R/K index */
+ VJMP, /* expression is a test/comparison;
+ info = pc of corresponding jump instruction */
+ VRELOCABLE, /* expression can put result in any register;
+ info = instruction pc */
+ VCALL, /* expression is a function call; info = instruction pc */
+ VVARARG /* vararg expression; info = instruction pc */
} expkind;
@@ -41,14 +54,14 @@ typedef enum {
typedef struct expdesc {
expkind k;
union {
+ lua_Integer ival; /* for VKINT */
+ lua_Number nval; /* for VKFLT */
+ int info; /* for generic use */
struct { /* for indexed variables (VINDEXED) */
short idx; /* index (R/K) */
lu_byte t; /* table (register or upvalue) */
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
} ind;
- int info; /* for generic use */
- lua_Number nval; /* for VKFLT */
- lua_Integer ival; /* for VKINT */
} u;
int t; /* patch list of 'exit when true' */
int f; /* patch list of 'exit when false' */
diff --git a/src/lstate.c b/src/lstate.c
index ff6b02d36ae0..9194ac3419e1 100644
--- a/src/lstate.c
+++ b/src/lstate.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.c,v 2.127 2014/11/02 19:33:33 roberto Exp $
+** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -37,9 +37,6 @@
#endif
-#define MEMERRMSG "not enough memory"
-
-
/*
** a macro to help the creation of a unique random seed when a state is
** created; the seed is used to randomize hashes.
@@ -79,7 +76,7 @@ typedef struct LG {
*/
#define addbuff(b,p,e) \
{ size_t t = cast(size_t, e); \
- memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); }
+ memcpy(b + p, &t, sizeof(t)); p += sizeof(t); }
static unsigned int makeseed (lua_State *L) {
char buff[4 * sizeof(size_t)];
@@ -96,10 +93,14 @@ static unsigned int makeseed (lua_State *L) {
/*
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
-** invariant
+** invariant (and avoiding underflows in 'totalbytes')
*/
void luaE_setdebt (global_State *g, l_mem debt) {
- g->totalbytes -= (debt - g->GCdebt);
+ l_mem tb = gettotalbytes(g);
+ lua_assert(tb > 0);
+ if (debt < tb - MAX_LMEM)
+ debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */
+ g->totalbytes = tb - debt;
g->GCdebt = debt;
}
@@ -110,6 +111,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
L->ci->next = ci;
ci->previous = L->ci;
ci->next = NULL;
+ L->nci++;
return ci;
}
@@ -124,6 +126,7 @@ void luaE_freeCI (lua_State *L) {
while ((ci = next) != NULL) {
next = ci->next;
luaM_free(L, ci);
+ L->nci--;
}
}
@@ -133,13 +136,14 @@ void luaE_freeCI (lua_State *L) {
*/
void luaE_shrinkCI (lua_State *L) {
CallInfo *ci = L->ci;
- while (ci->next != NULL) { /* while there is 'next' */
- CallInfo *next2 = ci->next->next; /* next's next */
- if (next2 == NULL) break;
- luaM_free(L, ci->next); /* remove next */
+ CallInfo *next2; /* next's next */
+ /* while there are two nexts */
+ while (ci->next != NULL && (next2 = ci->next->next) != NULL) {
+ luaM_free(L, ci->next); /* free next */
+ L->nci--;
ci->next = next2; /* remove 'next' from the list */
next2->previous = ci;
- ci = next2;
+ ci = next2; /* keep next's next */
}
}
@@ -169,6 +173,7 @@ static void freestack (lua_State *L) {
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
+ lua_assert(L->nci == 0);
luaM_freearray(L, L->stack, L->stacksize); /* free stack array */
}
@@ -200,12 +205,9 @@ static void f_luaopen (lua_State *L, void *ud) {
UNUSED(ud);
stack_init(L, L); /* init stack */
init_registry(L, g);
- luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
+ luaS_init(L);
luaT_init(L);
luaX_init(L);
- /* pre-create memory-error message */
- g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
- luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */
g->gcrunning = 1; /* allow gc */
g->version = lua_version(NULL);
luai_userstateopen(L);
@@ -220,6 +222,7 @@ static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
L->stack = NULL;
L->ci = NULL;
+ L->nci = 0;
L->stacksize = 0;
L->twups = L; /* thread has no upvalues */
L->errorJmp = NULL;
@@ -243,7 +246,6 @@ static void close_state (lua_State *L) {
if (g->version) /* closing a fully built state? */
luai_userstateclose(L);
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
- luaZ_freebuffer(L, &g->buff);
freestack(L);
lua_assert(gettotalbytes(g) == sizeof(LG));
(*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */
@@ -312,7 +314,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
- luaZ_initbuffer(L, &g->buff);
g->panic = NULL;
g->version = NULL;
g->gcstate = GCSpause;
diff --git a/src/lstate.h b/src/lstate.h
index 81e12c40db0a..a469466c4475 100644
--- a/src/lstate.h
+++ b/src/lstate.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstate.h,v 2.119 2014/10/30 18:53:28 roberto Exp $
+** $Id: lstate.h,v 2.133 2016/12/22 13:08:50 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -23,7 +23,7 @@
**
** 'allgc': all objects not marked for finalization;
** 'finobj': all objects marked for finalization;
-** 'tobefnz': all objects ready to be finalized;
+** 'tobefnz': all objects ready to be finalized;
** 'fixedgc': all objects that are not to be collected (currently
** only small strings, such as reserved words).
@@ -33,6 +33,15 @@
struct lua_longjmp; /* defined in ldo.c */
+/*
+** Atomic type (relative to signals) to better ensure that 'lua_sethook'
+** is thread safe
+*/
+#if !defined(l_signalT)
+#include <signal.h>
+#define l_signalT sig_atomic_t
+#endif
+
/* extra stack space to handle TM calls and some other extras */
#define EXTRA_STACK 5
@@ -57,7 +66,7 @@ typedef struct stringtable {
** Information about a call.
** When a thread yields, 'func' is adjusted to pretend that the
** top function has only the yielded values in its stack; in that
-** case, the actual 'func' value is saved in field 'extra'.
+** case, the actual 'func' value is saved in field 'extra'.
** When a function calls another with a continuation, 'extra' keeps
** the function index so that, in case of errors, the continuation
** function can be called with the correct top.
@@ -79,7 +88,7 @@ typedef struct CallInfo {
} u;
ptrdiff_t extra;
short nresults; /* expected number of results from this function */
- lu_byte callstatus;
+ unsigned short callstatus;
} CallInfo;
@@ -89,11 +98,13 @@ typedef struct CallInfo {
#define CIST_OAH (1<<0) /* original value of 'allowhook' */
#define CIST_LUA (1<<1) /* call is running a Lua function */
#define CIST_HOOKED (1<<2) /* call is running a debug hook */
-#define CIST_REENTRY (1<<3) /* call is running on same invocation of
- luaV_execute of previous call */
+#define CIST_FRESH (1<<3) /* call is running on a fresh invocation
+ of luaV_execute */
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
#define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
+#define CIST_LEQ (1<<7) /* using __lt for __le */
+#define CIST_FIN (1<<8) /* call is running a finalizer */
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
@@ -108,7 +119,7 @@ typedef struct CallInfo {
typedef struct global_State {
lua_Alloc frealloc; /* function to reallocate memory */
void *ud; /* auxiliary data to 'frealloc' */
- lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
+ l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
lu_mem GCmemtrav; /* memory traversed by the GC */
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
@@ -130,7 +141,6 @@ typedef struct global_State {
GCObject *tobefnz; /* list of userdata to be GC */
GCObject *fixedgc; /* list of objects not to be collected */
struct lua_State *twups; /* list of threads with open upvalues */
- Mbuffer buff; /* temporary buffer for string concatenation */
unsigned int gcfinnum; /* number of finalizers to call in each GC step */
int gcpause; /* size of pause between successive GCs */
int gcstepmul; /* GC 'granularity' */
@@ -140,6 +150,7 @@ typedef struct global_State {
TString *memerrmsg; /* memory-error message */
TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
+ TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
} global_State;
@@ -148,6 +159,7 @@ typedef struct global_State {
*/
struct lua_State {
CommonHeader;
+ unsigned short nci; /* number of items in 'ci' list */
lu_byte status;
StkId top; /* first free slot in the stack */
global_State *l_G;
@@ -160,14 +172,14 @@ struct lua_State {
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
- lua_Hook hook;
+ volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */
int stacksize;
int basehookcount;
int hookcount;
unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */
- lu_byte hookmask;
+ l_signalT hookmask;
lu_byte allowhook;
};
@@ -210,7 +222,7 @@ union GCUnion {
/* actual number of total bytes allocated */
-#define gettotalbytes(g) ((g)->totalbytes + (g)->GCdebt)
+#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt)
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
diff --git a/src/lstring.c b/src/lstring.c
index 2947113c3c9d..9351766fd63b 100644
--- a/src/lstring.c
+++ b/src/lstring.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.c,v 2.45 2014/11/02 19:19:04 roberto Exp $
+** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -22,6 +22,8 @@
#include "lstring.h"
+#define MEMERRMSG "not enough memory"
+
/*
** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
@@ -36,24 +38,33 @@
** equality for long strings
*/
int luaS_eqlngstr (TString *a, TString *b) {
- size_t len = a->len;
+ size_t len = a->u.lnglen;
lua_assert(a->tt == LUA_TLNGSTR && b->tt == LUA_TLNGSTR);
return (a == b) || /* same instance or... */
- ((len == b->len) && /* equal length and ... */
+ ((len == b->u.lnglen) && /* equal length and ... */
(memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
}
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
unsigned int h = seed ^ cast(unsigned int, l);
- size_t l1;
size_t step = (l >> LUAI_HASHLIMIT) + 1;
- for (l1 = l; l1 >= step; l1 -= step)
- h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1]));
+ for (; l >= step; l -= step)
+ h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
return h;
}
+unsigned int luaS_hashlongstr (TString *ts) {
+ lua_assert(ts->tt == LUA_TLNGSTR);
+ if (ts->extra == 0) { /* no hash? */
+ ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash);
+ ts->extra = 1; /* now it has its hash */
+ }
+ return ts->hash;
+}
+
+
/*
** resizes the string table
*/
@@ -69,9 +80,9 @@ void luaS_resize (lua_State *L, int newsize) {
TString *p = tb->hash[i];
tb->hash[i] = NULL;
while (p) { /* for each node in the list */
- TString *hnext = p->hnext; /* save next */
+ TString *hnext = p->u.hnext; /* save next */
unsigned int h = lmod(p->hash, newsize); /* new position */
- p->hnext = tb->hash[h]; /* chain it */
+ p->u.hnext = tb->hash[h]; /* chain it */
tb->hash[h] = p;
p = hnext;
}
@@ -85,23 +96,57 @@ void luaS_resize (lua_State *L, int newsize) {
}
+/*
+** Clear API string cache. (Entries cannot be empty, so fill them with
+** a non-collectable string.)
+*/
+void luaS_clearcache (global_State *g) {
+ int i, j;
+ for (i = 0; i < STRCACHE_N; i++)
+ for (j = 0; j < STRCACHE_M; j++) {
+ if (iswhite(g->strcache[i][j])) /* will entry be collected? */
+ g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */
+ }
+}
+
+
+/*
+** Initialize the string table and the string cache
+*/
+void luaS_init (lua_State *L) {
+ global_State *g = G(L);
+ int i, j;
+ luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
+ /* pre-create memory-error message */
+ g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
+ luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */
+ for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */
+ for (j = 0; j < STRCACHE_M; j++)
+ g->strcache[i][j] = g->memerrmsg;
+}
+
+
/*
** creates a new string object
*/
-static TString *createstrobj (lua_State *L, const char *str, size_t l,
- int tag, unsigned int h) {
+static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
TString *ts;
GCObject *o;
size_t totalsize; /* total size of TString object */
totalsize = sizelstring(l);
o = luaC_newobj(L, tag, totalsize);
ts = gco2ts(o);
- ts->len = l;
ts->hash = h;
ts->extra = 0;
- memcpy(getaddrstr(ts), str, l * sizeof(char));
- getaddrstr(ts)[l] = '\0'; /* ending 0 */
+ getstr(ts)[l] = '\0'; /* ending 0 */
+ return ts;
+}
+
+
+TString *luaS_createlngstrobj (lua_State *L, size_t l) {
+ TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed);
+ ts->u.lnglen = l;
return ts;
}
@@ -110,8 +155,8 @@ void luaS_remove (lua_State *L, TString *ts) {
stringtable *tb = &G(L)->strt;
TString **p = &tb->hash[lmod(ts->hash, tb->size)];
while (*p != ts) /* find previous element */
- p = &(*p)->hnext;
- *p = (*p)->hnext; /* remove element from its list */
+ p = &(*p)->u.hnext;
+ *p = (*p)->u.hnext; /* remove element from its list */
tb->nuse--;
}
@@ -124,8 +169,9 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
global_State *g = G(L);
unsigned int h = luaS_hash(str, l, g->seed);
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
- for (ts = *list; ts != NULL; ts = ts->hnext) {
- if (l == ts->len &&
+ lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
+ for (ts = *list; ts != NULL; ts = ts->u.hnext) {
+ if (l == ts->shrlen &&
(memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
/* found! */
if (isdead(g, ts)) /* dead (but not collected yet)? */
@@ -137,8 +183,10 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
luaS_resize(L, g->strt.size * 2);
list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */
}
- ts = createstrobj(L, str, l, LUA_TSHRSTR, h);
- ts->hnext = *list;
+ ts = createstrobj(L, l, LUA_TSHRSTR, h);
+ memcpy(getstr(ts), str, l * sizeof(char));
+ ts->shrlen = cast_byte(l);
+ ts->u.hnext = *list;
*list = ts;
g->strt.nuse++;
return ts;
@@ -152,18 +200,36 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
if (l <= LUAI_MAXSHORTLEN) /* short string? */
return internshrstr(L, str, l);
else {
- if (l + 1 > (MAX_SIZE - sizeof(TString))/sizeof(char))
+ TString *ts;
+ if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char))
luaM_toobig(L);
- return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed);
+ ts = luaS_createlngstrobj(L, l);
+ memcpy(getstr(ts), str, l * sizeof(char));
+ return ts;
}
}
/*
-** new zero-terminated string
+** Create or reuse a zero-terminated string, first checking in the
+** cache (using the string address as a key). The cache can contain
+** only zero-terminated strings, so it is safe to use 'strcmp' to
+** check hits.
*/
TString *luaS_new (lua_State *L, const char *str) {
- return luaS_newlstr(L, str, strlen(str));
+ unsigned int i = point2uint(str) % STRCACHE_N; /* hash */
+ int j;
+ TString **p = G(L)->strcache[i];
+ for (j = 0; j < STRCACHE_M; j++) {
+ if (strcmp(str, getstr(p[j])) == 0) /* hit? */
+ return p[j]; /* that is it */
+ }
+ /* normal route */
+ for (j = STRCACHE_M - 1; j > 0; j--)
+ p[j] = p[j - 1]; /* move out last element */
+ /* new element is first in the list */
+ p[0] = luaS_newlstr(L, str, strlen(str));
+ return p[0];
}
diff --git a/src/lstring.h b/src/lstring.h
index d3f04caf7289..27efd2077269 100644
--- a/src/lstring.h
+++ b/src/lstring.h
@@ -1,5 +1,5 @@
/*
-** $Id: lstring.h,v 1.56 2014/07/18 14:46:47 roberto Exp $
+** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -13,7 +13,6 @@
#define sizelstring(l) (sizeof(union UTString) + ((l) + 1) * sizeof(char))
-#define sizestring(s) sizelstring((s)->len)
#define sizeludata(l) (sizeof(union UUdata) + (l))
#define sizeudata(u) sizeludata((u)->len)
@@ -35,12 +34,16 @@
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
+LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
+LUAI_FUNC void luaS_clearcache (global_State *g);
+LUAI_FUNC void luaS_init (lua_State *L);
LUAI_FUNC void luaS_remove (lua_State *L, TString *ts);
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s);
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
+LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
#endif
diff --git a/src/lstrlib.c b/src/lstrlib.c
index a650b768d574..c7aa755fabd2 100644
--- a/src/lstrlib.c
+++ b/src/lstrlib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lstrlib.c,v 1.221 2014/12/11 14:03:07 roberto Exp $
+** $Id: lstrlib.c,v 1.254 2016/12/22 13:08:50 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -11,7 +11,9 @@
#include <ctype.h>
+#include <float.h>
#include <limits.h>
+#include <locale.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -25,7 +27,8 @@
/*
** maximum number of captures that a pattern can do during
-** pattern-matching. This limit is arbitrary.
+** pattern-matching. This limit is arbitrary, but must fit in
+** an unsigned char.
*/
#if !defined(LUA_MAXCAPTURES)
#define LUA_MAXCAPTURES 32
@@ -40,8 +43,10 @@
** Some sizes are better limited to fit in 'int', but must also fit in
** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
*/
+#define MAX_SIZET ((size_t)(~(size_t)0))
+
#define MAXSIZE \
- (sizeof(size_t) < sizeof(int) ? (~(size_t)0) : (size_t)(INT_MAX))
+ (sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))
@@ -70,7 +75,7 @@ static int str_sub (lua_State *L) {
if (start < 1) start = 1;
if (end > (lua_Integer)l) end = l;
if (start <= end)
- lua_pushlstring(L, s + start - 1, (size_t)(end - start + 1));
+ lua_pushlstring(L, s + start - 1, (size_t)(end - start) + 1);
else lua_pushliteral(L, "");
return 1;
}
@@ -149,9 +154,9 @@ static int str_byte (lua_State *L) {
if (posi < 1) posi = 1;
if (pose > (lua_Integer)l) pose = l;
if (posi > pose) return 0; /* empty interval; return no values */
- n = (int)(pose - posi + 1);
- if (posi + n <= pose) /* arithmetic overflow? */
+ if (pose - posi >= INT_MAX) /* arithmetic overflow? */
return luaL_error(L, "string slice too long");
+ n = (int)(pose - posi) + 1;
luaL_checkstack(L, n, "string slice too long");
for (i=0; i<n; i++)
lua_pushinteger(L, uchar(s[posi+i-1]));
@@ -207,12 +212,12 @@ static int str_dump (lua_State *L) {
typedef struct MatchState {
- int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
const char *src_init; /* init of source string */
const char *src_end; /* end ('\0') of source string */
const char *p_end; /* end ('\0') of pattern */
lua_State *L;
- int level; /* total number of captures (finished or unfinished) */
+ int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
+ unsigned char level; /* total number of captures (finished or unfinished) */
struct {
const char *init;
ptrdiff_t len;
@@ -499,7 +504,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) {
}
case '+': /* 1 or more repetitions */
s++; /* 1 match already done */
- /* go through */
+ /* FALLTHROUGH */
case '*': /* 0 or more repetitions */
s = max_expand(ms, s, p, ep);
break;
@@ -554,7 +559,7 @@ static void push_onecapture (MatchState *ms, int i, const char *s,
ptrdiff_t l = ms->capture[i].len;
if (l == CAP_UNFINISHED) luaL_error(ms->L, "unfinished capture");
if (l == CAP_POSITION)
- lua_pushinteger(ms->L, ms->capture[i].init - ms->src_init + 1);
+ lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1);
else
lua_pushlstring(ms->L, ms->capture[i].init, l);
}
@@ -583,6 +588,22 @@ static int nospecials (const char *p, size_t l) {
}
+static void prepstate (MatchState *ms, lua_State *L,
+ const char *s, size_t ls, const char *p, size_t lp) {
+ ms->L = L;
+ ms->matchdepth = MAXCCALLS;
+ ms->src_init = s;
+ ms->src_end = s + ls;
+ ms->p_end = p + lp;
+}
+
+
+static void reprepstate (MatchState *ms) {
+ ms->level = 0;
+ lua_assert(ms->matchdepth == MAXCCALLS);
+}
+
+
static int str_find_aux (lua_State *L, int find) {
size_t ls, lp;
const char *s = luaL_checklstring(L, 1, &ls);
@@ -598,8 +619,8 @@ static int str_find_aux (lua_State *L, int find) {
/* do a plain search */
const char *s2 = lmemfind(s + init - 1, ls - (size_t)init + 1, p, lp);
if (s2) {
- lua_pushinteger(L, s2 - s + 1);
- lua_pushinteger(L, s2 - s + lp);
+ lua_pushinteger(L, (s2 - s) + 1);
+ lua_pushinteger(L, (s2 - s) + lp);
return 2;
}
}
@@ -610,18 +631,13 @@ static int str_find_aux (lua_State *L, int find) {
if (anchor) {
p++; lp--; /* skip anchor character */
}
- ms.L = L;
- ms.matchdepth = MAXCCALLS;
- ms.src_init = s;
- ms.src_end = s + ls;
- ms.p_end = p + lp;
+ prepstate(&ms, L, s, ls, p, lp);
do {
const char *res;
- ms.level = 0;
- lua_assert(ms.matchdepth == MAXCCALLS);
+ reprepstate(&ms);
if ((res=match(&ms, s1, p)) != NULL) {
if (find) {
- lua_pushinteger(L, s1 - s + 1); /* start */
+ lua_pushinteger(L, (s1 - s) + 1); /* start */
lua_pushinteger(L, res - s); /* end */
return push_captures(&ms, NULL, 0) + 2;
}
@@ -645,29 +661,25 @@ static int str_match (lua_State *L) {
}
+/* state for 'gmatch' */
+typedef struct GMatchState {
+ const char *src; /* current position */
+ const char *p; /* pattern */
+ const char *lastmatch; /* end of last match */
+ MatchState ms; /* match state */
+} GMatchState;
+
+
static int gmatch_aux (lua_State *L) {
- MatchState ms;
- size_t ls, lp;
- const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
- const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp);
+ GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
const char *src;
- ms.L = L;
- ms.matchdepth = MAXCCALLS;
- ms.src_init = s;
- ms.src_end = s+ls;
- ms.p_end = p + lp;
- for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
- src <= ms.src_end;
- src++) {
+ gm->ms.L = L;
+ for (src = gm->src; src <= gm->ms.src_end; src++) {
const char *e;
- ms.level = 0;
- lua_assert(ms.matchdepth == MAXCCALLS);
- if ((e = match(&ms, src, p)) != NULL) {
- lua_Integer newstart = e-s;
- if (e == src) newstart++; /* empty match? go at least one position */
- lua_pushinteger(L, newstart);
- lua_replace(L, lua_upvalueindex(3));
- return push_captures(&ms, src, e);
+ reprepstate(&gm->ms);
+ if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
+ gm->src = gm->lastmatch = e;
+ return push_captures(&gm->ms, src, e);
}
}
return 0; /* not found */
@@ -675,10 +687,14 @@ static int gmatch_aux (lua_State *L) {
static int gmatch (lua_State *L) {
- luaL_checkstring(L, 1);
- luaL_checkstring(L, 2);
- lua_settop(L, 2);
- lua_pushinteger(L, 0);
+ size_t ls, lp;
+ const char *s = luaL_checklstring(L, 1, &ls);
+ const char *p = luaL_checklstring(L, 2, &lp);
+ GMatchState *gm;
+ lua_settop(L, 2); /* keep them on closure to avoid being collected */
+ gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState));
+ prepstate(&gm->ms, L, s, ls, p, lp);
+ gm->src = s; gm->p = p; gm->lastmatch = NULL;
lua_pushcclosure(L, gmatch_aux, 3);
return 1;
}
@@ -745,12 +761,13 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
static int str_gsub (lua_State *L) {
size_t srcl, lp;
- const char *src = luaL_checklstring(L, 1, &srcl);
- const char *p = luaL_checklstring(L, 2, &lp);
- int tr = lua_type(L, 3);
- lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);
+ const char *src = luaL_checklstring(L, 1, &srcl); /* subject */
+ const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
+ const char *lastmatch = NULL; /* end of last match */
+ int tr = lua_type(L, 3); /* replacement type */
+ lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
int anchor = (*p == '^');
- lua_Integer n = 0;
+ lua_Integer n = 0; /* replacement count */
MatchState ms;
luaL_Buffer b;
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
@@ -760,25 +777,18 @@ static int str_gsub (lua_State *L) {
if (anchor) {
p++; lp--; /* skip anchor character */
}
- ms.L = L;
- ms.matchdepth = MAXCCALLS;
- ms.src_init = src;
- ms.src_end = src+srcl;
- ms.p_end = p + lp;
+ prepstate(&ms, L, src, srcl, p, lp);
while (n < max_s) {
const char *e;
- ms.level = 0;
- lua_assert(ms.matchdepth == MAXCCALLS);
- e = match(&ms, src, p);
- if (e) {
+ reprepstate(&ms); /* (re)prepare state for new match */
+ if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
n++;
- add_value(&ms, &b, src, e, tr);
+ add_value(&ms, &b, src, e, tr); /* add replacement to buffer */
+ src = lastmatch = e;
}
- if (e && e>src) /* non empty match? */
- src = e; /* skip it */
- else if (src < ms.src_end)
+ else if (src < ms.src_end) /* otherwise, skip one character */
luaL_addchar(&b, *src++);
- else break;
+ else break; /* end of subject */
if (anchor) break;
}
luaL_addlstring(&b, src, ms.src_end-src);
@@ -797,34 +807,117 @@ static int str_gsub (lua_State *L) {
** =======================================================
*/
-/* maximum size of each formatted item (> len(format('%99.99f', -1e308))) */
-#define MAX_ITEM 512
+#if !defined(lua_number2strx) /* { */
+
+/*
+** Hexadecimal floating-point formatter
+*/
+
+#include <math.h>
+
+#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
+
+
+/*
+** Number of bits that goes into the first digit. It can be any value
+** between 1 and 4; the following definition tries to align the number
+** to nibble boundaries by making what is left after that first digit a
+** multiple of 4.
+*/
+#define L_NBFD ((l_mathlim(MANT_DIG) - 1)%4 + 1)
+
+
+/*
+** Add integer part of 'x' to buffer and return new 'x'
+*/
+static lua_Number adddigit (char *buff, int n, lua_Number x) {
+ lua_Number dd = l_mathop(floor)(x); /* get integer part from 'x' */
+ int d = (int)dd;
+ buff[n] = (d < 10 ? d + '0' : d - 10 + 'a'); /* add to buffer */
+ return x - dd; /* return what is left */
+}
+
+
+static int num2straux (char *buff, int sz, lua_Number x) {
+ /* if 'inf' or 'NaN', format it like '%g' */
+ if (x != x || x == (lua_Number)HUGE_VAL || x == -(lua_Number)HUGE_VAL)
+ return l_sprintf(buff, sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)x);
+ else if (x == 0) { /* can be -0... */
+ /* create "0" or "-0" followed by exponent */
+ return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", (LUAI_UACNUMBER)x);
+ }
+ else {
+ int e;
+ lua_Number m = l_mathop(frexp)(x, &e); /* 'x' fraction and exponent */
+ int n = 0; /* character count */
+ if (m < 0) { /* is number negative? */
+ buff[n++] = '-'; /* add signal */
+ m = -m; /* make it positive */
+ }
+ buff[n++] = '0'; buff[n++] = 'x'; /* add "0x" */
+ m = adddigit(buff, n++, m * (1 << L_NBFD)); /* add first digit */
+ e -= L_NBFD; /* this digit goes before the radix point */
+ if (m > 0) { /* more digits? */
+ buff[n++] = lua_getlocaledecpoint(); /* add radix point */
+ do { /* add as many digits as needed */
+ m = adddigit(buff, n++, m * 16);
+ } while (m > 0);
+ }
+ n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */
+ lua_assert(n < sz);
+ return n;
+ }
+}
+
+
+static int lua_number2strx (lua_State *L, char *buff, int sz,
+ const char *fmt, lua_Number x) {
+ int n = num2straux(buff, sz, x);
+ if (fmt[SIZELENMOD] == 'A') {
+ int i;
+ for (i = 0; i < n; i++)
+ buff[i] = toupper(uchar(buff[i]));
+ }
+ else if (fmt[SIZELENMOD] != 'a')
+ luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented");
+ return n;
+}
+
+#endif /* } */
+
+
+/*
+** Maximum size of each formatted item. This maximum size is produced
+** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.',
+** and '\0') + number of decimal digits to represent maxfloat (which
+** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra
+** expenses", such as locale-dependent stuff)
+*/
+#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP))
+
/* valid flags in a format specification */
#define FLAGS "-+ #0"
/*
** maximum size of each format specification (such as "%-099.99d")
-** (+2 for length modifiers; +10 accounts for %99.99x plus margin of error)
*/
-#define MAX_FORMAT (sizeof(FLAGS) + 2 + 10)
+#define MAX_FORMAT 32
-static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
- size_t l;
- const char *s = luaL_checklstring(L, arg, &l);
+static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
luaL_addchar(b, '"');
- while (l--) {
+ while (len--) {
if (*s == '"' || *s == '\\' || *s == '\n') {
luaL_addchar(b, '\\');
luaL_addchar(b, *s);
}
- else if (*s == '\0' || iscntrl(uchar(*s))) {
+ else if (iscntrl(uchar(*s))) {
char buff[10];
if (!isdigit(uchar(*(s+1))))
- sprintf(buff, "\\%d", (int)uchar(*s));
+ l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
else
- sprintf(buff, "\\%03d", (int)uchar(*s));
+ l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s));
luaL_addstring(b, buff);
}
else
@@ -834,6 +927,57 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
luaL_addchar(b, '"');
}
+
+/*
+** Ensures the 'buff' string uses a dot as the radix character.
+*/
+static void checkdp (char *buff, int nb) {
+ if (memchr(buff, '.', nb) == NULL) { /* no dot? */
+ char point = lua_getlocaledecpoint(); /* try locale point */
+ char *ppoint = (char *)memchr(buff, point, nb);
+ if (ppoint) *ppoint = '.'; /* change it to a dot */
+ }
+}
+
+
+static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
+ switch (lua_type(L, arg)) {
+ case LUA_TSTRING: {
+ size_t len;
+ const char *s = lua_tolstring(L, arg, &len);
+ addquoted(b, s, len);
+ break;
+ }
+ case LUA_TNUMBER: {
+ char *buff = luaL_prepbuffsize(b, MAX_ITEM);
+ int nb;
+ if (!lua_isinteger(L, arg)) { /* float? */
+ lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */
+ nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n);
+ checkdp(buff, nb); /* ensure it uses a dot */
+ }
+ else { /* integers */
+ lua_Integer n = lua_tointeger(L, arg);
+ const char *format = (n == LUA_MININTEGER) /* corner case? */
+ ? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */
+ : LUA_INTEGER_FMT; /* else use default format */
+ nb = l_sprintf(buff, MAX_ITEM, format, (LUAI_UACINT)n);
+ }
+ luaL_addsize(b, nb);
+ break;
+ }
+ case LUA_TNIL: case LUA_TBOOLEAN: {
+ luaL_tolstring(L, arg, NULL);
+ luaL_addvalue(b);
+ break;
+ }
+ default: {
+ luaL_argerror(L, arg, "value has no literal form");
+ }
+ }
+}
+
+
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
const char *p = strfrmt;
while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
@@ -849,8 +993,8 @@ static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
if (isdigit(uchar(*p)))
luaL_error(L, "invalid format (width or precision too long)");
*(form++) = '%';
- memcpy(form, strfrmt, (p - strfrmt + 1) * sizeof(char));
- form += p - strfrmt + 1;
+ memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char));
+ form += (p - strfrmt) + 1;
*form = '\0';
return p;
}
@@ -891,49 +1035,56 @@ static int str_format (lua_State *L) {
strfrmt = scanformat(L, strfrmt, form);
switch (*strfrmt++) {
case 'c': {
- nb = sprintf(buff, form, (int)luaL_checkinteger(L, arg));
+ nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg));
break;
}
case 'd': case 'i':
case 'o': case 'u': case 'x': case 'X': {
lua_Integer n = luaL_checkinteger(L, arg);
addlenmod(form, LUA_INTEGER_FRMLEN);
- nb = sprintf(buff, form, n);
+ nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n);
break;
}
-#if defined(LUA_USE_AFORMAT)
case 'a': case 'A':
-#endif
+ addlenmod(form, LUA_NUMBER_FRMLEN);
+ nb = lua_number2strx(L, buff, MAX_ITEM, form,
+ luaL_checknumber(L, arg));
+ break;
case 'e': case 'E': case 'f':
case 'g': case 'G': {
+ lua_Number n = luaL_checknumber(L, arg);
addlenmod(form, LUA_NUMBER_FRMLEN);
- nb = sprintf(buff, form, luaL_checknumber(L, arg));
+ nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n);
break;
}
case 'q': {
- addquoted(L, &b, arg);
+ addliteral(L, &b, arg);
break;
}
case 's': {
size_t l;
const char *s = luaL_tolstring(L, arg, &l);
- if (!strchr(form, '.') && l >= 100) {
- /* no precision and string is too long to be formatted;
- keep original string */
- luaL_addvalue(&b);
- break;
- }
+ if (form[2] == '\0') /* no modifiers? */
+ luaL_addvalue(&b); /* keep entire string */
else {
- nb = sprintf(buff, form, s);
- lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
- break;
+ luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
+ if (!strchr(form, '.') && l >= 100) {
+ /* no precision and string is too long to be formatted */
+ luaL_addvalue(&b); /* keep entire string */
+ }
+ else { /* format the string into 'buff' */
+ nb = l_sprintf(buff, MAX_ITEM, form, s);
+ lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
+ }
}
+ break;
}
default: { /* also treat cases 'pnLlh' */
return luaL_error(L, "invalid option '%%%c' to 'format'",
*(strfrmt - 1));
}
}
+ lua_assert(nb < MAX_ITEM);
luaL_addsize(&b, nb);
}
}
@@ -952,8 +1103,8 @@ static int str_format (lua_State *L) {
/* value used for padding */
-#if !defined(LUA_PACKPADBYTE)
-#define LUA_PACKPADBYTE 0x00
+#if !defined(LUAL_PACKPADBYTE)
+#define LUAL_PACKPADBYTE 0x00
#endif
/* maximum size for the binary representation of an integer */
@@ -1110,7 +1261,7 @@ static KOption getoption (Header *h, const char **fmt, int *size) {
** 'psize' is filled with option's size, 'notoalign' with its
** alignment requirements.
** Local variable 'size' gets the size to be aligned. (Kpadal option
-** always gets its full alignment, other options are limited by
+** always gets its full alignment, other options are limited by
** the maximum alignment ('maxalign'). Kchar option needs no alignment
** despite its size.
*/
@@ -1190,7 +1341,7 @@ static int str_pack (lua_State *L) {
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
totalsize += ntoalign + size;
while (ntoalign-- > 0)
- luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */
+ luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
arg++;
switch (opt) {
case Kint: { /* signed integers */
@@ -1225,8 +1376,11 @@ static int str_pack (lua_State *L) {
case Kchar: { /* fixed-size string */
size_t len;
const char *s = luaL_checklstring(L, arg, &len);
- luaL_argcheck(L, len == (size_t)size, arg, "wrong length");
- luaL_addlstring(&b, s, size);
+ luaL_argcheck(L, len <= (size_t)size, arg,
+ "string longer than given size");
+ luaL_addlstring(&b, s, len); /* add string */
+ while (len++ < (size_t)size) /* pad extra space */
+ luaL_addchar(&b, LUAL_PACKPADBYTE);
break;
}
case Kstring: { /* strings with length count */
@@ -1249,7 +1403,7 @@ static int str_pack (lua_State *L) {
totalsize += len + 1;
break;
}
- case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* go through */
+ case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */
case Kpaddalign: case Knop:
arg--; /* undo increment */
break;
@@ -1276,7 +1430,7 @@ static int str_packsize (lua_State *L) {
case Kstring: /* strings with length count */
case Kzstr: /* zero-terminated string */
luaL_argerror(L, 1, "variable-length format");
- break;
+ /* call never return, but to avoid warnings: *//* FALLTHROUGH */
default: break;
}
}
diff --git a/src/ltable.c b/src/ltable.c
index 38be00513dc8..d080189f28d0 100644
--- a/src/ltable.c
+++ b/src/ltable.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.c,v 2.100 2015/01/05 13:52:37 roberto Exp $
+** $Id: ltable.c,v 2.118 2016/11/07 12:38:35 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -14,8 +14,8 @@
** Implementation of tables (aka arrays, objects, or hash tables).
** Tables keep its elements in two parts: an array part and a hash part.
** Non-negative integer keys are all candidates to be kept in the array
-** part. The actual size of the array is the largest 'n' such that at
-** least half the slots between 0 and n are in use.
+** part. The actual size of the array is the largest 'n' such that
+** more than half the slots between 1 and n are in use.
** Hash uses a mix of chained scatter table with Brent's variation.
** A main invariant of these tables is that, if an element is not
** in its main position (i.e. the 'original' position that its hash gives
@@ -23,9 +23,7 @@
** Hence even when the load factor reaches 100%, performance remains good.
*/
-#include <float.h>
#include <math.h>
-#include <string.h>
#include <limits.h>
#include "lua.h"
@@ -71,13 +69,11 @@
#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1))))
-#define hashpointer(t,p) hashmod(t, point2int(p))
+#define hashpointer(t,p) hashmod(t, point2uint(p))
#define dummynode (&dummynode_)
-#define isdummy(n) ((n) == dummynode)
-
static const Node dummynode_ = {
{NILCONSTANT}, /* value */
{{NILCONSTANT, 0}} /* key */
@@ -85,31 +81,33 @@ static const Node dummynode_ = {
/*
-** Checks whether a float has a value representable as a lua_Integer
-** (and does the conversion if so)
-*/
-static int numisinteger (lua_Number x, lua_Integer *p) {
- if ((x) == l_floor(x)) /* integral value? */
- return lua_numbertointeger(x, p); /* try as an integer */
- else return 0;
-}
-
-
-/*
-** hash for floating-point numbers
+** Hash for floating-point numbers.
+** The main computation should be just
+** n = frexp(n, &i); return (n * INT_MAX) + i
+** but there are some numerical subtleties.
+** In a two-complement representation, INT_MAX does not has an exact
+** representation as a float, but INT_MIN does; because the absolute
+** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the
+** absolute value of the product 'frexp * -INT_MIN' is smaller or equal
+** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when
+** adding 'i'; the use of '~u' (instead of '-u') avoids problems with
+** INT_MIN.
*/
-static Node *hashfloat (const Table *t, lua_Number n) {
+#if !defined(l_hashfloat)
+static int l_hashfloat (lua_Number n) {
int i;
- n = l_mathop(frexp)(n, &i) * cast_num(INT_MAX - DBL_MAX_EXP);
- i += cast_int(n);
- if (i < 0) {
- if (cast(unsigned int, i) == 0u - i) /* use unsigned to avoid overflows */
- i = 0; /* handle INT_MIN */
- i = -i; /* must be a positive value */
+ lua_Integer ni;
+ n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN);
+ if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */
+ lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL));
+ return 0;
+ }
+ else { /* normal case */
+ unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni);
+ return cast_int(u <= cast(unsigned int, INT_MAX) ? u : ~u);
}
- return hashmod(t, i);
}
-
+#endif
/*
@@ -121,17 +119,11 @@ static Node *mainposition (const Table *t, const TValue *key) {
case LUA_TNUMINT:
return hashint(t, ivalue(key));
case LUA_TNUMFLT:
- return hashfloat(t, fltvalue(key));
+ return hashmod(t, l_hashfloat(fltvalue(key)));
case LUA_TSHRSTR:
return hashstr(t, tsvalue(key));
- case LUA_TLNGSTR: {
- TString *s = tsvalue(key);
- if (s->extra == 0) { /* no hash? */
- s->hash = luaS_hash(getstr(s), s->len, s->hash);
- s->extra = 1; /* now it has its hash */
- }
- return hashstr(t, tsvalue(key));
- }
+ case LUA_TLNGSTR:
+ return hashpow2(t, luaS_hashlongstr(tsvalue(key)));
case LUA_TBOOLEAN:
return hashboolean(t, bvalue(key));
case LUA_TLIGHTUSERDATA:
@@ -139,6 +131,7 @@ static Node *mainposition (const Table *t, const TValue *key) {
case LUA_TLCF:
return hashpointer(t, fvalue(key));
default:
+ lua_assert(!ttisdeadkey(key));
return hashpointer(t, gcvalue(key));
}
}
@@ -219,28 +212,29 @@ int luaH_next (lua_State *L, Table *t, StkId key) {
/*
** Compute the optimal size for the array part of table 't'. 'nums' is a
** "count array" where 'nums[i]' is the number of integers in the table
-** between 2^(i - 1) + 1 and 2^i. Put in '*narray' the optimal size, and
-** return the number of elements that will go to that part.
+** between 2^(i - 1) + 1 and 2^i. 'pna' enters with the total number of
+** integer keys in the table and leaves with the number of keys that
+** will go to the array part; return the optimal size.
*/
-static unsigned int computesizes (unsigned int nums[], unsigned int *narray) {
+static unsigned int computesizes (unsigned int nums[], unsigned int *pna) {
int i;
- unsigned int twotoi; /* 2^i */
+ unsigned int twotoi; /* 2^i (candidate for optimal size) */
unsigned int a = 0; /* number of elements smaller than 2^i */
unsigned int na = 0; /* number of elements to go to array part */
- unsigned int n = 0; /* optimal size for array part */
- for (i = 0, twotoi = 1; twotoi/2 < *narray; i++, twotoi *= 2) {
+ unsigned int optimal = 0; /* optimal size for array part */
+ /* loop while keys can fill more than half of total size */
+ for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) {
if (nums[i] > 0) {
a += nums[i];
if (a > twotoi/2) { /* more than half elements present? */
- n = twotoi; /* optimal size (till now) */
- na = a; /* all elements up to 'n' will go to array part */
+ optimal = twotoi; /* optimal size (till now) */
+ na = a; /* all elements up to 'optimal' will go to array part */
}
}
- if (a == *narray) break; /* all elements already counted */
}
- *narray = n;
- lua_assert(*narray/2 <= na && na <= *narray);
- return na;
+ lua_assert((optimal == 0 || optimal / 2 < na) && na <= optimal);
+ *pna = na;
+ return optimal;
}
@@ -255,6 +249,11 @@ static int countint (const TValue *key, unsigned int *nums) {
}
+/*
+** Count keys in array part of table 't': Fill 'nums[i]' with
+** number of keys that will go into corresponding slice and return
+** total number of non-nil keys.
+*/
static unsigned int numusearray (const Table *t, unsigned int *nums) {
int lg;
unsigned int ttlg; /* 2^lg */
@@ -281,8 +280,7 @@ static unsigned int numusearray (const Table *t, unsigned int *nums) {
}
-static int numusehash (const Table *t, unsigned int *nums,
- unsigned int *pnasize) {
+static int numusehash (const Table *t, unsigned int *nums, unsigned int *pna) {
int totaluse = 0; /* total number of elements */
int ause = 0; /* elements added to 'nums' (can go to array part) */
int i = sizenode(t);
@@ -293,7 +291,7 @@ static int numusehash (const Table *t, unsigned int *nums,
totaluse++;
}
}
- *pnasize += ause;
+ *pna += ause;
return totaluse;
}
@@ -308,14 +306,14 @@ static void setarrayvector (lua_State *L, Table *t, unsigned int size) {
static void setnodevector (lua_State *L, Table *t, unsigned int size) {
- int lsize;
if (size == 0) { /* no elements to hash part? */
t->node = cast(Node *, dummynode); /* use common 'dummynode' */
- lsize = 0;
+ t->lsizenode = 0;
+ t->lastfree = NULL; /* signal that it is using dummy node */
}
else {
int i;
- lsize = luaO_ceillog2(size);
+ int lsize = luaO_ceillog2(size);
if (lsize > MAXHBITS)
luaG_runerror(L, "table overflow");
size = twoto(lsize);
@@ -326,9 +324,9 @@ static void setnodevector (lua_State *L, Table *t, unsigned int size) {
setnilvalue(wgkey(n));
setnilvalue(gval(n));
}
+ t->lsizenode = cast_byte(lsize);
+ t->lastfree = gnode(t, size); /* all positions are free */
}
- t->lsizenode = cast_byte(lsize);
- t->lastfree = gnode(t, size); /* all positions are free */
}
@@ -337,7 +335,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
unsigned int i;
int j;
unsigned int oldasize = t->sizearray;
- int oldhsize = t->lsizenode;
+ int oldhsize = allocsizenode(t);
Node *nold = t->node; /* save old hash ... */
if (nasize > oldasize) /* array part must grow? */
setarrayvector(L, t, nasize);
@@ -354,7 +352,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
luaM_reallocvector(L, t->array, oldasize, nasize, TValue);
}
/* re-insert elements from hash part */
- for (j = twoto(oldhsize) - 1; j >= 0; j--) {
+ for (j = oldhsize - 1; j >= 0; j--) {
Node *old = nold + j;
if (!ttisnil(gval(old))) {
/* doesn't need barrier/invalidate cache, as entry was
@@ -362,13 +360,13 @@ void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
setobjt2t(L, luaH_set(L, t, gkey(old)), gval(old));
}
}
- if (!isdummy(nold))
- luaM_freearray(L, nold, cast(size_t, twoto(oldhsize))); /* free old array */
+ if (oldhsize > 0) /* not the dummy node? */
+ luaM_freearray(L, nold, cast(size_t, oldhsize)); /* free old hash */
}
void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
- int nsize = isdummy(t->node) ? 0 : sizenode(t);
+ int nsize = allocsizenode(t);
luaH_resize(L, t, nasize, nsize);
}
@@ -376,21 +374,22 @@ void luaH_resizearray (lua_State *L, Table *t, unsigned int nasize) {
** nums[i] = number of keys 'k' where 2^(i - 1) < k <= 2^i
*/
static void rehash (lua_State *L, Table *t, const TValue *ek) {
- unsigned int nasize, na;
+ unsigned int asize; /* optimal size for array part */
+ unsigned int na; /* number of keys in the array part */
unsigned int nums[MAXABITS + 1];
int i;
int totaluse;
for (i = 0; i <= MAXABITS; i++) nums[i] = 0; /* reset counts */
- nasize = numusearray(t, nums); /* count keys in array part */
- totaluse = nasize; /* all those keys are integer keys */
- totaluse += numusehash(t, nums, &nasize); /* count keys in hash part */
+ na = numusearray(t, nums); /* count keys in array part */
+ totaluse = na; /* all those keys are integer keys */
+ totaluse += numusehash(t, nums, &na); /* count keys in hash part */
/* count extra key */
- nasize += countint(ek, nums);
+ na += countint(ek, nums);
totaluse++;
/* compute new size for array part */
- na = computesizes(nums, &nasize);
+ asize = computesizes(nums, &na);
/* resize the table to new computed sizes */
- luaH_resize(L, t, nasize, totaluse - na);
+ luaH_resize(L, t, asize, totaluse - na);
}
@@ -413,7 +412,7 @@ Table *luaH_new (lua_State *L) {
void luaH_free (lua_State *L, Table *t) {
- if (!isdummy(t->node))
+ if (!isdummy(t))
luaM_freearray(L, t->node, cast(size_t, sizenode(t)));
luaM_freearray(L, t->array, t->sizearray);
luaM_free(L, t);
@@ -421,10 +420,12 @@ void luaH_free (lua_State *L, Table *t) {
static Node *getfreepos (Table *t) {
- while (t->lastfree > t->node) {
- t->lastfree--;
- if (ttisnil(gkey(t->lastfree)))
- return t->lastfree;
+ if (!isdummy(t)) {
+ while (t->lastfree > t->node) {
+ t->lastfree--;
+ if (ttisnil(gkey(t->lastfree)))
+ return t->lastfree;
+ }
}
return NULL; /* could not find a free place */
}
@@ -443,25 +444,24 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
TValue aux;
if (ttisnil(key)) luaG_runerror(L, "table index is nil");
else if (ttisfloat(key)) {
- lua_Number n = fltvalue(key);
lua_Integer k;
- if (luai_numisnan(n))
- luaG_runerror(L, "table index is NaN");
- if (numisinteger(n, &k)) { /* index is int? */
+ if (luaV_tointeger(key, &k, 0)) { /* does index fit in an integer? */
setivalue(&aux, k);
key = &aux; /* insert it as an integer */
}
+ else if (luai_numisnan(fltvalue(key)))
+ luaG_runerror(L, "table index is NaN");
}
mp = mainposition(t, key);
- if (!ttisnil(gval(mp)) || isdummy(mp)) { /* main position is taken? */
+ if (!ttisnil(gval(mp)) || isdummy(t)) { /* main position is taken? */
Node *othern;
Node *f = getfreepos(t); /* get a free place */
if (f == NULL) { /* cannot find a free place? */
rehash(L, t, key); /* grow table */
- /* whatever called 'newkey' takes care of TM cache and GC barrier */
+ /* whatever called 'newkey' takes care of TM cache */
return luaH_set(L, t, key); /* insert key into grown table */
}
- lua_assert(!isdummy(f));
+ lua_assert(!isdummy(t));
othern = mainposition(t, gkey(mp));
if (othern != mp) { /* is colliding node out of its main position? */
/* yes; move colliding node into free position */
@@ -496,7 +496,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
*/
const TValue *luaH_getint (Table *t, lua_Integer key) {
/* (1 <= key && key <= t->sizearray) */
- if (l_castS2U(key - 1) < t->sizearray)
+ if (l_castS2U(key) - 1 < t->sizearray)
return &t->array[key - 1];
else {
Node *n = hashint(t, key);
@@ -508,7 +508,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
if (nx == 0) break;
n += nx;
}
- };
+ }
return luaO_nilobject;
}
}
@@ -517,7 +517,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
/*
** search function for short strings
*/
-const TValue *luaH_getstr (Table *t, TString *key) {
+const TValue *luaH_getshortstr (Table *t, TString *key) {
Node *n = hashstr(t, key);
lua_assert(key->tt == LUA_TSHRSTR);
for (;;) { /* check whether 'key' is somewhere in the chain */
@@ -526,11 +526,41 @@ const TValue *luaH_getstr (Table *t, TString *key) {
return gval(n); /* that's it */
else {
int nx = gnext(n);
- if (nx == 0) break;
+ if (nx == 0)
+ return luaO_nilobject; /* not found */
n += nx;
}
- };
- return luaO_nilobject;
+ }
+}
+
+
+/*
+** "Generic" get version. (Not that generic: not valid for integers,
+** which may be in array part, nor for floats with integral values.)
+*/
+static const TValue *getgeneric (Table *t, const TValue *key) {
+ Node *n = mainposition(t, key);
+ for (;;) { /* check whether 'key' is somewhere in the chain */
+ if (luaV_rawequalobj(gkey(n), key))
+ return gval(n); /* that's it */
+ else {
+ int nx = gnext(n);
+ if (nx == 0)
+ return luaO_nilobject; /* not found */
+ n += nx;
+ }
+ }
+}
+
+
+const TValue *luaH_getstr (Table *t, TString *key) {
+ if (key->tt == LUA_TSHRSTR)
+ return luaH_getshortstr(t, key);
+ else { /* for long strings, use generic case */
+ TValue ko;
+ setsvalue(cast(lua_State *, NULL), &ko, key);
+ return getgeneric(t, &ko);
+ }
}
@@ -539,28 +569,17 @@ const TValue *luaH_getstr (Table *t, TString *key) {
*/
const TValue *luaH_get (Table *t, const TValue *key) {
switch (ttype(key)) {
- case LUA_TSHRSTR: return luaH_getstr(t, tsvalue(key));
+ case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key));
case LUA_TNUMINT: return luaH_getint(t, ivalue(key));
case LUA_TNIL: return luaO_nilobject;
case LUA_TNUMFLT: {
lua_Integer k;
- if (numisinteger(fltvalue(key), &k)) /* index is int? */
+ if (luaV_tointeger(key, &k, 0)) /* index is int? */
return luaH_getint(t, k); /* use specialized version */
- /* else go through */
- }
- default: {
- Node *n = mainposition(t, key);
- for (;;) { /* check whether 'key' is somewhere in the chain */
- if (luaV_rawequalobj(gkey(n), key))
- return gval(n); /* that's it */
- else {
- int nx = gnext(n);
- if (nx == 0) break;
- n += nx;
- }
- };
- return luaO_nilobject;
- }
+ /* else... */
+ } /* FALLTHROUGH */
+ default:
+ return getgeneric(t, key);
}
}
@@ -632,7 +651,7 @@ int luaH_getn (Table *t) {
return i;
}
/* else must find a boundary in hash part */
- else if (isdummy(t->node)) /* hash part is empty? */
+ else if (isdummy(t)) /* hash part is empty? */
return j; /* that is easy... */
else return unbound_search(t, j);
}
@@ -645,6 +664,6 @@ Node *luaH_mainposition (const Table *t, const TValue *key) {
return mainposition(t, key);
}
-int luaH_isdummy (Node *n) { return isdummy(n); }
+int luaH_isdummy (const Table *t) { return isdummy(t); }
#endif
diff --git a/src/ltable.h b/src/ltable.h
index 53d25511ad49..6da9024fe1fc 100644
--- a/src/ltable.h
+++ b/src/ltable.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltable.h,v 2.20 2014/09/04 18:15:29 roberto Exp $
+** $Id: ltable.h,v 2.23 2016/12/22 13:08:50 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -15,14 +15,26 @@
#define gnext(n) ((n)->i_key.nk.next)
-/* 'const' to avoid wrong writings that can mess up field 'next' */
+/* 'const' to avoid wrong writings that can mess up field 'next' */
#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk))
+/*
+** writable version of 'gkey'; allows updates to individual fields,
+** but not to the whole (which has incompatible type)
+*/
#define wgkey(n) (&(n)->i_key.nk)
#define invalidateTMcache(t) ((t)->flags = 0)
+/* true when 't' is using 'dummynode' as its hash part */
+#define isdummy(t) ((t)->lastfree == NULL)
+
+
+/* allocated size for hash nodes */
+#define allocsizenode(t) (isdummy(t) ? 0 : sizenode(t))
+
+
/* returns the key, given the value of a table entry */
#define keyfromval(v) \
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
@@ -31,6 +43,7 @@
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
TValue *value);
+LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);
@@ -46,7 +59,7 @@ LUAI_FUNC int luaH_getn (Table *t);
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
-LUAI_FUNC int luaH_isdummy (Node *n);
+LUAI_FUNC int luaH_isdummy (const Table *t);
#endif
diff --git a/src/ltablib.c b/src/ltablib.c
index 8f78afb7f25e..98b2f8713794 100644
--- a/src/ltablib.c
+++ b/src/ltablib.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltablib.c,v 1.79 2014/11/02 19:19:04 roberto Exp $
+** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/
@@ -12,6 +12,7 @@
#include <limits.h>
#include <stddef.h>
+#include <string.h>
#include "lua.h"
@@ -19,42 +20,44 @@
#include "lualib.h"
-
/*
-** Structure with table-access functions
+** Operations that an object must define to mimic a table
+** (some functions only need some of them)
*/
-typedef struct {
- int (*geti) (lua_State *L, int idx, lua_Integer n);
- void (*seti) (lua_State *L, int idx, lua_Integer n);
-} TabA;
+#define TAB_R 1 /* read */
+#define TAB_W 2 /* write */
+#define TAB_L 4 /* length */
+#define TAB_RW (TAB_R | TAB_W) /* read/write */
+
+
+#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n))
+
+
+static int checkfield (lua_State *L, const char *key, int n) {
+ lua_pushstring(L, key);
+ return (lua_rawget(L, -n) != LUA_TNIL);
+}
/*
-** Check that 'arg' has a table and set access functions in 'ta' to raw
-** or non-raw according to the presence of corresponding metamethods.
+** Check that 'arg' either is a table or can behave like one (that is,
+** has a metatable with the required metamethods)
*/
-static void checktab (lua_State *L, int arg, TabA *ta) {
- ta->geti = NULL; ta->seti = NULL;
- if (lua_getmetatable(L, arg)) {
- lua_pushliteral(L, "__index"); /* 'index' metamethod */
- if (lua_rawget(L, -2) != LUA_TNIL)
- ta->geti = lua_geti;
- lua_pushliteral(L, "__newindex"); /* 'newindex' metamethod */
- if (lua_rawget(L, -3) != LUA_TNIL)
- ta->seti = lua_seti;
- lua_pop(L, 3); /* pop metatable plus both metamethods */
- }
- if (ta->geti == NULL || ta->seti == NULL) {
- luaL_checktype(L, arg, LUA_TTABLE); /* must be table for raw methods */
- if (ta->geti == NULL) ta->geti = lua_rawgeti;
- if (ta->seti == NULL) ta->seti = lua_rawseti;
+static void checktab (lua_State *L, int arg, int what) {
+ if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */
+ int n = 1; /* number of elements to pop */
+ if (lua_getmetatable(L, arg) && /* must have metatable */
+ (!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
+ (!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
+ (!(what & TAB_L) || checkfield(L, "__len", ++n))) {
+ lua_pop(L, n); /* pop metatable and tested metamethods */
+ }
+ else
+ luaL_checktype(L, arg, LUA_TTABLE); /* force an error */
}
}
-#define aux_getn(L,n,ta) (checktab(L, n, ta), luaL_len(L, n))
-
-
#if defined(LUA_COMPAT_MAXN)
static int maxn (lua_State *L) {
lua_Number max = 0;
@@ -74,8 +77,7 @@ static int maxn (lua_State *L) {
static int tinsert (lua_State *L) {
- TabA ta;
- lua_Integer e = aux_getn(L, 1, &ta) + 1; /* first empty element */
+ lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
lua_Integer pos; /* where to insert new element */
switch (lua_gettop(L)) {
case 2: { /* called with only 2 arguments */
@@ -87,8 +89,8 @@ static int tinsert (lua_State *L) {
pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */
luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
for (i = e; i > pos; i--) { /* move up elements */
- (*ta.geti)(L, 1, i - 1);
- (*ta.seti)(L, 1, i); /* t[i] = t[i - 1] */
+ lua_geti(L, 1, i - 1);
+ lua_seti(L, 1, i); /* t[i] = t[i - 1] */
}
break;
}
@@ -96,65 +98,67 @@ static int tinsert (lua_State *L) {
return luaL_error(L, "wrong number of arguments to 'insert'");
}
}
- (*ta.seti)(L, 1, pos); /* t[pos] = v */
+ lua_seti(L, 1, pos); /* t[pos] = v */
return 0;
}
static int tremove (lua_State *L) {
- TabA ta;
- lua_Integer size = aux_getn(L, 1, &ta);
+ lua_Integer size = aux_getn(L, 1, TAB_RW);
lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */
luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
- (*ta.geti)(L, 1, pos); /* result = t[pos] */
+ lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) {
- (*ta.geti)(L, 1, pos + 1);
- (*ta.seti)(L, 1, pos); /* t[pos] = t[pos + 1] */
+ lua_geti(L, 1, pos + 1);
+ lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */
}
lua_pushnil(L);
- (*ta.seti)(L, 1, pos); /* t[pos] = nil */
+ lua_seti(L, 1, pos); /* t[pos] = nil */
return 1;
}
+/*
+** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever
+** possible, copy in increasing order, which is better for rehashing.
+** "possible" means destination after original range, or smaller
+** than origin, or copying to another table.
+*/
static int tmove (lua_State *L) {
- TabA ta;
lua_Integer f = luaL_checkinteger(L, 2);
lua_Integer e = luaL_checkinteger(L, 3);
lua_Integer t = luaL_checkinteger(L, 4);
int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */
- /* the following restriction avoids several problems with overflows */
- luaL_argcheck(L, f > 0, 2, "initial position must be positive");
+ checktab(L, 1, TAB_R);
+ checktab(L, tt, TAB_W);
if (e >= f) { /* otherwise, nothing to move */
lua_Integer n, i;
- ta.geti = (luaL_getmetafield(L, 1, "__index") == LUA_TNIL)
- ? (luaL_checktype(L, 1, LUA_TTABLE), lua_rawgeti)
- : lua_geti;
- ta.seti = (luaL_getmetafield(L, tt, "__newindex") == LUA_TNIL)
- ? (luaL_checktype(L, tt, LUA_TTABLE), lua_rawseti)
- : lua_seti;
+ luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3,
+ "too many elements to move");
n = e - f + 1; /* number of elements to move */
- if (t > f) {
- for (i = n - 1; i >= 0; i--) {
- (*ta.geti)(L, 1, f + i);
- (*ta.seti)(L, tt, t + i);
+ luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,
+ "destination wrap around");
+ if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {
+ for (i = 0; i < n; i++) {
+ lua_geti(L, 1, f + i);
+ lua_seti(L, tt, t + i);
}
}
else {
- for (i = 0; i < n; i++) {
- (*ta.geti)(L, 1, f + i);
- (*ta.seti)(L, tt, t + i);
+ for (i = n - 1; i >= 0; i--) {
+ lua_geti(L, 1, f + i);
+ lua_seti(L, tt, t + i);
}
}
}
- lua_pushvalue(L, tt); /* return "to table" */
+ lua_pushvalue(L, tt); /* return destination table */
return 1;
}
-static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) {
- (*ta->geti)(L, 1, i);
+static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
+ lua_geti(L, 1, i);
if (!lua_isstring(L, -1))
luaL_error(L, "invalid value (%s) at index %d in table for 'concat'",
luaL_typename(L, -1), i);
@@ -163,21 +167,19 @@ static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) {
static int tconcat (lua_State *L) {
- TabA ta;
luaL_Buffer b;
+ lua_Integer last = aux_getn(L, 1, TAB_R);
size_t lsep;
- lua_Integer i, last;
const char *sep = luaL_optlstring(L, 2, "", &lsep);
- checktab(L, 1, &ta);
- i = luaL_optinteger(L, 3, 1);
- last = luaL_opt(L, luaL_checkinteger, 4, luaL_len(L, 1));
+ lua_Integer i = luaL_optinteger(L, 3, 1);
+ last = luaL_optinteger(L, 4, last);
luaL_buffinit(L, &b);
for (; i < last; i++) {
- addfield(L, &b, &ta, i);
+ addfield(L, &b, i);
luaL_addlstring(&b, sep, lsep);
}
if (i == last) /* add last value (if interval was not empty) */
- addfield(L, &b, &ta, i);
+ addfield(L, &b, i);
luaL_pushresult(&b);
return 1;
}
@@ -195,7 +197,7 @@ static int pack (lua_State *L) {
lua_createtable(L, n, 1); /* create result table */
lua_insert(L, 1); /* put it at index 1 */
for (i = n; i >= 1; i--) /* assign elements */
- lua_rawseti(L, 1, i);
+ lua_seti(L, 1, i);
lua_pushinteger(L, n);
lua_setfield(L, 1, "n"); /* t.n = number of elements */
return 1; /* return table */
@@ -203,20 +205,17 @@ static int pack (lua_State *L) {
static int unpack (lua_State *L) {
- TabA ta;
- lua_Integer i, e;
lua_Unsigned n;
- checktab(L, 1, &ta);
- i = luaL_optinteger(L, 2, 1);
- e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
+ lua_Integer i = luaL_optinteger(L, 2, 1);
+ lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
if (i > e) return 0; /* empty range */
n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n)))
return luaL_error(L, "too many results to unpack");
- do { /* must have at least one element */
- (*ta.geti)(L, 1, i); /* push arg[i..e] */
- } while (i++ < e);
-
+ for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */
+ lua_geti(L, 1, i);
+ }
+ lua_geti(L, 1, e); /* push last element */
return (int)n;
}
@@ -233,97 +232,191 @@ static int unpack (lua_State *L) {
*/
-static void set2 (lua_State *L, TabA *ta, int i, int j) {
- (*ta->seti)(L, 1, i);
- (*ta->seti)(L, 1, j);
+/* type for array indices */
+typedef unsigned int IdxT;
+
+
+/*
+** Produce a "random" 'unsigned int' to randomize pivot choice. This
+** macro is used only when 'sort' detects a big imbalance in the result
+** of a partition. (If you don't want/need this "randomness", ~0 is a
+** good choice.)
+*/
+#if !defined(l_randomizePivot) /* { */
+
+#include <time.h>
+
+/* size of 'e' measured in number of 'unsigned int's */
+#define sof(e) (sizeof(e) / sizeof(unsigned int))
+
+/*
+** Use 'time' and 'clock' as sources of "randomness". Because we don't
+** know the types 'clock_t' and 'time_t', we cannot cast them to
+** anything without risking overflows. A safe way to use their values
+** is to copy them to an array of a known type and use the array values.
+*/
+static unsigned int l_randomizePivot (void) {
+ clock_t c = clock();
+ time_t t = time(NULL);
+ unsigned int buff[sof(c) + sof(t)];
+ unsigned int i, rnd = 0;
+ memcpy(buff, &c, sof(c) * sizeof(unsigned int));
+ memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int));
+ for (i = 0; i < sof(buff); i++)
+ rnd += buff[i];
+ return rnd;
+}
+
+#endif /* } */
+
+
+/* arrays larger than 'RANLIMIT' may use randomized pivots */
+#define RANLIMIT 100u
+
+
+static void set2 (lua_State *L, IdxT i, IdxT j) {
+ lua_seti(L, 1, i);
+ lua_seti(L, 1, j);
}
+
+/*
+** Return true iff value at stack index 'a' is less than the value at
+** index 'b' (according to the order of the sort).
+*/
static int sort_comp (lua_State *L, int a, int b) {
- if (!lua_isnil(L, 2)) { /* function? */
+ if (lua_isnil(L, 2)) /* no function? */
+ return lua_compare(L, a, b, LUA_OPLT); /* a < b */
+ else { /* function */
int res;
- lua_pushvalue(L, 2);
+ lua_pushvalue(L, 2); /* push function */
lua_pushvalue(L, a-1); /* -1 to compensate function */
lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */
- lua_call(L, 2, 1);
- res = lua_toboolean(L, -1);
- lua_pop(L, 1);
+ lua_call(L, 2, 1); /* call function */
+ res = lua_toboolean(L, -1); /* get result */
+ lua_pop(L, 1); /* pop result */
return res;
}
- else /* a < b? */
- return lua_compare(L, a, b, LUA_OPLT);
}
-static void auxsort (lua_State *L, TabA *ta, int l, int u) {
- while (l < u) { /* for tail recursion */
- int i, j;
- /* sort elements a[l], a[(l+u)/2] and a[u] */
- (*ta->geti)(L, 1, l);
- (*ta->geti)(L, 1, u);
- if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
- set2(L, ta, l, u); /* swap a[l] - a[u] */
+
+/*
+** Does the partition: Pivot P is at the top of the stack.
+** precondition: a[lo] <= P == a[up-1] <= a[up],
+** so it only needs to do the partition from lo + 1 to up - 2.
+** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]
+** returns 'i'.
+*/
+static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
+ IdxT i = lo; /* will be incremented before first use */
+ IdxT j = up - 1; /* will be decremented before first use */
+ /* loop invariant: a[lo .. i] <= P <= a[j .. up] */
+ for (;;) {
+ /* next loop: repeat ++i while a[i] < P */
+ while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
+ if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */
+ luaL_error(L, "invalid order function for sorting");
+ lua_pop(L, 1); /* remove a[i] */
+ }
+ /* after the loop, a[i] >= P and a[lo .. i - 1] < P */
+ /* next loop: repeat --j while P < a[j] */
+ while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
+ if (j < i) /* j < i but a[j] > P ?? */
+ luaL_error(L, "invalid order function for sorting");
+ lua_pop(L, 1); /* remove a[j] */
+ }
+ /* after the loop, a[j] <= P and a[j + 1 .. up] >= P */
+ if (j < i) { /* no elements out of place? */
+ /* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */
+ lua_pop(L, 1); /* pop a[j] */
+ /* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */
+ set2(L, up - 1, i);
+ return i;
+ }
+ /* otherwise, swap a[i] - a[j] to restore invariant and repeat */
+ set2(L, i, j);
+ }
+}
+
+
+/*
+** Choose an element in the middle (2nd-3th quarters) of [lo,up]
+** "randomized" by 'rnd'
+*/
+static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
+ IdxT r4 = (up - lo) / 4; /* range/4 */
+ IdxT p = rnd % (r4 * 2) + (lo + r4);
+ lua_assert(lo + r4 <= p && p <= up - r4);
+ return p;
+}
+
+
+/*
+** QuickSort algorithm (recursive function)
+*/
+static void auxsort (lua_State *L, IdxT lo, IdxT up,
+ unsigned int rnd) {
+ while (lo < up) { /* loop for tail recursion */
+ IdxT p; /* Pivot index */
+ IdxT n; /* to be used later */
+ /* sort elements 'lo', 'p', and 'up' */
+ lua_geti(L, 1, lo);
+ lua_geti(L, 1, up);
+ if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */
+ set2(L, lo, up); /* swap a[lo] - a[up] */
else
- lua_pop(L, 2);
- if (u-l == 1) break; /* only 2 elements */
- i = (l+u)/2;
- (*ta->geti)(L, 1, i);
- (*ta->geti)(L, 1, l);
- if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
- set2(L, ta, i, l);
+ lua_pop(L, 2); /* remove both values */
+ if (up - lo == 1) /* only 2 elements? */
+ return; /* already sorted */
+ if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */
+ p = (lo + up)/2; /* middle element is a good pivot */
+ else /* for larger intervals, it is worth a random pivot */
+ p = choosePivot(lo, up, rnd);
+ lua_geti(L, 1, p);
+ lua_geti(L, 1, lo);
+ if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */
+ set2(L, p, lo); /* swap a[p] - a[lo] */
else {
- lua_pop(L, 1); /* remove a[l] */
- (*ta->geti)(L, 1, u);
- if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
- set2(L, ta, i, u);
+ lua_pop(L, 1); /* remove a[lo] */
+ lua_geti(L, 1, up);
+ if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */
+ set2(L, p, up); /* swap a[up] - a[p] */
else
lua_pop(L, 2);
}
- if (u-l == 2) break; /* only 3 elements */
- (*ta->geti)(L, 1, i); /* Pivot */
- lua_pushvalue(L, -1);
- (*ta->geti)(L, 1, u-1);
- set2(L, ta, i, u-1);
- /* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
- i = l; j = u-1;
- for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
- /* repeat ++i until a[i] >= P */
- while ((*ta->geti)(L, 1, ++i), sort_comp(L, -1, -2)) {
- if (i>=u) luaL_error(L, "invalid order function for sorting");
- lua_pop(L, 1); /* remove a[i] */
- }
- /* repeat --j until a[j] <= P */
- while ((*ta->geti)(L, 1, --j), sort_comp(L, -3, -1)) {
- if (j<=l) luaL_error(L, "invalid order function for sorting");
- lua_pop(L, 1); /* remove a[j] */
- }
- if (j<i) {
- lua_pop(L, 3); /* pop pivot, a[i], a[j] */
- break;
- }
- set2(L, ta, i, j);
- }
- (*ta->geti)(L, 1, u-1);
- (*ta->geti)(L, 1, i);
- set2(L, ta, u-1, i); /* swap pivot (a[u-1]) with a[i] */
- /* a[l..i-1] <= a[i] == P <= a[i+1..u] */
- /* adjust so that smaller half is in [j..i] and larger one in [l..u] */
- if (i-l < u-i) {
- j=l; i=i-1; l=i+2;
+ if (up - lo == 2) /* only 3 elements? */
+ return; /* already sorted */
+ lua_geti(L, 1, p); /* get middle element (Pivot) */
+ lua_pushvalue(L, -1); /* push Pivot */
+ lua_geti(L, 1, up - 1); /* push a[up - 1] */
+ set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */
+ p = partition(L, lo, up);
+ /* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
+ if (p - lo < up - p) { /* lower interval is smaller? */
+ auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */
+ n = p - lo; /* size of smaller interval */
+ lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */
}
else {
- j=i+1; i=u; u=j-2;
+ auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */
+ n = up - p; /* size of smaller interval */
+ up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
}
- auxsort(L, ta, j, i); /* call recursively the smaller one */
- } /* repeat the routine for the larger one */
+ if ((up - lo) / 128 > n) /* partition too imbalanced? */
+ rnd = l_randomizePivot(); /* try a new randomization */
+ } /* tail call auxsort(L, lo, up, rnd) */
}
+
static int sort (lua_State *L) {
- TabA ta;
- int n = (int)aux_getn(L, 1, &ta);
- luaL_checkstack(L, 50, ""); /* assume array is smaller than 2^50 */
- if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
- luaL_checktype(L, 2, LUA_TFUNCTION);
- lua_settop(L, 2); /* make sure there are two arguments */
- auxsort(L, &ta, 1, n);
+ lua_Integer n = aux_getn(L, 1, TAB_RW);
+ if (n > 1) { /* non-trivial interval? */
+ luaL_argcheck(L, n < INT_MAX, 1, "array too big");
+ if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
+ luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */
+ lua_settop(L, 2); /* make sure there are two arguments */
+ auxsort(L, 1, (IdxT)n, 0);
+ }
return 0;
}
diff --git a/src/ltm.c b/src/ltm.c
index 25b46b17f90d..14e525788842 100644
--- a/src/ltm.c
+++ b/src/ltm.c
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.c,v 2.33 2014/11/21 12:15:57 roberto Exp $
+** $Id: ltm.c,v 2.38 2016/12/22 13:08:50 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -15,7 +15,7 @@
#include "lua.h"
#include "ldebug.h"
-#include "ldo.h"
+#include "ldo.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
@@ -57,7 +57,7 @@ void luaT_init (lua_State *L) {
** tag methods
*/
const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
- const TValue *tm = luaH_getstr(events, ename);
+ const TValue *tm = luaH_getshortstr(events, ename);
lua_assert(event <= TM_EQ);
if (ttisnil(tm)) { /* no tag method? */
events->flags |= cast_byte(1u<<event); /* cache this fact */
@@ -79,20 +79,41 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
default:
mt = G(L)->mt[ttnov(o)];
}
- return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject);
+ return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject);
+}
+
+
+/*
+** Return the name of the type of an object. For tables and userdata
+** with metatable, use their '__name' metafield, if present.
+*/
+const char *luaT_objtypename (lua_State *L, const TValue *o) {
+ Table *mt;
+ if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
+ (ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
+ const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name"));
+ if (ttisstring(name)) /* is '__name' a string? */
+ return getstr(tsvalue(name)); /* use it as type name */
+ }
+ return ttypename(ttnov(o)); /* else use standard type name */
}
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, TValue *p3, int hasres) {
ptrdiff_t result = savestack(L, p3);
- setobj2s(L, L->top++, f); /* push function (assume EXTRA_STACK) */
- setobj2s(L, L->top++, p1); /* 1st argument */
- setobj2s(L, L->top++, p2); /* 2nd argument */
+ StkId func = L->top;
+ setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
+ setobj2s(L, func + 1, p1); /* 1st argument */
+ setobj2s(L, func + 2, p2); /* 2nd argument */
+ L->top += 3;
if (!hasres) /* no result? 'p3' is third argument */
setobj2s(L, L->top++, p3); /* 3rd argument */
/* metamethod may yield only when called from Lua code */
- luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci));
+ if (isLua(L->ci))
+ luaD_call(L, func, hasres);
+ else
+ luaD_callnoyield(L, func, hasres);
if (hasres) { /* if has result, move it to its place */
p3 = restorestack(L, result);
setobjs2s(L, p3, --L->top);
@@ -117,6 +138,7 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
switch (event) {
case TM_CONCAT:
luaG_concaterror(L, p1, p2);
+ /* call never returns, but to avoid warnings: *//* FALLTHROUGH */
case TM_BAND: case TM_BOR: case TM_BXOR:
case TM_SHL: case TM_SHR: case TM_BNOT: {
lua_Number dummy;
@@ -124,8 +146,8 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2,
luaG_tointerror(L, p1, p2);
else
luaG_opinterror(L, p1, p2, "perform bitwise operation on");
- /* else go through */
}
+ /* calls never return, but to avoid warnings: *//* FALLTHROUGH */
default:
luaG_opinterror(L, p1, p2, "perform arithmetic on");
}
diff --git a/src/ltm.h b/src/ltm.h
index 180179ce038e..63db7269bbfc 100644
--- a/src/ltm.h
+++ b/src/ltm.h
@@ -1,5 +1,5 @@
/*
-** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp $
+** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -51,11 +51,12 @@ typedef enum {
#define fasttm(l,et,e) gfasttm(G(l), et, e)
#define ttypename(x) luaT_typenames_[(x) + 1]
-#define objtypename(x) ttypename(ttnov(x))
LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
+LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
+
LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
TMS event);
diff --git a/src/lua.c b/src/lua.c
index 34a3900a7949..3f082da6be61 100644
--- a/src/lua.c
+++ b/src/lua.c
@@ -1,5 +1,5 @@
/*
-** $Id: lua.c,v 1.222 2014/11/11 19:41:27 roberto Exp $
+** $Id: lua.c,v 1.230 2017/01/12 17:14:26 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@@ -20,6 +20,7 @@
#include "lualib.h"
+
#if !defined(LUA_PROMPT)
#define LUA_PROMPT "> "
#define LUA_PROMPT2 ">> "
@@ -37,8 +38,7 @@
#define LUA_INIT_VAR "LUA_INIT"
#endif
-#define LUA_INITVARVERSION \
- LUA_INIT_VAR "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
+#define LUA_INITVARVERSION LUA_INIT_VAR LUA_VERSUFFIX
/*
@@ -55,6 +55,8 @@
#elif defined(LUA_USE_WINDOWS) /* }{ */
#include <io.h>
+#include <windows.h>
+
#define lua_stdin_is_tty() _isatty(_fileno(stdin))
#else /* }{ */
@@ -80,9 +82,7 @@
#include <readline/readline.h>
#include <readline/history.h>
#define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL)
-#define lua_saveline(L,idx) \
- if (lua_rawlen(L,idx) > 0) /* non-empty line? */ \
- add_history(lua_tostring(L, idx)); /* add it to history */
+#define lua_saveline(L,line) ((void)L, add_history(line))
#define lua_freeline(L,b) ((void)L, free(b))
#else /* }{ */
@@ -90,7 +90,7 @@
#define lua_readline(L,b,p) \
((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \
fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */
-#define lua_saveline(L,idx) { (void)L; (void)idx; }
+#define lua_saveline(L,line) { (void)L; (void)line; }
#define lua_freeline(L,b) { (void)L; (void)b; }
#endif /* } */
@@ -315,31 +315,31 @@ static int pushline (lua_State *L, int firstline) {
lua_pop(L, 1); /* remove prompt */
l = strlen(b);
if (l > 0 && b[l-1] == '\n') /* line ends with newline? */
- b[l-1] = '\0'; /* remove it */
+ b[--l] = '\0'; /* remove it */
if (firstline && b[0] == '=') /* for compatibility with 5.2, ... */
lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */
else
- lua_pushstring(L, b);
+ lua_pushlstring(L, b, l);
lua_freeline(L, b);
return 1;
}
/*
-** Try to compile line on the stack as 'return <line>'; on return, stack
+** Try to compile line on the stack as 'return <line>;'; on return, stack
** has either compiled chunk or original line (if compilation failed).
*/
static int addreturn (lua_State *L) {
- int status;
- size_t len; const char *line;
- lua_pushliteral(L, "return ");
- lua_pushvalue(L, -2); /* duplicate line */
- lua_concat(L, 2); /* new line is "return ..." */
- line = lua_tolstring(L, -1, &len);
- if ((status = luaL_loadbuffer(L, line, len, "=stdin")) == LUA_OK)
- lua_remove(L, -3); /* remove original line */
+ const char *line = lua_tostring(L, -1); /* original line */
+ const char *retline = lua_pushfstring(L, "return %s;", line);
+ int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
+ if (status == LUA_OK) {
+ lua_remove(L, -2); /* remove modified line */
+ if (line[0] != '\0') /* non empty? */
+ lua_saveline(L, line); /* keep history */
+ }
else
- lua_pop(L, 2); /* remove result from 'luaL_loadbuffer' and new line */
+ lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */
return status;
}
@@ -352,8 +352,10 @@ static int multiline (lua_State *L) {
size_t len;
const char *line = lua_tolstring(L, 1, &len); /* get what it has */
int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */
- if (!incomplete(L, status) || !pushline(L, 0))
+ if (!incomplete(L, status) || !pushline(L, 0)) {
+ lua_saveline(L, line); /* keep history */
return status; /* cannot or should not try to add continuation line */
+ }
lua_pushliteral(L, "\n"); /* add newline... */
lua_insert(L, -2); /* ...between the two lines */
lua_concat(L, 3); /* join them */
@@ -374,7 +376,6 @@ static int loadline (lua_State *L) {
return -1; /* no input */
if ((status = addreturn(L)) != LUA_OK) /* 'return ...' did not work? */
status = multiline(L); /* try as command, maybe with continuation lines */
- lua_saveline(L, 1); /* keep history */
lua_remove(L, 1); /* remove line from the stack */
lua_assert(lua_gettop(L) == 1);
return status;
@@ -458,7 +459,7 @@ static int handle_script (lua_State *L, char **argv) {
/*
** Traverses all arguments from 'argv', returning a mask with those
** needed before running any Lua code (or an error code if it finds
-** any invalid argument). 'first' returns the first not-handled argument
+** any invalid argument). 'first' returns the first not-handled argument
** (either the script name or a bad argument in case of error).
*/
static int collectargs (char **argv, int *first) {
@@ -482,14 +483,14 @@ static int collectargs (char **argv, int *first) {
args |= has_E;
break;
case 'i':
- args |= has_i; /* goes through (-i implies -v) */
+ args |= has_i; /* (-i implies -v) *//* FALLTHROUGH */
case 'v':
if (argv[i][2] != '\0') /* extra characters after 1st? */
return has_error; /* invalid option */
args |= has_v;
break;
case 'e':
- args |= has_e; /* go through */
+ args |= has_e; /* FALLTHROUGH */
case 'l': /* both options need an argument */
if (argv[i][2] == '\0') { /* no concatenated argument? */
i++; /* try next 'argv' */
@@ -513,17 +514,16 @@ static int collectargs (char **argv, int *first) {
static int runargs (lua_State *L, char **argv, int n) {
int i;
for (i = 1; i < n; i++) {
- int status;
int option = argv[i][1];
lua_assert(argv[i][0] == '-'); /* already checked */
if (option == 'e' || option == 'l') {
+ int status;
const char *extra = argv[i] + 2; /* both options need an argument */
if (*extra == '\0') extra = argv[++i];
lua_assert(extra != NULL);
- if (option == 'e')
- status = dostring(L, extra, "=(command line)");
- else
- status = dolibrary(L, extra);
+ status = (option == 'e')
+ ? dostring(L, extra, "=(command line)")
+ : dolibrary(L, extra);
if (status != LUA_OK) return 0;
}
}
@@ -531,6 +531,7 @@ static int runargs (lua_State *L, char **argv, int n) {
}
+
static int handle_luainit (lua_State *L) {
const char *name = "=" LUA_INITVARVERSION;
const char *init = getenv(name + 1);
diff --git a/src/lua.h b/src/lua.h
index 09a4ccaf89f2..26c0e2d698c4 100644
--- a/src/lua.h
+++ b/src/lua.h
@@ -1,5 +1,5 @@
/*
-** $Id: lua.h,v 1.325 2014/12/26 17:24:27 roberto Exp $
+** $Id: lua.h,v 1.332 2016/12/22 15:51:20 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503
-#define LUA_VERSION_RELEASE "0"
+#define LUA_VERSION_RELEASE "4"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
-#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2015 Lua.org, PUC-Rio"
+#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2017 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -35,9 +35,11 @@
/*
-** pseudo-indices
+** Pseudo-indices
+** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
+** space after that to help overflow detection)
*/
-#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX
+#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
@@ -356,11 +358,10 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
-#define lua_pushliteral(L, s) \
- lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
+#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
#define lua_pushglobaltable(L) \
- lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
+ ((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
@@ -459,7 +460,7 @@ struct lua_Debug {
/******************************************************************************
-* Copyright (C) 1994-2015 Lua.org, PUC-Rio.
+* Copyright (C) 1994-2017 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
diff --git a/src/luac.c b/src/luac.c
index c565f46aa50a..c0c91d017ae3 100644
--- a/src/luac.c
+++ b/src/luac.c
@@ -1,5 +1,5 @@
/*
-** $Id: luac.c,v 1.72 2015/01/06 03:09:13 lhf Exp $
+** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
** Lua compiler (saves bytecodes to files; also lists bytecodes)
** See Copyright Notice in lua.h
*/
@@ -206,7 +206,7 @@ int main(int argc, char* argv[])
}
/*
-** $Id: print.c,v 1.76 2015/01/05 16:12:50 lhf Exp $
+** $Id: luac.c,v 1.75 2015/03/12 01:58:27 lhf Exp $
** print bytecodes
** See Copyright Notice in lua.h
*/
@@ -226,7 +226,7 @@ int main(int argc, char* argv[])
static void PrintString(const TString* ts)
{
const char* s=getstr(ts);
- size_t i,n=ts->len;
+ size_t i,n=tsslen(ts);
printf("%c",'"');
for (i=0; i<n; i++)
{
diff --git a/src/luaconf.h b/src/luaconf.h
index fd28d21aec96..f37bea0964bd 100644
--- a/src/luaconf.h
+++ b/src/luaconf.h
@@ -1,5 +1,5 @@
/*
-** $Id: luaconf.h,v 1.238 2014/12/29 13:27:55 roberto Exp $
+** $Id: luaconf.h,v 1.259 2016/12/22 13:08:50 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@@ -96,10 +96,8 @@
/*
-@@ LUA_INT_INT / LUA_INT_LONG / LUA_INT_LONGLONG defines the type for
-** Lua integers.
-@@ LUA_REAL_FLOAT / LUA_REAL_DOUBLE / LUA_REAL_LONGDOUBLE defines
-** the type for Lua floats.
+@@ LUA_INT_TYPE defines the type for Lua integers.
+@@ LUA_FLOAT_TYPE defines the type for Lua floats.
** Lua should work fine with any mix of these options (if supported
** by your C compiler). The usual configurations are 64-bit integers
** and 'double' (the default), 32-bit integers and 'float' (for
@@ -107,32 +105,47 @@
** compliant with C99, which may not have support for 'long long').
*/
+/* predefined options for LUA_INT_TYPE */
+#define LUA_INT_INT 1
+#define LUA_INT_LONG 2
+#define LUA_INT_LONGLONG 3
+
+/* predefined options for LUA_FLOAT_TYPE */
+#define LUA_FLOAT_FLOAT 1
+#define LUA_FLOAT_DOUBLE 2
+#define LUA_FLOAT_LONGDOUBLE 3
+
#if defined(LUA_32BITS) /* { */
/*
** 32-bit integers and 'float'
*/
#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
-#define LUA_INT_INT
+#define LUA_INT_TYPE LUA_INT_INT
#else /* otherwise use 'long' */
-#define LUA_INT_LONG
+#define LUA_INT_TYPE LUA_INT_LONG
#endif
-#define LUA_REAL_FLOAT
+#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
#elif defined(LUA_C89_NUMBERS) /* }{ */
/*
** largest types available for C89 ('long' and 'double')
*/
-#define LUA_INT_LONG
-#define LUA_REAL_DOUBLE
+#define LUA_INT_TYPE LUA_INT_LONG
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+
+#endif /* } */
+
-#else /* }{ */
/*
** default configuration for 64-bit Lua ('long long' and 'double')
*/
-#define LUA_INT_LONGLONG
-#define LUA_REAL_DOUBLE
+#if !defined(LUA_INT_TYPE)
+#define LUA_INT_TYPE LUA_INT_LONGLONG
+#endif
-#endif /* } */
+#if !defined(LUA_FLOAT_TYPE)
+#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
+#endif
/* }================================================================== */
@@ -146,6 +159,18 @@
*/
/*
+** LUA_PATH_SEP is the character that separates templates in a path.
+** LUA_PATH_MARK is the string that marks the substitution points in a
+** template.
+** LUA_EXEC_DIR in a Windows path is replaced by the executable's
+** directory.
+*/
+#define LUA_PATH_SEP ";"
+#define LUA_PATH_MARK "?"
+#define LUA_EXEC_DIR "!"
+
+
+/*
@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
** Lua libraries.
@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
@@ -155,7 +180,7 @@
** non-conventional directories.
*/
#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
-#if defined(_WIN32) /* { */
+#if defined(_WIN32) /* { */
/*
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
@@ -300,20 +325,15 @@
*/
#define LUA_COMPAT_APIINTCASTS
-
-/*
-@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
-@@ a float mark ('.0').
-** This macro is not on by default even in compatibility mode,
-** because this is not really an incompatibility.
-*/
-/* #define LUA_COMPAT_FLOATSTRING */
-
#endif /* } */
#if defined(LUA_COMPAT_5_1) /* { */
+/* Incompatibilities from 5.2 -> 5.3 */
+#define LUA_COMPAT_MATHLIB
+#define LUA_COMPAT_APIINTCASTS
+
/*
@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
** You can replace it with 'table.unpack'.
@@ -373,6 +393,15 @@
#endif /* } */
+
+/*
+@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
+@@ a float mark ('.0').
+** This macro is not on by default even in compatibility mode,
+** because this is not really an incompatibility.
+*/
+/* #define LUA_COMPAT_FLOATSTRING */
+
/* }================================================================== */
@@ -380,30 +409,55 @@
/*
** {==================================================================
** Configuration for Numbers.
-** Change these definitions if no predefined LUA_REAL_* / LUA_INT_*
+** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
** satisfy your needs.
** ===================================================================
*/
/*
@@ LUA_NUMBER is the floating-point type used by Lua.
-**
-@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
+@@ LUAI_UACNUMBER is the result of a 'default argument promotion'
@@ over a floating number.
-**
+@@ l_mathlim(x) corrects limit name 'x' to the proper float type
+** by prefixing it with one of FLT/DBL/LDBL.
@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
@@ LUA_NUMBER_FMT is the format for writing floats.
@@ lua_number2str converts a float to a string.
-**
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
-**
+@@ l_floor takes the floor of a float.
@@ lua_str2number converts a decimal numeric string to a number.
*/
-#if defined(LUA_REAL_FLOAT) /* { single float */
+
+/* The following definitions are good for most cases here */
+
+#define l_floor(x) (l_mathop(floor)(x))
+
+#define lua_number2str(s,sz,n) \
+ l_sprintf((s), sz, LUA_NUMBER_FMT, (LUAI_UACNUMBER)(n))
+
+/*
+@@ lua_numbertointeger converts a float number to an integer, or
+** returns 0 if float is not within the range of a lua_Integer.
+** (The range comparisons are tricky because of rounding. The tests
+** here assume a two-complement representation, where MININTEGER always
+** has an exact representation as a float; MAXINTEGER may not have one,
+** and therefore its conversion to float may have an ill-defined value.)
+*/
+#define lua_numbertointeger(n,p) \
+ ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
+ (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
+ (*(p) = (LUA_INTEGER)(n), 1))
+
+
+/* now the variable definitions */
+
+#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
#define LUA_NUMBER float
+#define l_mathlim(n) (FLT_##n)
+
#define LUAI_UACNUMBER double
#define LUA_NUMBER_FRMLEN ""
@@ -414,10 +468,12 @@
#define lua_str2number(s,p) strtof((s), (p))
-#elif defined(LUA_REAL_LONGDOUBLE) /* }{ long double */
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
#define LUA_NUMBER long double
+#define l_mathlim(n) (LDBL_##n)
+
#define LUAI_UACNUMBER long double
#define LUA_NUMBER_FRMLEN "L"
@@ -427,10 +483,12 @@
#define lua_str2number(s,p) strtold((s), (p))
-#elif defined(LUA_REAL_DOUBLE) /* }{ double */
+#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
#define LUA_NUMBER double
+#define l_mathlim(n) (DBL_##n)
+
#define LUAI_UACNUMBER double
#define LUA_NUMBER_FRMLEN ""
@@ -440,79 +498,20 @@
#define lua_str2number(s,p) strtod((s), (p))
-#else /* }{ */
+#else /* }{ */
-#error "numeric real type not defined"
+#error "numeric float type not defined"
#endif /* } */
-#define l_floor(x) (l_mathop(floor)(x))
-
-#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
-
-
-/*
-@@ lua_numbertointeger converts a float number to an integer, or
-** returns 0 if float is not within the range of a lua_Integer.
-** (The range comparisons are tricky because of rounding. The tests
-** here assume a two-complement representation, where MININTEGER always
-** has an exact representation as a float; MAXINTEGER may not have one,
-** and therefore its conversion to float may have an ill-defined value.)
-*/
-#define lua_numbertointeger(n,p) \
- ((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
- (n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
- (*(p) = (LUA_INTEGER)(n), 1))
-
-
-/*
-@@ The luai_num* macros define the primitive operations over numbers.
-** They should work for any size of floating numbers.
-*/
-
-/* the following operations need the math library */
-#if defined(lobject_c) || defined(lvm_c)
-#include <math.h>
-
-/* floor division (defined as 'floor(a/b)') */
-#define luai_numidiv(L,a,b) ((void)L, l_mathop(floor)(luai_numdiv(L,a,b)))
-
-/*
-** module: defined as 'a - floor(a/b)*b'; the previous definition gives
-** NaN when 'b' is huge, but the result should be 'a'. 'fmod' gives the
-** result of 'a - trunc(a/b)*b', and therefore must be corrected when
-** 'trunc(a/b) ~= floor(a/b)'. That happens when the division has a
-** non-integer negative result, which is equivalent to the test below
-*/
-#define luai_nummod(L,a,b,m) \
- { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); }
-
-/* exponentiation */
-#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b))
-
-#endif
-
-/* these are quite standard operations */
-#if defined(LUA_CORE)
-#define luai_numadd(L,a,b) ((a)+(b))
-#define luai_numsub(L,a,b) ((a)-(b))
-#define luai_nummul(L,a,b) ((a)*(b))
-#define luai_numdiv(L,a,b) ((a)/(b))
-#define luai_numunm(L,a) (-(a))
-#define luai_numeq(a,b) ((a)==(b))
-#define luai_numlt(a,b) ((a)<(b))
-#define luai_numle(a,b) ((a)<=(b))
-#define luai_numisnan(a) (!luai_numeq((a), (a)))
-#endif
-
/*
@@ LUA_INTEGER is the integer type used by Lua.
**
@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
**
-@@ LUAI_UACINT is the result of an 'usual argument conversion'
+@@ LUAI_UACINT is the result of a 'default argument promotion'
@@ over a lUA_INTEGER.
@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
@@ LUA_INTEGER_FMT is the format for writing integers.
@@ -525,10 +524,12 @@
/* The following definitions are good for most cases here */
#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
-#define lua_integer2str(s,n) sprintf((s), LUA_INTEGER_FMT, (n))
#define LUAI_UACINT LUA_INTEGER
+#define lua_integer2str(s,sz,n) \
+ l_sprintf((s), sz, LUA_INTEGER_FMT, (LUAI_UACINT)(n))
+
/*
** use LUAI_UACINT here to avoid problems with promotions (which
** can turn a comparison between unsigneds into a signed comparison)
@@ -538,7 +539,7 @@
/* now the variable definitions */
-#if defined(LUA_INT_INT) /* { int */
+#if LUA_INT_TYPE == LUA_INT_INT /* { int */
#define LUA_INTEGER int
#define LUA_INTEGER_FRMLEN ""
@@ -546,7 +547,7 @@
#define LUA_MAXINTEGER INT_MAX
#define LUA_MININTEGER INT_MIN
-#elif defined(LUA_INT_LONG) /* }{ long */
+#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
#define LUA_INTEGER long
#define LUA_INTEGER_FRMLEN "l"
@@ -554,8 +555,9 @@
#define LUA_MAXINTEGER LONG_MAX
#define LUA_MININTEGER LONG_MIN
-#elif defined(LUA_INT_LONGLONG) /* }{ long long */
+#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
+/* use presence of macro LLONG_MAX as proxy for C99 compliance */
#if defined(LLONG_MAX) /* { */
/* use ISO C99 stuff */
@@ -592,28 +594,41 @@
/*
** {==================================================================
-** Dependencies with C99
+** Dependencies with C99 and other C details
** ===================================================================
*/
/*
+@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
+** (All uses in Lua have only one format item.)
+*/
+#if !defined(LUA_USE_C89)
+#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
+#else
+#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
+#endif
+
+
+/*
@@ lua_strx2number converts an hexadecimal numeric string to a number.
-** In C99, 'strtod' does both conversions. Otherwise, you can
+** In C99, 'strtod' does that conversion. Otherwise, you can
** leave 'lua_strx2number' undefined and Lua will provide its own
** implementation.
*/
#if !defined(LUA_USE_C89)
-#define lua_strx2number(s,p) lua_str2number(s,p)
+#define lua_strx2number(s,p) lua_str2number(s,p)
#endif
/*
-@@ LUA_USE_AFORMAT allows '%a'/'%A' specifiers in 'string.format'
-** Enable it if the C function 'printf' supports these specifiers.
-** (C99 demands it and Windows also supports it.)
+@@ lua_number2strx converts a float to an hexadecimal numeric string.
+** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
+** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
+** provide its own implementation.
*/
-#if !defined(LUA_USE_C89) || defined(LUA_USE_WINDOWS)
-#define LUA_USE_AFORMAT
+#if !defined(LUA_USE_C89)
+#define lua_number2strx(L,b,sz,f,n) \
+ ((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n)))
#endif
@@ -642,12 +657,50 @@
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 199901L
#include <stdint.h>
-#if defined (INTPTR_MAX) /* even in C99 this type is optional */
+#if defined(INTPTR_MAX) /* even in C99 this type is optional */
#undef LUA_KCONTEXT
#define LUA_KCONTEXT intptr_t
#endif
#endif
+
+/*
+@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
+** Change that if you do not want to use C locales. (Code using this
+** macro must include header 'locale.h'.)
+*/
+#if !defined(lua_getlocaledecpoint)
+#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
+#endif
+
+/* }================================================================== */
+
+
+/*
+** {==================================================================
+** Language Variations
+** =====================================================================
+*/
+
+/*
+@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some
+** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from
+** numbers to strings. Define LUA_NOCVTS2N to turn off automatic
+** coercion from strings to numbers.
+*/
+/* #define LUA_NOCVTN2S */
+/* #define LUA_NOCVTS2N */
+
+
+/*
+@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
+** Define it as a help when debugging C code.
+*/
+#if defined(LUA_USE_APICHECK)
+#include <assert.h>
+#define luai_apicheck(l,e) assert(e)
+#endif
+
/* }================================================================== */
@@ -671,9 +724,6 @@
#define LUAI_MAXSTACK 15000
#endif
-/* reserve some space for error handling */
-#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000)
-
/*
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
@@ -692,19 +742,17 @@
/*
-@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is,
-** strings that are internalized. (Cannot be smaller than reserved words
-** or tags for metamethods, as these strings must be internalized;
-** #("function") = 8, #("__newindex") = 10.)
-*/
-#define LUAI_MAXSHORTLEN 40
-
-
-/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
-** CHANGE it if it uses too much C-stack space.
+** CHANGE it if it uses too much C-stack space. (For long double,
+** 'string.format("%.99f", -1e4932)' needs 5034 bytes, so a
+** smaller buffer would force a memory allocation for each call to
+** 'string.format'.)
*/
-#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
+#if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE
+#define LUAL_BUFFERSIZE 8192
+#else
+#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
+#endif
/* }================================================================== */
diff --git a/src/lualib.h b/src/lualib.h
index 5165c0fb3f0f..6c0bc4cb084e 100644
--- a/src/lualib.h
+++ b/src/lualib.h
@@ -1,5 +1,5 @@
/*
-** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $
+** $Id: lualib.h,v 1.45 2017/01/12 17:14:26 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
@@ -11,6 +11,9 @@
#include "lua.h"
+/* version suffix for environment variable names */
+#define LUA_VERSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR
+
LUAMOD_API int (luaopen_base) (lua_State *L);
diff --git a/src/lundump.c b/src/lundump.c
index 510f32582748..4080af9c0d94 100644
--- a/src/lundump.c
+++ b/src/lundump.c
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.c,v 2.41 2014/11/02 19:19:04 roberto Exp $
+** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -32,7 +32,6 @@
typedef struct {
lua_State *L;
ZIO *Z;
- Mbuffer *b;
const char *name;
} LoadState;
@@ -92,10 +91,15 @@ static TString *LoadString (LoadState *S) {
LoadVar(S, size);
if (size == 0)
return NULL;
- else {
- char *s = luaZ_openspace(S->L, S->b, --size);
- LoadVector(S, s, size);
- return luaS_newlstr(S->L, s, size);
+ else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
+ char buff[LUAI_MAXSHORTLEN];
+ LoadVector(S, buff, size);
+ return luaS_newlstr(S->L, buff, size);
+ }
+ else { /* long string */
+ TString *ts = luaS_createlngstrobj(S->L, size);
+ LoadVector(S, getstr(ts), size); /* load directly in final place */
+ return ts;
}
}
@@ -251,8 +255,7 @@ static void checkHeader (LoadState *S) {
/*
** load precompiled chunk
*/
-LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
- const char *name) {
+LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
LoadState S;
LClosure *cl;
if (*name == '@' || *name == '=')
@@ -263,11 +266,10 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
S.name = name;
S.L = L;
S.Z = Z;
- S.b = buff;
checkHeader(&S);
cl = luaF_newLclosure(L, LoadByte(&S));
setclLvalue(L, L->top, cl);
- incr_top(L);
+ luaD_inctop(L);
cl->p = luaF_newproto(L);
LoadFunction(&S, cl->p, NULL);
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
diff --git a/src/lundump.h b/src/lundump.h
index ef43d5126476..aa5cc82f1b58 100644
--- a/src/lundump.h
+++ b/src/lundump.h
@@ -1,5 +1,5 @@
/*
-** $Id: lundump.h,v 1.44 2014/06/19 18:27:20 roberto Exp $
+** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -23,8 +23,7 @@
#define LUAC_FORMAT 0 /* this is the official format */
/* load one chunk; from lundump.c */
-LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff,
- const char* name);
+LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name);
/* dump one chunk; from ldump.c */
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,
diff --git a/src/lutf8lib.c b/src/lutf8lib.c
index be4f087f7606..de9e3dcdd648 100644
--- a/src/lutf8lib.c
+++ b/src/lutf8lib.c
@@ -1,5 +1,5 @@
/*
-** $Id: lutf8lib.c,v 1.13 2014/11/02 19:19:04 roberto Exp $
+** $Id: lutf8lib.c,v 1.16 2016/12/22 13:08:50 roberto Exp $
** Standard library for UTF-8 manipulation
** See Copyright Notice in lua.h
*/
@@ -11,6 +11,7 @@
#include <assert.h>
+#include <limits.h>
#include <stdlib.h>
#include <string.h>
@@ -37,7 +38,7 @@ static lua_Integer u_posrelat (lua_Integer pos, size_t len) {
** Decode one UTF-8 sequence, returning NULL if byte sequence is invalid.
*/
static const char *utf8_decode (const char *o, int *val) {
- static unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF};
+ static const unsigned int limits[] = {0xFF, 0x7F, 0x7FF, 0xFFFF};
const unsigned char *s = (const unsigned char *)o;
unsigned int c = s[0];
unsigned int res = 0; /* final result */
@@ -106,9 +107,9 @@ static int codepoint (lua_State *L) {
luaL_argcheck(L, posi >= 1, 2, "out of range");
luaL_argcheck(L, pose <= (lua_Integer)len, 3, "out of range");
if (posi > pose) return 0; /* empty interval; return no values */
- n = (int)(pose - posi + 1);
- if (posi + n <= pose) /* (lua_Integer -> int) overflow? */
+ if (pose - posi >= INT_MAX) /* (lua_Integer -> int) overflow? */
return luaL_error(L, "string slice too long");
+ n = (int)(pose - posi) + 1;
luaL_checkstack(L, n, "string slice too long");
n = 0;
se = s + pose;
@@ -193,7 +194,7 @@ static int byteoffset (lua_State *L) {
lua_pushinteger(L, posi + 1);
else /* no such character */
lua_pushnil(L);
- return 1;
+ return 1;
}
@@ -234,7 +235,7 @@ static int iter_codes (lua_State *L) {
#define UTF8PATT "[\0-\x7F\xC2-\xF4][\x80-\xBF]*"
-static struct luaL_Reg funcs[] = {
+static const luaL_Reg funcs[] = {
{"offset", byteoffset},
{"codepoint", codepoint},
{"char", utfchar},
@@ -248,7 +249,7 @@ static struct luaL_Reg funcs[] = {
LUAMOD_API int luaopen_utf8 (lua_State *L) {
luaL_newlib(L, funcs);
- lua_pushliteral(L, UTF8PATT);
+ lua_pushlstring(L, UTF8PATT, sizeof(UTF8PATT)/sizeof(char) - 1);
lua_setfield(L, -2, "charpattern");
return 1;
}
diff --git a/src/lvm.c b/src/lvm.c
index 2ac1b02df48f..84ade6b2fa6c 100644
--- a/src/lvm.c
+++ b/src/lvm.c
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 2.232 2014/12/27 20:30:38 roberto Exp $
+** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -9,8 +9,9 @@
#include "lprefix.h"
-
+#include <float.h>
#include <limits.h>
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -30,36 +31,38 @@
#include "lvm.h"
-/*
-** You can define LUA_FLOORN2I if you want to convert floats to integers
-** by flooring them (instead of raising an error if they are not
-** integral values)
-*/
-#if !defined(LUA_FLOORN2I)
-#define LUA_FLOORN2I 0
-#endif
-
-
/* limit for table tag-method chains (to avoid loops) */
#define MAXTAGLOOP 2000
+
/*
-** Similar to 'tonumber', but does not attempt to convert strings and
-** ensure correct precision (no extra bits). Used in comparisons.
+** 'l_intfitsf' checks whether a given integer can be converted to a
+** float without rounding. Used in comparisons. Left undefined if
+** all integers fit in a float precisely.
*/
-static int tofloat (const TValue *obj, lua_Number *n) {
- if (ttisfloat(obj)) *n = fltvalue(obj);
- else if (ttisinteger(obj)) {
- volatile lua_Number x = cast_num(ivalue(obj)); /* avoid extra precision */
- *n = x;
- }
- else {
- *n = 0; /* to avoid warnings */
- return 0;
- }
- return 1;
-}
+#if !defined(l_intfitsf)
+
+/* number of bits in the mantissa of a float */
+#define NBM (l_mathlim(MANT_DIG))
+
+/*
+** Check whether some integers may not fit in a float, that is, whether
+** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger).
+** (The shifts are done in parts to avoid shifting by more than the size
+** of an integer. In a worst case, NBM == 113 for long double and
+** sizeof(integer) == 32.)
+*/
+#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \
+ >> (NBM - (3 * (NBM / 4)))) > 0
+
+#define l_intfitsf(i) \
+ (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM))
+
+#endif
+
+#endif
+
/*
@@ -73,7 +76,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
return 1;
}
else if (cvt2num(obj) && /* string convertible to number? */
- luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) {
+ luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
*n = nvalue(&v); /* convert result of 'luaO_str2num' to a float */
return 1;
}
@@ -88,7 +91,7 @@ int luaV_tonumber_ (const TValue *obj, lua_Number *n) {
** mode == 1: takes the floor of the number
** mode == 2: takes the ceil of the number
*/
-static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) {
+int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode) {
TValue v;
again:
if (ttisfloat(obj)) {
@@ -106,7 +109,7 @@ static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) {
return 1;
}
else if (cvt2num(obj) &&
- luaO_str2num(svalue(obj), &v) == tsvalue(obj)->len + 1) {
+ luaO_str2num(svalue(obj), &v) == vslen(obj) + 1) {
obj = &v;
goto again; /* convert result from 'luaO_str2num' to an integer */
}
@@ -115,14 +118,6 @@ static int tointeger_aux (const TValue *obj, lua_Integer *p, int mode) {
/*
-** try to convert a value to an integer
-*/
-int luaV_tointeger_ (const TValue *obj, lua_Integer *p) {
- return tointeger_aux(obj, p, LUA_FLOORN2I);
-}
-
-
-/*
** Try to convert a 'for' limit to an integer, preserving the
** semantics of the loop.
** (The following explanation assumes a non-negative step; it is valid
@@ -140,11 +135,11 @@ int luaV_tointeger_ (const TValue *obj, lua_Integer *p) {
static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
int *stopnow) {
*stopnow = 0; /* usually, let loops run */
- if (!tointeger_aux(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */
+ if (!luaV_tointeger(obj, p, (step < 0 ? 2 : 1))) { /* not fit in integer? */
lua_Number n; /* try to convert to float */
if (!tonumber(obj, &n)) /* cannot convert to float? */
return 0; /* not a number */
- if (n > 0) { /* if true, float is larger than max integer */
+ if (luai_numlt(0, n)) { /* if true, float is larger than max integer */
*p = LUA_MAXINTEGER;
if (step < 0) *stopnow = 1;
}
@@ -158,75 +153,88 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
/*
-** Main function for table access (invoking metamethods if needed).
-** Compute 'val = t[key]'
+** Finish the table access 'val = t[key]'.
+** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
+** t[k] entry (which must be nil).
*/
-void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
+void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
+ const TValue *slot) {
int loop; /* counter to avoid infinite loops */
+ const TValue *tm; /* metamethod */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
- const TValue *tm;
- if (ttistable(t)) { /* 't' is a table? */
- Table *h = hvalue(t);
- const TValue *res = luaH_get(h, key); /* do a primitive get */
- if (!ttisnil(res) || /* result is not nil? */
- (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
- setobj2s(L, val, res); /* result is the raw get */
+ if (slot == NULL) { /* 't' is not a table? */
+ lua_assert(!ttistable(t));
+ tm = luaT_gettmbyobj(L, t, TM_INDEX);
+ if (ttisnil(tm))
+ luaG_typeerror(L, t, "index"); /* no metamethod */
+ /* else will try the metamethod */
+ }
+ else { /* 't' is a table */
+ lua_assert(ttisnil(slot));
+ tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
+ if (tm == NULL) { /* no metamethod? */
+ setnilvalue(val); /* result is nil */
return;
}
- /* else will try metamethod */
+ /* else will try the metamethod */
+ }
+ if (ttisfunction(tm)) { /* is metamethod a function? */
+ luaT_callTM(L, tm, t, key, val, 1); /* call it */
+ return;
}
- else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
- luaG_typeerror(L, t, "index"); /* no metamethod */
- if (ttisfunction(tm)) { /* metamethod is a function */
- luaT_callTM(L, tm, t, key, val, 1);
+ t = tm; /* else try to access 'tm[key]' */
+ if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */
+ setobj2s(L, val, slot); /* done */
return;
}
- t = tm; /* else repeat access over 'tm' */
+ /* else repeat (tail call 'luaV_finishget') */
}
- luaG_runerror(L, "gettable chain too long; possible loop");
+ luaG_runerror(L, "'__index' chain too long; possible loop");
}
/*
-** Main function for table assignment (invoking metamethods if needed).
-** Compute 't[key] = val'
+** Finish a table assignment 't[key] = val'.
+** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points
+** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
+** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset'
+** would have done the job.)
*/
-void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
+void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
+ StkId val, const TValue *slot) {
int loop; /* counter to avoid infinite loops */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
- const TValue *tm;
- if (ttistable(t)) { /* 't' is a table? */
- Table *h = hvalue(t);
- TValue *oldval = cast(TValue *, luaH_get(h, key));
- /* if previous value is not nil, there must be a previous entry
- in the table; a metamethod has no relevance */
- if (!ttisnil(oldval) ||
- /* previous value is nil; must check the metamethod */
- ((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL &&
- /* no metamethod; is there a previous entry in the table? */
- (oldval != luaO_nilobject ||
- /* no previous entry; must create one. (The next test is
- always true; we only need the assignment.) */
- (oldval = luaH_newkey(L, h, key), 1)))) {
+ const TValue *tm; /* '__newindex' metamethod */
+ if (slot != NULL) { /* is 't' a table? */
+ Table *h = hvalue(t); /* save 't' table */
+ lua_assert(ttisnil(slot)); /* old value must be nil */
+ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
+ if (tm == NULL) { /* no metamethod? */
+ if (slot == luaO_nilobject) /* no previous entry? */
+ slot = luaH_newkey(L, h, key); /* create one */
/* no metamethod and (now) there is an entry with given key */
- setobj2t(L, oldval, val); /* assign new value to that entry */
+ setobj2t(L, cast(TValue *, slot), val); /* set its new value */
invalidateTMcache(h);
luaC_barrierback(L, h, val);
return;
}
/* else will try the metamethod */
}
- else /* not a table; check metamethod */
+ else { /* not a table; check metamethod */
if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
luaG_typeerror(L, t, "index");
+ }
/* try the metamethod */
if (ttisfunction(tm)) {
luaT_callTM(L, tm, t, key, val, 0);
return;
}
t = tm; /* else repeat assignment over 'tm' */
+ if (luaV_fastset(L, t, key, slot, luaH_get, val))
+ return; /* done */
+ /* else loop */
}
- luaG_runerror(L, "settable chain too long; possible loop");
+ luaG_runerror(L, "'__newindex' chain too long; possible loop");
}
@@ -239,9 +247,9 @@ void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
*/
static int l_strcmp (const TString *ls, const TString *rs) {
const char *l = getstr(ls);
- size_t ll = ls->len;
+ size_t ll = tsslen(ls);
const char *r = getstr(rs);
- size_t lr = rs->len;
+ size_t lr = tsslen(rs);
for (;;) { /* for each segment */
int temp = strcoll(l, r);
if (temp != 0) /* not equal? */
@@ -261,15 +269,102 @@ static int l_strcmp (const TString *ls, const TString *rs) {
/*
+** Check whether integer 'i' is less than float 'f'. If 'i' has an
+** exact representation as a float ('l_intfitsf'), compare numbers as
+** floats. Otherwise, if 'f' is outside the range for integers, result
+** is trivial. Otherwise, compare them as integers. (When 'i' has no
+** float representation, either 'f' is "far away" from 'i' or 'f' has
+** no precision left for a fractional part; either way, how 'f' is
+** truncated is irrelevant.) When 'f' is NaN, comparisons must result
+** in false.
+*/
+static int LTintfloat (lua_Integer i, lua_Number f) {
+#if defined(l_intfitsf)
+ if (!l_intfitsf(i)) {
+ if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
+ return 1; /* f >= maxint + 1 > i */
+ else if (f > cast_num(LUA_MININTEGER)) /* minint < f <= maxint ? */
+ return (i < cast(lua_Integer, f)); /* compare them as integers */
+ else /* f <= minint <= i (or 'f' is NaN) --> not(i < f) */
+ return 0;
+ }
+#endif
+ return luai_numlt(cast_num(i), f); /* compare them as floats */
+}
+
+
+/*
+** Check whether integer 'i' is less than or equal to float 'f'.
+** See comments on previous function.
+*/
+static int LEintfloat (lua_Integer i, lua_Number f) {
+#if defined(l_intfitsf)
+ if (!l_intfitsf(i)) {
+ if (f >= -cast_num(LUA_MININTEGER)) /* -minint == maxint + 1 */
+ return 1; /* f >= maxint + 1 > i */
+ else if (f >= cast_num(LUA_MININTEGER)) /* minint <= f <= maxint ? */
+ return (i <= cast(lua_Integer, f)); /* compare them as integers */
+ else /* f < minint <= i (or 'f' is NaN) --> not(i <= f) */
+ return 0;
+ }
+#endif
+ return luai_numle(cast_num(i), f); /* compare them as floats */
+}
+
+
+/*
+** Return 'l < r', for numbers.
+*/
+static int LTnum (const TValue *l, const TValue *r) {
+ if (ttisinteger(l)) {
+ lua_Integer li = ivalue(l);
+ if (ttisinteger(r))
+ return li < ivalue(r); /* both are integers */
+ else /* 'l' is int and 'r' is float */
+ return LTintfloat(li, fltvalue(r)); /* l < r ? */
+ }
+ else {
+ lua_Number lf = fltvalue(l); /* 'l' must be float */
+ if (ttisfloat(r))
+ return luai_numlt(lf, fltvalue(r)); /* both are float */
+ else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
+ return 0; /* NaN < i is always false */
+ else /* without NaN, (l < r) <--> not(r <= l) */
+ return !LEintfloat(ivalue(r), lf); /* not (r <= l) ? */
+ }
+}
+
+
+/*
+** Return 'l <= r', for numbers.
+*/
+static int LEnum (const TValue *l, const TValue *r) {
+ if (ttisinteger(l)) {
+ lua_Integer li = ivalue(l);
+ if (ttisinteger(r))
+ return li <= ivalue(r); /* both are integers */
+ else /* 'l' is int and 'r' is float */
+ return LEintfloat(li, fltvalue(r)); /* l <= r ? */
+ }
+ else {
+ lua_Number lf = fltvalue(l); /* 'l' must be float */
+ if (ttisfloat(r))
+ return luai_numle(lf, fltvalue(r)); /* both are float */
+ else if (luai_numisnan(lf)) /* 'r' is int and 'l' is float */
+ return 0; /* NaN <= i is always false */
+ else /* without NaN, (l <= r) <--> not(r < l) */
+ return !LTintfloat(ivalue(r), lf); /* not (r < l) ? */
+ }
+}
+
+
+/*
** Main operation less than; return 'l < r'.
*/
int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
int res;
- lua_Number nl, nr;
- if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */
- return (ivalue(l) < ivalue(r));
- else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */
- return luai_numlt(nl, nr);
+ if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
+ return LTnum(l, r);
else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
return l_strcmp(tsvalue(l), tsvalue(r)) < 0;
else if ((res = luaT_callorderTM(L, l, r, TM_LT)) < 0) /* no metamethod? */
@@ -279,27 +374,34 @@ int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r) {
/*
-** Main operation less than or equal to; return 'l <= r'.
+** Main operation less than or equal to; return 'l <= r'. If it needs
+** a metamethod and there is no '__le', try '__lt', based on
+** l <= r iff !(r < l) (assuming a total order). If the metamethod
+** yields during this substitution, the continuation has to know
+** about it (to negate the result of r<l); bit CIST_LEQ in the call
+** status keeps that information.
*/
int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r) {
int res;
- lua_Number nl, nr;
- if (ttisinteger(l) && ttisinteger(r)) /* both operands are integers? */
- return (ivalue(l) <= ivalue(r));
- else if (tofloat(l, &nl) && tofloat(r, &nr)) /* both are numbers? */
- return luai_numle(nl, nr);
+ if (ttisnumber(l) && ttisnumber(r)) /* both operands are numbers? */
+ return LEnum(l, r);
else if (ttisstring(l) && ttisstring(r)) /* both are strings? */
return l_strcmp(tsvalue(l), tsvalue(r)) <= 0;
- else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* first try 'le' */
+ else if ((res = luaT_callorderTM(L, l, r, TM_LE)) >= 0) /* try 'le' */
return res;
- else if ((res = luaT_callorderTM(L, r, l, TM_LT)) < 0) /* else try 'lt' */
- luaG_ordererror(L, l, r);
- return !res;
+ else { /* try 'lt': */
+ L->ci->callstatus |= CIST_LEQ; /* mark it is doing 'lt' for 'le' */
+ res = luaT_callorderTM(L, r, l, TM_LT);
+ L->ci->callstatus ^= CIST_LEQ; /* clear mark */
+ if (res < 0)
+ luaG_ordererror(L, l, r);
+ return !res; /* result is negated */
+ }
}
/*
-** Main operation for equality of Lua values; return 't1 == t2'.
+** Main operation for equality of Lua values; return 't1 == t2'.
** L == NULL means raw equality (no metamethods)
*/
int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
@@ -308,10 +410,8 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
if (ttnov(t1) != ttnov(t2) || ttnov(t1) != LUA_TNUMBER)
return 0; /* only numbers can be equal with different variants */
else { /* two numbers with different variants */
- lua_Number n1, n2; /* compare them as floats */
- lua_assert(ttisnumber(t1) && ttisnumber(t2));
- cast_void(tofloat(t1, &n1)); cast_void(tofloat(t2, &n2));
- return luai_numeq(n1, n2);
+ lua_Integer i1, i2; /* compare them as integers */
+ return (tointeger(t1, &i1) && tointeger(t2, &i2) && i1 == i2);
}
}
/* values have same type and same variant */
@@ -354,6 +454,19 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
#define tostring(L,o) \
(ttisstring(o) || (cvt2str(o) && (luaO_tostring(L, o), 1)))
+#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0)
+
+/* copy strings in stack from top - n up to top - 1 to buffer */
+static void copy2buff (StkId top, int n, char *buff) {
+ size_t tl = 0; /* size already copied */
+ do {
+ size_t l = vslen(top - n); /* length of string being copied */
+ memcpy(buff + tl, svalue(top - n), l * sizeof(char));
+ tl += l;
+ } while (--n > 0);
+}
+
+
/*
** Main operation for concatenation: concat 'total' values in the stack,
** from 'L->top - total' up to 'L->top - 1'.
@@ -365,32 +478,32 @@ void luaV_concat (lua_State *L, int total) {
int n = 2; /* number of elements handled in this pass (at least 2) */
if (!(ttisstring(top-2) || cvt2str(top-2)) || !tostring(L, top-1))
luaT_trybinTM(L, top-2, top-1, top-2, TM_CONCAT);
- else if (tsvalue(top-1)->len == 0) /* second operand is empty? */
+ else if (isemptystr(top - 1)) /* second operand is empty? */
cast_void(tostring(L, top - 2)); /* result is first operand */
- else if (ttisstring(top-2) && tsvalue(top-2)->len == 0) {
+ else if (isemptystr(top - 2)) { /* first operand is an empty string? */
setobjs2s(L, top - 2, top - 1); /* result is second op. */
}
else {
/* at least two non-empty string values; get as many as possible */
- size_t tl = tsvalue(top-1)->len;
- char *buffer;
- int i;
- /* collect total length */
- for (i = 1; i < total && tostring(L, top-i-1); i++) {
- size_t l = tsvalue(top-i-1)->len;
+ size_t tl = vslen(top - 1);
+ TString *ts;
+ /* collect total length and number of strings */
+ for (n = 1; n < total && tostring(L, top - n - 1); n++) {
+ size_t l = vslen(top - n - 1);
if (l >= (MAX_SIZE/sizeof(char)) - tl)
luaG_runerror(L, "string length overflow");
tl += l;
}
- buffer = luaZ_openspace(L, &G(L)->buff, tl);
- tl = 0;
- n = i;
- do { /* copy all strings to buffer */
- size_t l = tsvalue(top-i)->len;
- memcpy(buffer+tl, svalue(top-i), l * sizeof(char));
- tl += l;
- } while (--i > 0);
- setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); /* create result */
+ if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
+ char buff[LUAI_MAXSHORTLEN];
+ copy2buff(top, n, buff); /* copy strings to buffer */
+ ts = luaS_newlstr(L, buff, tl);
+ }
+ else { /* long string; copy strings directly to final result */
+ ts = luaS_createlngstrobj(L, tl);
+ copy2buff(top, n, getstr(ts));
+ }
+ setsvalue2s(L, top - n, ts); /* create result */
}
total -= n-1; /* got 'n' strings to create 1 new */
L->top -= n-1; /* popped 'n' strings and pushed one */
@@ -403,7 +516,7 @@ void luaV_concat (lua_State *L, int total) {
*/
void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
const TValue *tm;
- switch (ttnov(rb)) {
+ switch (ttype(rb)) {
case LUA_TTABLE: {
Table *h = hvalue(rb);
tm = fasttm(L, h->metatable, TM_LEN);
@@ -411,8 +524,12 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
setivalue(ra, luaH_getn(h)); /* else primitive len */
return;
}
- case LUA_TSTRING: {
- setivalue(ra, tsvalue(rb)->len);
+ case LUA_TSHRSTR: {
+ setivalue(ra, tsvalue(rb)->shrlen);
+ return;
+ }
+ case LUA_TLNGSTR: {
+ setivalue(ra, tsvalue(rb)->u.lnglen);
return;
}
default: { /* try metamethod */
@@ -448,7 +565,7 @@ lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) {
/*
-** Integer modulus; return 'm % n'. (Assume that C '%' with
+** Integer modulus; return 'm % n'. (Assume that C '%' with
** negative operands follows C99 behavior. See previous comment
** about luaV_div.)
*/
@@ -553,11 +670,11 @@ void luaV_finishOp (lua_State *L) {
case OP_LE: case OP_LT: case OP_EQ: {
int res = !l_isfalse(L->top - 1);
L->top--;
- /* metamethod should not be called when operand is K */
- lua_assert(!ISK(GETARG_B(inst)));
- if (op == OP_LE && /* "<=" using "<" instead? */
- ttisnil(luaT_gettmbyobj(L, base + GETARG_B(inst), TM_LE)))
- res = !res; /* invert result */
+ if (ci->callstatus & CIST_LEQ) { /* "<=" using "<" instead? */
+ lua_assert(op == OP_LE);
+ ci->callstatus ^= CIST_LEQ; /* clear mark */
+ res = !res; /* negate result */
+ }
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_JMP);
if (res != GETARG_A(inst)) /* condition failed? */
ci->u.l.savedpc++; /* skip jump instruction */
@@ -607,27 +724,20 @@ void luaV_finishOp (lua_State *L) {
** some macros for common tasks in 'luaV_execute'
*/
-#if !defined luai_runtimecheck
-#define luai_runtimecheck(L, c) /* void */
-#endif
-
#define RA(i) (base+GETARG_A(i))
-/* to be used after possible stack reallocation */
#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
-#define KBx(i) \
- (k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++)))
/* execute a jump instruction */
#define dojump(ci,i,e) \
{ int a = GETARG_A(i); \
- if (a > 0) luaF_close(L, ci->u.l.base + a - 1); \
+ if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \
ci->u.l.savedpc += GETARG_sBx(i) + e; }
/* for test instructions, execute the jump instruction that follows it */
@@ -637,38 +747,58 @@ void luaV_finishOp (lua_State *L) {
#define Protect(x) { {x;}; base = ci->u.l.base; }
#define checkGC(L,c) \
- Protect( luaC_condGC(L,{L->top = (c); /* limit of live values */ \
- luaC_step(L); \
- L->top = ci->top;}) /* restore top */ \
- luai_threadyield(L); )
-
+ { luaC_condGC(L, L->top = (c), /* limit of live values */ \
+ Protect(L->top = ci->top)); /* restore top */ \
+ luai_threadyield(L); }
+
+
+/* fetch an instruction and prepare its execution */
+#define vmfetch() { \
+ i = *(ci->u.l.savedpc++); \
+ if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
+ Protect(luaG_traceexec(L)); \
+ ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
+ lua_assert(base == ci->u.l.base); \
+ lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
+}
#define vmdispatch(o) switch(o)
#define vmcase(l) case l:
#define vmbreak break
+
+/*
+** copy of 'luaV_gettable', but protecting the call to potential
+** metamethod (which can reallocate the stack)
+*/
+#define gettableProtected(L,t,k,v) { const TValue *slot; \
+ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
+ else Protect(luaV_finishget(L,t,k,v,slot)); }
+
+
+/* same for 'luaV_settable' */
+#define settableProtected(L,t,k,v) { const TValue *slot; \
+ if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
+ Protect(luaV_finishset(L,t,k,v,slot)); }
+
+
+
void luaV_execute (lua_State *L) {
CallInfo *ci = L->ci;
LClosure *cl;
TValue *k;
StkId base;
+ ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */
newframe: /* reentry point when frame changes (call/return) */
lua_assert(ci == L->ci);
- cl = clLvalue(ci->func);
- k = cl->p->k;
- base = ci->u.l.base;
+ cl = clLvalue(ci->func); /* local reference to function's closure */
+ k = cl->p->k; /* local reference to function's constant table */
+ base = ci->u.l.base; /* local copy of function's base */
/* main loop of interpreter */
for (;;) {
- Instruction i = *(ci->u.l.savedpc++);
+ Instruction i;
StkId ra;
- if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
- (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
- Protect(luaG_traceexec(L));
- }
- /* WARNING: several calls may realloc the stack and invalidate 'ra' */
- ra = RA(i);
- lua_assert(base == ci->u.l.base);
- lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
+ vmfetch();
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
setobjs2s(L, ra, RB(i));
@@ -704,17 +834,22 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_GETTABUP) {
- int b = GETARG_B(i);
- Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra));
+ TValue *upval = cl->upvals[GETARG_B(i)]->v;
+ TValue *rc = RKC(i);
+ gettableProtected(L, upval, rc, ra);
vmbreak;
}
vmcase(OP_GETTABLE) {
- Protect(luaV_gettable(L, RB(i), RKC(i), ra));
+ StkId rb = RB(i);
+ TValue *rc = RKC(i);
+ gettableProtected(L, rb, rc, ra);
vmbreak;
}
vmcase(OP_SETTABUP) {
- int a = GETARG_A(i);
- Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i)));
+ TValue *upval = cl->upvals[GETARG_A(i)]->v;
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ settableProtected(L, upval, rb, rc);
vmbreak;
}
vmcase(OP_SETUPVAL) {
@@ -724,7 +859,9 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_SETTABLE) {
- Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
+ TValue *rb = RKB(i);
+ TValue *rc = RKC(i);
+ settableProtected(L, ra, rb, rc);
vmbreak;
}
vmcase(OP_NEWTABLE) {
@@ -738,12 +875,18 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_SELF) {
+ const TValue *aux;
StkId rb = RB(i);
- setobjs2s(L, ra+1, rb);
- Protect(luaV_gettable(L, rb, RKC(i), ra));
+ TValue *rc = RKC(i);
+ TString *key = tsvalue(rc); /* key must be a string */
+ setobjs2s(L, ra + 1, rb);
+ if (luaV_fastget(L, rb, key, aux, luaH_getstr)) {
+ setobj2s(L, ra, aux);
+ }
+ else Protect(luaV_finishget(L, rb, rc, ra, aux));
vmbreak;
}
- vmcase(OP_ADD) {
+ vmcase(OP_ADD) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
lua_Number nb; lua_Number nc;
@@ -927,8 +1070,8 @@ void luaV_execute (lua_State *L) {
StkId rb;
L->top = base + c + 1; /* mark the end of concat operands */
Protect(luaV_concat(L, c - b + 1));
- ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */
- rb = b + base;
+ ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */
+ rb = base + b;
setobjs2s(L, ra, rb);
checkGC(L, (ra >= rb ? ra + 1 : rb));
L->top = ci->top; /* restore top */
@@ -942,7 +1085,7 @@ void luaV_execute (lua_State *L) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
Protect(
- if (cast_int(luaV_equalobj(L, rb, rc)) != GETARG_A(i))
+ if (luaV_equalobj(L, rb, rc) != GETARG_A(i))
ci->u.l.savedpc++;
else
donextjump(ci);
@@ -989,12 +1132,12 @@ void luaV_execute (lua_State *L) {
int nresults = GETARG_C(i) - 1;
if (b != 0) L->top = ra+b; /* else previous instruction set top */
if (luaD_precall(L, ra, nresults)) { /* C function? */
- if (nresults >= 0) L->top = ci->top; /* adjust results */
- base = ci->u.l.base;
+ if (nresults >= 0)
+ L->top = ci->top; /* adjust results */
+ Protect((void)0); /* update 'base' */
}
else { /* Lua function */
ci = L->ci;
- ci->callstatus |= CIST_REENTRY;
goto newframe; /* restart luaV_execute over new Lua function */
}
vmbreak;
@@ -1003,8 +1146,9 @@ void luaV_execute (lua_State *L) {
int b = GETARG_B(i);
if (b != 0) L->top = ra+b; /* else previous instruction set top */
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
- if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */
- base = ci->u.l.base;
+ if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */
+ Protect((void)0); /* update 'base' */
+ }
else {
/* tail call: put called frame (n) in place of caller one (o) */
CallInfo *nci = L->ci; /* called frame */
@@ -1031,10 +1175,9 @@ void luaV_execute (lua_State *L) {
}
vmcase(OP_RETURN) {
int b = GETARG_B(i);
- if (b != 0) L->top = ra+b-1;
if (cl->p->sizep > 0) luaF_close(L, base);
- b = luaD_poscall(L, ra);
- if (!(ci->callstatus & CIST_REENTRY)) /* 'ci' still the called one */
+ b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
+ if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */
return; /* external invocation: return */
else { /* invocation via reentry: continue execution */
ci = L->ci;
@@ -1047,11 +1190,11 @@ void luaV_execute (lua_State *L) {
vmcase(OP_FORLOOP) {
if (ttisinteger(ra)) { /* integer loop? */
lua_Integer step = ivalue(ra + 2);
- lua_Integer idx = ivalue(ra) + step; /* increment index */
+ lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */
lua_Integer limit = ivalue(ra + 1);
if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
- setivalue(ra, idx); /* update internal index... */
+ chgivalue(ra, idx); /* update internal index... */
setivalue(ra + 3, idx); /* ...and external index */
}
}
@@ -1062,7 +1205,7 @@ void luaV_execute (lua_State *L) {
if (luai_numlt(0, step) ? luai_numle(idx, limit)
: luai_numle(limit, idx)) {
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
- setfltvalue(ra, idx); /* update internal index... */
+ chgfltvalue(ra, idx); /* update internal index... */
setfltvalue(ra + 3, idx); /* ...and external index */
}
}
@@ -1079,7 +1222,7 @@ void luaV_execute (lua_State *L) {
/* all values are integer */
lua_Integer initv = (stopnow ? 0 : ivalue(init));
setivalue(plimit, ilimit);
- setivalue(init, initv - ivalue(pstep));
+ setivalue(init, intop(-, initv, ivalue(pstep)));
}
else { /* try making all values floats */
lua_Number ninit; lua_Number nlimit; lua_Number nstep;
@@ -1102,7 +1245,7 @@ void luaV_execute (lua_State *L) {
setobjs2s(L, cb+1, ra+1);
setobjs2s(L, cb, ra);
L->top = cb + 3; /* func. + 2 args (state and index) */
- Protect(luaD_call(L, cb, GETARG_C(i), 1));
+ Protect(luaD_call(L, cb, GETARG_C(i)));
L->top = ci->top;
i = *(ci->u.l.savedpc++); /* go to next instruction */
ra = RA(i);
@@ -1127,11 +1270,10 @@ void luaV_execute (lua_State *L) {
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
c = GETARG_Ax(*ci->u.l.savedpc++);
}
- luai_runtimecheck(L, ttistable(ra));
h = hvalue(ra);
last = ((c-1)*LFIELDS_PER_FLUSH) + n;
if (last > h->sizearray) /* needs more space? */
- luaH_resizearray(L, h, last); /* pre-allocate it at once */
+ luaH_resizearray(L, h, last); /* preallocate it at once */
for (; n > 0; n--) {
TValue *val = ra+n;
luaH_setint(L, h, last--, val);
@@ -1151,23 +1293,21 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_VARARG) {
- int b = GETARG_B(i) - 1;
+ int b = GETARG_B(i) - 1; /* required results */
int j;
int n = cast_int(base - ci->func) - cl->p->numparams - 1;
+ if (n < 0) /* less arguments than parameters? */
+ n = 0; /* no vararg arguments */
if (b < 0) { /* B == 0? */
b = n; /* get all var. arguments */
Protect(luaD_checkstack(L, n));
ra = RA(i); /* previous call may change the stack */
L->top = ra + n;
}
- for (j = 0; j < b; j++) {
- if (j < n) {
- setobjs2s(L, ra + j, base - n + j);
- }
- else {
- setnilvalue(ra + j);
- }
- }
+ for (j = 0; j < b && j < n; j++)
+ setobjs2s(L, ra + j, base - n + j);
+ for (; j < b; j++) /* complete required results with nil */
+ setnilvalue(ra + j);
vmbreak;
}
vmcase(OP_EXTRAARG) {
diff --git a/src/lvm.h b/src/lvm.h
index 5c5e18c3ac7c..422f87194918 100644
--- a/src/lvm.h
+++ b/src/lvm.h
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.h,v 2.34 2014/08/01 17:24:02 roberto Exp $
+** $Id: lvm.h,v 2.41 2016/12/22 13:08:50 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -27,26 +27,81 @@
#endif
+/*
+** You can define LUA_FLOORN2I if you want to convert floats to integers
+** by flooring them (instead of raising an error if they are not
+** integral values)
+*/
+#if !defined(LUA_FLOORN2I)
+#define LUA_FLOORN2I 0
+#endif
+
+
#define tonumber(o,n) \
(ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o,n))
#define tointeger(o,i) \
- (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger_(o,i))
+ (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I))
#define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))
#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)
+/*
+** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
+** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
+** return 0 (meaning it will have to check metamethod) with 'slot'
+** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
+** 'f' is the raw get function to use.
+*/
+#define luaV_fastget(L,t,k,slot,f) \
+ (!ttistable(t) \
+ ? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
+ : (slot = f(hvalue(t), k), /* else, do raw access */ \
+ !ttisnil(slot))) /* result not nil? */
+
+/*
+** standard implementation for 'gettable'
+*/
+#define luaV_gettable(L,t,k,v) { const TValue *slot; \
+ if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
+ else luaV_finishget(L,t,k,v,slot); }
+
+
+/*
+** Fast track for set table. If 't' is a table and 't[k]' is not nil,
+** call GC barrier, do a raw 't[k]=v', and return true; otherwise,
+** return false with 'slot' equal to NULL (if 't' is not a table) or
+** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro
+** returns true, there is no need to 'invalidateTMcache', because the
+** call is not creating a new entry.
+*/
+#define luaV_fastset(L,t,k,slot,f,v) \
+ (!ttistable(t) \
+ ? (slot = NULL, 0) \
+ : (slot = f(hvalue(t), k), \
+ ttisnil(slot) ? 0 \
+ : (luaC_barrierback(L, hvalue(t), v), \
+ setobj2t(L, cast(TValue *,slot), v), \
+ 1)))
+
+
+#define luaV_settable(L,t,k,v) { const TValue *slot; \
+ if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
+ luaV_finishset(L,t,k,v,slot); }
+
+
+
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
-LUAI_FUNC int luaV_tointeger_ (const TValue *obj, lua_Integer *p);
-LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
- StkId val);
-LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
- StkId val);
+LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
+LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
+ StkId val, const TValue *slot);
+LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
+ StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total);
diff --git a/src/lzio.c b/src/lzio.c
index 46493920f414..c9e1f491f34d 100644
--- a/src/lzio.c
+++ b/src/lzio.c
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.c,v 1.36 2014/11/02 19:19:04 roberto Exp $
+** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -66,13 +66,3 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) {
return 0;
}
-/* ------------------------------------------------------------------------ */
-char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) {
- if (n > buff->buffsize) {
- if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
- luaZ_resizebuffer(L, buff, n);
- }
- return buff->buffer;
-}
-
-
diff --git a/src/lzio.h b/src/lzio.h
index b2e56bcd6e39..e7b6f34b1e3c 100644
--- a/src/lzio.h
+++ b/src/lzio.h
@@ -1,5 +1,5 @@
/*
-** $Id: lzio.h,v 1.30 2014/12/19 17:26:14 roberto Exp $
+** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -44,7 +44,6 @@ typedef struct Mbuffer {
#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0)
-LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n);
LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
void *data);
LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */