From 71b9532659abb531bd1597d88451426dcc895824 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Tue, 5 Jan 2021 16:48:53 +0800 Subject: update Lua. --- src/lua/lapi.c | 29 +++++++++------ src/lua/lauxlib.c | 96 +++++++++++++++++++++++++++++++++---------------- src/lua/lauxlib.h | 16 +++++++++ src/lua/lcode.c | 28 +++++++++------ src/lua/ldblib.c | 4 +-- src/lua/ldo.c | 18 +++++----- src/lua/lgc.c | 4 +-- src/lua/liolib.c | 18 ++++++---- src/lua/llex.c | 56 +++++++++++++++-------------- src/lua/llimits.h | 3 +- src/lua/lobject.c | 2 +- src/lua/lparser.c | 104 +++++++++++++++++------------------------------------- src/lua/lparser.h | 11 +++--- src/lua/lstate.c | 11 +++--- src/lua/ltable.c | 69 +++++++++++++++++++++++------------- src/lua/ltable.h | 8 +++-- src/lua/lualib.h | 6 ---- src/lua/lvm.c | 5 +-- 18 files changed, 270 insertions(+), 218 deletions(-) diff --git a/src/lua/lapi.c b/src/lua/lapi.c index c824da2..03e756d 100644 --- a/src/lua/lapi.c +++ b/src/lua/lapi.c @@ -629,11 +629,21 @@ static int auxgetstr (lua_State *L, const TValue *t, const char *k) { } +/* +** Get the global table in the registry. Since all predefined +** indices in the registry were inserted right when the registry +** was created and never removed, they must always be in the array +** part of the registry. +*/ +#define getGtable(L) \ + (&hvalue(&G(L)->l_registry)->array[LUA_RIDX_GLOBALS - 1]) + + LUA_API int lua_getglobal (lua_State *L, const char *name) { - Table *reg; + const TValue *G; lua_lock(L); - reg = hvalue(&G(L)->l_registry); - return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); + G = getGtable(L); + return auxgetstr(L, G, name); } @@ -811,10 +821,10 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) { LUA_API void lua_setglobal (lua_State *L, const char *name) { - Table *reg; + const TValue *G; lua_lock(L); /* unlock done in 'auxsetstr' */ - reg = hvalue(&G(L)->l_registry); - auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name); + G = getGtable(L); + auxsetstr(L, G, name); } @@ -861,12 +871,10 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) { static void aux_rawset (lua_State *L, int idx, TValue *key, int n) { Table *t; - TValue *slot; lua_lock(L); api_checknelems(L, n); t = gettable(L, idx); - slot = luaH_set(L, t, key); - setobj2t(L, slot, s2v(L->top - 1)); + luaH_set(L, t, key, s2v(L->top - 1)); invalidateTMcache(t); luaC_barrierback(L, obj2gco(t), s2v(L->top - 1)); L->top -= n; @@ -1063,8 +1071,7 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data, LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */ if (f->nupvalues >= 1) { /* does it have an upvalue? */ /* get global table from registry */ - Table *reg = hvalue(&G(L)->l_registry); - const TValue *gt = luaH_getint(reg, LUA_RIDX_GLOBALS); + const TValue *gt = getGtable(L); /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ setobj(L, f->upvals[0]->v, gt); luaC_barrier(L, f->upvals[0], gt); diff --git a/src/lua/lauxlib.c b/src/lua/lauxlib.c index cbe9ed3..074ff08 100644 --- a/src/lua/lauxlib.c +++ b/src/lua/lauxlib.c @@ -283,10 +283,10 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { LUALIB_API int luaL_execresult (lua_State *L, int stat) { - const char *what = "exit"; /* type of termination */ if (stat != 0 && errno != 0) /* error with an 'errno'? */ return luaL_fileresult(L, 0, NULL); else { + const char *what = "exit"; /* type of termination */ l_inspectstat(stat, what); /* interpret result */ if (*what == 'e' && stat == 0) /* successful termination? */ lua_pushboolean(L, 1); @@ -639,10 +639,14 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { ** ======================================================= */ -/* index of free-list header */ -#define freelist 0 - +/* index of free-list header (after the predefined values) */ +#define freelist (LUA_RIDX_LAST + 1) +/* +** The previously freed references form a linked list: +** t[freelist] is the index of a first free index, or zero if list is +** empty; t[t[freelist]] is the index of the second element; etc. +*/ LUALIB_API int luaL_ref (lua_State *L, int t) { int ref; if (lua_isnil(L, -1)) { @@ -650,9 +654,16 @@ LUALIB_API int luaL_ref (lua_State *L, int t) { return LUA_REFNIL; /* 'nil' has a unique fixed reference */ } t = lua_absindex(L, t); - lua_rawgeti(L, t, freelist); /* get first free element */ - ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ - lua_pop(L, 1); /* remove it from stack */ + if (lua_rawgeti(L, t, freelist) == LUA_TNIL) { /* first access? */ + ref = 0; /* list is empty */ + lua_pushinteger(L, 0); /* initialize as an empty list */ + lua_rawseti(L, t, freelist); /* ref = t[freelist] = 0 */ + } + else { /* already initialized */ + lua_assert(lua_isinteger(L, -1)); + ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */ + } + lua_pop(L, 1); /* remove element from stack */ if (ref != 0) { /* any free element? */ lua_rawgeti(L, t, ref); /* remove it from list */ lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */ @@ -668,6 +679,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { if (ref >= 0) { t = lua_absindex(L, t); lua_rawgeti(L, t, freelist); + lua_assert(lua_isinteger(L, -1)); lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */ lua_pushinteger(L, ref); lua_rawseti(L, t, freelist); /* t[freelist] = ref */ @@ -1006,43 +1018,67 @@ static int panic (lua_State *L) { /* -** Emit a warning. '*warnstate' means: -** 0 - warning system is off; -** 1 - ready to start a new message; -** 2 - previous message is to be continued. +** Warning functions: +** warnfoff: warning system is off +** warnfon: ready to start a new message +** warnfcont: previous message is to be continued */ -static void warnf (void *ud, const char *message, int tocont) { - int *warnstate = (int *)ud; - if (*warnstate != 2 && !tocont && *message == '@') { /* control message? */ - if (strcmp(message, "@off") == 0) - *warnstate = 0; - else if (strcmp(message, "@on") == 0) - *warnstate = 1; - return; +static void warnfoff (void *ud, const char *message, int tocont); +static void warnfon (void *ud, const char *message, int tocont); +static void warnfcont (void *ud, const char *message, int tocont); + + +/* +** Check whether message is a control message. If so, execute the +** control or ignore it if unknown. +*/ +static int checkcontrol (lua_State *L, const char *message, int tocont) { + if (tocont || *(message++) != '@') /* not a control message? */ + return 0; + else { + if (strcmp(message, "off") == 0) + lua_setwarnf(L, warnfoff, L); /* turn warnings off */ + else if (strcmp(message, "on") == 0) + lua_setwarnf(L, warnfon, L); /* turn warnings on */ + return 1; /* it was a control message */ } - else if (*warnstate == 0) /* warnings off? */ - return; - if (*warnstate == 1) /* previous message was the last? */ - lua_writestringerror("%s", "Lua warning: "); /* start a new warning */ +} + + +static void warnfoff (void *ud, const char *message, int tocont) { + checkcontrol((lua_State *)ud, message, tocont); +} + + +/* +** Writes the message and handle 'tocont', finishing the message +** if needed and setting the next warn function. +*/ +static void warnfcont (void *ud, const char *message, int tocont) { + lua_State *L = (lua_State *)ud; lua_writestringerror("%s", message); /* write message */ if (tocont) /* not the last part? */ - *warnstate = 2; /* to be continued */ + lua_setwarnf(L, warnfcont, L); /* to be continued */ else { /* last part */ lua_writestringerror("%s", "\n"); /* finish message with end-of-line */ - *warnstate = 1; /* ready to start a new message */ + lua_setwarnf(L, warnfon, L); /* next call is a new message */ } } +static void warnfon (void *ud, const char *message, int tocont) { + if (checkcontrol((lua_State *)ud, message, tocont)) /* control message? */ + return; /* nothing else to be done */ + lua_writestringerror("%s", "Lua warning: "); /* start a new warning */ + warnfcont(ud, message, tocont); /* finish processing */ +} + + LUALIB_API lua_State *luaL_newstate (void) { lua_State *L = lua_newstate(l_alloc, NULL); if (L) { - int *warnstate; /* space for warning state */ lua_atpanic(L, &panic); - warnstate = (int *)lua_newuserdatauv(L, sizeof(int), 0); - luaL_ref(L, LUA_REGISTRYINDEX); /* make sure it won't be collected */ - *warnstate = 0; /* default is warnings off */ - lua_setwarnf(L, warnf, warnstate); + lua_setwarnf(L, warnfoff, L); /* default is warnings off */ } return L; } diff --git a/src/lua/lauxlib.h b/src/lua/lauxlib.h index 59fef6a..6571491 100644 --- a/src/lua/lauxlib.h +++ b/src/lua/lauxlib.h @@ -157,6 +157,22 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, #define luaL_pushfail(L) lua_pushnil(L) +/* +** Internal assertions for in-house debugging +*/ +#if !defined(lua_assert) + +#if defined LUAI_ASSERT + #include + #define lua_assert(c) assert(c) +#else + #define lua_assert(c) ((void)0) +#endif + +#endif + + + /* ** {====================================================== ** Generic Buffer manipulation diff --git a/src/lua/lcode.c b/src/lua/lcode.c index 6f241c9..d8d353f 100644 --- a/src/lua/lcode.c +++ b/src/lua/lcode.c @@ -545,11 +545,14 @@ static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { ** 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. +** Note that all functions share the same table, so entering or exiting +** a function can make some indices wrong. */ static int addk (FuncState *fs, TValue *key, TValue *v) { + TValue val; lua_State *L = fs->ls->L; Proto *f = fs->f; - TValue *idx = luaH_set(L, fs->ls->h, key); /* index scanner table */ + const TValue *idx = luaH_get(fs->ls->h, key); /* query scanner table */ int k, oldsize; if (ttisinteger(idx)) { /* is there an index there? */ k = cast_int(ivalue(idx)); @@ -563,7 +566,8 @@ static int addk (FuncState *fs, TValue *key, TValue *v) { k = fs->nk; /* numerical value does not need GC barrier; table has no metatable, so it does not need to invalidate cache */ - setivalue(idx, k); + setivalue(&val, k); + luaH_finishset(L, fs->ls->h, key, idx, &val); luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants"); while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); setobj(L, &f->k[k], v); @@ -753,7 +757,7 @@ void luaK_setoneret (FuncState *fs, expdesc *e) { /* -** Ensure that expression 'e' is not a variable (nor a constant). +** Ensure that expression 'e' is not a variable (nor a ). ** (Expression still may have jump lists.) */ void luaK_dischargevars (FuncState *fs, expdesc *e) { @@ -763,7 +767,7 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { break; } case VLOCAL: { /* already in a register */ - e->u.info = e->u.var.sidx; + e->u.info = e->u.var.ridx; e->k = VNONRELOC; /* becomes a non-relocatable value */ break; } @@ -805,8 +809,8 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { /* -** Ensures expression value is in register 'reg' (and therefore -** 'e' will become a non-relocatable expression). +** Ensure expression value is in register 'reg', making 'e' a +** non-relocatable expression. ** (Expression still may have jump lists.) */ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { @@ -860,7 +864,8 @@ static void discharge2reg (FuncState *fs, expdesc *e, int reg) { /* -** Ensures expression value is in any register. +** Ensure expression value is in a register, making 'e' a +** non-relocatable expression. ** (Expression still may have jump lists.) */ static void discharge2anyreg (FuncState *fs, expdesc *e) { @@ -946,8 +951,11 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) { exp2reg(fs, e, e->u.info); /* put final result in it */ return e->u.info; } + /* else expression has jumps and cannot change its register + to hold the jump values, because it is a local variable. + Go through to the default case. */ } - luaK_exp2nextreg(fs, e); /* otherwise, use next available register */ + luaK_exp2nextreg(fs, e); /* default: use next available register */ return e->u.info; } @@ -1032,7 +1040,7 @@ void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { switch (var->k) { case VLOCAL: { freeexp(fs, ex); - exp2reg(fs, ex, var->u.var.sidx); /* compute 'ex' into proper place */ + exp2reg(fs, ex, var->u.var.ridx); /* compute 'ex' into proper place */ return; } case VUPVAL: { @@ -1272,7 +1280,7 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { } else { /* register index of the table */ - t->u.ind.t = (t->k == VLOCAL) ? t->u.var.sidx: t->u.info; + t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info; if (isKstr(fs, k)) { t->u.ind.idx = k->u.info; /* literal string */ t->k = VINDEXSTR; diff --git a/src/lua/ldblib.c b/src/lua/ldblib.c index 5a326ad..15593bf 100644 --- a/src/lua/ldblib.c +++ b/src/lua/ldblib.c @@ -377,7 +377,7 @@ static int db_sethook (lua_State *L) { } if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) { /* table just created; initialize it */ - lua_pushstring(L, "k"); + lua_pushliteral(L, "k"); lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */ lua_pushvalue(L, -1); lua_setmetatable(L, -2); /* metatable(hooktable) = hooktable */ @@ -420,7 +420,7 @@ static int db_debug (lua_State *L) { for (;;) { char buffer[250]; lua_writestringerror("%s", "lua_debug> "); - if (fgets(buffer, sizeof(buffer), stdin) == 0 || + if (fgets(buffer, sizeof(buffer), stdin) == NULL || strcmp(buffer, "cont\n") == 0) return 0; if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || diff --git a/src/lua/ldo.c b/src/lua/ldo.c index 5729b19..4b55c31 100644 --- a/src/lua/ldo.c +++ b/src/lua/ldo.c @@ -192,7 +192,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { else return 0; /* do not raise an error */ } for (; lim < newsize; lim++) - setnilvalue(s2v(newstack + lim)); /* erase new segment */ + setnilvalue(s2v(newstack + lim + EXTRA_STACK)); /* erase new segment */ correctstack(L, L->stack, newstack); L->stack = newstack; L->stack_last = L->stack + newsize; @@ -534,11 +534,11 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { /* -** Call a function (C or Lua). 'inc' can be 1 (increment number -** of recursive invocations in the C stack) or nyci (the same plus -** increment number of non-yieldable calls). +** Call a function (C or Lua) through C. 'inc' can be 1 (increment +** number of recursive invocations in the C stack) or nyci (the same +** plus increment number of non-yieldable calls). */ -static void docall (lua_State *L, StkId func, int nResults, int inc) { +static void ccall (lua_State *L, StkId func, int nResults, int inc) { CallInfo *ci; L->nCcalls += inc; if (unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) @@ -552,10 +552,10 @@ static void docall (lua_State *L, StkId func, int nResults, int inc) { /* -** External interface for 'docall' +** External interface for 'ccall' */ void luaD_call (lua_State *L, StkId func, int nResults) { - return docall(L, func, nResults, 1); + ccall(L, func, nResults, 1); } @@ -563,7 +563,7 @@ void luaD_call (lua_State *L, StkId func, int nResults) { ** Similar to 'luaD_call', but does not allow yields during the call. */ void luaD_callnoyield (lua_State *L, StkId func, int nResults) { - return docall(L, func, nResults, nyci); + ccall(L, func, nResults, nyci); } @@ -678,7 +678,7 @@ static void resume (lua_State *L, void *ud) { StkId firstArg = L->top - n; /* first argument */ CallInfo *ci = L->ci; if (L->status == LUA_OK) /* starting a coroutine? */ - docall(L, firstArg - 1, LUA_MULTRET, 1); /* just call its body */ + ccall(L, firstArg - 1, LUA_MULTRET, 1); /* just call its body */ else { /* resuming from previous yield */ lua_assert(L->status == LUA_YIELD); L->status = LUA_OK; /* mark that it is running (again) */ diff --git a/src/lua/lgc.c b/src/lua/lgc.c index 5dba56f..bab9beb 100644 --- a/src/lua/lgc.c +++ b/src/lua/lgc.c @@ -632,8 +632,8 @@ static int traversethread (global_State *g, lua_State *th) { for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) markobject(g, uv); /* open upvalues cannot be collected */ if (g->gcstate == GCSatomic) { /* final traversal? */ - for (; o < th->stack_last; o++) /* clear not-marked stack slice */ - setnilvalue(s2v(o)); + for (; o < th->stack_last + EXTRA_STACK; o++) + setnilvalue(s2v(o)); /* clear dead stack slice */ /* 'remarkupvals' may have removed thread from 'twups' list */ if (!isintwups(th) && th->openupval != NULL) { th->twups = g->twups; /* link it back to the list */ diff --git a/src/lua/liolib.c b/src/lua/liolib.c index 60ab1bf..7951672 100644 --- a/src/lua/liolib.c +++ b/src/lua/liolib.c @@ -52,12 +52,6 @@ static int l_checkmode (const char *mode) { ** ======================================================= */ -#if !defined(l_checkmodep) -/* By default, Lua accepts only "r" or "w" as mode */ -#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0') -#endif - - #if !defined(l_popen) /* { */ #if defined(LUA_USE_POSIX) /* { */ @@ -70,6 +64,12 @@ static int l_checkmode (const char *mode) { #define l_popen(L,c,m) (_popen(c,m)) #define l_pclose(L,file) (_pclose(file)) +#if !defined(l_checkmodep) +/* Windows accepts "[rw][bt]?" as valid modes */ +#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && \ + (m[1] == '\0' || ((m[1] == 'b' || m[1] == 't') && m[2] == '\0'))) +#endif + #else /* }{ */ /* ISO C definitions */ @@ -83,6 +83,12 @@ static int l_checkmode (const char *mode) { #endif /* } */ + +#if !defined(l_checkmodep) +/* By default, Lua accepts only "r" or "w" as valid modes */ +#define l_checkmodep(m) ((m[0] == 'r' || m[0] == 'w') && m[1] == '\0') +#endif + /* }====================================================== */ diff --git a/src/lua/llex.c b/src/lua/llex.c index 3d6b2b9..e991517 100644 --- a/src/lua/llex.c +++ b/src/lua/llex.c @@ -122,26 +122,29 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) { /* -** creates a new string and anchors it in scanner's table so that -** it will not be collected until the end of the compilation -** (by that time it should be anchored somewhere) +** Creates a new string and anchors it in scanner's table so that it +** will not be collected until the end of the compilation; by that time +** it should be anchored somewhere. It also internalizes long strings, +** ensuring there is only one copy of each unique string. The table +** here is used as a set: the string enters as the key, while its value +** is irrelevant. We use the string itself as the value only because it +** is a TValue readly available. Later, the code generation can change +** this value. */ TString *luaX_newstring (LexState *ls, const char *str, size_t l) { lua_State *L = ls->L; - TValue *o; /* entry for 'str' */ TString *ts = luaS_newlstr(L, str, l); /* create new string */ - setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */ - o = luaH_set(L, ls->h, s2v(L->top - 1)); - if (isempty(o)) { /* not in use yet? */ - /* boolean value does not need GC barrier; - table is not a metatable, so it does not need to invalidate cache */ - setbtvalue(o); /* t[string] = true */ + const TValue *o = luaH_getstr(ls->h, ts); + if (!ttisnil(o)) /* string already present? */ + ts = keystrval(nodefromval(o)); /* get saved copy */ + else { /* not in use yet */ + TValue *stv = s2v(L->top++); /* reserve stack space for string */ + setsvalue(L, stv, ts); /* temporarily anchor the string */ + luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */ + /* table is not a metatable, so it does not need to invalidate cache */ luaC_checkGC(L); + L->top--; /* remove string from stack */ } - else { /* string already present */ - ts = keystrval(nodefromval(o)); /* re-use value previously stored */ - } - L->top--; /* remove string from stack */ return ts; } @@ -254,9 +257,10 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) { /* -** reads a sequence '[=*[' or ']=*]', leaving the last bracket. -** If sequence is well formed, return its number of '='s + 2; otherwise, -** return 1 if there is no '='s or 0 otherwise (an unfinished '[==...'). +** read a sequence '[=*[' or ']=*]', leaving the last bracket. If +** sequence is well formed, return its number of '='s + 2; otherwise, +** return 1 if it is a single bracket (no '='s and no 2nd bracket); +** otherwise (an unfinished '[==...') return 0. */ static size_t skip_sep (LexState *ls) { size_t count = 0; @@ -481,34 +485,34 @@ static int llex (LexState *ls, SemInfo *seminfo) { } case '=': { next(ls); - if (check_next1(ls, '=')) return TK_EQ; + if (check_next1(ls, '=')) return TK_EQ; /* '==' */ else return '='; } case '<': { next(ls); - if (check_next1(ls, '=')) return TK_LE; - else if (check_next1(ls, '<')) return TK_SHL; + if (check_next1(ls, '=')) return TK_LE; /* '<=' */ + else if (check_next1(ls, '<')) return TK_SHL; /* '<<' */ else return '<'; } case '>': { next(ls); - if (check_next1(ls, '=')) return TK_GE; - else if (check_next1(ls, '>')) return TK_SHR; + if (check_next1(ls, '=')) return TK_GE; /* '>=' */ + else if (check_next1(ls, '>')) return TK_SHR; /* '>>' */ else return '>'; } case '/': { next(ls); - if (check_next1(ls, '/')) return TK_IDIV; + if (check_next1(ls, '/')) return TK_IDIV; /* '//' */ else return '/'; } case '~': { next(ls); - if (check_next1(ls, '=')) return TK_NE; + if (check_next1(ls, '=')) return TK_NE; /* '~=' */ else return '~'; } case ':': { next(ls); - if (check_next1(ls, ':')) return TK_DBCOLON; + if (check_next1(ls, ':')) return TK_DBCOLON; /* '::' */ else return ':'; } case '"': case '\'': { /* short literal strings */ @@ -547,7 +551,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { return TK_NAME; } } - else { /* single-char tokens (+ - / ...) */ + else { /* single-char tokens ('+', '*', '%', '{', '}', ...) */ int c = ls->current; next(ls); return c; diff --git a/src/lua/llimits.h b/src/lua/llimits.h index a76c13e..d039483 100644 --- a/src/lua/llimits.h +++ b/src/lua/llimits.h @@ -326,7 +326,8 @@ typedef l_uint32 Instruction; /* exponentiation */ #if !defined(luai_numpow) -#define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b)) +#define luai_numpow(L,a,b) \ + ((void)L, (b == 2) ? (a)*(a) : l_mathop(pow)(a,b)) #endif /* the others are quite standard operations */ diff --git a/src/lua/lobject.c b/src/lua/lobject.c index f8ea917..0e504be 100644 --- a/src/lua/lobject.c +++ b/src/lua/lobject.c @@ -258,7 +258,7 @@ static const char *l_str2d (const char *s, lua_Number *result) { 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) + if (pdot == NULL || strlen(s) > L_MAXLENNUM) return NULL; /* string too long or no dot; fail */ strcpy(buff, s); /* copy string to buffer */ buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */ diff --git a/src/lua/lparser.c b/src/lua/lparser.c index bcdcfb6..249ba9a 100644 --- a/src/lua/lparser.c +++ b/src/lua/lparser.c @@ -222,26 +222,26 @@ static Vardesc *getlocalvardesc (FuncState *fs, int vidx) { /* -** Convert 'nvar', a compiler index level, to it corresponding -** stack index level. For that, search for the highest variable -** below that level that is in the stack and uses its stack -** index ('sidx'). +** Convert 'nvar', a compiler index level, to its corresponding +** register. For that, search for the highest variable below that level +** that is in a register and uses its register index ('ridx') plus one. */ -static int stacklevel (FuncState *fs, int nvar) { +static int reglevel (FuncState *fs, int nvar) { while (nvar-- > 0) { - Vardesc *vd = getlocalvardesc(fs, nvar); /* get variable */ - if (vd->vd.kind != RDKCTC) /* is in the stack? */ - return vd->vd.sidx + 1; + Vardesc *vd = getlocalvardesc(fs, nvar); /* get previous variable */ + if (vd->vd.kind != RDKCTC) /* is in a register? */ + return vd->vd.ridx + 1; } - return 0; /* no variables in the stack */ + return 0; /* no variables in registers */ } /* -** Return the number of variables in the stack for function 'fs' +** Return the number of variables in the register stack for the given +** function. */ int luaY_nvarstack (FuncState *fs) { - return stacklevel(fs, fs->nactvar); + return reglevel(fs, fs->nactvar); } @@ -267,7 +267,7 @@ static void init_var (FuncState *fs, expdesc *e, int vidx) { e->f = e->t = NO_JUMP; e->k = VLOCAL; e->u.var.vidx = vidx; - e->u.var.sidx = getlocalvardesc(fs, vidx)->vd.sidx; + e->u.var.ridx = getlocalvardesc(fs, vidx)->vd.ridx; } @@ -310,12 +310,12 @@ static void check_readonly (LexState *ls, expdesc *e) { */ static void adjustlocalvars (LexState *ls, int nvars) { FuncState *fs = ls->fs; - int stklevel = luaY_nvarstack(fs); + int reglevel = luaY_nvarstack(fs); int i; for (i = 0; i < nvars; i++) { int vidx = fs->nactvar++; Vardesc *var = getlocalvardesc(fs, vidx); - var->vd.sidx = stklevel++; + var->vd.ridx = reglevel++; var->vd.pidx = registerlocalvar(ls, fs, var->vd.name); } } @@ -366,7 +366,7 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { FuncState *prev = fs->prev; if (v->k == VLOCAL) { up->instack = 1; - up->idx = v->u.var.sidx; + up->idx = v->u.var.ridx; up->kind = getlocalvardesc(prev, v->u.var.vidx)->vd.kind; lua_assert(eqstr(name, getlocalvardesc(prev, v->u.var.vidx)->vd.name)); } @@ -620,7 +620,7 @@ static void movegotosout (FuncState *fs, BlockCnt *bl) { for (i = bl->firstgoto; i < gl->n; i++) { /* for each pending goto */ Labeldesc *gt = &gl->arr[i]; /* leaving a variable scope? */ - if (stacklevel(fs, gt->nactvar) > stacklevel(fs, bl->nactvar)) + if (reglevel(fs, gt->nactvar) > reglevel(fs, bl->nactvar)) gt->close |= bl->upval; /* jump may need a close */ gt->nactvar = bl->nactvar; /* update goto level */ } @@ -661,7 +661,7 @@ static void leaveblock (FuncState *fs) { BlockCnt *bl = fs->bl; LexState *ls = fs->ls; int hasclose = 0; - int stklevel = stacklevel(fs, bl->nactvar); /* level outside the block */ + int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */ if (bl->isloop) /* fix pending breaks? */ hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0); if (!hasclose && bl->previous && bl->upval) @@ -945,7 +945,7 @@ static void setvararg (FuncState *fs, int nparams) { static void parlist (LexState *ls) { - /* parlist -> [ param { ',' param } ] */ + /* parlist -> [ {NAME ','} (NAME | '...') ] */ FuncState *fs = ls->fs; Proto *f = fs->f; int nparams = 0; @@ -953,12 +953,12 @@ static void parlist (LexState *ls) { if (ls->t.token != ')') { /* is 'parlist' not empty? */ do { switch (ls->t.token) { - case TK_NAME: { /* param -> NAME */ + case TK_NAME: { new_localvar(ls, str_checkname(ls)); nparams++; break; } - case TK_DOTS: { /* param -> '...' */ + case TK_DOTS: { luaX_next(ls); isvararg = 1; break; @@ -1330,13 +1330,13 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { } } else { /* table is a register */ - if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.sidx) { + if (v->k == VLOCAL && lh->v.u.ind.t == v->u.var.ridx) { conflict = 1; /* table is the local being assigned now */ lh->v.u.ind.t = extra; /* assignment will use safe copy */ } /* is index the local being assigned? */ if (lh->v.k == VINDEXED && v->k == VLOCAL && - lh->v.u.ind.idx == v->u.var.sidx) { + lh->v.u.ind.idx == v->u.var.ridx) { conflict = 1; lh->v.u.ind.idx = extra; /* previous assignment will use safe copy */ } @@ -1346,7 +1346,7 @@ static void check_conflict (LexState *ls, struct LHS_assign *lh, expdesc *v) { if (conflict) { /* copy upvalue/local value to a temporary (in position 'extra') */ if (v->k == VLOCAL) - luaK_codeABC(fs, OP_MOVE, extra, v->u.var.sidx, 0); + luaK_codeABC(fs, OP_MOVE, extra, v->u.var.ridx, 0); else luaK_codeABC(fs, OP_GETUPVAL, extra, v->u.info, 0); luaK_reserveregs(fs, 1); @@ -1411,7 +1411,7 @@ static void gotostat (LexState *ls) { newgotoentry(ls, name, line, luaK_jump(fs)); else { /* found a label */ /* backward jump; will be resolved here */ - int lblevel = stacklevel(fs, lb->nactvar); /* label level */ + int lblevel = reglevel(fs, lb->nactvar); /* label level */ if (luaY_nvarstack(fs) > lblevel) /* leaving the scope of a variable? */ luaK_codeABC(fs, OP_CLOSE, lblevel, 0, 0); /* create jump and link it to the label */ @@ -1488,7 +1488,7 @@ static void repeatstat (LexState *ls, int line) { if (bl2.upval) { /* upvalues? */ int exit = luaK_jump(fs); /* normal exit must jump over fix */ luaK_patchtohere(fs, condexit); /* repetition must close upvalues */ - luaK_codeABC(fs, OP_CLOSE, stacklevel(fs, bl2.nactvar), 0, 0); + luaK_codeABC(fs, OP_CLOSE, reglevel(fs, bl2.nactvar), 0, 0); condexit = luaK_jump(fs); /* repeat after closing upvalues */ luaK_patchtohere(fs, exit); /* normal exit comes to here */ } @@ -1623,59 +1623,21 @@ static void forstat (LexState *ls, int line) { } -/* -** Check whether next instruction is a single jump (a 'break', a 'goto' -** to a forward label, or a 'goto' to a backward label with no variable -** to close). If so, set the name of the 'label' it is jumping to -** ("break" for a 'break') or to where it is jumping to ('target') and -** return true. If not a single jump, leave input unchanged, to be -** handled as a regular statement. -*/ -static int issinglejump (LexState *ls, TString **label, int *target) { - if (testnext(ls, TK_BREAK)) { /* a break? */ - *label = luaS_newliteral(ls->L, "break"); - return 1; - } - else if (ls->t.token != TK_GOTO || luaX_lookahead(ls) != TK_NAME) - return 0; /* not a valid goto */ - else { - TString *lname = ls->lookahead.seminfo.ts; /* label's id */ - Labeldesc *lb = findlabel(ls, lname); - if (lb) { /* a backward jump? */ - /* does it need to close variables? */ - if (luaY_nvarstack(ls->fs) > stacklevel(ls->fs, lb->nactvar)) - return 0; /* not a single jump; cannot optimize */ - *target = lb->pc; - } - else /* jump forward */ - *label = lname; - luaX_next(ls); /* skip goto */ - luaX_next(ls); /* skip name */ - return 1; - } -} - - static void test_then_block (LexState *ls, int *escapelist) { /* test_then_block -> [IF | ELSEIF] cond THEN block */ BlockCnt bl; - int line; FuncState *fs = ls->fs; - TString *jlb = NULL; - int target = NO_JUMP; expdesc v; int jf; /* instruction to skip 'then' code (if condition is false) */ luaX_next(ls); /* skip IF or ELSEIF */ expr(ls, &v); /* read condition */ checknext(ls, TK_THEN); - line = ls->linenumber; - if (issinglejump(ls, &jlb, &target)) { /* 'if x then goto' ? */ - luaK_goiffalse(ls->fs, &v); /* will jump to label if condition is true */ + if (ls->t.token == TK_BREAK) { /* 'if x then break' ? */ + int line = ls->linenumber; + luaK_goiffalse(ls->fs, &v); /* will jump if condition is true */ + luaX_next(ls); /* skip 'break' */ enterblock(fs, &bl, 0); /* must enter block before 'goto' */ - if (jlb != NULL) /* forward jump? */ - newgotoentry(ls, jlb, line, v.t); /* will be resolved later */ - else /* backward jump */ - luaK_patchlist(fs, v.t, target); /* jump directly to 'target' */ + newgotoentry(ls, luaS_newliteral(ls->L, "break"), line, v.t); while (testnext(ls, ';')) {} /* skip semicolons */ if (block_follow(ls, 0)) { /* jump is the entire block? */ leaveblock(fs); @@ -1684,7 +1646,7 @@ static void test_then_block (LexState *ls, int *escapelist) { else /* must skip over 'then' part if condition is false */ jf = luaK_jump(fs); } - else { /* regular case (not a jump) */ + else { /* regular case (not a break) */ luaK_goiftrue(ls->fs, &v); /* skip over block if condition is false */ enterblock(fs, &bl, 0); jf = v.f; @@ -1746,13 +1708,13 @@ static void checktoclose (LexState *ls, int level) { FuncState *fs = ls->fs; markupval(fs, level + 1); fs->bl->insidetbc = 1; /* in the scope of a to-be-closed variable */ - luaK_codeABC(fs, OP_TBC, stacklevel(fs, level), 0, 0); + luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0); } } static void localstat (LexState *ls) { - /* stat -> LOCAL ATTRIB NAME {',' ATTRIB NAME} ['=' explist] */ + /* stat -> LOCAL NAME ATTRIB { ',' NAME ATTRIB } ['=' explist] */ FuncState *fs = ls->fs; int toclose = -1; /* index of to-be-closed variable (if any) */ Vardesc *var; /* last variable */ diff --git a/src/lua/lparser.h b/src/lua/lparser.h index 618cb01..5e4500f 100644 --- a/src/lua/lparser.h +++ b/src/lua/lparser.h @@ -23,7 +23,7 @@ /* kinds of variables/expressions */ typedef enum { - VVOID, /* when 'expdesc' describes the last expression a list, + VVOID, /* when 'expdesc' describes the last expression of a list, this kind means an empty list (so, no expression) */ VNIL, /* constant nil */ VTRUE, /* constant true */ @@ -35,10 +35,11 @@ typedef enum { (string is fixed by the lexer) */ VNONRELOC, /* expression has its value in a fixed register; info = result register */ - VLOCAL, /* local variable; var.sidx = stack index (local register); + VLOCAL, /* local variable; var.ridx = register index; var.vidx = relative index in 'actvar.arr' */ VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */ - VCONST, /* compile-time constant; info = absolute index in 'actvar.arr' */ + VCONST, /* compile-time variable; + info = absolute index in 'actvar.arr' */ VINDEXED, /* indexed variable; ind.t = table register; ind.idx = key's R index */ @@ -76,7 +77,7 @@ typedef struct expdesc { lu_byte t; /* table (register or upvalue) */ } ind; struct { /* for local variables */ - lu_byte sidx; /* index in the stack */ + lu_byte ridx; /* register holding the variable */ unsigned short vidx; /* compiler index (in 'actvar.arr') */ } var; } u; @@ -96,7 +97,7 @@ typedef union Vardesc { struct { TValuefields; /* constant value (if it is a compile-time constant) */ lu_byte kind; - lu_byte sidx; /* index of the variable in the stack */ + lu_byte ridx; /* register holding the variable */ short pidx; /* index of the variable in the Proto's 'locvars' array */ TString *name; /* variable name */ } vd; diff --git a/src/lua/lstate.c b/src/lua/lstate.c index 4227429..1596b51 100644 --- a/src/lua/lstate.c +++ b/src/lua/lstate.c @@ -181,7 +181,7 @@ static void stack_init (lua_State *L1, lua_State *L) { int i; CallInfo *ci; /* initialize stack array */ L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, StackValue); - for (i = 0; i < BASIC_STACK_SIZE; i++) + for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) setnilvalue(s2v(L1->stack + i)); /* erase new stack */ L1->top = L1->stack; L1->stack_last = L1->stack + BASIC_STACK_SIZE; @@ -213,17 +213,14 @@ static void freestack (lua_State *L) { ** Create registry table and its predefined values */ static void init_registry (lua_State *L, global_State *g) { - TValue temp; /* create registry */ Table *registry = luaH_new(L); sethvalue(L, &g->l_registry, registry); luaH_resize(L, registry, LUA_RIDX_LAST, 0); /* registry[LUA_RIDX_MAINTHREAD] = L */ - setthvalue(L, &temp, L); /* temp = L */ - luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); - /* registry[LUA_RIDX_GLOBALS] = table of globals */ - sethvalue(L, &temp, luaH_new(L)); /* temp = new table (global table) */ - luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); + setthvalue(L, ®istry->array[LUA_RIDX_MAINTHREAD - 1], L); + /* registry[LUA_RIDX_GLOBALS] = new table (table of globals) */ + sethvalue(L, ®istry->array[LUA_RIDX_GLOBALS - 1], luaH_new(L)); } diff --git a/src/lua/ltable.c b/src/lua/ltable.c index 38bee1d..e9410f9 100644 --- a/src/lua/ltable.c +++ b/src/lua/ltable.c @@ -166,17 +166,24 @@ static Node *mainpositionTV (const Table *t, const TValue *key) { /* -** Check whether key 'k1' is equal to the key in node 'n2'. -** This equality is raw, so there are no metamethods. Floats -** with integer values have been normalized, so integers cannot -** be equal to floats. It is assumed that 'eqshrstr' is simply -** pointer equality, so that short strings are handled in the -** default case. +** Check whether key 'k1' is equal to the key in node 'n2'. This +** equality is raw, so there are no metamethods. Floats with integer +** values have been normalized, so integers cannot be equal to +** floats. It is assumed that 'eqshrstr' is simply pointer equality, so +** that short strings are handled in the default case. ** A true 'deadok' means to accept dead keys as equal to their original -** values, which can only happen if the original key was collectable. -** All dead values are compared in the default case, by pointer -** identity. (Note that dead long strings are also compared by -** identity). +** values. All dead keys are compared in the default case, by pointer +** identity. (Only collectable objects can produce dead keys.) Note that +** dead long strings are also compared by identity. +** Once a key is dead, its corresponding value may be collected, and +** then another value can be created with the same address. If this +** other value is given to 'next', 'equalkey' will signal a false +** positive. In a regular traversal, this situation should never happen, +** as all keys given to 'next' came from the table itself, and therefore +** could not have been collected. Outside a regular traversal, we +** have garbage in, garbage out. What is relevant is that this false +** positive does not break anything. (In particular, 'next' will return +** some other valid item on the table or nil.) */ static int equalkey (const TValue *k1, const Node *n2, int deadok) { if ((rawtt(k1) != keytt(n2)) && /* not the same variants? */ @@ -478,7 +485,7 @@ static void reinsert (lua_State *L, Table *ot, Table *t) { already present in the table */ TValue k; getnodekey(L, &k, old); - setobjt2t(L, luaH_set(L, t, &k), gval(old)); + luaH_set(L, t, &k, gval(old)); } } } @@ -625,7 +632,7 @@ static Node *getfreepos (Table *t) { ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ -TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { +void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { Node *mp; TValue aux; if (unlikely(ttisnil(key))) @@ -647,7 +654,8 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { if (f == NULL) { /* cannot find a free place? */ rehash(L, t, key); /* grow table */ /* whatever called 'newkey' takes care of TM cache */ - return luaH_set(L, t, key); /* insert key into grown table */ + luaH_set(L, t, key, value); /* insert key into grown table */ + return; } lua_assert(!isdummy(t)); othern = mainposition(t, keytt(mp), &keyval(mp)); @@ -675,7 +683,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { setnodekey(L, mp, key); luaC_barrierback(L, obj2gco(t), key); lua_assert(isempty(gval(mp))); - return gval(mp); + setobj2t(L, gval(mp), value); } @@ -762,29 +770,40 @@ const TValue *luaH_get (Table *t, const TValue *key) { } +/* +** Finish a raw "set table" operation, where 'slot' is where the value +** should have been (the result of a previous "get table"). +** Beware: when using this function you probably need to check a GC +** barrier and invalidate the TM cache. +*/ +void luaH_finishset (lua_State *L, Table *t, const TValue *key, + const TValue *slot, TValue *value) { + if (isabstkey(slot)) + luaH_newkey(L, t, key, value); + else + setobj2t(L, cast(TValue *, slot), value); +} + + /* ** beware: when using this function you probably need to check a GC ** barrier and invalidate the TM cache. */ -TValue *luaH_set (lua_State *L, Table *t, const TValue *key) { - const TValue *p = luaH_get(t, key); - if (!isabstkey(p)) - return cast(TValue *, p); - else return luaH_newkey(L, t, key); +void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value) { + const TValue *slot = luaH_get(t, key); + luaH_finishset(L, t, key, slot, value); } void luaH_setint (lua_State *L, Table *t, lua_Integer key, TValue *value) { const TValue *p = luaH_getint(t, key); - TValue *cell; - if (!isabstkey(p)) - cell = cast(TValue *, p); - else { + if (isabstkey(p)) { TValue k; setivalue(&k, key); - cell = luaH_newkey(L, t, &k); + luaH_newkey(L, t, &k, value); } - setobj2t(L, cell, value); + else + setobj2t(L, cast(TValue *, p), value); } diff --git a/src/lua/ltable.h b/src/lua/ltable.h index c0060f4..7bbbcb2 100644 --- a/src/lua/ltable.h +++ b/src/lua/ltable.h @@ -41,8 +41,12 @@ LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_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); -LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key); +LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key, + TValue *value); +LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key, + TValue *value); +LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key, + const TValue *slot, TValue *value); LUAI_FUNC Table *luaH_new (lua_State *L); LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned int nasize, unsigned int nhsize); diff --git a/src/lua/lualib.h b/src/lua/lualib.h index eb08b53..2625529 100644 --- a/src/lua/lualib.h +++ b/src/lua/lualib.h @@ -49,10 +49,4 @@ LUAMOD_API int (luaopen_package) (lua_State *L); LUALIB_API void (luaL_openlibs) (lua_State *L); - -#if !defined(lua_assert) -#define lua_assert(x) ((void)0) -#endif - - #endif diff --git a/src/lua/lvm.c b/src/lua/lvm.c index aa3b22b..ccebdbe 100644 --- a/src/lua/lvm.c +++ b/src/lua/lvm.c @@ -337,10 +337,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, lua_assert(isempty(slot)); /* slot must be empty */ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ if (tm == NULL) { /* no metamethod? */ - if (isabstkey(slot)) /* no previous entry? */ - slot = luaH_newkey(L, h, key); /* create one */ - /* no metamethod and (now) there is an entry with given key */ - setobj2t(L, cast(TValue *, slot), val); /* set its new value */ + luaH_finishset(L, h, key, slot, val); /* set new value */ invalidateTMcache(h); luaC_barrierback(L, obj2gco(h), val); return; -- cgit v1.2.3-55-g6feb