diff --git a/contrib/lua/Makefile b/contrib/lua/Makefile index 36447a0f61c7..fef1af4821e6 100644 --- a/contrib/lua/Makefile +++ b/contrib/lua/Makefile @@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1 # Lua version and release. V= 5.4 -R= $V.2 +R= $V.4 # Targets start here. all: $(PLAT) diff --git a/contrib/lua/README b/contrib/lua/README index bc8a9d737d26..c394c69828b5 100644 --- a/contrib/lua/README +++ b/contrib/lua/README @@ -1,5 +1,5 @@ -This is Lua 5.4.2, released on 13 Nov 2020. +This is Lua 5.4.4, released on 13 Jan 2022. For installation instructions, license details, and further information about Lua, see doc/readme.html. diff --git a/contrib/lua/doc/contents.html b/contrib/lua/doc/contents.html index 8ea0616b25ce..ab82eb4a9278 100644 --- a/contrib/lua/doc/contents.html +++ b/contrib/lua/doc/contents.html @@ -32,7 +32,7 @@ For a complete introduction to Lua programming, see the book

-Copyright © 2020 Lua.org, PUC-Rio. +Copyright © 2020–2022 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -396,6 +396,7 @@ Freely available under the terms of the lua_callk
lua_checkstack
lua_close
+lua_closeslot
lua_compare
lua_concat
lua_copy
@@ -663,10 +664,10 @@ Freely available under the terms of the

diff --git a/contrib/lua/doc/manual.html b/contrib/lua/doc/manual.html index 6de396c41d1c..61a8220d7fd1 100644 --- a/contrib/lua/doc/manual.html +++ b/contrib/lua/doc/manual.html @@ -19,7 +19,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes

-Copyright © 2020 Lua.org, PUC-Rio. +Copyright © 2020–2022 Lua.org, PUC-Rio. Freely available under the terms of the Lua license. @@ -143,6 +143,11 @@ The type boolean has two values, false and true. Both nil and false make a condition false; they are collectively called false values. Any other value makes a condition true. +Despite its name, +false is frequently used as an alternative to nil, +with the key difference that false behaves +like a regular value in a table, +while a nil in a table represents an absent key.

@@ -434,7 +439,7 @@ under certain events. You can change several aspects of the behavior of a value by setting specific fields in its metatable. For instance, when a non-numeric value is the operand of an addition, -Lua checks for a function in the field "__add" of the value's metatable. +Lua checks for a function in the field __add of the value's metatable. If it finds one, Lua calls this function to perform the addition. @@ -901,7 +906,7 @@ For an object (table or userdata) to be finalized when collected, you must mark it for finalization. You mark an object for finalization when you set its metatable -and the metatable has a field indexed by the string "__gc". +and the metatable has a __gc metamethod. Note that if you set a metatable without a __gc field and later create that field in the metatable, the object will not be marked for finalization. @@ -956,11 +961,8 @@ these marks have no effect.

-Finalizers cannot yield. -Except for that, they can do anything, -such as raise errors, create new objects, -or even run the garbage collector. -However, because they can run in unpredictable times, +Finalizers cannot yield nor run the garbage collector. +Because they can run in unpredictable times, it is good practice to restrict each finalizer to the minimum necessary to properly release its associated resource. @@ -1631,8 +1633,10 @@ before the adjustment

-The assignment statement first evaluates all its expressions -and only then the assignments are performed. +If a variable is both assigned and read +inside a multiple assignment, +Lua ensures all reads get the value of the variable +before the assignment. Thus the code

@@ -1656,6 +1660,14 @@ and
 cyclically permutes the values of x, y, and z.
 
 
+

+Note that this guarantee covers only accesses +syntactically inside the assignment statement. +If a function or a metamethod called during the assignment +changes the value of a variable, +Lua gives no guarantees about the order of that access. + +

An assignment to a global name x = val is equivalent to the assignment @@ -1992,16 +2004,8 @@ they are closed in the reverse order that they were declared. If there is any error while running a closing method, that error is handled like an error in the regular code where the variable was defined. -However, Lua may call the method one more time. - - -

After an error, the other pending closing methods will still be called. -Errors in these methods -interrupt the respective method and generate a warning, -but are otherwise ignored; -the error reported is only the original one.

@@ -2419,16 +2423,21 @@ character is one byte.)

The length operator applied on a table returns a border in that table. -A border in a table t is any natural number +A border in a table t is any non-negative integer that satisfies the following condition:

-     (border == 0 or t[border] ~= nil) and t[border + 1] == nil
+     (border == 0 or t[border] ~= nil) and
+     (t[border + 1] == nil or border == math.maxinteger)
 

In words, -a border is any (natural) index present in the table -that is followed by an absent index -(or zero, when index 1 is absent). +a border is any positive integer index present in the table +that is followed by an absent index, +plus two limit cases: +zero, when index 1 is absent; +and the maximum value for an integer, when that index is present. +Note that keys that are not positive integers +do not interfere with borders.

@@ -2439,12 +2448,9 @@ The table {10, 20, 30, nil, 50} has two borders (3 and 5), and therefore it is not a sequence. (The nil at index 4 is called a hole.) The table {nil, 20, 30, nil, nil, 60, nil} -has three borders (0, 3, and 6) and three holes -(at indices 1, 4, and 5), +has three borders (0, 3, and 6), so it is not a sequence, too. The table {} is a sequence with border 0. -Note that non-natural keys do not interfere -with whether a table is a sequence.

@@ -2462,7 +2468,7 @@ the memory addresses of its non-numeric keys.)

The computation of the length of a table has a guaranteed worst time of O(log n), -where n is the largest natural key in the table. +where n is the largest integer key in the table.

@@ -3763,6 +3769,29 @@ will probably need to close states as soon as they are not needed. +


lua_closeslot

+[-0, +0, e] +

void lua_closeslot (lua_State *L, int index);
+ +

+Close the to-be-closed slot at the given index and set its value to nil. +The index must be the last index previously marked to be closed +(see lua_toclose) that is still active (that is, not closed yet). + + +

+A __close metamethod cannot yield +when called through this function. + + +

+(Exceptionally, this function was introduced in release 5.4.3. +It is not present in previous 5.4 releases.) + + + + +


lua_compare

[-0, +0, e]

int lua_compare (lua_State *L, int index1, int index2, int op);
@@ -3959,6 +3988,10 @@ For more details about these options, see collectgarbage. +

+This function should not be called by a finalizer. + + @@ -4657,11 +4690,7 @@ except that it allows the called function to yield (see §4.5

Pops n elements from the stack. - - -

-This function can run arbitrary code when removing an index -marked as to-be-closed from the stack. +It is implemented as a macro over lua_settop. @@ -5140,10 +5169,12 @@ and then pops the top element. Resets a thread, cleaning its call stack and closing all pending to-be-closed variables. Returns a status code: -LUA_OK for no errors in closing methods, +LUA_OK for no errors in the thread +(either the original error that stopped the thread or +errors in closing methods), or an error status otherwise. In case of error, -leaves the error object on the top of the stack, +leaves the error object on the top of the stack. @@ -5466,28 +5497,24 @@ otherwise, returns NULL.

Marks the given index in the stack as a -to-be-closed "variable" (see §3.3.8). +to-be-closed slot (see §3.3.8). Like a to-be-closed variable in Lua, -the value at that index in the stack will be closed +the value at that slot in the stack will be closed when it goes out of scope. Here, in the context of a C function, to go out of scope means that the running function returns to Lua, -there is an error, -or the index is removed from the stack through -lua_settop or lua_pop. -An index marked as to-be-closed should not be removed from the stack -by any other function in the API except lua_settop or lua_pop. +or there is an error, +or the slot is removed from the stack through +lua_settop or lua_pop, +or there is a call to lua_closeslot. +A slot marked as to-be-closed should not be removed from the stack +by any other function in the API except lua_settop or lua_pop, +unless previously deactivated by lua_closeslot.

This function should not be called for an index -that is equal to or below an active to-be-closed index. - - -

-In the case of an out-of-memory error, -the value in the given index is immediately closed, -as if it was already marked. +that is equal to or below an active to-be-closed slot.

@@ -5495,7 +5522,7 @@ Note that, both in case of errors and of a regular return, by the time the __close metamethod runs, the C stack was already unwound, so that any automatic C variable declared in the calling function -will be out of scope. +(e.g., a buffer) will be out of scope. @@ -5919,7 +5946,10 @@ information about a function or an activation record. lua_getstack fills only the private part of this structure, for later use. To fill the other fields of lua_Debug with useful information, -you must call lua_getinfo. +you must call lua_getinfo with an appropriate parameter. +(Specifically, to get a field, +you must add the letter between parentheses in the field's comment +to the parameter what of lua_getinfo.)

@@ -6096,11 +6126,25 @@ you can write the following code:

Each character in the string what selects some fields of the structure ar to be filled or -a value to be pushed on the stack: +a value to be pushed on the stack. +(These characters are also documented in the declaration of +the structure lua_Debug, +between parentheses in the comments following each field.)

-This specifier does not support modifiers (flags, width, length). +This specifier does not support modifiers (flags, width, precision).

@@ -9960,23 +10001,23 @@ from list[1] to list[#list]. If comp is given, then it must be a function that receives two list elements and returns true when the first element must come -before the second in the final order -(so that, after the sort, -i < j implies not comp(list[j],list[i])). +before the second in the final order, +so that, after the sort, +i <= j implies not comp(list[j],list[i]). If comp is not given, then the standard Lua operator < is used instead.

-Note that the comp function must define -a strict partial order over the elements in the list; -that is, it must be asymmetric and transitive. -Otherwise, no valid sort may be possible. +The comp function must define a consistent order; +more formally, the function must define a strict weak order. +(A weak order is similar to a total order, +but it can equate different elements for comparison purposes.)

The sort algorithm is not stable: -elements considered equal by the given order +Different elements considered equal by the given order may have their relative positions changed by the sort. @@ -10346,7 +10387,7 @@ or fail if x is not a number.

Returns a boolean, -true if and only if integer m is below integer n when +true if and only if integer m is below integer n when they are compared as unsigned integers. @@ -11908,10 +11949,10 @@ and LiteralString, see §3.1.)

diff --git a/contrib/lua/doc/readme.html b/contrib/lua/doc/readme.html index e20a9bda138a..8afe38de923b 100644 --- a/contrib/lua/doc/readme.html +++ b/contrib/lua/doc/readme.html @@ -110,7 +110,7 @@ Here are the details.
  1. Open a terminal window and move to -the top-level directory, which is named lua-5.4.2. +the top-level directory, which is named lua-5.4.4. The Makefile there controls both the build process and the installation process.

  2. @@ -303,7 +303,7 @@ For details, see this.
    -Copyright © 1994–2020 Lua.org, PUC-Rio. +Copyright © 1994–2022 Lua.org, PUC-Rio.

    Permission is hereby granted, free of charge, to any person obtaining a copy @@ -330,10 +330,10 @@ THE SOFTWARE.

    diff --git a/contrib/lua/src/lapi.c b/contrib/lua/src/lapi.c index c824da27cbc4..5ee65792d277 100644 --- a/contrib/lua/src/lapi.c +++ b/contrib/lua/src/lapi.c @@ -39,7 +39,7 @@ const char lua_ident[] = /* -** Test for a valid index. +** Test for a valid index (one that is not the 'nilvalue'). ** '!ttisnil(o)' implies 'o != &G(L)->nilvalue', so it is not needed. ** However, it covers the most common cases in a faster way. */ @@ -53,6 +53,10 @@ const char lua_ident[] = #define isupvalue(i) ((i) < LUA_REGISTRYINDEX) +/* +** Convert an acceptable index to a pointer to its respective value. +** Non-valid indices return the special nil value 'G(L)->nilvalue'. +*/ static TValue *index2value (lua_State *L, int idx) { CallInfo *ci = L->ci; if (idx > 0) { @@ -70,21 +74,28 @@ static TValue *index2value (lua_State *L, int idx) { else { /* upvalues */ idx = LUA_REGISTRYINDEX - idx; api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); - if (ttislcf(s2v(ci->func))) /* light C function? */ - return &G(L)->nilvalue; /* it has no upvalues */ - else { + if (ttisCclosure(s2v(ci->func))) { /* C closure? */ CClosure *func = clCvalue(s2v(ci->func)); - return (idx <= func->nupvalues) ? &func->upvalue[idx-1] : &G(L)->nilvalue; + return (idx <= func->nupvalues) ? &func->upvalue[idx-1] + : &G(L)->nilvalue; + } + else { /* light C function or Lua function (through a hook)?) */ + api_check(L, ttislcf(s2v(ci->func)), "caller not a C function"); + return &G(L)->nilvalue; /* no upvalues */ } } } -static StkId index2stack (lua_State *L, int idx) { + +/* +** Convert a valid actual index (not a pseudo-index) to its address. +*/ +l_sinline StkId index2stack (lua_State *L, int idx) { CallInfo *ci = L->ci; if (idx > 0) { StkId o = ci->func + idx; - api_check(L, o < L->top, "unacceptable index"); + api_check(L, o < L->top, "invalid index"); return o; } else { /* non-positive index */ @@ -172,7 +183,7 @@ LUA_API int lua_gettop (lua_State *L) { LUA_API void lua_settop (lua_State *L, int idx) { CallInfo *ci; - StkId func; + StkId func, newtop; ptrdiff_t diff; /* difference for new top */ lua_lock(L); ci = L->ci; @@ -187,9 +198,26 @@ LUA_API void lua_settop (lua_State *L, int idx) { api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); diff = idx + 1; /* will "subtract" index (as it is negative) */ } - if (diff < 0 && hastocloseCfunc(ci->nresults)) - luaF_close(L, L->top + diff, LUA_OK); - L->top += diff; /* correct top only after closing any upvalue */ + api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot"); + newtop = L->top + diff; + if (diff < 0 && L->tbclist >= newtop) { + lua_assert(hastocloseCfunc(ci->nresults)); + luaF_close(L, newtop, CLOSEKTOP, 0); + } + L->top = newtop; /* correct top only after closing any upvalue */ + lua_unlock(L); +} + + +LUA_API void lua_closeslot (lua_State *L, int idx) { + StkId level; + lua_lock(L); + level = index2stack(L, idx); + api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level, + "no variable to close at given level"); + luaF_close(L, level, CLOSEKTOP, 0); + level = index2stack(L, idx); /* stack may be moved */ + setnilvalue(s2v(level)); lua_unlock(L); } @@ -200,7 +228,7 @@ LUA_API void lua_settop (lua_State *L, int idx) { ** Note that we move(copy) only the value inside the stack. ** (We do not move additional fields that may exist.) */ -static void reverse (lua_State *L, StkId from, StkId to) { +l_sinline void reverse (lua_State *L, StkId from, StkId to) { for (; from < to; from++, to--) { TValue temp; setobj(L, &temp, s2v(from)); @@ -420,7 +448,7 @@ LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx) { } -static void *touserdata (const TValue *o) { +l_sinline void *touserdata (const TValue *o) { switch (ttype(o)) { case LUA_TUSERDATA: return getudatamem(uvalue(o)); case LUA_TLIGHTUSERDATA: return pvalue(o); @@ -612,7 +640,7 @@ LUA_API int lua_pushthread (lua_State *L) { */ -static int auxgetstr (lua_State *L, const TValue *t, const char *k) { +l_sinline 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)) { @@ -629,11 +657,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); } @@ -677,7 +715,7 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) { } -static int finishrawget (lua_State *L, const TValue *val) { +l_sinline int finishrawget (lua_State *L, const TValue *val) { if (isempty(val)) /* avoid copying empty items to the stack */ setnilvalue(s2v(L->top)); else @@ -811,10 +849,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 +899,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 +1099,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); @@ -1101,18 +1136,19 @@ LUA_API int lua_status (lua_State *L) { LUA_API int lua_gc (lua_State *L, int what, ...) { va_list argp; int res = 0; - global_State *g; + global_State *g = G(L); + if (g->gcstp & GCSTPGC) /* internal stop? */ + return -1; /* all options are invalid when stopped */ lua_lock(L); - g = G(L); va_start(argp, what); switch (what) { case LUA_GCSTOP: { - g->gcrunning = 0; + g->gcstp = GCSTPUSR; /* stopped by the user */ break; } case LUA_GCRESTART: { luaE_setdebt(g, 0); - g->gcrunning = 1; + g->gcstp = 0; /* (GCSTPGC must be already zero here) */ break; } case LUA_GCCOLLECT: { @@ -1131,8 +1167,8 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { case LUA_GCSTEP: { int data = va_arg(argp, int); l_mem debt = 1; /* =1 to signal that it did an actual step */ - lu_byte oldrunning = g->gcrunning; - g->gcrunning = 1; /* allow GC to run */ + lu_byte oldstp = g->gcstp; + g->gcstp = 0; /* allow GC to run (GCSTPGC must be zero here) */ if (data == 0) { luaE_setdebt(g, 0); /* do a basic step */ luaC_step(L); @@ -1142,7 +1178,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { luaE_setdebt(g, debt); luaC_checkGC(L); } - g->gcrunning = oldrunning; /* restore previous state */ + g->gcstp = oldstp; /* restore previous state */ if (debt > 0 && g->gcstate == GCSpause) /* end of cycle? */ res = 1; /* signal it */ break; @@ -1160,7 +1196,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { break; } case LUA_GCISRUNNING: { - res = g->gcrunning; + res = gcrunning(g); break; } case LUA_GCGEN: { @@ -1240,8 +1276,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) { lua_lock(L); o = index2stack(L, idx); nresults = L->ci->nresults; - api_check(L, L->openupval == NULL || uplevel(L->openupval) <= o, - "marked index below or equal new one"); + api_check(L, L->tbclist < o, "given index below or equal a marked one"); luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ if (!hastocloseCfunc(nresults)) /* function not marked yet? */ L->ci->nresults = codeNresults(nresults); /* mark it */ diff --git a/contrib/lua/src/lapi.h b/contrib/lua/src/lapi.h index 41216b270902..9e99cc44824d 100644 --- a/contrib/lua/src/lapi.h +++ b/contrib/lua/src/lapi.h @@ -42,6 +42,8 @@ #define hastocloseCfunc(n) ((n) < LUA_MULTRET) +/* Map [-1, inf) (range of 'nresults') into (-inf, -2] */ #define codeNresults(n) (-(n) - 3) +#define decodeNresults(n) (-(n) - 3) #endif diff --git a/contrib/lua/src/lauxlib.c b/contrib/lua/src/lauxlib.c index 73504389e1a4..8ed1da1122fc 100644 --- a/contrib/lua/src/lauxlib.c +++ b/contrib/lua/src/lauxlib.c @@ -190,7 +190,7 @@ LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) { } -int luaL_typeerror (lua_State *L, int arg, const char *tname) { +LUALIB_API int luaL_typeerror (lua_State *L, int arg, const char *tname) { const char *msg; const char *typearg; /* name for the type of the actual argument */ if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING) @@ -378,7 +378,7 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def, ** but without 'msg'.) */ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { - if (!lua_checkstack(L, space)) { + if (l_unlikely(!lua_checkstack(L, space))) { if (msg) luaL_error(L, "stack overflow (%s)", msg); else @@ -388,20 +388,20 @@ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) { LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) { - if (lua_type(L, arg) != t) + if (l_unlikely(lua_type(L, arg) != t)) tag_error(L, arg, t); } LUALIB_API void luaL_checkany (lua_State *L, int arg) { - if (lua_type(L, arg) == LUA_TNONE) + if (l_unlikely(lua_type(L, arg) == LUA_TNONE)) luaL_argerror(L, arg, "value expected"); } LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) { const char *s = lua_tolstring(L, arg, len); - if (!s) tag_error(L, arg, LUA_TSTRING); + if (l_unlikely(!s)) tag_error(L, arg, LUA_TSTRING); return s; } @@ -420,7 +420,7 @@ LUALIB_API const char *luaL_optlstring (lua_State *L, int arg, LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) { int isnum; lua_Number d = lua_tonumberx(L, arg, &isnum); - if (!isnum) + if (l_unlikely(!isnum)) tag_error(L, arg, LUA_TNUMBER); return d; } @@ -442,7 +442,7 @@ static void interror (lua_State *L, int arg) { LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) { int isnum; lua_Integer d = lua_tointegerx(L, arg, &isnum); - if (!isnum) { + if (l_unlikely(!isnum)) { interror(L, arg); } return d; @@ -475,7 +475,7 @@ static void *resizebox (lua_State *L, int idx, size_t newsize) { 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? */ + if (l_unlikely(temp == NULL && newsize > 0)) { /* allocation error? */ lua_pushliteral(L, "not enough memory"); lua_error(L); /* raise a memory error */ } @@ -515,13 +515,22 @@ static void newbox (lua_State *L) { #define buffonstack(B) ((B)->b != (B)->init.b) +/* +** Whenever buffer is accessed, slot 'idx' must either be a box (which +** cannot be NULL) or it is a placeholder for the buffer. +*/ +#define checkbufferlevel(B,idx) \ + lua_assert(buffonstack(B) ? lua_touserdata(B->L, idx) != NULL \ + : lua_touserdata(B->L, idx) == (void*)B) + + /* ** Compute new size for buffer 'B', enough to accommodate extra 'sz' ** bytes. */ static size_t newbuffsize (luaL_Buffer *B, size_t sz) { size_t newsize = B->size * 2; /* double buffer size */ - if (MAX_SIZET - sz < B->n) /* overflow in (B->n + sz)? */ + if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ return luaL_error(B->L, "buffer too large"); if (newsize < B->n + sz) /* double is not big enough? */ newsize = B->n + sz; @@ -531,10 +540,11 @@ static size_t newbuffsize (luaL_Buffer *B, size_t sz) { /* ** Returns a pointer to a free area with at least 'sz' bytes in buffer -** 'B'. 'boxidx' is the relative position in the stack where the -** buffer's box is or should be. +** 'B'. 'boxidx' is the relative position in the stack where is the +** buffer's box or its placeholder. */ static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) { + checkbufferlevel(B, boxidx); if (B->size - B->n >= sz) /* enough space? */ return B->b + B->n; else { @@ -545,10 +555,9 @@ static char *prepbuffsize (luaL_Buffer *B, size_t sz, int boxidx) { if (buffonstack(B)) /* buffer already has a box? */ newbuff = (char *)resizebox(L, boxidx, newsize); /* resize it */ else { /* no box yet */ - lua_pushnil(L); /* reserve slot for final result */ + lua_remove(L, boxidx); /* remove placeholder */ newbox(L); /* create a new box */ - /* move box (and slot) to its intended position */ - lua_rotate(L, boxidx - 1, 2); + lua_insert(L, boxidx); /* move box to its intended position */ lua_toclose(L, boxidx); newbuff = (char *)resizebox(L, boxidx, newsize); memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */ @@ -583,11 +592,11 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { LUALIB_API void luaL_pushresult (luaL_Buffer *B) { lua_State *L = B->L; + checkbufferlevel(B, -1); lua_pushlstring(L, B->b, B->n); - if (buffonstack(B)) { - lua_copy(L, -1, -3); /* move string to reserved slot */ - lua_pop(L, 2); /* pop string and box (closing the box) */ - } + if (buffonstack(B)) + lua_closeslot(L, -2); /* close the box */ + lua_remove(L, -2); /* remove box or placeholder from the stack */ } @@ -622,6 +631,7 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { B->b = B->init.b; B->n = 0; B->size = LUAL_BUFFERSIZE; + lua_pushlightuserdata(L, (void*)B); /* push placeholder */ } @@ -639,10 +649,14 @@ LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { ** ======================================================= */ -/* index of free-list header */ -#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 +664,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 +689,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 */ @@ -851,7 +873,7 @@ LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) { int isnum; lua_len(L, idx); l = lua_tointegerx(L, -1, &isnum); - if (!isnum) + if (l_unlikely(!isnum)) luaL_error(L, "object length is not an integer"); lua_pop(L, 1); /* remove object */ return l; @@ -859,6 +881,7 @@ 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) { + idx = lua_absindex(L,idx); if (luaL_callmeta(L, idx, "__tostring")) { /* metafield? */ if (!lua_isstring(L, -1)) luaL_error(L, "'__tostring' must return a string"); @@ -1064,7 +1087,7 @@ static void warnfon (void *ud, const char *message, int tocont) { LUALIB_API lua_State *luaL_newstate (void) { lua_State *L = lua_newstate(l_alloc, NULL); - if (L) { + if (l_likely(L)) { lua_atpanic(L, &panic); lua_setwarnf(L, warnfoff, L); /* default is warnings off */ } diff --git a/contrib/lua/src/lauxlib.h b/contrib/lua/src/lauxlib.h index 59fef6af132b..5b977e2a39f1 100644 --- a/contrib/lua/src/lauxlib.h +++ b/contrib/lua/src/lauxlib.h @@ -12,6 +12,7 @@ #include #include +#include "luaconf.h" #include "lua.h" @@ -101,7 +102,7 @@ LUALIB_API lua_State *(luaL_newstate) (void); LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx); -LUALIB_API void luaL_addgsub (luaL_Buffer *b, const char *s, +LUALIB_API void (luaL_addgsub) (luaL_Buffer *b, const char *s, const char *p, const char *r); LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, const char *r); @@ -130,10 +131,10 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, (luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0)) #define luaL_argcheck(L, cond,arg,extramsg) \ - ((void)((cond) || luaL_argerror(L, (arg), (extramsg)))) + ((void)(luai_likely(cond) || luaL_argerror(L, (arg), (extramsg)))) #define luaL_argexpected(L,cond,arg,tname) \ - ((void)((cond) || luaL_typeerror(L, (arg), (tname)))) + ((void)(luai_likely(cond) || luaL_typeerror(L, (arg), (tname)))) #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) #define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) @@ -153,10 +154,34 @@ LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname, #define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL) +/* +** Perform arithmetic operations on lua_Integer values with wrap-around +** semantics, as the Lua core does. +*/ +#define luaL_intop(op,v1,v2) \ + ((lua_Integer)((lua_Unsigned)(v1) op (lua_Unsigned)(v2))) + + /* push the value used to represent failure/error */ #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/contrib/lua/src/lbaselib.c b/contrib/lua/src/lbaselib.c index 747fd45a2fe5..1d60c9dede59 100644 --- a/contrib/lua/src/lbaselib.c +++ b/contrib/lua/src/lbaselib.c @@ -138,7 +138,7 @@ static int luaB_setmetatable (lua_State *L) { int t = lua_type(L, 2); luaL_checktype(L, 1, LUA_TTABLE); luaL_argexpected(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table"); - if (luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL) + if (l_unlikely(luaL_getmetafield(L, 1, "__metatable") != LUA_TNIL)) return luaL_error(L, "cannot change a protected metatable"); lua_settop(L, 2); lua_setmetatable(L, 1); @@ -182,11 +182,20 @@ static int luaB_rawset (lua_State *L) { static int pushmode (lua_State *L, int oldmode) { - lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" : "generational"); + if (oldmode == -1) + luaL_pushfail(L); /* invalid call to 'lua_gc' */ + else + lua_pushstring(L, (oldmode == LUA_GCINC) ? "incremental" + : "generational"); return 1; } +/* +** check whether call to 'lua_gc' was valid (not inside a finalizer) +*/ +#define checkvalres(res) { if (res == -1) break; } + static int luaB_collectgarbage (lua_State *L) { static const char *const opts[] = {"stop", "restart", "collect", "count", "step", "setpause", "setstepmul", @@ -199,12 +208,14 @@ static int luaB_collectgarbage (lua_State *L) { case LUA_GCCOUNT: { int k = lua_gc(L, o); int b = lua_gc(L, LUA_GCCOUNTB); + checkvalres(k); lua_pushnumber(L, (lua_Number)k + ((lua_Number)b/1024)); return 1; } case LUA_GCSTEP: { int step = (int)luaL_optinteger(L, 2, 0); int res = lua_gc(L, o, step); + checkvalres(res); lua_pushboolean(L, res); return 1; } @@ -212,11 +223,13 @@ static int luaB_collectgarbage (lua_State *L) { case LUA_GCSETSTEPMUL: { int p = (int)luaL_optinteger(L, 2, 0); int previous = lua_gc(L, o, p); + checkvalres(previous); lua_pushinteger(L, previous); return 1; } case LUA_GCISRUNNING: { int res = lua_gc(L, o); + checkvalres(res); lua_pushboolean(L, res); return 1; } @@ -233,10 +246,13 @@ static int luaB_collectgarbage (lua_State *L) { } default: { int res = lua_gc(L, o); + checkvalres(res); lua_pushinteger(L, res); return 1; } } + luaL_pushfail(L); /* invalid call (inside a finalizer) */ + return 1; } @@ -260,6 +276,11 @@ static int luaB_next (lua_State *L) { } +static int pairscont (lua_State *L, int status, lua_KContext k) { + (void)L; (void)status; (void)k; /* unused */ + return 3; +} + static int luaB_pairs (lua_State *L) { luaL_checkany(L, 1); if (luaL_getmetafield(L, 1, "__pairs") == LUA_TNIL) { /* no metamethod? */ @@ -269,7 +290,7 @@ static int luaB_pairs (lua_State *L) { } else { lua_pushvalue(L, 1); /* argument 'self' to metamethod */ - lua_call(L, 1, 3); /* get 3 values from metamethod */ + lua_callk(L, 1, 3, 0, pairscont); /* get 3 values from metamethod */ } return 3; } @@ -279,7 +300,8 @@ static int luaB_pairs (lua_State *L) { ** Traversal function for 'ipairs' */ static int ipairsaux (lua_State *L) { - lua_Integer i = luaL_checkinteger(L, 2) + 1; + lua_Integer i = luaL_checkinteger(L, 2); + i = luaL_intop(+, i, 1); lua_pushinteger(L, i); return (lua_geti(L, 1, i) == LUA_TNIL) ? 1 : 2; } @@ -299,7 +321,7 @@ static int luaB_ipairs (lua_State *L) { static int load_aux (lua_State *L, int status, int envidx) { - if (status == LUA_OK) { + if (l_likely(status == LUA_OK)) { if (envidx != 0) { /* 'env' parameter? */ lua_pushvalue(L, envidx); /* environment for loaded function */ if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */ @@ -355,7 +377,7 @@ static const char *generic_reader (lua_State *L, void *ud, size_t *size) { *size = 0; return NULL; } - else if (!lua_isstring(L, -1)) + else if (l_unlikely(!lua_isstring(L, -1))) luaL_error(L, "reader function must return a string"); lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */ return lua_tolstring(L, RESERVEDSLOT, size); @@ -393,7 +415,7 @@ static int dofilecont (lua_State *L, int d1, lua_KContext d2) { static int luaB_dofile (lua_State *L) { const char *fname = luaL_optstring(L, 1, NULL); lua_settop(L, 1); - if (luaL_loadfile(L, fname) != LUA_OK) + if (l_unlikely(luaL_loadfile(L, fname) != LUA_OK)) return lua_error(L); lua_callk(L, 0, LUA_MULTRET, 0, dofilecont); return dofilecont(L, 0, 0); @@ -401,7 +423,7 @@ static int luaB_dofile (lua_State *L) { static int luaB_assert (lua_State *L) { - if (lua_toboolean(L, 1)) /* condition is true? */ + if (l_likely(lua_toboolean(L, 1))) /* condition is true? */ return lua_gettop(L); /* return all arguments */ else { /* error */ luaL_checkany(L, 1); /* there must be a condition */ @@ -437,7 +459,7 @@ static int luaB_select (lua_State *L) { ** ignored). */ static int finishpcall (lua_State *L, int status, lua_KContext extra) { - if (status != LUA_OK && status != LUA_YIELD) { /* error? */ + if (l_unlikely(status != LUA_OK && status != LUA_YIELD)) { /* error? */ lua_pushboolean(L, 0); /* first result (false) */ lua_pushvalue(L, -2); /* error message */ return 2; /* return false, msg */ diff --git a/contrib/lua/src/lcode.c b/contrib/lua/src/lcode.c index 14d41f1a7ef4..97e3c72857a5 100644 --- a/contrib/lua/src/lcode.c +++ b/contrib/lua/src/lcode.c @@ -10,6 +10,7 @@ #include "lprefix.h" +#include #include #include #include @@ -314,15 +315,6 @@ void luaK_patchtohere (FuncState *fs, int list) { } -/* -** MAXimum number of successive Instructions WiTHout ABSolute line -** information. -*/ -#if !defined(MAXIWTHABS) -#define MAXIWTHABS 120 -#endif - - /* limit for difference between lines in relative line info. */ #define LIMLINEDIFF 0x80 @@ -337,13 +329,13 @@ void luaK_patchtohere (FuncState *fs, int list) { static void savelineinfo (FuncState *fs, Proto *f, int line) { int linedif = line - fs->previousline; int pc = fs->pc - 1; /* last instruction coded */ - if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ > MAXIWTHABS) { + if (abs(linedif) >= LIMLINEDIFF || fs->iwthabs++ >= MAXIWTHABS) { luaM_growvector(fs->ls->L, f->abslineinfo, fs->nabslineinfo, f->sizeabslineinfo, AbsLineInfo, MAX_INT, "lines"); f->abslineinfo[fs->nabslineinfo].pc = pc; f->abslineinfo[fs->nabslineinfo++].line = line; linedif = ABSLINEINFO; /* signal that there is absolute information */ - fs->iwthabs = 0; /* restart counter */ + fs->iwthabs = 1; /* restart counter */ } luaM_growvector(fs->ls->L, f->lineinfo, pc, f->sizelineinfo, ls_byte, MAX_INT, "opcodes"); @@ -545,11 +537,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 +558,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); @@ -585,24 +581,48 @@ static int stringK (FuncState *fs, TString *s) { /* ** 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. */ static int luaK_intK (FuncState *fs, lua_Integer n) { - TValue k, o; - setpvalue(&k, cast_voidp(cast_sizet(n))); + TValue o; setivalue(&o, n); - return addk(fs, &k, &o); + return addk(fs, &o, &o); /* use integer itself as key */ } /* -** Add a float to list of constants and return its index. +** Add a float to list of constants and return its index. Floats +** with integral values need a different key, to avoid collision +** with actual integers. To that, we add to the number its smaller +** power-of-two fraction that is still significant in its scale. +** For doubles, that would be 1/2^52. +** (This method is not bulletproof: there may be another float +** with that value, and for floats larger than 2^53 the result is +** still an integer. At worst, this only wastes an entry with +** a duplicate.) */ static int luaK_numberK (FuncState *fs, lua_Number r) { TValue o; + lua_Integer ik; setfltvalue(&o, r); +#ifndef LUA_AVOID_FLOAT + if (!luaV_flttointeger(r, &ik, F2Ieq)) /* not an integral value? */ + return addk(fs, &o, &o); /* use number itself as key */ + else { /* must build an alternative key */ + const int nbm = l_floatatt(MANT_DIG); + const lua_Number q = l_mathop(ldexp)(l_mathop(1.0), -nbm + 1); + const lua_Number k = (ik == 0) ? q : r + r*q; /* new key */ + TValue kv; + setfltvalue(&kv, k); + /* result is not an integral value, unless value is too large */ + lua_assert(!luaV_flttointeger(k, &ik, F2Ieq) || + l_mathop(fabs)(r) >= l_mathop(1e6)); + return addk(fs, &kv, &o); + } +#else + /* + ** When we're avoiding floats, allow any collision since floats are ints. + */ return addk(fs, &o, &o); /* use number itself as key */ +#endif } @@ -763,7 +783,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; } @@ -1036,7 +1056,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: { @@ -1276,7 +1296,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; @@ -1303,7 +1323,8 @@ static int validop (int op, TValue *v1, TValue *v2) { case LUA_OPBAND: case LUA_OPBOR: case LUA_OPBXOR: case LUA_OPSHL: case LUA_OPSHR: case LUA_OPBNOT: { /* conversion errors */ lua_Integer i; - return (tointegerns(v1, &i) && tointegerns(v2, &i)); + return (luaV_tointegerns(v1, &i, LUA_FLOORN2I) && + luaV_tointegerns(v2, &i, LUA_FLOORN2I)); } case LUA_OPDIV: case LUA_OPIDIV: case LUA_OPMOD: /* division by 0 */ return (nvalue(v2) != 0); diff --git a/contrib/lua/src/lcorolib.c b/contrib/lua/src/lcorolib.c index c165031d280a..785a1e81aa0a 100644 --- a/contrib/lua/src/lcorolib.c +++ b/contrib/lua/src/lcorolib.c @@ -31,14 +31,14 @@ static lua_State *getco (lua_State *L) { */ static int auxresume (lua_State *L, lua_State *co, int narg) { int status, nres; - if (!lua_checkstack(co, narg)) { + if (l_unlikely(!lua_checkstack(co, narg))) { lua_pushliteral(L, "too many arguments to resume"); return -1; /* error flag */ } lua_xmove(L, co, narg); status = lua_resume(co, L, narg, &nres); - if (status == LUA_OK || status == LUA_YIELD) { - if (!lua_checkstack(L, nres + 1)) { + if (l_likely(status == LUA_OK || status == LUA_YIELD)) { + if (l_unlikely(!lua_checkstack(L, nres + 1))) { lua_pop(co, nres); /* remove results anyway */ lua_pushliteral(L, "too many results to resume"); return -1; /* error flag */ @@ -57,7 +57,7 @@ static int luaB_coresume (lua_State *L) { lua_State *co = getco(L); int r; r = auxresume(L, co, lua_gettop(L) - 1); - if (r < 0) { + if (l_unlikely(r < 0)) { lua_pushboolean(L, 0); lua_insert(L, -2); return 2; /* return false + error message */ @@ -73,10 +73,13 @@ static int luaB_coresume (lua_State *L) { 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) { /* error? */ + if (l_unlikely(r < 0)) { /* error? */ int stat = lua_status(co); - if (stat != LUA_OK && stat != LUA_YIELD) /* error in the coroutine? */ - lua_resetthread(co); /* close its tbc variables */ + if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ + stat = lua_resetthread(co); /* close its tbc variables */ + lua_assert(stat != LUA_OK); + lua_xmove(co, L, 1); /* move error message to the caller */ + } if (stat != LUA_ERRMEM && /* not a memory error and ... */ lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */ luaL_where(L, 1); /* add extra info, if available */ @@ -176,7 +179,7 @@ static int luaB_close (lua_State *L) { } else { lua_pushboolean(L, 0); - lua_xmove(co, L, 1); /* copy error message */ + lua_xmove(co, L, 1); /* move error message */ return 2; } } diff --git a/contrib/lua/src/ldblib.c b/contrib/lua/src/ldblib.c index 5a326adedb02..6dcbaa9824ba 100644 --- a/contrib/lua/src/ldblib.c +++ b/contrib/lua/src/ldblib.c @@ -33,7 +33,7 @@ static const char *const HOOKKEY = "_HOOKKEY"; ** checked. */ static void checkstack (lua_State *L, lua_State *L1, int n) { - if (L != L1 && !lua_checkstack(L1, n)) + if (l_unlikely(L != L1 && !lua_checkstack(L1, n))) luaL_error(L, "stack overflow"); } @@ -152,6 +152,7 @@ static int db_getinfo (lua_State *L) { lua_State *L1 = getthread(L, &arg); const char *options = luaL_optstring(L, arg+2, "flnSrtu"); checkstack(L, L1, 3); + luaL_argcheck(L, options[0] != '>', arg + 2, "invalid option '>'"); 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 */ @@ -212,7 +213,7 @@ static int db_getlocal (lua_State *L) { lua_Debug ar; const char *name; int level = (int)luaL_checkinteger(L, arg + 1); - if (!lua_getstack(L1, level, &ar)) /* out of range? */ + if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); checkstack(L, L1, 1); name = lua_getlocal(L1, &ar, nvar); @@ -237,7 +238,7 @@ static int db_setlocal (lua_State *L) { lua_Debug ar; int level = (int)luaL_checkinteger(L, arg + 1); int nvar = (int)luaL_checkinteger(L, arg + 2); - if (!lua_getstack(L1, level, &ar)) /* out of range? */ + if (l_unlikely(!lua_getstack(L1, level, &ar))) /* out of range? */ return luaL_argerror(L, arg+1, "level out of range"); luaL_checkany(L, arg+3); lua_settop(L, arg+3); @@ -377,7 +378,7 @@ static int db_sethook (lua_State *L) { } if (!luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)) { /* 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 +421,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/contrib/lua/src/ldebug.c b/contrib/lua/src/ldebug.c index 8cb00e51a100..a716d95e22f6 100644 --- a/contrib/lua/src/ldebug.c +++ b/contrib/lua/src/ldebug.c @@ -33,11 +33,9 @@ #define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) -/* inverse of 'pcRel' */ -#define invpcRel(pc, p) ((p)->code + (pc) + 1) -static const char *funcnamefromcode (lua_State *L, CallInfo *ci, - const char **name); +static const char *funcnamefromcall (lua_State *L, CallInfo *ci, + const char **name); static int currentpc (CallInfo *ci) { @@ -48,10 +46,16 @@ static int currentpc (CallInfo *ci) { /* ** Get a "base line" to find the line corresponding to an instruction. -** For that, search the array of absolute line info for the largest saved -** instruction smaller or equal to the wanted instruction. A special -** case is when there is no absolute info or the instruction is before -** the first absolute one. +** Base lines are regularly placed at MAXIWTHABS intervals, so usually +** an integer division gets the right place. When the source file has +** large sequences of empty/comment lines, it may need extra entries, +** so the original estimate needs a correction. +** If the original estimate is -1, the initial 'if' ensures that the +** 'while' will run at least once. +** The assertion that the estimate is a lower bound for the correct base +** is valid as long as the debug info has been generated with the same +** value for MAXIWTHABS or smaller. (Previous releases use a little +** smaller value.) */ static int getbaseline (const Proto *f, int pc, int *basepc) { if (f->sizeabslineinfo == 0 || pc < f->abslineinfo[0].pc) { @@ -59,20 +63,12 @@ static int getbaseline (const Proto *f, int pc, int *basepc) { return f->linedefined; } else { - unsigned int i; - if (pc >= f->abslineinfo[f->sizeabslineinfo - 1].pc) - i = f->sizeabslineinfo - 1; /* instruction is after last saved one */ - else { /* binary search */ - unsigned int j = f->sizeabslineinfo - 1; /* pc < anchorlines[j] */ - i = 0; /* abslineinfo[i] <= pc */ - while (i < j - 1) { - unsigned int m = (j + i) / 2; - if (pc >= f->abslineinfo[m].pc) - i = m; - else - j = m; - } - } + int i = cast_uint(pc) / MAXIWTHABS - 1; /* get an estimate */ + /* estimate must be a lower bound of the correct base */ + lua_assert(i < 0 || + (i < f->sizeabslineinfo && f->abslineinfo[i].pc <= pc)); + while (i + 1 < f->sizeabslineinfo && pc >= f->abslineinfo[i + 1].pc) + i++; /* low estimate; adjust it */ *basepc = f->abslineinfo[i].pc; return f->abslineinfo[i].line; } @@ -305,8 +301,15 @@ static void collectvalidlines (lua_State *L, Closure *f) { sethvalue2s(L, L->top, t); /* push it on stack */ api_incr_top(L); setbtvalue(&v); /* boolean 'true' to be the value of all indices */ - for (i = 0; i < p->sizelineinfo; i++) { /* for all lines with code */ - currentline = nextline(p, currentline, i); + if (!p->is_vararg) /* regular function? */ + i = 0; /* consider all instructions */ + else { /* vararg function */ + lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); + currentline = nextline(p, currentline, 0); + i = 1; /* skip first instruction (OP_VARARGPREP) */ + } + for (; i < p->sizelineinfo; i++) { /* for each instruction */ + currentline = nextline(p, currentline, i); /* get its line */ luaH_setint(L, t, currentline, &v); /* table[line] = true */ } } @@ -314,15 +317,9 @@ 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); + /* calling function is a known function? */ + if (ci != NULL && !(ci->callstatus & CIST_TAIL)) + return funcnamefromcall(L, ci->previous, name); else return NULL; /* no way to find a name */ } @@ -594,16 +591,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, ** 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) { +static const char *funcnamefromcode (lua_State *L, const Proto *p, + int pc, const char **name) { TMS tm = (TMS)0; /* (initial value avoids warnings) */ - const Proto *p = ci_func(ci)->p; /* calling function */ - int pc = currentpc(ci); /* calling instruction index */ Instruction i = p->code[pc]; /* calling instruction */ - if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ - *name = "?"; - return "hook"; - } switch (GET_OPCODE(i)) { case OP_CALL: case OP_TAILCALL: @@ -629,12 +620,10 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci, case OP_LEN: tm = TM_LEN; break; case OP_CONCAT: tm = TM_CONCAT; break; case OP_EQ: tm = TM_EQ; break; - case OP_LT: case OP_LE: case OP_LTI: case OP_LEI: - *name = "order"; /* '<=' can call '__lt', etc. */ - return "metamethod"; - case OP_CLOSE: case OP_RETURN: - *name = "close"; - return "metamethod"; + /* no cases for OP_EQI and OP_EQK, as they don't call metamethods */ + case OP_LT: case OP_LTI: case OP_GTI: tm = TM_LT; break; + case OP_LE: case OP_LEI: case OP_GEI: tm = TM_LE; break; + case OP_CLOSE: case OP_RETURN: tm = TM_CLOSE; break; default: return NULL; /* cannot find a reasonable name */ } @@ -642,19 +631,43 @@ static const char *funcnamefromcode (lua_State *L, CallInfo *ci, return "metamethod"; } + +/* +** Try to find a name for a function based on how it was called. +*/ +static const char *funcnamefromcall (lua_State *L, CallInfo *ci, + const char **name) { + if (ci->callstatus & CIST_HOOKED) { /* was it called inside a hook? */ + *name = "?"; + return "hook"; + } + else if (ci->callstatus & CIST_FIN) { /* was it called as a finalizer? */ + *name = "__gc"; + return "metamethod"; /* report it as such */ + } + else if (isLua(ci)) + return funcnamefromcode(L, ci_func(ci)->p, currentpc(ci), name); + else + return NULL; +} + /* }====================================================== */ /* -** The subtraction of two potentially unrelated pointers is -** not ISO C, but it should not crash a program; the subsequent -** checks are ISO C and ensure a correct result. +** Check whether pointer 'o' points to some value in the stack +** frame of the current function. Because 'o' may not point to a +** value in this stack, we cannot compare it with the region +** boundaries (undefined behaviour in ISO C). */ static int isinstack (CallInfo *ci, const TValue *o) { - StkId base = ci->func + 1; - ptrdiff_t i = cast(StkId, o) - base; - return (0 <= i && i < (ci->top - base) && s2v(base + i) == o); + StkId pos; + for (pos = ci->func + 1; pos < ci->top; pos++) { + if (o == s2v(pos)) + return 1; + } + return 0; /* not found */ } @@ -677,9 +690,21 @@ static const char *getupvalname (CallInfo *ci, const TValue *o, } +static const char *formatvarinfo (lua_State *L, const char *kind, + const char *name) { + if (kind == NULL) + return ""; /* no information */ + else + return luaO_pushfstring(L, " (%s '%s')", kind, name); +} + +/* +** Build a string with a "description" for the value 'o', such as +** "variable 'x'" or "upvalue 'y'". +*/ static const char *varinfo (lua_State *L, const TValue *o) { - const char *name = NULL; /* to avoid warnings */ CallInfo *ci = L->ci; + const char *name = NULL; /* to avoid warnings */ const char *kind = NULL; if (isLua(ci)) { kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ @@ -687,13 +712,40 @@ static const char *varinfo (lua_State *L, const TValue *o) { kind = getobjname(ci_func(ci)->p, currentpc(ci), cast_int(cast(StkId, o) - (ci->func + 1)), &name); } - return (kind) ? luaO_pushfstring(L, " (%s '%s')", kind, name) : ""; + return formatvarinfo(L, kind, name); } -l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { +/* +** Raise a type error +*/ +static l_noret typeerror (lua_State *L, const TValue *o, const char *op, + const char *extra) { const char *t = luaT_objtypename(L, o); - luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o)); + luaG_runerror(L, "attempt to %s a %s value%s", op, t, extra); +} + + +/* +** Raise a type error with "standard" information about the faulty +** object 'o' (using 'varinfo'). +*/ +l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) { + typeerror(L, o, op, varinfo(L, o)); +} + + +/* +** Raise an error for calling a non-callable object. Try to find a name +** for the object based on how it was called ('funcnamefromcall'); if it +** cannot get a name there, try 'varinfo'. +*/ +l_noret luaG_callerror (lua_State *L, const TValue *o) { + CallInfo *ci = L->ci; + const char *name = NULL; /* to avoid warnings */ + const char *kind = funcnamefromcall(L, ci, &name); + const char *extra = kind ? formatvarinfo(L, kind, name) : varinfo(L, o); + typeerror(L, o, "call", extra); } @@ -722,7 +774,7 @@ l_noret luaG_opinterror (lua_State *L, const TValue *p1, */ l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) { lua_Integer temp; - if (!tointegerns(p1, &temp)) + if (!luaV_tointegerns(p1, &temp, LUA_FLOORN2I)) p2 = p1; luaG_runerror(L, "number%s has no integer representation", varinfo(L, p2)); } @@ -780,16 +832,30 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) { /* ** Check whether new instruction 'newpc' is in a different line from -** previous instruction 'oldpc'. +** previous instruction 'oldpc'. More often than not, 'newpc' is only +** one or a few instructions after 'oldpc' (it must be after, see +** caller), so try to avoid calling 'luaG_getfuncline'. If they are +** too far apart, there is a good chance of a ABSLINEINFO in the way, +** so it goes directly to 'luaG_getfuncline'. */ static int changedline (const Proto *p, int oldpc, int newpc) { if (p->lineinfo == NULL) /* no debug information? */ return 0; - while (oldpc++ < newpc) { - if (p->lineinfo[oldpc] != 0) - return (luaG_getfuncline(p, oldpc - 1) != luaG_getfuncline(p, newpc)); + if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */ + int delta = 0; /* line diference */ + int pc = oldpc; + for (;;) { + int lineinfo = p->lineinfo[++pc]; + if (lineinfo == ABSLINEINFO) + break; /* cannot compute delta; fall through */ + delta += lineinfo; + if (pc == newpc) + return (delta != 0); /* delta computed successfully */ + } } - return 0; /* no line changes between positions */ + /* either instructions are too far apart or there is an absolute line + info in the way; compute line difference explicitly */ + return (luaG_getfuncline(p, oldpc) != luaG_getfuncline(p, newpc)); } @@ -797,20 +863,19 @@ static int changedline (const Proto *p, int oldpc, int newpc) { ** Traces the execution of a Lua function. Called before the execution ** of each opcode, when debug is on. 'L->oldpc' stores the last ** instruction traced, to detect line changes. When entering a new -** function, 'npci' will be zero and will test as a new line without -** the need for 'oldpc'; so, 'oldpc' does not need to be initialized -** before. Some exceptional conditions may return to a function without -** updating 'oldpc'. In that case, 'oldpc' may be invalid; if so, it is -** reset to zero. (A wrong but valid 'oldpc' at most causes an extra -** call to a line hook.) +** function, 'npci' will be zero and will test as a new line whatever +** the value of 'oldpc'. Some exceptional conditions may return to +** a function without setting 'oldpc'. In that case, 'oldpc' may be +** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc' +** at most causes an extra call to a line hook.) +** This function is not "Protected" when called, so it should correct +** 'L->top' before calling anything that can run the GC. */ int luaG_traceexec (lua_State *L, const Instruction *pc) { CallInfo *ci = L->ci; lu_byte mask = L->hookmask; const Proto *p = ci_func(ci)->p; int counthook; - /* 'L->oldpc' may be invalid; reset it in this case */ - int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0; if (!(mask & (LUA_MASKLINE | LUA_MASKCOUNT))) { /* no hooks? */ ci->u.l.trap = 0; /* don't need to stop again */ return 0; /* turn off 'trap' */ @@ -826,15 +891,16 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) { ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ return 1; /* do not call hook again (VM yielded, so it did not move) */ } - if (!isIT(*(ci->u.l.savedpc - 1))) - L->top = ci->top; /* prepare top */ + if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */ + L->top = ci->top; /* correct top */ if (counthook) luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ if (mask & LUA_MASKLINE) { + /* 'L->oldpc' may be invalid; use zero in this case */ + int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0; int npci = pcRel(pc, p); - if (npci == 0 || /* call linehook when enter a new function, */ - pc <= invpcRel(oldpc, p) || /* when jump back (loop), or when */ - changedline(p, oldpc, npci)) { /* enter new line */ + if (npci <= oldpc || /* call hook when jump back (loop), */ + changedline(p, oldpc, npci)) { /* or when enter new line */ int newline = luaG_getfuncline(p, npci); luaD_hook(L, LUA_HOOKLINE, newline, 0, 0); /* call line hook */ } diff --git a/contrib/lua/src/ldebug.h b/contrib/lua/src/ldebug.h index a0a584862e96..974960e99da0 100644 --- a/contrib/lua/src/ldebug.h +++ b/contrib/lua/src/ldebug.h @@ -26,11 +26,22 @@ */ #define ABSLINEINFO (-0x80) + +/* +** MAXimum number of successive Instructions WiTHout ABSolute line +** information. (A power of two allows fast divisions.) +*/ +#if !defined(MAXIWTHABS) +#define MAXIWTHABS 128 +#endif + + LUAI_FUNC int luaG_getfuncline (const Proto *f, int pc); LUAI_FUNC const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos); LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *opname); +LUAI_FUNC l_noret luaG_callerror (lua_State *L, const TValue *o); LUAI_FUNC l_noret luaG_forerror (lua_State *L, const TValue *o, const char *what); LUAI_FUNC l_noret luaG_concaterror (lua_State *L, const TValue *p1, diff --git a/contrib/lua/src/ldo.c b/contrib/lua/src/ldo.c index 4b55c31c2d8c..a48e35f9dba9 100644 --- a/contrib/lua/src/ldo.c +++ b/contrib/lua/src/ldo.c @@ -98,11 +98,12 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); break; } - case CLOSEPROTECT: { + case LUA_OK: { /* special case only for closing upvalues */ setnilvalue(s2v(oldtop)); /* no error message */ break; } default: { + lua_assert(errorstatus(errcode)); /* real error */ setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ break; } @@ -118,17 +119,13 @@ l_noret luaD_throw (lua_State *L, int errcode) { } else { /* thread has no error handler */ global_State *g = G(L); - errcode = luaF_close(L, L->stack, errcode); /* close all upvalues */ - L->status = cast_byte(errcode); /* mark it as dead */ + errcode = luaE_resetthread(L, errcode); /* close all upvalues */ if (g->mainthread->errorJmp) { /* main thread has a handler? */ setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ } else { /* no handler at all; abort */ if (g->panic) { /* panic function? */ - luaD_seterrorobj(L, errcode, L->top); /* assume EXTRA_STACK */ - if (L->ci->top < L->top) - L->ci->top = L->top; /* pushing msg. can break this invariant */ lua_unlock(L); g->panic(L); /* call panic function (last chance to jump out) */ } @@ -163,9 +160,8 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { static void correctstack (lua_State *L, StkId oldstack, StkId newstack) { CallInfo *ci; UpVal *up; - if (oldstack == newstack) - return; /* stack address did not change */ L->top = (L->top - oldstack) + newstack; + L->tbclist = (L->tbclist - oldstack) + newstack; for (up = L->openupval; up != NULL; up = up->u.open.next) up->v = s2v((uplevel(up) - oldstack) + newstack); for (ci = L->ci; ci != NULL; ci = ci->previous) { @@ -181,19 +177,35 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) { #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) +/* +** Reallocate the stack to a new size, correcting all pointers into +** it. (There are pointers to a stack from its upvalues, from its list +** of call infos, plus a few individual pointers.) The reallocation is +** done in two steps (allocation + free) because the correction must be +** done while both addresses (the old stack and the new one) are valid. +** (In ISO C, any pointer use after the pointer has been deallocated is +** undefined behavior.) +** In case of allocation error, raise an error or return false according +** to 'raiseerror'. +*/ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { - int lim = stacksize(L); - StkId newstack = luaM_reallocvector(L, L->stack, - lim + EXTRA_STACK, newsize + EXTRA_STACK, StackValue); + int oldsize = stacksize(L); + int i; + StkId newstack = luaM_reallocvector(L, NULL, 0, + newsize + EXTRA_STACK, StackValue); lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); - if (unlikely(newstack == NULL)) { /* reallocation failed? */ + if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ if (raiseerror) luaM_error(L); else return 0; /* do not raise an error */ } - for (; lim < newsize; lim++) - setnilvalue(s2v(newstack + lim + EXTRA_STACK)); /* erase new segment */ + /* number of elements to be copied to the new stack */ + i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK; + memcpy(newstack, L->stack, i * sizeof(StackValue)); + for (; i < newsize + EXTRA_STACK; i++) + setnilvalue(s2v(newstack + i)); /* erase new segment */ correctstack(L, L->stack, newstack); + luaM_freearray(L, L->stack, oldsize + EXTRA_STACK); L->stack = newstack; L->stack_last = L->stack + newsize; return 1; @@ -206,7 +218,7 @@ int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { */ int luaD_growstack (lua_State *L, int n, int raiseerror) { int size = stacksize(L); - if (unlikely(size > LUAI_MAXSTACK)) { + if (l_unlikely(size > LUAI_MAXSTACK)) { /* if stack is larger than maximum, thread is already using the extra space reserved for errors, that is, thread is handling a stack error; cannot grow further than that. */ @@ -222,7 +234,7 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) { newsize = LUAI_MAXSTACK; if (newsize < needed) /* but must respect what was asked for */ newsize = needed; - if (likely(newsize <= LUAI_MAXSTACK)) + if (l_likely(newsize <= LUAI_MAXSTACK)) return luaD_reallocstack(L, newsize, raiseerror); else { /* stack overflow */ /* add extra size to be able to handle the error message */ @@ -297,8 +309,8 @@ void luaD_hook (lua_State *L, int event, int line, if (hook && L->allowhook) { /* make sure there is a hook */ int mask = CIST_HOOKED; CallInfo *ci = L->ci; - ptrdiff_t top = savestack(L, L->top); - ptrdiff_t ci_top = savestack(L, ci->top); + ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */ + ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */ lua_Debug ar; ar.event = event; ar.currentline = line; @@ -308,8 +320,10 @@ void luaD_hook (lua_State *L, int event, int line, ci->u2.transferinfo.ftransfer = ftransfer; ci->u2.transferinfo.ntransfer = ntransfer; } + if (isLua(ci) && L->top < ci->top) + L->top = ci->top; /* protect entire activation register */ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ - if (L->top + LUA_MINSTACK > ci->top) + if (ci->top < L->top + LUA_MINSTACK) ci->top = L->top + LUA_MINSTACK; L->allowhook = 0; /* cannot call hooks inside a hook */ ci->callstatus |= mask; @@ -331,38 +345,40 @@ void luaD_hook (lua_State *L, int event, int line, ** active. */ void luaD_hookcall (lua_State *L, CallInfo *ci) { - int hook = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL : LUA_HOOKCALL; - Proto *p; - if (!(L->hookmask & LUA_MASKCALL)) /* some other hook? */ - return; /* don't call hook */ - p = clLvalue(s2v(ci->func))->p; - L->top = ci->top; /* prepare top */ - ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ - luaD_hook(L, hook, -1, 1, p->numparams); - ci->u.l.savedpc--; /* correct 'pc' */ + L->oldpc = 0; /* set 'oldpc' for new function */ + if (L->hookmask & LUA_MASKCALL) { /* is call hook on? */ + int event = (ci->callstatus & CIST_TAIL) ? LUA_HOOKTAILCALL + : LUA_HOOKCALL; + Proto *p = ci_func(ci)->p; + ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */ + luaD_hook(L, event, -1, 1, p->numparams); + ci->u.l.savedpc--; /* correct 'pc' */ + } } -static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) { - ptrdiff_t oldtop = savestack(L, L->top); /* hook may change top */ - int delta = 0; - if (isLuacode(ci)) { - Proto *p = ci_func(ci)->p; - if (p->is_vararg) - delta = ci->u.l.nextraargs + p->numparams + 1; - if (L->top < ci->top) - L->top = ci->top; /* correct top to run hook */ - } +/* +** Executes a return hook for Lua and C functions and sets/corrects +** 'oldpc'. (Note that this correction is needed by the line hook, so it +** is done even when return hooks are off.) +*/ +static void rethook (lua_State *L, CallInfo *ci, int nres) { if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ + StkId firstres = L->top - nres; /* index of first result */ + int delta = 0; /* correction for vararg functions */ int ftransfer; + if (isLua(ci)) { + Proto *p = ci_func(ci)->p; + if (p->is_vararg) + delta = ci->u.l.nextraargs + p->numparams + 1; + } ci->func += delta; /* if vararg, back to virtual 'func' */ ftransfer = cast(unsigned short, firstres - ci->func); luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ ci->func -= delta; } if (isLua(ci = ci->previous)) - L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* update 'oldpc' */ - return restorestack(L, oldtop); + L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */ } @@ -371,15 +387,18 @@ static StkId rethook (lua_State *L, CallInfo *ci, StkId firstres, int nres) { ** stack, below original 'func', so that 'luaD_precall' can call it. Raise ** an error if there is no '__call' metafield. */ -void luaD_tryfuncTM (lua_State *L, StkId func) { - const TValue *tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); +StkId luaD_tryfuncTM (lua_State *L, StkId func) { + const TValue *tm; StkId p; - if (unlikely(ttisnil(tm))) - luaG_typeerror(L, s2v(func), "call"); /* nothing to call */ + checkstackGCp(L, 1, func); /* space for metamethod */ + tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */ + if (l_unlikely(ttisnil(tm))) + luaG_callerror(L, s2v(func)); /* nothing to call */ for (p = L->top; p > func; p--) /* open space for metamethod */ setobjs2s(L, p, p-1); L->top++; /* stack space pre-allocated by the caller */ setobj2s(L, func, tm); /* metamethod is the new function to be called */ + return func; } @@ -389,7 +408,7 @@ void luaD_tryfuncTM (lua_State *L, StkId func) { ** expressions, multiple results for tail calls/single parameters) ** separated. */ -static void moveresults (lua_State *L, StkId res, int nres, int wanted) { +l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) { StkId firstresult; int i; switch (wanted) { /* handle typical cases separately */ @@ -399,27 +418,34 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) { case 1: /* one value needed */ if (nres == 0) /* no results? */ setnilvalue(s2v(res)); /* adjust with nil */ - else + else /* at least one result */ setobjs2s(L, res, L->top - nres); /* move it to proper place */ L->top = res + 1; return; case LUA_MULTRET: wanted = nres; /* we want all results */ break; - default: /* multiple results (or to-be-closed variables) */ + default: /* two/more results and/or to-be-closed variables */ if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ ptrdiff_t savedres = savestack(L, res); - luaF_close(L, res, LUA_OK); /* may change the stack */ - res = restorestack(L, savedres); - wanted = codeNresults(wanted); /* correct value */ + L->ci->callstatus |= CIST_CLSRET; /* in case of yields */ + L->ci->u2.nres = nres; + luaF_close(L, res, CLOSEKTOP, 1); + L->ci->callstatus &= ~CIST_CLSRET; + if (L->hookmask) /* if needed, call hook after '__close's */ + rethook(L, L->ci, nres); + res = restorestack(L, savedres); /* close and hook can move stack */ + wanted = decodeNresults(wanted); if (wanted == LUA_MULTRET) - wanted = nres; + wanted = nres; /* we want all results */ } break; } + /* generic case */ firstresult = L->top - nres; /* index of first result */ - /* move all results to correct place */ - for (i = 0; i < nres && i < wanted; i++) + if (nres > wanted) /* extra results? */ + nres = wanted; /* don't need them */ + 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(s2v(res + i)); @@ -428,15 +454,21 @@ static void moveresults (lua_State *L, StkId res, int nres, int wanted) { /* -** Finishes a function call: calls hook if necessary, removes CallInfo, -** moves current number of results to proper place. +** Finishes a function call: calls hook if necessary, moves current +** number of results to proper place, and returns to previous call +** info. If function has to close variables, hook must be called after +** that. */ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { - if (L->hookmask) - L->top = rethook(L, ci, L->top - nres, nres); - L->ci = ci->previous; /* back to caller */ + int wanted = ci->nresults; + if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted))) + rethook(L, ci, nres); /* move results to proper place */ - moveresults(L, ci->func, nres, ci->nresults); + moveresults(L, ci->func, nres, wanted); + /* function cannot be in any of these cases when returning */ + lua_assert(!(ci->callstatus & + (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET))); + L->ci = ci->previous; /* back to caller (after closing variables) */ } @@ -444,27 +476,81 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) { #define next_ci(L) (L->ci->next ? L->ci->next : luaE_extendCI(L)) +l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, + int mask, StkId top) { + CallInfo *ci = L->ci = next_ci(L); /* new frame */ + ci->func = func; + ci->nresults = nret; + ci->callstatus = mask; + ci->top = top; + return ci; +} + + +/* +** precall for C functions +*/ +l_sinline int precallC (lua_State *L, StkId func, int nresults, + lua_CFunction f) { + int n; /* number of returns */ + CallInfo *ci; + checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ + L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, + L->top + LUA_MINSTACK); + lua_assert(ci->top <= L->stack_last); + if (l_unlikely(L->hookmask & LUA_MASKCALL)) { + int narg = cast_int(L->top - func) - 1; + luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); + } + lua_unlock(L); + n = (*f)(L); /* do the actual call */ + lua_lock(L); + api_checknelems(L, n); + luaD_poscall(L, ci, n); + return n; +} + + /* ** Prepare a function for a tail call, building its call info on top ** of the current call info. 'narg1' is the number of arguments plus 1 -** (so that it includes the function itself). +** (so that it includes the function itself). Return the number of +** results, if it was a C function, or -1 for a Lua function. */ -void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { - Proto *p = clLvalue(s2v(func))->p; - int fsize = p->maxstacksize; /* frame size */ - int nfixparams = p->numparams; - int i; - for (i = 0; i < narg1; i++) /* move down function and arguments */ - setobjs2s(L, ci->func + i, func + i); - checkstackGC(L, fsize); - func = ci->func; /* moved-down function */ - for (; narg1 <= nfixparams; narg1++) - setnilvalue(s2v(func + narg1)); /* complete missing arguments */ - ci->top = func + 1 + fsize; /* top for new function */ - lua_assert(ci->top <= L->stack_last); - ci->u.l.savedpc = p->code; /* starting point */ - ci->callstatus |= CIST_TAIL; - L->top = func + narg1; /* set top */ +int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, + int narg1, int delta) { + retry: + switch (ttypetag(s2v(func))) { + case LUA_VCCL: /* C closure */ + return precallC(L, func, LUA_MULTRET, clCvalue(s2v(func))->f); + case LUA_VLCF: /* light C function */ + return precallC(L, func, LUA_MULTRET, fvalue(s2v(func))); + case LUA_VLCL: { /* Lua function */ + Proto *p = clLvalue(s2v(func))->p; + int fsize = p->maxstacksize; /* frame size */ + int nfixparams = p->numparams; + int i; + checkstackGCp(L, fsize - delta, func); + ci->func -= delta; /* restore 'func' (if vararg) */ + for (i = 0; i < narg1; i++) /* move down function and arguments */ + setobjs2s(L, ci->func + i, func + i); + func = ci->func; /* moved-down function */ + for (; narg1 <= nfixparams; narg1++) + setnilvalue(s2v(func + narg1)); /* complete missing arguments */ + ci->top = func + 1 + fsize; /* top for new function */ + lua_assert(ci->top <= L->stack_last); + ci->u.l.savedpc = p->code; /* starting point */ + ci->callstatus |= CIST_TAIL; + L->top = func + narg1; /* set top */ + return -1; + } + default: { /* not a function */ + func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + /* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */ + narg1++; + goto retry; /* try again */ + } + } } @@ -477,35 +563,14 @@ void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1) { ** original function position. */ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { - lua_CFunction f; retry: switch (ttypetag(s2v(func))) { case LUA_VCCL: /* C closure */ - f = clCvalue(s2v(func))->f; - goto Cfunc; - case LUA_VLCF: /* light C function */ - f = fvalue(s2v(func)); - Cfunc: { - int n; /* number of returns */ - CallInfo *ci; - checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ - L->ci = ci = next_ci(L); - ci->nresults = nresults; - ci->callstatus = CIST_C; - ci->top = L->top + LUA_MINSTACK; - ci->func = func; - lua_assert(ci->top <= L->stack_last); - if (L->hookmask & LUA_MASKCALL) { - int narg = cast_int(L->top - func) - 1; - luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); - } - lua_unlock(L); - n = (*f)(L); /* do the actual call */ - lua_lock(L); - api_checknelems(L, n); - luaD_poscall(L, ci, n); + precallC(L, func, nresults, clCvalue(s2v(func))->f); + return NULL; + case LUA_VLCF: /* light C function */ + precallC(L, func, nresults, fvalue(s2v(func))); return NULL; - } case LUA_VLCL: { /* Lua function */ CallInfo *ci; Proto *p = clLvalue(s2v(func))->p; @@ -513,20 +578,16 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { int nfixparams = p->numparams; int fsize = p->maxstacksize; /* frame size */ checkstackGCp(L, fsize, func); - L->ci = ci = next_ci(L); - ci->nresults = nresults; + L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); ci->u.l.savedpc = p->code; /* starting point */ - ci->top = func + 1 + fsize; - ci->func = func; - L->ci = ci; for (; narg < nfixparams; narg++) setnilvalue(s2v(L->top++)); /* complete missing arguments */ lua_assert(ci->top <= L->stack_last); return ci; } default: { /* not a function */ - checkstackGCp(L, 1, func); /* space for metamethod */ - luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + /* return luaD_precall(L, func, nresults); */ goto retry; /* try again with metamethod */ } } @@ -538,10 +599,10 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { ** number of recursive invocations in the C stack) or nyci (the same ** plus increment number of non-yieldable calls). */ -static void ccall (lua_State *L, StkId func, int nResults, int inc) { +l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) { CallInfo *ci; L->nCcalls += inc; - if (unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) + if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) luaE_checkcstack(L); if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ @@ -568,27 +629,74 @@ void luaD_callnoyield (lua_State *L, StkId func, int nResults) { /* -** Completes the execution of an interrupted C function, calling its -** continuation function. +** Finish the job of 'lua_pcallk' after it was interrupted by an yield. +** (The caller, 'finishCcall', does the final call to 'adjustresults'.) +** The main job is to complete the 'luaD_pcall' called by 'lua_pcallk'. +** If a '__close' method yields here, eventually control will be back +** to 'finishCcall' (when that '__close' method finally returns) and +** 'finishpcallk' will run again and close any still pending '__close' +** methods. Similarly, if a '__close' method errs, 'precover' calls +** 'unroll' which calls ''finishCcall' and we are back here again, to +** close any pending '__close' methods. +** Note that, up to the call to 'luaF_close', the corresponding +** 'CallInfo' is not modified, so that this repeated run works like the +** first one (except that it has at least one less '__close' to do). In +** particular, field CIST_RECST preserves the error status across these +** multiple runs, changing only if there is a new error. */ -static void finishCcall (lua_State *L, int status) { - CallInfo *ci = L->ci; - int n; - /* must have a continuation and must be able to call it */ - lua_assert(ci->u.c.k != NULL && yieldable(L)); - /* 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; /* continuation is also inside it */ - L->errfunc = ci->u.c.old_errfunc; /* with the same error function */ +static int finishpcallk (lua_State *L, CallInfo *ci) { + int status = getcistrecst(ci); /* get original status */ + if (l_likely(status == LUA_OK)) /* no error? */ + status = LUA_YIELD; /* was interrupted by an yield */ + else { /* error */ + StkId func = restorestack(L, ci->u2.funcidx); + L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */ + luaF_close(L, func, status, 1); /* can yield or raise an error */ + func = restorestack(L, ci->u2.funcidx); /* stack may be moved */ + luaD_seterrorobj(L, status, func); + luaD_shrinkstack(L); /* restore stack size in case of overflow */ + setcistrecst(ci, LUA_OK); /* clear original status */ + } + ci->callstatus &= ~CIST_YPCALL; + L->errfunc = ci->u.c.old_errfunc; + /* if it is here, there were errors or yields; unlike 'lua_pcallk', + do not change status */ + return status; +} + + +/* +** Completes the execution of a C function interrupted by an yield. +** The interruption must have happened while the function was either +** closing its tbc variables in 'moveresults' or executing +** 'lua_callk'/'lua_pcallk'. In the first case, it just redoes +** 'luaD_poscall'. In the second case, the call to 'finishpcallk' +** finishes the interrupted execution of 'lua_pcallk'. After that, it +** calls the continuation of the interrupted function and finally it +** completes the job of the 'luaD_call' that called the function. In +** the call to 'adjustresults', we do not know the number of results +** of the function called by 'lua_callk'/'lua_pcallk', so we are +** conservative and use LUA_MULTRET (always adjust). +*/ +static void finishCcall (lua_State *L, CallInfo *ci) { + int n; /* actual number of results from C function */ + if (ci->callstatus & CIST_CLSRET) { /* was returning? */ + lua_assert(hastocloseCfunc(ci->nresults)); + n = ci->u2.nres; /* just redo 'luaD_poscall' */ + /* don't need to reset CIST_CLSRET, as it will be set again anyway */ + } + else { + int status = LUA_YIELD; /* default if there were no errors */ + /* must have a continuation and must be able to call it */ + lua_assert(ci->u.c.k != NULL && yieldable(L)); + if (ci->callstatus & CIST_YPCALL) /* was inside a 'lua_pcallk'? */ + status = finishpcallk(L, ci); /* finish it */ + adjustresults(L, LUA_MULTRET); /* finish 'lua_callk' */ + lua_unlock(L); + n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation */ + lua_lock(L); + api_checknelems(L, n); } - /* finish 'lua_callk'/'lua_pcall'; CIST_YPCALL and 'errfunc' already - handled */ - adjustresults(L, ci->nresults); - lua_unlock(L); - n = (*ci->u.c.k)(L, status, ci->u.c.ctx); /* call continuation function */ - lua_lock(L); - api_checknelems(L, n); luaD_poscall(L, ci, n); /* finish 'luaD_call' */ } @@ -596,18 +704,14 @@ static void finishCcall (lua_State *L, int status) { /* ** Executes "full continuation" (everything in the stack) of a ** previously interrupted coroutine until the stack is empty (or another -** interruption long-jumps out of the loop). If the coroutine is -** recovering from an error, 'ud' points to the error status, which must -** be passed to the first continuation function (otherwise the default -** status is LUA_YIELD). +** interruption long-jumps out of the loop). */ static void unroll (lua_State *L, void *ud) { CallInfo *ci; - if (ud != NULL) /* error status? */ - finishCcall(L, *(int *)ud); /* finish 'lua_pcallk' callee */ + UNUSED(ud); while ((ci = L->ci) != &L->base_ci) { /* something in the stack */ if (!isLua(ci)) /* C function? */ - finishCcall(L, LUA_YIELD); /* complete its execution */ + finishCcall(L, ci); /* complete its execution */ else { /* Lua function */ luaV_finishOp(L); /* finish interrupted instruction */ luaV_execute(L, ci); /* execute down to higher C 'boundary' */ @@ -630,28 +734,6 @@ static CallInfo *findpcall (lua_State *L) { } -/* -** Recovers from an error in a coroutine. Finds a recover point (if -** there is one) and completes the execution of the interrupted -** 'luaD_pcall'. If there is no recover point, returns zero. -*/ -static int recover (lua_State *L, int status) { - StkId oldtop; - CallInfo *ci = findpcall(L); - if (ci == NULL) return 0; /* no recovery point */ - /* "finish" luaD_pcall */ - oldtop = restorestack(L, ci->u2.funcidx); - L->ci = ci; - L->allowhook = getoah(ci->callstatus); /* restore original 'allowhook' */ - status = luaF_close(L, oldtop, status); /* may change the stack */ - oldtop = restorestack(L, ci->u2.funcidx); - luaD_seterrorobj(L, status, oldtop); - luaD_shrinkstack(L); /* restore stack size in case of overflow */ - L->errfunc = ci->u.c.old_errfunc; - return 1; /* continue running the coroutine */ -} - - /* ** Signal an error in the call to 'lua_resume', not in the execution ** of the coroutine itself. (Such errors should not be handled by any @@ -678,13 +760,14 @@ 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? */ - ccall(L, firstArg - 1, LUA_MULTRET, 1); /* just call its body */ + ccall(L, firstArg - 1, LUA_MULTRET, 0); /* 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) */ - luaE_incCstack(L); /* control the C stack */ - if (isLua(ci)) /* yielded inside a hook? */ + if (isLua(ci)) { /* yielded inside a hook? */ + L->top = firstArg; /* discard arguments */ luaV_execute(L, ci); /* just continue running Lua code */ + } else { /* 'common' yield */ if (ci->u.c.k != NULL) { /* does it have a continuation function? */ lua_unlock(L); @@ -698,6 +781,26 @@ static void resume (lua_State *L, void *ud) { } } + +/* +** Unrolls a coroutine in protected mode while there are recoverable +** errors, that is, errors inside a protected call. (Any error +** interrupts 'unroll', and this loop protects it again so it can +** continue.) Stops with a normal end (status == LUA_OK), an yield +** (status == LUA_YIELD), or an unprotected error ('findpcall' doesn't +** find a recover point). +*/ +static int precover (lua_State *L, int status) { + CallInfo *ci; + while (errorstatus(status) && (ci = findpcall(L)) != NULL) { + L->ci = ci; /* go down to recovery functions */ + setcistrecst(ci, status); /* status to finish 'pcall' */ + status = luaD_rawrunprotected(L, unroll, NULL); + } + return status; +} + + LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, int *nresults) { int status; @@ -711,15 +814,15 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs, else if (L->status != LUA_YIELD) /* ended with errors? */ return resume_error(L, "cannot resume dead coroutine", nargs); L->nCcalls = (from) ? getCcalls(from) : 0; + if (getCcalls(L) >= LUAI_MAXCCALLS) + return resume_error(L, "C stack overflow", nargs); + L->nCcalls++; luai_userstateresume(L, nargs); api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs); status = luaD_rawrunprotected(L, resume, &nargs); /* continue running after recoverable errors */ - while (errorstatus(status) && recover(L, status)) { - /* unroll continuation */ - status = luaD_rawrunprotected(L, unroll, &status); - } - if (likely(!errorstatus(status))) + status = precover(L, status); + if (l_likely(!errorstatus(status))) lua_assert(status == L->status); /* normal end or yield */ else { /* unrecoverable error */ L->status = cast_byte(status); /* mark thread as 'dead' */ @@ -745,22 +848,22 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, lua_lock(L); ci = L->ci; api_checknelems(L, nresults); - if (unlikely(!yieldable(L))) { + if (l_unlikely(!yieldable(L))) { if (L != G(L)->mainthread) luaG_runerror(L, "attempt to yield across a C-call boundary"); else luaG_runerror(L, "attempt to yield from outside a coroutine"); } L->status = LUA_YIELD; + ci->u2.nyield = nresults; /* save number of results */ if (isLua(ci)) { /* inside a hook? */ lua_assert(!isLuacode(ci)); + api_check(L, nresults == 0, "hooks cannot yield values"); api_check(L, k == NULL, "hooks cannot continue after yielding"); - ci->u2.nyield = 0; /* no results */ } else { if ((ci->u.c.k = k) != NULL) /* is there a continuation? */ ci->u.c.ctx = ctx; /* save context */ - ci->u2.nyield = nresults; /* save number of results */ luaD_throw(L, LUA_YIELD); } lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */ @@ -769,6 +872,45 @@ LUA_API int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, } +/* +** Auxiliary structure to call 'luaF_close' in protected mode. +*/ +struct CloseP { + StkId level; + int status; +}; + + +/* +** Auxiliary function to call 'luaF_close' in protected mode. +*/ +static void closepaux (lua_State *L, void *ud) { + struct CloseP *pcl = cast(struct CloseP *, ud); + luaF_close(L, pcl->level, pcl->status, 0); +} + + +/* +** Calls 'luaF_close' in protected mode. Return the original status +** or, in case of errors, the new status. +*/ +int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status) { + CallInfo *old_ci = L->ci; + lu_byte old_allowhooks = L->allowhook; + for (;;) { /* keep closing upvalues until no more errors */ + struct CloseP pcl; + pcl.level = restorestack(L, level); pcl.status = status; + status = luaD_rawrunprotected(L, &closepaux, &pcl); + if (l_likely(status == LUA_OK)) /* no more errors? */ + return pcl.status; + else { /* an error occurred; restore saved state and repeat */ + L->ci = old_ci; + L->allowhook = old_allowhooks; + } + } +} + + /* ** Call the C function 'func' in protected mode, restoring basic ** thread information ('allowhook', etc.) and in particular @@ -782,13 +924,11 @@ int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t old_errfunc = L->errfunc; L->errfunc = ef; status = luaD_rawrunprotected(L, func, u); - if (unlikely(status != LUA_OK)) { /* an error occurred? */ - StkId oldtop = restorestack(L, old_top); + if (l_unlikely(status != LUA_OK)) { /* an error occurred? */ L->ci = old_ci; L->allowhook = old_allowhooks; - status = luaF_close(L, oldtop, status); - oldtop = restorestack(L, old_top); /* previous call may change stack */ - luaD_seterrorobj(L, status, oldtop); + status = luaD_closeprotected(L, old_top, status); + luaD_seterrorobj(L, status, restorestack(L, old_top)); luaD_shrinkstack(L); /* restore stack size in case of overflow */ } L->errfunc = old_errfunc; diff --git a/contrib/lua/src/ldo.h b/contrib/lua/src/ldo.h index 4d30d072ede3..911e67f660a1 100644 --- a/contrib/lua/src/ldo.h +++ b/contrib/lua/src/ldo.h @@ -23,7 +23,7 @@ ** at every check. */ #define luaD_checkstackaux(L,n,pre,pos) \ - if (L->stack_last - L->top <= (n)) \ + if (l_unlikely(L->stack_last - L->top <= (n))) \ { pre; luaD_growstack(L, n, 1); pos; } \ else { condmovestack(L,pre,pos); } @@ -58,11 +58,12 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, int fTransfer, int nTransfer); LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); -LUAI_FUNC void luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int n); +LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta); LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); -LUAI_FUNC void luaD_tryfuncTM (lua_State *L, StkId func); +LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func); +LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); LUAI_FUNC void luaD_poscall (lua_State *L, CallInfo *ci, int nres); diff --git a/contrib/lua/src/lfunc.c b/contrib/lua/src/lfunc.c index c4360f0950a7..f5889a21d12e 100644 --- a/contrib/lua/src/lfunc.c +++ b/contrib/lua/src/lfunc.c @@ -100,115 +100,83 @@ UpVal *luaF_findupval (lua_State *L, StkId level) { } -static void callclose (lua_State *L, void *ud) { - UNUSED(ud); - luaD_callnoyield(L, L->top - 3, 0); -} - - /* -** Prepare closing method plus its arguments for object 'obj' with -** error message 'err'. (This function assumes EXTRA_STACK.) +** Call closing method for object 'obj' with error message 'err'. The +** boolean 'yy' controls whether the call is yieldable. +** (This function assumes EXTRA_STACK.) */ -static int prepclosingmethod (lua_State *L, TValue *obj, TValue *err) { +static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { StkId top = L->top; const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); - if (ttisnil(tm)) /* no metamethod? */ - return 0; /* nothing to call */ setobj2s(L, top, tm); /* will call metamethod... */ setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ L->top = top + 3; /* add function and arguments */ - return 1; + if (yy) + luaD_call(L, top, 0); + else + luaD_callnoyield(L, top, 0); } /* -** Raise an error with message 'msg', inserting the name of the -** local variable at position 'level' in the stack. +** Check whether object at given level has a close metamethod and raise +** an error if not. */ -static void varerror (lua_State *L, StkId level, const char *msg) { - int idx = cast_int(level - L->ci->func); - const char *vname = luaG_findlocal(L, L->ci, idx, NULL); - if (vname == NULL) vname = "?"; - luaG_runerror(L, msg, vname); +static void checkclosemth (lua_State *L, StkId level) { + const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE); + if (ttisnil(tm)) { /* no metamethod? */ + int idx = cast_int(level - L->ci->func); /* variable index */ + const char *vname = luaG_findlocal(L, L->ci, idx, NULL); + if (vname == NULL) vname = "?"; + luaG_runerror(L, "variable '%s' got a non-closable value", vname); + } } /* -** Prepare and call a closing method. If status is OK, code is still -** inside the original protected call, and so any error will be handled -** there. Otherwise, a previous error already activated the original -** protected call, and so the call to the closing method must be -** protected here. (A status == CLOSEPROTECT behaves like a previous -** error, to also run the closing method in protected mode). -** If status is OK, the call to the closing method will be pushed -** at the top of the stack. Otherwise, values are pushed after -** the 'level' of the upvalue being closed, as everything after -** that won't be used again. +** Prepare and call a closing method. +** If status is CLOSEKTOP, the call to the closing method will be pushed +** at the top of the stack. Otherwise, values can be pushed right after +** the 'level' of the upvalue being closed, as everything after that +** won't be used again. */ -static int callclosemth (lua_State *L, StkId level, int status) { +static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) { TValue *uv = s2v(level); /* value being closed */ - if (likely(status == LUA_OK)) { - if (prepclosingmethod(L, uv, &G(L)->nilvalue)) /* something to call? */ - callclose(L, NULL); /* call closing method */ - else if (!l_isfalse(uv)) /* non-closable non-false value? */ - varerror(L, level, "attempt to close non-closable variable '%s'"); + TValue *errobj; + if (status == CLOSEKTOP) + errobj = &G(L)->nilvalue; /* error object is nil */ + else { /* 'luaD_seterrorobj' will set top to level + 2 */ + errobj = s2v(level + 1); /* error object goes after 'uv' */ + luaD_seterrorobj(L, status, level + 1); /* set error object */ } - else { /* must close the object in protected mode */ - ptrdiff_t oldtop; - level++; /* space for error message */ - oldtop = savestack(L, level + 1); /* top will be after that */ - luaD_seterrorobj(L, status, level); /* set error message */ - if (prepclosingmethod(L, uv, s2v(level))) { /* something to call? */ - int newstatus = luaD_pcall(L, callclose, NULL, oldtop, 0); - if (newstatus != LUA_OK && status == CLOSEPROTECT) /* first error? */ - status = newstatus; /* this will be the new error */ - else { - if (newstatus != LUA_OK) /* suppressed error? */ - luaE_warnerror(L, "__close metamethod"); - /* leave original error (or nil) on top */ - L->top = restorestack(L, oldtop); - } - } - /* else no metamethod; ignore this case and keep original error */ - } - return status; + callclosemethod(L, uv, errobj, yy); } /* -** Try to create a to-be-closed upvalue -** (can raise a memory-allocation error) +** Maximum value for deltas in 'tbclist', dependent on the type +** of delta. (This macro assumes that an 'L' is in scope where it +** is used.) */ -static void trynewtbcupval (lua_State *L, void *ud) { - newupval(L, 1, cast(StkId, ud), &L->openupval); -} +#define MAXDELTA \ + ((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1) /* -** Create a to-be-closed upvalue. If there is a memory error -** when creating the upvalue, the closing method must be called here, -** as there is no upvalue to call it later. +** Insert a variable in the list of to-be-closed variables. */ void luaF_newtbcupval (lua_State *L, StkId level) { - TValue *obj = s2v(level); - lua_assert(L->openupval == NULL || uplevel(L->openupval) < level); - if (!l_isfalse(obj)) { /* false doesn't need to be closed */ - int status; - const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); - if (ttisnil(tm)) /* no metamethod? */ - varerror(L, level, "variable '%s' got a non-closable value"); - status = luaD_rawrunprotected(L, trynewtbcupval, level); - if (unlikely(status != LUA_OK)) { /* memory error creating upvalue? */ - lua_assert(status == LUA_ERRMEM); - luaD_seterrorobj(L, LUA_ERRMEM, level + 1); /* save error message */ - /* next call must succeed, as object is closable */ - prepclosingmethod(L, s2v(level), s2v(level + 1)); - callclose(L, NULL); /* call closing method */ - luaD_throw(L, LUA_ERRMEM); /* throw memory error */ - } + lua_assert(level > L->tbclist); + if (l_isfalse(s2v(level))) + return; /* false doesn't need to be closed */ + checkclosemth(L, level); /* value must have a close method */ + while (cast_uint(level - L->tbclist) > MAXDELTA) { + L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */ + L->tbclist->tbclist.delta = 0; } + level->tbclist.delta = cast(unsigned short, level - L->tbclist); + L->tbclist = level; } @@ -220,18 +188,16 @@ void luaF_unlinkupval (UpVal *uv) { } -int luaF_close (lua_State *L, StkId level, int status) { +/* +** Close all upvalues up to the given stack level. +*/ +void luaF_closeupval (lua_State *L, StkId level) { UpVal *uv; - while ((uv = L->openupval) != NULL && uplevel(uv) >= level) { + StkId upl; /* stack index pointed by 'uv' */ + while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { TValue *slot = &uv->u.value; /* new position for value */ lua_assert(uplevel(uv) < L->top); - if (uv->tbc && status != NOCLOSINGMETH) { - /* must run closing method, which may change the stack */ - ptrdiff_t levelrel = savestack(L, level); - status = callclosemth(L, uplevel(uv), status); - level = restorestack(L, levelrel); - } - luaF_unlinkupval(uv); + luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */ setobj(L, slot, uv->v); /* move value to upvalue slot */ uv->v = slot; /* now current value lives here */ if (!iswhite(uv)) { /* neither white nor dead? */ @@ -239,7 +205,35 @@ int luaF_close (lua_State *L, StkId level, int status) { luaC_barrier(L, uv, slot); } } - return status; +} + + +/* +** Remove firt element from the tbclist plus its dummy nodes. +*/ +static void poptbclist (lua_State *L) { + StkId tbc = L->tbclist; + lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */ + tbc -= tbc->tbclist.delta; + while (tbc > L->stack && tbc->tbclist.delta == 0) + tbc -= MAXDELTA; /* remove dummy nodes */ + L->tbclist = tbc; +} + + +/* +** Close all upvalues and to-be-closed variables up to the given stack +** level. +*/ +void luaF_close (lua_State *L, StkId level, int status, int yy) { + ptrdiff_t levelrel = savestack(L, level); + luaF_closeupval(L, level); /* first, close the upvalues */ + while (L->tbclist >= level) { /* traverse tbc's down to that level */ + StkId tbc = L->tbclist; /* get variable index */ + poptbclist(L); /* remove it from list */ + prepcallclosemth(L, tbc, status, yy); /* close variable */ + level = restorestack(L, levelrel); + } } diff --git a/contrib/lua/src/lfunc.h b/contrib/lua/src/lfunc.h index 8d6f965cfca9..dc1cebccd1bc 100644 --- a/contrib/lua/src/lfunc.h +++ b/contrib/lua/src/lfunc.h @@ -42,15 +42,9 @@ #define MAXMISS 10 -/* -** Special "status" for 'luaF_close' -*/ -/* close upvalues without running their closing methods */ -#define NOCLOSINGMETH (-1) - -/* close upvalues running all closing methods in protected mode */ -#define CLOSEPROTECT (-2) +/* special status to close upvalues preserving the top of the stack */ +#define CLOSEKTOP (-1) LUAI_FUNC Proto *luaF_newproto (lua_State *L); @@ -59,7 +53,8 @@ LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nupvals); LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); -LUAI_FUNC int luaF_close (lua_State *L, StkId level, int status); +LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level); +LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy); LUAI_FUNC void luaF_unlinkupval (UpVal *uv); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, diff --git a/contrib/lua/src/lgc.c b/contrib/lua/src/lgc.c index bab9beb12b00..42a73d813acc 100644 --- a/contrib/lua/src/lgc.c +++ b/contrib/lua/src/lgc.c @@ -906,18 +906,18 @@ static void GCTM (lua_State *L) { if (!notm(tm)) { /* is there a finalizer? */ int status; lu_byte oldah = L->allowhook; - int running = g->gcrunning; + int oldgcstp = g->gcstp; + g->gcstp |= GCSTPGC; /* avoid GC steps */ L->allowhook = 0; /* stop debug hooks during GC metamethod */ - g->gcrunning = 0; /* avoid GC steps */ setobj2s(L, L->top++, tm); /* push finalizer... */ setobj2s(L, L->top++, &v); /* ... and its argument */ 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 (unlikely(status != LUA_OK)) { /* error while running __gc? */ - luaE_warnerror(L, "__gc metamethod"); + g->gcstp = oldgcstp; /* restore state */ + if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ + luaE_warnerror(L, "__gc"); L->top--; /* pops error object */ } } @@ -1011,7 +1011,8 @@ static void correctpointers (global_State *g, GCObject *o) { void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { global_State *g = G(L); if (tofinalize(o) || /* obj. is already marked... */ - gfasttm(g, mt, TM_GC) == NULL) /* or has no finalizer? */ + gfasttm(g, mt, TM_GC) == NULL || /* or has no finalizer... */ + (g->gcstp & GCSTPCLS)) /* or closing state? */ return; /* nothing to be done */ else { /* move 'o' to 'finobj' list */ GCObject **p; @@ -1502,12 +1503,13 @@ static void deletelist (lua_State *L, GCObject *p, GCObject *limit) { */ void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); + g->gcstp = GCSTPCLS; /* no extra finalizers after here */ luaC_changemode(L, KGC_INC); separatetobefnz(g, 1); /* separate all objects with finalizers */ lua_assert(g->finobj == NULL); callallpendingfinalizers(L); deletelist(L, g->allgc, obj2gco(g->mainthread)); - deletelist(L, g->finobj, NULL); + lua_assert(g->finobj == NULL); /* no new finalizers */ deletelist(L, g->fixedgc, NULL); /* collect fixed objects */ lua_assert(g->strt.nuse == 0); } @@ -1575,52 +1577,64 @@ static int sweepstep (lua_State *L, global_State *g, static lu_mem singlestep (lua_State *L) { global_State *g = G(L); + lu_mem work; + lua_assert(!g->gcstopem); /* collector is not reentrant */ + g->gcstopem = 1; /* no emergency collections while collecting */ switch (g->gcstate) { case GCSpause: { restartcollection(g); g->gcstate = GCSpropagate; - return 1; + work = 1; + break; } case GCSpropagate: { if (g->gray == NULL) { /* no more gray objects? */ g->gcstate = GCSenteratomic; /* finish propagate phase */ - return 0; + work = 0; } else - return propagatemark(g); /* traverse one gray object */ + work = propagatemark(g); /* traverse one gray object */ + break; } case GCSenteratomic: { - lu_mem work = atomic(L); /* work is what was traversed by 'atomic' */ + work = atomic(L); /* work is what was traversed by 'atomic' */ entersweep(L); g->GCestimate = gettotalbytes(g); /* first estimate */; - return work; + break; } case GCSswpallgc: { /* sweep "regular" objects */ - return sweepstep(L, g, GCSswpfinobj, &g->finobj); + work = sweepstep(L, g, GCSswpfinobj, &g->finobj); + break; } case GCSswpfinobj: { /* sweep objects with finalizers */ - return sweepstep(L, g, GCSswptobefnz, &g->tobefnz); + work = sweepstep(L, g, GCSswptobefnz, &g->tobefnz); + break; } case GCSswptobefnz: { /* sweep objects to be finalized */ - return sweepstep(L, g, GCSswpend, NULL); + work = sweepstep(L, g, GCSswpend, NULL); + break; } case GCSswpend: { /* finish sweeps */ checkSizes(L, g); g->gcstate = GCScallfin; - return 0; + work = 0; + break; } case GCScallfin: { /* call remaining finalizers */ if (g->tobefnz && !g->gcemergency) { - int n = runafewfinalizers(L, GCFINMAX); - return n * GCFINALIZECOST; + g->gcstopem = 0; /* ok collections during finalizers */ + work = runafewfinalizers(L, GCFINMAX) * GCFINALIZECOST; } else { /* emergency mode or no more finalizers */ g->gcstate = GCSpause; /* finish collection */ - return 0; + work = 0; } + break; } default: lua_assert(0); return 0; } + g->gcstopem = 0; + return work; } @@ -1635,6 +1649,7 @@ void luaC_runtilstate (lua_State *L, int statesmask) { } + /* ** Performs a basic incremental step. The debt and step size are ** converted from bytes to "units of work"; then the function loops @@ -1666,7 +1681,7 @@ static void incstep (lua_State *L, global_State *g) { void luaC_step (lua_State *L) { global_State *g = G(L); lua_assert(!g->gcemergency); - if (g->gcrunning) { /* running? */ + if (gcrunning(g)) { /* running? */ if(isdecGCmodegen(g)) genstep(L, g); else diff --git a/contrib/lua/src/lgc.h b/contrib/lua/src/lgc.h index 073e2a402948..4a125634b9ea 100644 --- a/contrib/lua/src/lgc.h +++ b/contrib/lua/src/lgc.h @@ -148,6 +148,16 @@ */ #define isdecGCmodegen(g) (g->gckind == KGC_GEN || g->lastatomic != 0) + +/* +** Control when GC is running: +*/ +#define GCSTPUSR 1 /* bit true when GC stopped by user */ +#define GCSTPGC 2 /* bit true when GC stopped by itself */ +#define GCSTPCLS 4 /* bit true when closing Lua state */ +#define gcrunning(g) ((g)->gcstp == 0) + + /* ** Does one step of collection when debt becomes positive. 'pre'/'pos' ** allows some adjustments to be done only when needed. macro diff --git a/contrib/lua/src/liolib.c b/contrib/lua/src/liolib.c index 60ab1bfab64f..b08397da45da 100644 --- a/contrib/lua/src/liolib.c +++ b/contrib/lua/src/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 + /* }====================================================== */ @@ -180,7 +186,7 @@ static int f_tostring (lua_State *L) { static FILE *tofile (lua_State *L) { LStream *p = tolstream(L); - if (isclosed(p)) + if (l_unlikely(isclosed(p))) luaL_error(L, "attempt to use a closed file"); lua_assert(p->f); return p->f; @@ -255,7 +261,7 @@ static LStream *newfile (lua_State *L) { static void opencheck (lua_State *L, const char *fname, const char *mode) { LStream *p = newfile(L); p->f = fopen(fname, mode); - if (p->f == NULL) + if (l_unlikely(p->f == NULL)) luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); } @@ -303,7 +309,7 @@ static FILE *getiofile (lua_State *L, const char *findex) { LStream *p; lua_getfield(L, LUA_REGISTRYINDEX, findex); p = (LStream *)lua_touserdata(L, -1); - if (isclosed(p)) + if (l_unlikely(isclosed(p))) luaL_error(L, "default %s file is closed", findex + IOPREF_LEN); return p->f; } @@ -430,7 +436,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 >= L_MAXLENNUM) { /* buffer overflow? */ + if (l_unlikely(rn->n >= L_MAXLENNUM)) { /* buffer overflow? */ rn->buff[0] = '\0'; /* invalidate result */ return 0; /* fail */ } @@ -493,8 +499,8 @@ static int read_number (lua_State *L, FILE *f) { ungetc(rn.c, rn.f); /* unread look-ahead char */ l_unlockfile(rn.f); rn.buff[rn.n] = '\0'; /* finish string */ - if (lua_stringtonumber(L, rn.buff)) /* is this a valid number? */ - return 1; /* ok */ + if (l_likely(lua_stringtonumber(L, rn.buff))) + return 1; /* ok, it is a valid number */ else { /* invalid format */ lua_pushnil(L); /* "result" to be removed */ return 0; /* read fails */ @@ -670,7 +676,8 @@ static int g_write (lua_State *L, FILE *f, int arg) { status = status && (fwrite(s, sizeof(char), l, f) == l); } } - if (status) return 1; /* file handle already on stack top */ + if (l_likely(status)) + return 1; /* file handle already on stack top */ else return luaL_fileresult(L, status, NULL); } @@ -697,7 +704,7 @@ static int f_seek (lua_State *L) { luaL_argcheck(L, (lua_Integer)offset == p3, 3, "not an integer in proper range"); op = l_fseek(f, offset, mode[op]); - if (op) + if (l_unlikely(op)) return luaL_fileresult(L, 0, NULL); /* error */ else { lua_pushinteger(L, (lua_Integer)l_ftell(f)); diff --git a/contrib/lua/src/llex.c b/contrib/lua/src/llex.c index 4b8dec99859a..e99151787a63 100644 --- a/contrib/lua/src/llex.c +++ b/contrib/lua/src/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; } diff --git a/contrib/lua/src/llimits.h b/contrib/lua/src/llimits.h index d03948314f5c..52a32f92e302 100644 --- a/contrib/lua/src/llimits.h +++ b/contrib/lua/src/llimits.h @@ -149,22 +149,6 @@ typedef LUAI_UACINT l_uacInt; #endif -/* -** macros to improve jump prediction (used mainly for error handling) -*/ -#if !defined(likely) - -#if defined(__GNUC__) -#define likely(x) (__builtin_expect(((x) != 0), 1)) -#define unlikely(x) (__builtin_expect(((x) != 0), 0)) -#else -#define likely(x) (x) -#define unlikely(x) (x) -#endif - -#endif - - /* ** non-return type */ @@ -181,6 +165,20 @@ typedef LUAI_UACINT l_uacInt; #endif +/* +** Inline functions +*/ +#if !defined(LUA_USE_C89) +#define l_inline inline +#elif defined(__GNUC__) +#define l_inline __inline__ +#else +#define l_inline /* empty */ +#endif + +#define l_sinline static l_inline + + /* ** type for virtual-machine instructions; ** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h) @@ -363,7 +361,7 @@ typedef l_uint32 Instruction; #define condchangemem(L,pre,pos) ((void)0) #else #define condchangemem(L,pre,pos) \ - { if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } } + { if (gcrunning(G(L))) { pre; luaC_fullgc(L, 0); pos; } } #endif #endif diff --git a/contrib/lua/src/lmathlib.c b/contrib/lua/src/lmathlib.c index 86def470c44e..e0c61a168d98 100644 --- a/contrib/lua/src/lmathlib.c +++ b/contrib/lua/src/lmathlib.c @@ -73,7 +73,7 @@ static int math_atan (lua_State *L) { static int math_toint (lua_State *L) { int valid; lua_Integer n = lua_tointegerx(L, 1, &valid); - if (valid) + if (l_likely(valid)) lua_pushinteger(L, n); else { luaL_checkany(L, 1); @@ -175,7 +175,8 @@ static int math_log (lua_State *L) { lua_Number base = luaL_checknumber(L, 2); #if !defined(LUA_USE_C89) if (base == l_mathop(2.0)) - res = l_mathop(log2)(x); else + res = l_mathop(log2)(x); + else #endif if (base == l_mathop(10.0)) res = l_mathop(log10)(x); @@ -474,7 +475,7 @@ static lua_Number I2d (Rand64 x) { /* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */ #define scaleFIG \ - ((lua_Number)1.0 / (UONE << 30) / 8.0 / (UONE << (FIGS - 33))) + (l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33))) /* ** use FIGS - 32 bits from lower half, throwing out the other @@ -485,7 +486,7 @@ static lua_Number I2d (Rand64 x) { /* ** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32) */ -#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * 2.0) +#define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * l_mathop(2.0)) static lua_Number I2d (Rand64 x) { diff --git a/contrib/lua/src/lmem.c b/contrib/lua/src/lmem.c index 43739bffd1d0..9029d588c12e 100644 --- a/contrib/lua/src/lmem.c +++ b/contrib/lua/src/lmem.c @@ -24,12 +24,12 @@ #if defined(EMERGENCYGCTESTS) /* -** First allocation will fail whenever not building initial state -** and not shrinking a block. (This fail will trigger 'tryagain' and -** a full GC cycle at every allocation.) +** First allocation will fail whenever not building initial state. +** (This fail will trigger 'tryagain' and a full GC cycle at every +** allocation.) */ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) { - if (ttisnil(&g->nilvalue) && ns > os) + if (completestate(g) && ns > 0) /* frees never fail */ return NULL; /* fail */ else /* normal allocation */ return (*g->frealloc)(g->ud, block, os, ns); @@ -83,7 +83,7 @@ void *luaM_growaux_ (lua_State *L, void *block, int nelems, int *psize, if (nelems + 1 <= size) /* does one extra element still fit? */ return block; /* nothing to be done */ if (size >= limit / 2) { /* cannot double it? */ - if (unlikely(size >= limit)) /* cannot grow even a little? */ + if (l_unlikely(size >= limit)) /* cannot grow even a little? */ luaG_runerror(L, "too many %s (limit is %d)", what, limit); size = limit; /* still have at least one free place */ } @@ -138,15 +138,17 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) { /* -** In case of allocation fail, this function will call the GC to try -** to free some memory and then try the allocation again. -** (It should not be called when shrinking a block, because then the -** interpreter may be in the middle of a collection step.) +** In case of allocation fail, this function will do an emergency +** collection to free some memory and then try the allocation again. +** The GC should not be called while state is not fully built, as the +** collector is not yet fully initialized. Also, it should not be called +** when 'gcstopem' is true, because then the interpreter is in the +** middle of a collection step. */ static void *tryagain (lua_State *L, void *block, size_t osize, size_t nsize) { global_State *g = G(L); - if (ttisnil(&g->nilvalue)) { /* is state fully build? */ + if (completestate(g) && !g->gcstopem) { luaC_fullgc(L, 1); /* try to free some memory... */ return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ } @@ -156,17 +158,14 @@ static void *tryagain (lua_State *L, void *block, /* ** Generic allocation routine. -** If allocation fails while shrinking a block, do not try again; the -** GC shrinks some blocks and it is not reentrant. */ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { void *newblock; global_State *g = G(L); lua_assert((osize == 0) == (block == NULL)); newblock = firsttry(g, block, osize, nsize); - if (unlikely(newblock == NULL && nsize > 0)) { - if (nsize > osize) /* not shrinking a block? */ - newblock = tryagain(L, block, osize, nsize); + if (l_unlikely(newblock == NULL && nsize > 0)) { + newblock = tryagain(L, block, osize, nsize); if (newblock == NULL) /* still no memory? */ return NULL; /* do not update 'GCdebt' */ } @@ -179,7 +178,7 @@ void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { void *luaM_saferealloc_ (lua_State *L, void *block, size_t osize, size_t nsize) { void *newblock = luaM_realloc_(L, block, osize, nsize); - if (unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */ + if (l_unlikely(newblock == NULL && nsize > 0)) /* allocation failed? */ luaM_error(L); return newblock; } @@ -191,7 +190,7 @@ void *luaM_malloc_ (lua_State *L, size_t size, int tag) { else { global_State *g = G(L); void *newblock = firsttry(g, NULL, tag, size); - if (unlikely(newblock == NULL)) { + if (l_unlikely(newblock == NULL)) { newblock = tryagain(L, NULL, tag, size); if (newblock == NULL) luaM_error(L); diff --git a/contrib/lua/src/loadlib.c b/contrib/lua/src/loadlib.c index c0ec9a131b50..6f9fa37366e4 100644 --- a/contrib/lua/src/loadlib.c +++ b/contrib/lua/src/loadlib.c @@ -132,14 +132,16 @@ static void lsys_unloadlib (void *lib) { static void *lsys_load (lua_State *L, const char *path, int seeglb) { void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); - if (lib == NULL) lua_pushstring(L, dlerror()); + if (l_unlikely(lib == NULL)) + lua_pushstring(L, dlerror()); return lib; } static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { lua_CFunction f = cast_func(dlsym(lib, sym)); - if (f == NULL) lua_pushstring(L, dlerror()); + if (l_unlikely(f == NULL)) + lua_pushstring(L, dlerror()); return f; } @@ -410,7 +412,7 @@ static int ll_loadlib (lua_State *L) { const char *path = luaL_checkstring(L, 1); const char *init = luaL_checkstring(L, 2); int stat = lookforfunc(L, path, init); - if (stat == 0) /* no errors? */ + if (l_likely(stat == 0)) /* no errors? */ return 1; /* return the loaded function */ else { /* error; error message is on stack top */ luaL_pushfail(L); @@ -523,14 +525,14 @@ static const char *findfile (lua_State *L, const char *name, const char *path; lua_getfield(L, lua_upvalueindex(1), pname); path = lua_tostring(L, -1); - if (path == NULL) + if (l_unlikely(path == NULL)) luaL_error(L, "'package.%s' must be a string", pname); return searchpath(L, name, path, ".", dirsep); } static int checkload (lua_State *L, int stat, const char *filename) { - if (stat) { /* module loaded successfully? */ + if (l_likely(stat)) { /* module loaded successfully? */ lua_pushstring(L, filename); /* will be 2nd argument to module */ return 2; /* return open function and file name */ } @@ -623,13 +625,14 @@ static void findloader (lua_State *L, const char *name) { int i; luaL_Buffer msg; /* to build error message */ /* push 'package.searchers' to index 3 in the stack */ - if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE) + if (l_unlikely(lua_getfield(L, lua_upvalueindex(1), "searchers") + != LUA_TTABLE)) luaL_error(L, "'package.searchers' must be a table"); luaL_buffinit(L, &msg); /* iterate over available searchers to find a loader */ for (i = 1; ; i++) { luaL_addstring(&msg, "\n\t"); /* error-message prefix */ - if (lua_rawgeti(L, 3, i) == LUA_TNIL) { /* no more searchers? */ + if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */ lua_pop(L, 1); /* remove nil */ luaL_buffsub(&msg, 2); /* remove prefix */ luaL_pushresult(&msg); /* create error message */ diff --git a/contrib/lua/src/lobject.c b/contrib/lua/src/lobject.c index 0e504be03e87..301aa900be0a 100644 --- a/contrib/lua/src/lobject.c +++ b/contrib/lua/src/lobject.c @@ -164,7 +164,7 @@ static int isneg (const char **s) { */ static lua_Number lua_strx2number (const char *s, char **endptr) { int dot = lua_getlocaledecpoint(); - lua_Number r = 0.0; /* result (accumulator) */ + lua_Number r = l_mathop(0.0); /* result (accumulator) */ int sigdig = 0; /* number of significant digits */ int nosigdig = 0; /* number of non-significant digits */ int e = 0; /* exponent correction */ @@ -174,7 +174,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { while (lisspace(cast_uchar(*s))) s++; /* skip initial spaces */ neg = isneg(&s); /* check sign */ if (!(*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X'))) /* check '0x' */ - return 0.0; /* invalid format (no '0x') */ + return l_mathop(0.0); /* invalid format (no '0x') */ for (s += 2; ; s++) { /* skip '0x' and read numeral */ if (*s == dot) { if (hasdot) break; /* second dot? stop loop */ @@ -184,14 +184,14 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { if (sigdig == 0 && *s == '0') /* non-significant digit (zero)? */ nosigdig++; else if (++sigdig <= MAXSIGDIG) /* can read it without overflow? */ - r = (r * cast_num(16.0)) + luaO_hexavalue(*s); + r = (r * l_mathop(16.0)) + luaO_hexavalue(*s); else e++; /* too many digits; ignore, but still count for exponent */ if (hasdot) e--; /* decimal digit? correct exponent */ } else break; /* neither a dot nor a digit */ } if (nosigdig + sigdig == 0) /* no digits? */ - return 0.0; /* invalid format */ + return l_mathop(0.0); /* invalid format */ *endptr = cast_charp(s); /* valid up to here */ e *= 4; /* each digit multiplies/divides value by 2^4 */ if (*s == 'p' || *s == 'P') { /* exponent part? */ @@ -200,7 +200,7 @@ static lua_Number lua_strx2number (const char *s, char **endptr) { s++; /* skip 'p' */ neg1 = isneg(&s); /* sign */ if (!lisdigit(cast_uchar(*s))) - return 0.0; /* invalid; must have at least one digit */ + return l_mathop(0.0); /* invalid; must have at least one digit */ while (lisdigit(cast_uchar(*s))) /* read exponent */ exp1 = exp1 * 10 + *(s++) - '0'; if (neg1) exp1 = -exp1; diff --git a/contrib/lua/src/lobject.h b/contrib/lua/src/lobject.h index 1cc8e757bf16..0e05b3e42ea9 100644 --- a/contrib/lua/src/lobject.h +++ b/contrib/lua/src/lobject.h @@ -68,7 +68,7 @@ typedef struct TValue { #define val_(o) ((o)->value_) -#define valraw(o) (&val_(o)) +#define valraw(o) (val_(o)) /* raw type tag of a TValue */ @@ -112,7 +112,7 @@ typedef struct TValue { #define settt_(o,t) ((o)->tt_=(t)) -/* main macro to copy values (from 'obj1' to 'obj2') */ +/* main macro to copy values (from 'obj2' to 'obj1') */ #define setobj(L,obj1,obj2) \ { TValue *io1=(obj1); const TValue *io2=(obj2); \ io1->value_ = io2->value_; settt_(io1, io2->tt_); \ @@ -136,10 +136,19 @@ typedef struct TValue { /* -** Entries in the Lua stack +** Entries in a Lua stack. Field 'tbclist' forms a list of all +** to-be-closed variables active in this stack. Dummy entries are +** used when the distance between two tbc variables does not fit +** in an unsigned short. They are represented by delta==0, and +** their real delta is always the maximum value that fits in +** that field. */ typedef union StackValue { TValue val; + struct { + TValuefields; + unsigned short delta; + } tbclist; } StackValue; @@ -570,10 +579,11 @@ typedef struct Proto { #define LUA_VCCL makevariant(LUA_TFUNCTION, 2) /* C closure */ #define ttisfunction(o) checktype(o, LUA_TFUNCTION) -#define ttisclosure(o) ((rawtt(o) & 0x1F) == LUA_VLCL) #define ttisLclosure(o) checktag((o), ctb(LUA_VLCL)) #define ttislcf(o) checktag((o), LUA_VLCF) #define ttisCclosure(o) checktag((o), ctb(LUA_VCCL)) +#define ttisclosure(o) (ttisLclosure(o) || ttisCclosure(o)) + #define isLfunction(o) ttisLclosure(o) diff --git a/contrib/lua/src/lopcodes.h b/contrib/lua/src/lopcodes.h index 120cdd94383c..7c2745159606 100644 --- a/contrib/lua/src/lopcodes.h +++ b/contrib/lua/src/lopcodes.h @@ -190,7 +190,8 @@ enum OpMode {iABC, iABx, iAsBx, iAx, isJ}; /* basic instruction formats */ /* -** grep "ORDER OP" if you change these enums +** Grep "ORDER OP" if you change these enums. Opcodes marked with a (*) +** has extra descriptions in the notes after the enumeration. */ typedef enum { @@ -203,7 +204,7 @@ OP_LOADF,/* A sBx R[A] := (lua_Number)sBx */ OP_LOADK,/* A Bx R[A] := K[Bx] */ OP_LOADKX,/* A R[A] := K[extra arg] */ OP_LOADFALSE,/* A R[A] := false */ -OP_LFALSESKIP,/*A R[A] := false; pc++ */ +OP_LFALSESKIP,/*A R[A] := false; pc++ (*) */ OP_LOADTRUE,/* A R[A] := true */ OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */ OP_GETUPVAL,/* A B R[A] := UpValue[B] */ @@ -225,13 +226,13 @@ OP_SELF,/* A B C R[A+1] := R[B]; R[A] := R[B][RK(C):string] */ OP_ADDI,/* A B sC R[A] := R[B] + sC */ -OP_ADDK,/* A B C R[A] := R[B] + K[C] */ -OP_SUBK,/* A B C R[A] := R[B] - K[C] */ -OP_MULK,/* A B C R[A] := R[B] * K[C] */ -OP_MODK,/* A B C R[A] := R[B] % K[C] */ -OP_POWK,/* A B C R[A] := R[B] ^ K[C] */ -OP_DIVK,/* A B C R[A] := R[B] / K[C] */ -OP_IDIVK,/* A B C R[A] := R[B] // K[C] */ +OP_ADDK,/* A B C R[A] := R[B] + K[C]:number */ +OP_SUBK,/* A B C R[A] := R[B] - K[C]:number */ +OP_MULK,/* A B C R[A] := R[B] * K[C]:number */ +OP_MODK,/* A B C R[A] := R[B] % K[C]:number */ +OP_POWK,/* A B C R[A] := R[B] ^ K[C]:number */ +OP_DIVK,/* A B C R[A] := R[B] / K[C]:number */ +OP_IDIVK,/* A B C R[A] := R[B] // K[C]:number */ OP_BANDK,/* A B C R[A] := R[B] & K[C]:integer */ OP_BORK,/* A B C R[A] := R[B] | K[C]:integer */ @@ -254,7 +255,7 @@ OP_BXOR,/* A B C R[A] := R[B] ~ R[C] */ OP_SHL,/* A B C R[A] := R[B] << R[C] */ OP_SHR,/* A B C R[A] := R[B] >> R[C] */ -OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] */ +OP_MMBIN,/* A B C call C metamethod over R[A] and R[B] (*) */ OP_MMBINI,/* A sB C k call C metamethod over R[A] and sB */ OP_MMBINK,/* A B C k call C metamethod over R[A] and K[B] */ @@ -280,7 +281,7 @@ OP_GTI,/* A sB k if ((R[A] > sB) ~= k) then pc++ */ OP_GEI,/* A sB k if ((R[A] >= sB) ~= k) then pc++ */ OP_TEST,/* A k if (not R[A] == k) then pc++ */ -OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] */ +OP_TESTSET,/* A B k if (not R[B] == k) then pc++ else R[A] := R[B] (*) */ OP_CALL,/* A B C R[A], ... ,R[A+C-2] := R[A](R[A+1], ... ,R[A+B-1]) */ OP_TAILCALL,/* A B C k return R[A](R[A+1], ... ,R[A+B-1]) */ @@ -315,6 +316,18 @@ OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */ /*=========================================================================== Notes: + + (*) Opcode OP_LFALSESKIP is used to convert a condition to a boolean + value, in a code equivalent to (not cond ? false : true). (It + produces false and skips the next instruction producing true.) + + (*) Opcodes OP_MMBIN and variants follow each arithmetic and + bitwise opcode. If the operation succeeds, it skips this next + opcode. Otherwise, this opcode calls the corresponding metamethod. + + (*) Opcode OP_TESTSET is used in short-circuit expressions that need + both to jump and to produce a value, such as (a = b or c). + (*) In OP_CALL, if (B == 0) then B = top - A. If (C == 0), then 'top' is set to last_result+1, so next open instruction (OP_CALL, OP_RETURN*, OP_SETLIST) may use 'top'. diff --git a/contrib/lua/src/loslib.c b/contrib/lua/src/loslib.c index e65e188bd727..3e20d622bacd 100644 --- a/contrib/lua/src/loslib.c +++ b/contrib/lua/src/loslib.c @@ -170,7 +170,7 @@ static int os_tmpname (lua_State *L) { char buff[LUA_TMPNAMBUFSIZE]; int err; lua_tmpnam(buff, err); - if (err) + if (l_unlikely(err)) return luaL_error(L, "unable to generate a unique filename"); lua_pushstring(L, buff); return 1; @@ -208,7 +208,7 @@ static int os_clock (lua_State *L) { */ static void setfield (lua_State *L, const char *key, int value, int delta) { #if (defined(LUA_NUMTIME) && LUA_MAXINTEGER <= INT_MAX) - if (value > LUA_MAXINTEGER - delta) + if (l_unlikely(value > LUA_MAXINTEGER - delta)) luaL_error(L, "field '%s' is out-of-bound", key); #endif lua_pushinteger(L, (lua_Integer)value + delta); @@ -253,9 +253,9 @@ static int getfield (lua_State *L, const char *key, int d, int delta) { int t = lua_getfield(L, -1, key); /* get field and its type */ lua_Integer res = lua_tointegerx(L, -1, &isnum); if (!isnum) { /* field is not an integer? */ - if (t != LUA_TNIL) /* some other value? */ + if (l_unlikely(t != LUA_TNIL)) /* some other value? */ return luaL_error(L, "field '%s' is not an integer", key); - else if (d < 0) /* absent field; no default? */ + else if (l_unlikely(d < 0)) /* absent field; no default? */ return luaL_error(L, "field '%s' missing in date table", key); res = d; } diff --git a/contrib/lua/src/lparser.c b/contrib/lua/src/lparser.c index 77813a74e942..3abe3d75187b 100644 --- a/contrib/lua/src/lparser.c +++ b/contrib/lua/src/lparser.c @@ -128,7 +128,7 @@ static void checknext (LexState *ls, int c) { ** in line 'where' (if that is not the current line). */ static void check_match (LexState *ls, int what, int who, int where) { - if (unlikely(!testnext(ls, what))) { + if (l_unlikely(!testnext(ls, what))) { if (where == ls->linenumber) /* all in the same line? */ error_expected(ls, what); /* do not need a complex message */ else { @@ -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)); } @@ -416,6 +416,17 @@ static void markupval (FuncState *fs, int level) { } +/* +** Mark that current block has a to-be-closed variable. +*/ +static void marktobeclosed (FuncState *fs) { + BlockCnt *bl = fs->bl; + bl->upval = 1; + bl->insidetbc = 1; + fs->needclose = 1; +} + + /* ** Find a variable with the given name 'n'. If it is an upvalue, add ** this upvalue into all intermediate functions. If it is a global, set @@ -517,7 +528,7 @@ static void solvegoto (LexState *ls, int g, Labeldesc *label) { Labellist *gl = &ls->dyd->gt; /* list of goto's */ Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */ lua_assert(eqstr(gt->name, label->name)); - if (unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */ + if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */ jumpscopeerror(ls, gt); luaK_patchlist(ls->fs, gt->pc, label->pc); for (i = g; i < gl->n - 1; i++) /* remove goto from pending list */ @@ -620,7 +631,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 +672,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) @@ -1330,13 +1341,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 +1357,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 +1422,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 */ @@ -1435,7 +1446,7 @@ static void breakstat (LexState *ls) { */ static void checkrepeated (LexState *ls, TString *name) { Labeldesc *lb = findlabel(ls, name); - if (unlikely(lb != NULL)) { /* already defined? */ + if (l_unlikely(lb != NULL)) { /* already defined? */ const char *msg = "label '%s' already defined on line %d"; msg = luaO_pushfstring(ls->L, msg, getstr(name), lb->line); luaK_semerror(ls, msg); /* error */ @@ -1488,7 +1499,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 */ } @@ -1520,7 +1531,7 @@ static void fixforjump (FuncState *fs, int pc, int dest, int back) { int offset = dest - (pc + 1); if (back) offset = -offset; - if (unlikely(offset > MAXARG_Bx)) + if (l_unlikely(offset > MAXARG_Bx)) luaX_syntaxerror(fs->ls, "control structure too long"); SETARG_Bx(*jmp, offset); } @@ -1599,7 +1610,7 @@ static void forlist (LexState *ls, TString *indexname) { line = ls->linenumber; adjust_assign(ls, 4, explist(ls, &e), &e); adjustlocalvars(ls, 4); /* control variables */ - markupval(fs, fs->nactvar); /* last control var. must be closed */ + marktobeclosed(fs); /* last control var. must be closed */ luaK_checkstack(fs, 3); /* extra space to call generator */ forbody(ls, base, line, nvars - 4, 1); } @@ -1703,12 +1714,10 @@ static int getlocalattribute (LexState *ls) { } -static void checktoclose (LexState *ls, int level) { +static void checktoclose (FuncState *fs, int level) { if (level != -1) { /* is there a to-be-closed variable? */ - 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); + marktobeclosed(fs); + luaK_codeABC(fs, OP_TBC, reglevel(fs, level), 0, 0); } } @@ -1751,7 +1760,7 @@ static void localstat (LexState *ls) { adjust_assign(ls, nvars, nexps, &e); adjustlocalvars(ls, nvars); } - checktoclose(ls, toclose); + checktoclose(fs, toclose); } @@ -1776,6 +1785,7 @@ static void funcstat (LexState *ls, int line) { luaX_next(ls); /* skip FUNCTION */ ismethod = funcname(ls, &v); body(ls, &b, ismethod, line); + check_readonly(ls, &v); luaK_storevar(ls->fs, &v, &b); luaK_fixline(ls->fs, line); /* definition "happens" in the first line */ } diff --git a/contrib/lua/src/lparser.h b/contrib/lua/src/lparser.h index 2e6dae72f247..5e4500f181a8 100644 --- a/contrib/lua/src/lparser.h +++ b/contrib/lua/src/lparser.h @@ -35,7 +35,7 @@ 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 variable; @@ -77,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; @@ -97,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/contrib/lua/src/lstate.c b/contrib/lua/src/lstate.c index 1c7b8791daf8..1ffe1a0f71cd 100644 --- a/contrib/lua/src/lstate.c +++ b/contrib/lua/src/lstate.c @@ -166,13 +166,13 @@ void luaE_checkcstack (lua_State *L) { if (getCcalls(L) == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11)) - luaD_throw(L, LUA_ERRERR); /* error while handing stack error */ + luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ } LUAI_FUNC void luaE_incCstack (lua_State *L) { L->nCcalls++; - if (unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) + if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) luaE_checkcstack(L); } @@ -181,6 +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); + L1->tbclist = L1->stack; for (i = 0; i < BASIC_STACK_SIZE + EXTRA_STACK; i++) setnilvalue(s2v(L1->stack + i)); /* erase new stack */ L1->top = L1->stack; @@ -213,24 +214,19 @@ 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)); } /* ** open parts of the state that may cause memory-allocation errors. -** ('g->nilvalue' being a nil value flags that the state was completely -** build.) */ static void f_luaopen (lua_State *L, void *ud) { global_State *g = G(L); @@ -240,8 +236,8 @@ static void f_luaopen (lua_State *L, void *ud) { luaS_init(L); luaT_init(L); luaX_init(L); - g->gcrunning = 1; /* allow gc */ - setnilvalue(&g->nilvalue); + g->gcstp = 0; /* allow gc */ + setnilvalue(&g->nilvalue); /* now state is complete */ luai_userstateopen(L); } @@ -256,6 +252,7 @@ static void preinit_thread (lua_State *L, global_State *g) { L->ci = NULL; L->nci = 0; L->twups = L; /* thread has no upvalues */ + L->nCcalls = 0; L->errorJmp = NULL; L->hook = NULL; L->hookmask = 0; @@ -271,10 +268,14 @@ static void preinit_thread (lua_State *L, global_State *g) { static void close_state (lua_State *L) { global_State *g = G(L); - luaF_close(L, L->stack, CLOSEPROTECT); /* close all upvalues */ - luaC_freeallobjects(L); /* collect all objects */ - if (ttisnil(&g->nilvalue)) /* closing a fully built state? */ + if (!completestate(g)) /* closing a partially built state? */ + luaC_freeallobjects(L); /* just collect its objects */ + else { /* closing a fully built state */ + L->ci = &L->base_ci; /* unwind CallInfo list */ + luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */ + luaC_freeallobjects(L); /* collect all objects */ luai_userstateclose(L); + } luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size); freestack(L); lua_assert(gettotalbytes(g) == sizeof(LG)); @@ -299,7 +300,6 @@ LUA_API lua_State *lua_newthread (lua_State *L) { setthvalue2s(L, L->top, L1); api_incr_top(L); preinit_thread(L1, g); - L1->nCcalls = 0; L1->hookmask = L->hookmask; L1->basehookcount = L->basehookcount; L1->hook = L->hook; @@ -316,7 +316,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) { void luaE_freethread (lua_State *L, lua_State *L1) { LX *l = fromstate(L1); - luaF_close(L1, L1->stack, NOCLOSINGMETH); /* close all upvalues */ + luaF_closeupval(L1, L1->stack); /* close all upvalues */ lua_assert(L1->openupval == NULL); luai_userstatefree(L, L1); freestack(L1); @@ -324,23 +324,29 @@ void luaE_freethread (lua_State *L, lua_State *L1) { } -int lua_resetthread (lua_State *L) { - CallInfo *ci; - int status; - lua_lock(L); - L->ci = ci = &L->base_ci; /* unwind CallInfo list */ +int luaE_resetthread (lua_State *L, int status) { + CallInfo *ci = L->ci = &L->base_ci; /* unwind CallInfo list */ setnilvalue(s2v(L->stack)); /* 'function' entry for basic 'ci' */ ci->func = L->stack; ci->callstatus = CIST_C; - status = luaF_close(L, L->stack, CLOSEPROTECT); - if (status != CLOSEPROTECT) /* real errors? */ - luaD_seterrorobj(L, status, L->stack + 1); - else { + if (status == LUA_YIELD) status = LUA_OK; + L->status = LUA_OK; /* so it can run __close metamethods */ + status = luaD_closeprotected(L, 1, status); + if (status != LUA_OK) /* errors? */ + luaD_seterrorobj(L, status, L->stack + 1); + else L->top = L->stack + 1; - } ci->top = L->top + LUA_MINSTACK; - L->status = status; + luaD_reallocstack(L, cast_int(ci->top - L->stack), 0); + return status; +} + + +LUA_API int lua_resetthread (lua_State *L) { + int status; + lua_lock(L); + status = luaE_resetthread(L, L->status); lua_unlock(L); return status; } @@ -360,7 +366,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { preinit_thread(L, g); g->allgc = obj2gco(L); /* by now, only object is the main thread */ L->next = NULL; - L->nCcalls = 0; incnny(L); /* main thread is always non yieldable */ g->frealloc = f; g->ud = ud; @@ -368,13 +373,14 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->ud_warn = NULL; g->mainthread = L; g->seed = luai_makeseed(L); - g->gcrunning = 0; /* no GC while building state */ + g->gcstp = GCSTPGC; /* no GC while building state */ g->strt.size = g->strt.nuse = 0; g->strt.hash = NULL; setnilvalue(&g->l_registry); g->panic = NULL; g->gcstate = GCSpause; g->gckind = KGC_INC; + g->gcstopem = 0; g->gcemergency = 0; g->finobj = g->tobefnz = g->fixedgc = NULL; g->firstold1 = g->survival = g->old1 = g->reallyold = NULL; diff --git a/contrib/lua/src/lstate.h b/contrib/lua/src/lstate.h index cbcf07e203a6..61e82cde7253 100644 --- a/contrib/lua/src/lstate.h +++ b/contrib/lua/src/lstate.h @@ -156,6 +156,18 @@ typedef struct stringtable { /* ** Information about a call. +** About union 'u': +** - field 'l' is used only for Lua functions; +** - field 'c' is used only for C functions. +** About union 'u2': +** - field 'funcidx' is used only by C functions while doing a +** protected call; +** - field 'nyield' is used only while a function is "doing" an +** yield (from the yield until the next resume); +** - field 'nres' is used only while closing tbc variables when +** returning from a function; +** - field 'transferinfo' is used only during call/returnhooks, +** before the function starts or after it ends. */ typedef struct CallInfo { StkId func; /* function index in the stack */ @@ -176,6 +188,7 @@ typedef struct CallInfo { union { int funcidx; /* called-function index */ int nyield; /* number of values yielded */ + int nres; /* number of values returned */ struct { /* info about transferred values (for call/return hooks) */ unsigned short ftransfer; /* offset of first value transferred */ unsigned short ntransfer; /* number of values transferred */ @@ -191,17 +204,34 @@ typedef struct CallInfo { */ #define CIST_OAH (1<<0) /* original value of 'allowhook' */ #define CIST_C (1<<1) /* call is running a C function */ -#define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */ +#define CIST_FRESH (1<<2) /* call is on a fresh "luaV_execute" frame */ #define CIST_HOOKED (1<<3) /* call is running a debug hook */ -#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */ +#define CIST_YPCALL (1<<4) /* doing a yieldable protected call */ #define CIST_TAIL (1<<5) /* call was tail called */ #define CIST_HOOKYIELD (1<<6) /* last hook called yielded */ -#define CIST_FIN (1<<7) /* call is running a finalizer */ +#define CIST_FIN (1<<7) /* function "called" a finalizer */ #define CIST_TRAN (1<<8) /* 'ci' has transfer information */ +#define CIST_CLSRET (1<<9) /* function is closing tbc variables */ +/* Bits 10-12 are used for CIST_RECST (see below) */ +#define CIST_RECST 10 #if defined(LUA_COMPAT_LT_LE) -#define CIST_LEQ (1<<9) /* using __lt for __le */ +#define CIST_LEQ (1<<13) /* using __lt for __le */ #endif + +/* +** Field CIST_RECST stores the "recover status", used to keep the error +** status while closing to-be-closed variables in coroutines, so that +** Lua can correctly resume after an yield from a __close method called +** because of an error. (Three bits are enough for error status.) +*/ +#define getcistrecst(ci) (((ci)->callstatus >> CIST_RECST) & 7) +#define setcistrecst(ci,st) \ + check_exp(((st) & 7) == (st), /* status must fit in three bits */ \ + ((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST)) \ + | ((st) << CIST_RECST))) + + /* active function is a Lua function */ #define isLua(ci) (!((ci)->callstatus & CIST_C)) @@ -230,9 +260,10 @@ typedef struct global_State { lu_byte currentwhite; lu_byte gcstate; /* state of garbage collector */ lu_byte gckind; /* kind of GC running */ + lu_byte gcstopem; /* stops emergency collections */ lu_byte genminormul; /* control for minor generational collections */ lu_byte genmajormul; /* control for major generational collections */ - lu_byte gcrunning; /* true if GC is running */ + lu_byte gcstp; /* control whether GC is running */ lu_byte gcemergency; /* true if this is an emergency collection */ lu_byte gcpause; /* size of pause between successive GCs */ lu_byte gcstepmul; /* GC "speed" */ @@ -281,6 +312,7 @@ struct lua_State { StkId stack_last; /* end of stack (last element + 1) */ StkId stack; /* stack base */ UpVal *openupval; /* list of open upvalues in this stack */ + StkId tbclist; /* list of to-be-closed variables */ GCObject *gclist; struct lua_State *twups; /* list of threads with open upvalues */ struct lua_longjmp *errorJmp; /* current error recover point */ @@ -297,6 +329,12 @@ struct lua_State { #define G(L) (L->l_G) +/* +** 'g->nilvalue' being a nil value flags that the state was completely +** build. +*/ +#define completestate(g) ttisnil(&g->nilvalue) + /* ** Union of all collectable objects (only for conversions) @@ -359,6 +397,7 @@ LUAI_FUNC void luaE_checkcstack (lua_State *L); LUAI_FUNC void luaE_incCstack (lua_State *L); LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont); LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where); +LUAI_FUNC int luaE_resetthread (lua_State *L, int status); #endif diff --git a/contrib/lua/src/lstring.c b/contrib/lua/src/lstring.c index 138871c70da0..13dcaf4259bc 100644 --- a/contrib/lua/src/lstring.c +++ b/contrib/lua/src/lstring.c @@ -89,7 +89,7 @@ void luaS_resize (lua_State *L, int nsize) { if (nsize < osize) /* shrinking table? */ tablerehash(tb->hash, osize, nsize); /* depopulate shrinking part */ newvect = luaM_reallocvector(L, tb->hash, osize, nsize, TString*); - if (unlikely(newvect == NULL)) { /* reallocation failed? */ + if (l_unlikely(newvect == NULL)) { /* reallocation failed? */ if (nsize < osize) /* was it shrinking table? */ tablerehash(tb->hash, nsize, osize); /* restore to original size */ /* leave table as it was */ @@ -172,7 +172,7 @@ void luaS_remove (lua_State *L, TString *ts) { static void growstrtab (lua_State *L, stringtable *tb) { - if (unlikely(tb->nuse == MAX_INT)) { /* too many strings? */ + if (l_unlikely(tb->nuse == MAX_INT)) { /* too many strings? */ luaC_fullgc(L, 1); /* try to free some... */ if (tb->nuse == MAX_INT) /* still too many? */ luaM_error(L); /* cannot even create a message... */ @@ -223,7 +223,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { return internshrstr(L, str, l); else { TString *ts; - if (unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) + if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) luaM_toobig(L); ts = luaS_createlngstrobj(L, l); memcpy(getstr(ts), str, l * sizeof(char)); @@ -259,7 +259,7 @@ Udata *luaS_newudata (lua_State *L, size_t s, int nuvalue) { Udata *u; int i; GCObject *o; - if (unlikely(s > MAX_SIZE - udatamemoffset(nuvalue))) + if (l_unlikely(s > MAX_SIZE - udatamemoffset(nuvalue))) luaM_toobig(L); o = luaC_newobj(L, LUA_VUSERDATA, sizeudata(nuvalue, s)); u = gco2u(o); diff --git a/contrib/lua/src/lstrlib.c b/contrib/lua/src/lstrlib.c index ed88abdb4db2..2b5cd64b6ed9 100644 --- a/contrib/lua/src/lstrlib.c +++ b/contrib/lua/src/lstrlib.c @@ -152,8 +152,9 @@ static int str_rep (lua_State *L) { const char *s = luaL_checklstring(L, 1, &l); lua_Integer n = luaL_checkinteger(L, 2); const char *sep = luaL_optlstring(L, 3, "", &lsep); - if (n <= 0) lua_pushliteral(L, ""); - else if (l + lsep < l || l + lsep > MAXSIZE / n) /* may overflow? */ + if (n <= 0) + lua_pushliteral(L, ""); + else if (l_unlikely(l + lsep < l || l + lsep > MAXSIZE / n)) return luaL_error(L, "resulting string too large"); else { size_t totallen = (size_t)n * l + (size_t)(n - 1) * lsep; @@ -181,7 +182,7 @@ static int str_byte (lua_State *L) { size_t pose = getendpos(L, 3, pi, l); int n, i; if (posi > pose) return 0; /* empty interval; return no values */ - if (pose - posi >= (size_t)INT_MAX) /* arithmetic overflow? */ + if (l_unlikely(pose - posi >= (size_t)INT_MAX)) /* arithmetic overflow? */ return luaL_error(L, "string slice too long"); n = (int)(pose - posi) + 1; luaL_checkstack(L, n, "string slice too long"); @@ -235,7 +236,7 @@ static int str_dump (lua_State *L) { luaL_checktype(L, 1, LUA_TFUNCTION); lua_settop(L, 1); /* ensure function is on the top of the stack */ state.init = 0; - if (lua_dump(L, writer, &state, strip) != 0) + if (l_unlikely(lua_dump(L, writer, &state, strip) != 0)) return luaL_error(L, "unable to dump given function"); luaL_pushresult(&state.B); return 1; @@ -275,7 +276,8 @@ static int tonum (lua_State *L, int arg) { static void trymt (lua_State *L, const char *mtname) { lua_settop(L, 2); /* back to the original arguments */ - if (lua_type(L, 2) == LUA_TSTRING || !luaL_getmetafield(L, 2, mtname)) + if (l_unlikely(lua_type(L, 2) == LUA_TSTRING || + !luaL_getmetafield(L, 2, mtname))) luaL_error(L, "attempt to %s a '%s' with a '%s'", mtname + 2, luaL_typename(L, -2), luaL_typename(L, -1)); lua_insert(L, -3); /* put metamethod before arguments */ @@ -383,7 +385,8 @@ static const char *match (MatchState *ms, const char *s, const char *p); static int check_capture (MatchState *ms, int l) { l -= '1'; - if (l < 0 || l >= ms->level || ms->capture[l].len == CAP_UNFINISHED) + if (l_unlikely(l < 0 || l >= ms->level || + ms->capture[l].len == CAP_UNFINISHED)) return luaL_error(ms->L, "invalid capture index %%%d", l + 1); return l; } @@ -400,14 +403,14 @@ static int capture_to_close (MatchState *ms) { static const char *classend (MatchState *ms, const char *p) { switch (*p++) { case L_ESC: { - if (p == ms->p_end) + if (l_unlikely(p == ms->p_end)) luaL_error(ms->L, "malformed pattern (ends with '%%')"); return p+1; } case '[': { if (*p == '^') p++; do { /* look for a ']' */ - if (p == ms->p_end) + if (l_unlikely(p == ms->p_end)) luaL_error(ms->L, "malformed pattern (missing ']')"); if (*(p++) == L_ESC && p < ms->p_end) p++; /* skip escapes (e.g. '%]') */ @@ -482,7 +485,7 @@ static int singlematch (MatchState *ms, const char *s, const char *p, static const char *matchbalance (MatchState *ms, const char *s, const char *p) { - if (p >= ms->p_end - 1) + if (l_unlikely(p >= ms->p_end - 1)) luaL_error(ms->L, "malformed pattern (missing arguments to '%%b')"); if (*s != *p) return NULL; else { @@ -565,7 +568,7 @@ static const char *match_capture (MatchState *ms, const char *s, int l) { static const char *match (MatchState *ms, const char *s, const char *p) { - if (ms->matchdepth-- == 0) + if (l_unlikely(ms->matchdepth-- == 0)) luaL_error(ms->L, "pattern too complex"); init: /* using goto's to optimize tail recursion */ if (p != ms->p_end) { /* end of pattern? */ @@ -599,7 +602,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { case 'f': { /* frontier? */ const char *ep; char previous; p += 2; - if (*p != '[') + if (l_unlikely(*p != '[')) luaL_error(ms->L, "missing '[' after '%%f' in pattern"); ep = classend(ms, p); /* points to what is next */ previous = (s == ms->src_init) ? '\0' : *(s - 1); @@ -699,7 +702,7 @@ static const char *lmemfind (const char *s1, size_t l1, static size_t get_onecapture (MatchState *ms, int i, const char *s, const char *e, const char **cap) { if (i >= ms->level) { - if (i != 0) + if (l_unlikely(i != 0)) luaL_error(ms->L, "invalid capture index %%%d", i + 1); *cap = s; return e - s; @@ -707,7 +710,7 @@ static size_t get_onecapture (MatchState *ms, int i, const char *s, else { ptrdiff_t capl = ms->capture[i].len; *cap = ms->capture[i].init; - if (capl == CAP_UNFINISHED) + if (l_unlikely(capl == CAP_UNFINISHED)) luaL_error(ms->L, "unfinished capture"); else if (capl == CAP_POSITION) lua_pushinteger(ms->L, (ms->capture[i].init - ms->src_init) + 1); @@ -926,7 +929,7 @@ static int add_value (MatchState *ms, luaL_Buffer *b, const char *s, luaL_addlstring(b, s, e - s); /* keep original text */ return 0; /* no changes */ } - else if (!lua_isstring(L, -1)) + else if (l_unlikely(!lua_isstring(L, -1))) return luaL_error(L, "invalid replacement value (a %s)", luaL_typename(L, -1)); else { @@ -1058,7 +1061,7 @@ static int lua_number2strx (lua_State *L, char *buff, int sz, for (i = 0; i < n; i++) buff[i] = toupper(uchar(buff[i])); } - else if (fmt[SIZELENMOD] != 'a') + else if (l_unlikely(fmt[SIZELENMOD] != 'a')) return luaL_error(L, "modifiers for format '%%a'/'%%A' not implemented"); return n; } @@ -1087,13 +1090,31 @@ static int lua_number2strx (lua_State *L, char *buff, int sz, /* valid flags in a format specification */ -#if !defined(L_FMTFLAGS) -#define L_FMTFLAGS "-+ #0" +#if !defined(L_FMTFLAGSF) + +/* valid flags for a, A, e, E, f, F, g, and G conversions */ +#define L_FMTFLAGSF "-+#0 " + +/* valid flags for o, x, and X conversions */ +#define L_FMTFLAGSX "-#0" + +/* valid flags for d and i conversions */ +#define L_FMTFLAGSI "-+0 " + +/* valid flags for u conversions */ +#define L_FMTFLAGSU "-0" + +/* valid flags for c, p, and s conversions */ +#define L_FMTFLAGSC "-" + #endif /* -** maximum size of each format specification (such as "%-099.99d") +** Maximum size of each format specification (such as "%-099.99d"): +** Initial '%', flags (up to 5), width (2), period, precision (2), +** length modifier (8), conversion specifier, and final '\0', plus some +** extra. */ #define MAX_FORMAT 32 @@ -1121,7 +1142,7 @@ static void addquoted (luaL_Buffer *b, const char *s, size_t len) { } -#if LUA_FLOAT_TYPE != LUA_FLOAT_INT64 +#ifndef LUA_AVOID_FLOAT /* ** Serialize a floating-point number in such a way that it can be ** scanned back by Lua. Use hexadecimal format for "common" numbers @@ -1152,6 +1173,7 @@ static int quotefloat (lua_State *L, char *buff, lua_Number n) { } #endif + static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { switch (lua_type(L, arg)) { case LUA_TSTRING: { @@ -1163,7 +1185,7 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { case LUA_TNUMBER: { char *buff = luaL_prepbuffsize(b, MAX_ITEM); int nb; -#if LUA_FLOAT_TYPE != LUA_FLOAT_INT64 +#ifndef LUA_AVOID_FLOAT if (!lua_isinteger(L, arg)) /* float? */ nb = quotefloat(L, buff, lua_tonumber(L, arg)); else { /* integers */ @@ -1191,25 +1213,53 @@ static void addliteral (lua_State *L, luaL_Buffer *b, int arg) { } -static const char *scanformat (lua_State *L, const char *strfrmt, char *form) { - const char *p = strfrmt; - while (*p != '\0' && strchr(L_FMTFLAGS, *p) != NULL) p++; /* skip flags */ - if ((size_t)(p - strfrmt) >= sizeof(L_FMTFLAGS)/sizeof(char)) - luaL_error(L, "invalid format (repeated flags)"); - if (isdigit(uchar(*p))) p++; /* skip width */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ - if (*p == '.') { - p++; - if (isdigit(uchar(*p))) p++; /* skip precision */ - if (isdigit(uchar(*p))) p++; /* (2 digits at most) */ +static const char *get2digits (const char *s) { + if (isdigit(uchar(*s))) { + s++; + if (isdigit(uchar(*s))) s++; /* (2 digits at most) */ } - if (isdigit(uchar(*p))) - luaL_error(L, "invalid format (width or precision too long)"); + return s; +} + + +/* +** Check whether a conversion specification is valid. When called, +** first character in 'form' must be '%' and last character must +** be a valid conversion specifier. 'flags' are the accepted flags; +** 'precision' signals whether to accept a precision. +*/ +static void checkformat (lua_State *L, const char *form, const char *flags, + int precision) { + const char *spec = form + 1; /* skip '%' */ + spec += strspn(spec, flags); /* skip flags */ + if (*spec != '0') { /* a width cannot start with '0' */ + spec = get2digits(spec); /* skip width */ + if (*spec == '.' && precision) { + spec++; + spec = get2digits(spec); /* skip precision */ + } + } + if (!isalpha(uchar(*spec))) /* did not go to the end? */ + luaL_error(L, "invalid conversion specification: '%s'", form); +} + + +/* +** Get a conversion specification and copy it to 'form'. +** Return the address of its last character. +*/ +static const char *getformat (lua_State *L, const char *strfrmt, + char *form) { + /* spans flags, width, and precision ('0' is included as a flag) */ + size_t len = strspn(strfrmt, L_FMTFLAGSF "123456789."); + len++; /* adds following character (should be the specifier) */ + /* still needs space for '%', '\0', plus a length modifier */ + if (len >= MAX_FORMAT - 10) + luaL_error(L, "invalid format (too long)"); *(form++) = '%'; - memcpy(form, strfrmt, ((p - strfrmt) + 1) * sizeof(char)); - form += (p - strfrmt) + 1; - *form = '\0'; - return p; + memcpy(form, strfrmt, len * sizeof(char)); + *(form + len) = '\0'; + return strfrmt + len - 1; } @@ -1232,6 +1282,7 @@ static int str_format (lua_State *L) { size_t sfl; const char *strfrmt = luaL_checklstring(L, arg, &sfl); const char *strfrmt_end = strfrmt+sfl; + const char *flags; luaL_Buffer b; luaL_buffinit(L, &b); while (strfrmt < strfrmt_end) { @@ -1241,30 +1292,40 @@ static int str_format (lua_State *L) { luaL_addchar(&b, *strfrmt++); /* %% */ else { /* format item */ char form[MAX_FORMAT]; /* to store the format ('%...') */ - int maxitem = MAX_ITEM; - char *buff = luaL_prepbuffsize(&b, maxitem); /* to put formatted item */ - int nb = 0; /* number of bytes in added item */ + int maxitem = MAX_ITEM; /* maximum length for the result */ + char *buff = luaL_prepbuffsize(&b, maxitem); /* to put result */ + int nb = 0; /* number of bytes in result */ if (++arg > top) return luaL_argerror(L, arg, "no value"); - strfrmt = scanformat(L, strfrmt, form); + strfrmt = getformat(L, strfrmt, form); switch (*strfrmt++) { case 'c': { + checkformat(L, form, L_FMTFLAGSC, 0); nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg)); break; } case 'd': case 'i': - case 'o': case 'u': case 'x': case 'X': { + flags = L_FMTFLAGSI; + goto intcase; + case 'u': + flags = L_FMTFLAGSU; + goto intcase; + case 'o': case 'x': case 'X': + flags = L_FMTFLAGSX; + intcase: { lua_Integer n = luaL_checkinteger(L, arg); + checkformat(L, form, flags, 1); addlenmod(form, LUA_INTEGER_FRMLEN); nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n); break; } case 'a': case 'A': + checkformat(L, form, L_FMTFLAGSF, 1); addlenmod(form, LUA_NUMBER_FRMLEN); nb = lua_number2strx(L, buff, maxitem, form, luaL_checknumber(L, arg)); break; -#if LUA_FLOAT_TYPE != LUA_FLOAT_INT64 +#ifndef LUA_AVOID_FLOAT case 'f': maxitem = MAX_ITEMF; /* extra space for '%f' */ buff = luaL_prepbuffsize(&b, maxitem); @@ -1272,12 +1333,14 @@ static int str_format (lua_State *L) { #endif case 'e': case 'E': case 'g': case 'G': { lua_Number n = luaL_checknumber(L, arg); + checkformat(L, form, L_FMTFLAGSF, 1); addlenmod(form, LUA_NUMBER_FRMLEN); nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n); break; } case 'p': { const void *p = lua_topointer(L, arg); + checkformat(L, form, L_FMTFLAGSC, 0); if (p == NULL) { /* avoid calling 'printf' with argument NULL */ p = "(null)"; /* result */ form[strlen(form) - 1] = 's'; /* format it as a string */ @@ -1298,7 +1361,8 @@ static int str_format (lua_State *L) { luaL_addvalue(&b); /* keep entire string */ else { luaL_argcheck(L, l == strlen(s), arg, "string contains zeros"); - if (!strchr(form, '.') && l >= 100) { + checkformat(L, form, L_FMTFLAGSC, 1); + if (strchr(form, '.') == NULL && l >= 100) { /* no precision and string is too long to be formatted */ luaL_addvalue(&b); /* keep entire string */ } @@ -1356,31 +1420,6 @@ static const union { } nativeendian = {1}; -/* dummy structure to get native alignment requirements */ -struct cD { - char c; - union { -#if LUA_FLOAT_TYPE != LUA_FLOAT_INT64 - double d; -#endif - void *p; lua_Integer i; lua_Number n; } u; -}; - -#define MAXALIGN (offsetof(struct cD, u)) - - -/* -** Union for serializing floats -*/ -typedef union Ftypes { -#if LUA_FLOAT_TYPE != LUA_FLOAT_INT64 - float f; - double d; -#endif - lua_Number n; -} Ftypes; - - /* ** information to pack/unpack stuff */ @@ -1397,7 +1436,11 @@ typedef struct Header { typedef enum KOption { Kint, /* signed integers */ Kuint, /* unsigned integers */ - Kfloat, /* floating-point numbers */ +#ifndef LUA_AVOID_FLOAT + Kfloat, /* single-precision floating-point numbers */ + Kdouble, /* double-precision floating-point numbers */ +#endif + Knumber, /* Lua "native" floating-point numbers */ Kchar, /* fixed-length strings */ Kstring, /* strings with prefixed length */ Kzstr, /* zero-terminated strings */ @@ -1432,7 +1475,7 @@ static int getnum (const char **fmt, int df) { */ static int getnumlimit (Header *h, const char **fmt, int df) { int sz = getnum(fmt, df); - if (sz > MAXINTSIZE || sz <= 0) + if (l_unlikely(sz > MAXINTSIZE || sz <= 0)) return luaL_error(h->L, "integral size (%d) out of limits [1,%d]", sz, MAXINTSIZE); return sz; @@ -1453,6 +1496,8 @@ static void initheader (lua_State *L, Header *h) { ** Read and classify next option. 'size' is filled with option's size. */ static KOption getoption (Header *h, const char **fmt, int *size) { + /* dummy structure to get native alignment requirements */ + struct cD { char c; union { LUAI_MAXALIGN; } u; }; int opt = *((*fmt)++); *size = 0; /* default */ switch (opt) { @@ -1465,17 +1510,17 @@ static KOption getoption (Header *h, const char **fmt, int *size) { case 'j': *size = sizeof(lua_Integer); return Kint; case 'J': *size = sizeof(lua_Integer); return Kuint; case 'T': *size = sizeof(size_t); return Kuint; -#if LUA_FLOAT_TYPE != LUA_FLOAT_INT64 +#ifndef LUA_AVOID_FLOAT case 'f': *size = sizeof(float); return Kfloat; - case 'd': *size = sizeof(double); return Kfloat; + case 'd': *size = sizeof(double); return Kdouble; #endif - case 'n': *size = sizeof(lua_Number); return Kfloat; + case 'n': *size = sizeof(lua_Number); return Knumber; case 'i': *size = getnumlimit(h, fmt, sizeof(int)); return Kint; case 'I': *size = getnumlimit(h, fmt, sizeof(int)); return Kuint; case 's': *size = getnumlimit(h, fmt, sizeof(size_t)); return Kstring; case 'c': *size = getnum(fmt, -1); - if (*size == -1) + if (l_unlikely(*size == -1)) luaL_error(h->L, "missing size for format option 'c'"); return Kchar; case 'z': return Kzstr; @@ -1485,7 +1530,11 @@ static KOption getoption (Header *h, const char **fmt, int *size) { case '<': h->islittle = 1; break; case '>': h->islittle = 0; break; case '=': h->islittle = nativeendian.little; break; - case '!': h->maxalign = getnumlimit(h, fmt, MAXALIGN); break; + case '!': { + const int maxalign = offsetof(struct cD, u); + h->maxalign = getnumlimit(h, fmt, maxalign); + break; + } default: luaL_error(h->L, "invalid format option '%c'", opt); } return Knop; @@ -1514,7 +1563,7 @@ static KOption getdetails (Header *h, size_t totalsize, else { if (align > h->maxalign) /* enforce maximum alignment */ align = h->maxalign; - if ((align & (align - 1)) != 0) /* is 'align' not a power of 2? */ + if (l_unlikely((align & (align - 1)) != 0)) /* not a power of 2? */ luaL_argerror(h->L, 1, "format asks for alignment not power of 2"); *ntoalign = (align - (int)(totalsize & (align - 1))) & (align - 1); } @@ -1595,22 +1644,34 @@ static int str_pack (lua_State *L) { packint(&b, (lua_Unsigned)n, h.islittle, size, 0); break; } - case Kfloat: { /* floating-point options */ - Ftypes u; - char *buff = luaL_prepbuffsize(&b, size); - lua_Number n = luaL_checknumber(L, arg); /* get argument */ -#if LUA_FLOAT_TYPE != LUA_FLOAT_INT64 - if (size == sizeof(u.f)) u.f = (float)n; /* copy it into 'u' */ - else if (size == sizeof(u.d)) u.d = (double)n; - else u.n = n; -#else - u.n = n; -#endif - /* move 'u' to final result, correcting endianness if needed */ - copywithendian(buff, (char *)&u, size, h.islittle); +#ifndef LUA_AVOID_FLOAT + case Kfloat: { /* C float */ + float f = (float)luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); luaL_addsize(&b, size); break; } +#endif + case Knumber: { /* Lua float */ + lua_Number f = luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); + luaL_addsize(&b, size); + break; + } +#ifndef LUA_AVOID_FLOAT + case Kdouble: { /* C double */ + double f = (double)luaL_checknumber(L, arg); /* get argument */ + char *buff = luaL_prepbuffsize(&b, sizeof(f)); + /* move 'f' to final result, correcting endianness if needed */ + copywithendian(buff, (char *)&f, sizeof(f), h.islittle); + luaL_addsize(&b, size); + break; + } +#endif case Kchar: { /* fixed-size string */ size_t len; const char *s = luaL_checklstring(L, arg, &len); @@ -1698,7 +1759,7 @@ static lua_Integer unpackint (lua_State *L, const char *str, else if (size > SZINT) { /* must check unread bytes */ int mask = (!issigned || (lua_Integer)res >= 0) ? 0 : MC; for (i = limit; i < size; i++) { - if ((unsigned char)str[islittle ? i : size - 1 - i] != mask) + if (l_unlikely((unsigned char)str[islittle ? i : size - 1 - i] != mask)) luaL_error(L, "%d-byte integer does not fit into Lua Integer", size); } } @@ -1732,20 +1793,28 @@ static int str_unpack (lua_State *L) { lua_pushinteger(L, res); break; } +#ifndef LUA_AVOID_FLOAT case Kfloat: { - Ftypes u; - lua_Number num; - copywithendian((char *)&u, data + pos, size, h.islittle); -#if LUA_FLOAT_TYPE != LUA_FLOAT_INT64 - if (size == sizeof(u.f)) num = (lua_Number)u.f; - else if (size == sizeof(u.d)) num = (lua_Number)u.d; - else num = u.n; -#else - num = u.n; -#endif - lua_pushnumber(L, num); + float f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, (lua_Number)f); break; } +#endif + case Knumber: { + lua_Number f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, f); + break; + } +#ifndef LUA_AVOID_FLOAT + case Kdouble: { + double f; + copywithendian((char *)&f, data + pos, sizeof(f), h.islittle); + lua_pushnumber(L, (lua_Number)f); + break; + } +#endif case Kchar: { lua_pushlstring(L, data + pos, size); break; diff --git a/contrib/lua/src/ltable.c b/contrib/lua/src/ltable.c index 7e7cbed97cbf..1b1cd2415b60 100644 --- a/contrib/lua/src/ltable.c +++ b/contrib/lua/src/ltable.c @@ -68,18 +68,21 @@ #define MAXHSIZE luaM_limitN(1u << MAXHBITS, Node) +/* +** When the original hash value is good, hashing by a power of 2 +** avoids the cost of '%'. +*/ #define hashpow2(t,n) (gnode(t, lmod((n), sizenode(t)))) +/* +** for other types, it is better to avoid modulo by power of 2, as +** they can have many 2 factors. +*/ +#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) + + #define hashstr(t,str) hashpow2(t, (str)->hash) #define hashboolean(t,p) hashpow2(t, p) -#define hashint(t,i) hashpow2(t, i) - - -/* -** for some types, it is better to avoid modulus by power of 2, as -** they tend to have many 2 factors. -*/ -#define hashmod(t,n) (gnode(t, ((n) % ((sizenode(t)-1)|1)))) #define hashpointer(t,p) hashmod(t, point2uint(p)) @@ -96,6 +99,20 @@ static const Node dummynode_ = { static const TValue absentkey = {ABSTKEYCONSTANT}; +/* +** Hash for integers. To allow a good hash, use the remainder operator +** ('%'). If integer fits as a non-negative int, compute an int +** remainder, which is faster. Otherwise, use an unsigned-integer +** remainder, which uses all bits and ensures a non-negative result. +*/ +static Node *hashint (const Table *t, lua_Integer i) { + lua_Unsigned ui = l_castS2U(i); + if (ui <= (unsigned int)INT_MAX) + return hashmod(t, cast_int(ui)); + else + return hashmod(t, ui); +} + /* ** Hash for floating-point numbers. @@ -129,39 +146,50 @@ static int l_hashfloat (lua_Number n) { /* ** returns the 'main' position of an element in a table (that is, -** the index of its hash value). The key comes broken (tag in 'ktt' -** and value in 'vkl') so that we can call it on keys inserted into -** nodes. +** the index of its hash value). */ -static Node *mainposition (const Table *t, int ktt, const Value *kvl) { - switch (withvariant(ktt)) { - case LUA_VNUMINT: - return hashint(t, ivalueraw(*kvl)); - case LUA_VNUMFLT: - return hashmod(t, l_hashfloat(fltvalueraw(*kvl))); - case LUA_VSHRSTR: - return hashstr(t, tsvalueraw(*kvl)); - case LUA_VLNGSTR: - return hashpow2(t, luaS_hashlongstr(tsvalueraw(*kvl))); +static Node *mainpositionTV (const Table *t, const TValue *key) { + switch (ttypetag(key)) { + case LUA_VNUMINT: { + lua_Integer i = ivalue(key); + return hashint(t, i); + } + case LUA_VNUMFLT: { + lua_Number n = fltvalue(key); + return hashmod(t, l_hashfloat(n)); + } + case LUA_VSHRSTR: { + TString *ts = tsvalue(key); + return hashstr(t, ts); + } + case LUA_VLNGSTR: { + TString *ts = tsvalue(key); + return hashpow2(t, luaS_hashlongstr(ts)); + } case LUA_VFALSE: return hashboolean(t, 0); case LUA_VTRUE: return hashboolean(t, 1); - case LUA_VLIGHTUSERDATA: - return hashpointer(t, pvalueraw(*kvl)); - case LUA_VLCF: - return hashpointer(t, fvalueraw(*kvl)); - default: - return hashpointer(t, gcvalueraw(*kvl)); + case LUA_VLIGHTUSERDATA: { + void *p = pvalue(key); + return hashpointer(t, p); + } + case LUA_VLCF: { + lua_CFunction f = fvalue(key); + return hashpointer(t, f); + } + default: { + GCObject *o = gcvalue(key); + return hashpointer(t, o); + } } } -/* -** Returns the main position of an element given as a 'TValue' -*/ -static Node *mainpositionTV (const Table *t, const TValue *key) { - return mainposition(t, rawtt(key), valraw(key)); +l_sinline Node *mainpositionfromnode (const Table *t, Node *nd) { + TValue key; + getnodekey(cast(lua_State *, NULL), &key, nd); + return mainpositionTV(t, &key); } @@ -307,7 +335,7 @@ static unsigned int findindex (lua_State *L, Table *t, TValue *key, return i; /* yes; that's the index */ else { const TValue *n = getgeneric(t, key, 1); - if (unlikely(isabstkey(n))) + if (l_unlikely(isabstkey(n))) luaG_runerror(L, "invalid key to 'next'"); /* key not found */ i = cast_int(nodefromval(n) - gnode(t, 0)); /* key index in hash table */ /* hash elements are numbered after array ones */ @@ -485,7 +513,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)); } } } @@ -541,7 +569,7 @@ void luaH_resize (lua_State *L, Table *t, unsigned int newasize, } /* allocate new array */ newarray = luaM_reallocvector(L, t->array, oldasize, newasize, TValue); - if (unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ + if (l_unlikely(newarray == NULL && newasize > 0)) { /* allocation failed? */ freehash(L, &newt); /* release new hash part */ luaM_error(L); /* raise error (with array unchanged) */ } @@ -632,10 +660,10 @@ 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))) + if (l_unlikely(ttisnil(key))) luaG_runerror(L, "table index is nil"); else if (ttisfloat(key)) { lua_Number f = fltvalue(key); @@ -644,9 +672,11 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) { setivalue(&aux, k); key = &aux; /* insert it as an integer */ } - else if (unlikely(luai_numisnan(f))) + else if (l_unlikely(luai_numisnan(f))) luaG_runerror(L, "table index is NaN"); } + if (ttisnil(value)) + return; /* do not insert nil values */ mp = mainpositionTV(t, key); if (!isempty(gval(mp)) || isdummy(t)) { /* main position is taken? */ Node *othern; @@ -654,10 +684,11 @@ 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)); + othern = mainpositionfromnode(t, mp); if (othern != mp) { /* is colliding node out of its main position? */ /* yes; move colliding node into free position */ while (othern + gnext(othern) != mp) /* find previous */ @@ -682,7 +713,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); } @@ -769,29 +800,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/contrib/lua/src/ltable.h b/contrib/lua/src/ltable.h index c0060f4b6e70..7bbbcb213f8b 100644 --- a/contrib/lua/src/ltable.h +++ b/contrib/lua/src/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/contrib/lua/src/ltablib.c b/contrib/lua/src/ltablib.c index d344a47e9ad2..868d78fd83ec 100644 --- a/contrib/lua/src/ltablib.c +++ b/contrib/lua/src/ltablib.c @@ -59,8 +59,9 @@ static void checktab (lua_State *L, int arg, int what) { static int tinsert (lua_State *L) { - lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */ lua_Integer pos; /* where to insert new element */ + lua_Integer e = aux_getn(L, 1, TAB_RW); + e = luaL_intop(+, e, 1); /* first empty element */ switch (lua_gettop(L)) { case 2: { /* called with only 2 arguments */ pos = e; /* insert new element at the end */ @@ -145,9 +146,9 @@ static int tmove (lua_State *L) { 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); + if (l_unlikely(!lua_isstring(L, -1))) + luaL_error(L, "invalid value (%s) at index %I in table for 'concat'", + luaL_typename(L, -1), (LUAI_UACINT)i); luaL_addvalue(b); } @@ -196,7 +197,8 @@ static int tunpack (lua_State *L) { 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))) + if (l_unlikely(n >= (unsigned int)INT_MAX || + !lua_checkstack(L, (int)(++n)))) return luaL_error(L, "too many results to unpack"); for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */ lua_geti(L, 1, i); @@ -300,14 +302,14 @@ static IdxT partition (lua_State *L, IdxT lo, IdxT up) { for (;;) { /* next loop: repeat ++i while a[i] < P */ while ((void)lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) { - if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */ + if (l_unlikely(i == up - 1)) /* a[i] < P but a[up - 1] == P ?? */ luaL_error(L, "invalid order function for sorting"); 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 ((void)lua_geti(L, 1, --j), sort_comp(L, -3, -1)) { - if (j < i) /* j < i but a[j] > P ?? */ + if (l_unlikely(j < i)) /* j < i but a[j] > P ?? */ luaL_error(L, "invalid order function for sorting"); lua_pop(L, 1); /* remove a[j] */ } diff --git a/contrib/lua/src/ltm.c b/contrib/lua/src/ltm.c index 4770f96bb612..b657b783a801 100644 --- a/contrib/lua/src/ltm.c +++ b/contrib/lua/src/ltm.c @@ -147,7 +147,7 @@ static int callbinTM (lua_State *L, const TValue *p1, const TValue *p2, void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, StkId res, TMS event) { - if (!callbinTM(L, p1, p2, res, event)) { + if (l_unlikely(!callbinTM(L, p1, p2, res, event))) { switch (event) { case TM_BAND: case TM_BOR: case TM_BXOR: case TM_SHL: case TM_SHR: case TM_BNOT: { @@ -166,7 +166,8 @@ void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, void luaT_tryconcatTM (lua_State *L) { StkId top = L->top; - if (!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, TM_CONCAT)) + if (l_unlikely(!callbinTM(L, s2v(top - 2), s2v(top - 1), top - 2, + TM_CONCAT))) luaG_concaterror(L, s2v(top - 2), s2v(top - 1)); } diff --git a/contrib/lua/src/lua.c b/contrib/lua/src/lua.c index b5b884b6d016..0f1900444499 100644 --- a/contrib/lua/src/lua.c +++ b/contrib/lua/src/lua.c @@ -37,6 +37,26 @@ static lua_State *globalL = NULL; static const char *progname = LUA_PROGNAME; +#if defined(LUA_USE_POSIX) /* { */ + +/* +** Use 'sigaction' when available. +*/ +static void setsignal (int sig, void (*handler)(int)) { + struct sigaction sa; + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); /* do not mask any signal */ + sigaction(sig, &sa, NULL); +} + +#else /* }{ */ + +#define setsignal signal + +#endif /* } */ + + /* ** Hook set by signal function to stop the interpreter. */ @@ -55,7 +75,7 @@ static void lstop (lua_State *L, lua_Debug *ar) { */ static void laction (int i) { int flag = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT; - signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */ + setsignal(i, SIG_DFL); /* if another SIGINT happens, terminate process */ lua_sethook(globalL, lstop, flag, 1); } @@ -69,14 +89,15 @@ static void print_usage (const char *badoption) { lua_writestringerror( "usage: %s [options] [script [args]]\n" "Available options are:\n" - " -e stat execute string 'stat'\n" - " -i enter interactive mode after executing 'script'\n" - " -l name require library 'name' into global 'name'\n" - " -v show version information\n" - " -E ignore environment variables\n" - " -W turn warnings on\n" - " -- stop handling options\n" - " - stop handling options and execute stdin\n" + " -e stat execute string 'stat'\n" + " -i enter interactive mode after executing 'script'\n" + " -l mod require library 'mod' into global 'mod'\n" + " -l g=mod require library 'mod' into global 'g'\n" + " -v show version information\n" + " -E ignore environment variables\n" + " -W turn warnings on\n" + " -- stop handling options\n" + " - stop handling options and execute stdin\n" , progname); } @@ -135,9 +156,9 @@ static int docall (lua_State *L, int narg, int nres) { lua_pushcfunction(L, msghandler); /* push message handler */ lua_insert(L, base); /* put it under function and args */ globalL = L; /* to be available to 'laction' */ - signal(SIGINT, laction); /* set C-signal handler */ + setsignal(SIGINT, laction); /* set C-signal handler */ status = lua_pcall(L, narg, nres, base); - signal(SIGINT, SIG_DFL); /* reset C-signal handler */ + setsignal(SIGINT, SIG_DFL); /* reset C-signal handler */ lua_remove(L, base); /* remove message handler from the stack */ return status; } @@ -187,16 +208,22 @@ static int dostring (lua_State *L, const char *s, const char *name) { /* -** Calls 'require(name)' and stores the result in a global variable -** with the given name. +** Receives 'globname[=modname]' and runs 'globname = require(modname)'. */ -static int dolibrary (lua_State *L, const char *name) { +static int dolibrary (lua_State *L, char *globname) { int status; + char *modname = strchr(globname, '='); + if (modname == NULL) /* no explicit name? */ + modname = globname; /* module name is equal to global name */ + else { + *modname = '\0'; /* global name ends here */ + modname++; /* module name starts after the '=' */ + } lua_getglobal(L, "require"); - lua_pushstring(L, name); - status = docall(L, 1, 1); /* call 'require(name)' */ + lua_pushstring(L, modname); + status = docall(L, 1, 1); /* call 'require(modname)' */ if (status == LUA_OK) - lua_setglobal(L, name); /* global[name] = require return */ + lua_setglobal(L, globname); /* globname = require(modname) */ return report(L, status); } @@ -307,7 +334,7 @@ static int runargs (lua_State *L, char **argv, int n) { switch (option) { case 'e': case 'l': { int status; - const char *extra = argv[i] + 2; /* both options need an argument */ + char *extra = argv[i] + 2; /* both options need an argument */ if (*extra == '\0') extra = argv[++i]; lua_assert(extra != NULL); status = (option == 'e') diff --git a/contrib/lua/src/lua.h b/contrib/lua/src/lua.h index c9d64d7f2124..e6618392cc7e 100644 --- a/contrib/lua/src/lua.h +++ b/contrib/lua/src/lua.h @@ -18,14 +18,14 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "4" -#define LUA_VERSION_RELEASE "2" +#define LUA_VERSION_RELEASE "4" #define LUA_VERSION_NUM 504 -#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 0) +#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 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-2020 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -347,7 +347,8 @@ LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s); LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud); -LUA_API void (lua_toclose) (lua_State *L, int idx); +LUA_API void (lua_toclose) (lua_State *L, int idx); +LUA_API void (lua_closeslot) (lua_State *L, int idx); /* @@ -491,7 +492,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2020 Lua.org, PUC-Rio. +* Copyright (C) 1994-2022 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/contrib/lua/src/luac.c b/contrib/lua/src/luac.c index 56ddc41483f4..f6db9cf656bb 100644 --- a/contrib/lua/src/luac.c +++ b/contrib/lua/src/luac.c @@ -155,6 +155,7 @@ static const Proto* combine(lua_State* L, int n) f->p[i]=toproto(L,i-n-1); if (f->p[i]->sizeupvalues>0) f->p[i]->upvalues[0].instack=0; } + luaM_freearray(L,f->lineinfo,f->sizelineinfo); f->sizelineinfo=0; return f; } @@ -600,11 +601,11 @@ static void PrintCode(const Proto* f) if (c==0) printf("all out"); else printf("%d out",c-1); break; case OP_TAILCALL: - printf("%d %d %d",a,b,c); + printf("%d %d %d%s",a,b,c,ISK); printf(COMMENT "%d in",b-1); break; case OP_RETURN: - printf("%d %d %d",a,b,c); + printf("%d %d %d%s",a,b,c,ISK); printf(COMMENT); if (b==0) printf("all out"); else printf("%d out",b-1); break; @@ -619,7 +620,7 @@ static void PrintCode(const Proto* f) break; case OP_FORPREP: printf("%d %d",a,bx); - printf(COMMENT "to %d",pc+bx+2); + printf(COMMENT "exit to %d",pc+bx+3); break; case OP_TFORPREP: printf("%d %d",a,bx); diff --git a/contrib/lua/src/luaconf.h b/contrib/lua/src/luaconf.h new file mode 100644 index 000000000000..eab6318aaaef --- /dev/null +++ b/contrib/lua/src/luaconf.h @@ -0,0 +1,786 @@ +/* +** $Id: luaconf.h $ +** Configuration file for Lua +** See Copyright Notice in lua.h +*/ + + +#ifndef luaconf_h +#define luaconf_h + +#include +#include + + +/* +** =================================================================== +** General Configuration File for Lua +** +** Some definitions here can be changed externally, through the compiler +** (e.g., with '-D' options): They are commented out or protected +** by '#if !defined' guards. However, several other definitions +** should be changed directly here, either because they affect the +** Lua ABI (by making the changes here, you ensure that all software +** connected to Lua, such as C libraries, will be compiled with the same +** configuration); or because they are seldom changed. +** +** Search for "@@" to find all configurable definitions. +** =================================================================== +*/ + + +/* +** {==================================================================== +** System Configuration: macros to adapt (if needed) Lua to some +** particular platform, for instance restricting it to C89. +** ===================================================================== +*/ + +/* +@@ LUA_USE_C89 controls the use of non-ISO-C89 features. +** Define it if you want Lua to avoid the use of a few C99 features +** or Windows-specific features on Windows. +*/ +/* #define LUA_USE_C89 */ + + +/* +** By default, Lua on Windows use (some) specific Windows features +*/ +#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE) +#define LUA_USE_WINDOWS /* enable goodies for regular Windows */ +#endif + + +#if defined(LUA_USE_WINDOWS) +#define LUA_DL_DLL /* enable support for DLL */ +#define LUA_USE_C89 /* broadly, Windows is C89 */ +#endif + + +#if defined(LUA_USE_LINUX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* needs an extra library: -ldl */ +#endif + + +#if defined(LUA_USE_MACOSX) +#define LUA_USE_POSIX +#define LUA_USE_DLOPEN /* MacOS does not need -ldl */ +#endif + + +/* +@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits. +*/ +#define LUAI_IS32INT ((UINT_MAX >> 30) >= 3) + +/* }================================================================== */ + + + +/* +** {================================================================== +** Configuration for Number types. These options should not be +** set externally, because any other code connected to Lua must +** use the same configuration. +** =================================================================== +*/ + +/* +@@ 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 supported +** by your C compiler. The usual configurations are 64-bit integers +** and 'double' (the default), 32-bit integers and 'float' (for +** restricted platforms), and 'long'/'double' (for C compilers not +** 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 + + +/* Default configuration ('long long' and 'double', for 64-bit Lua) */ +#define LUA_INT_DEFAULT LUA_INT_LONGLONG +#define LUA_FLOAT_DEFAULT LUA_FLOAT_DOUBLE + + +/* +@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. +*/ +#define LUA_32BITS 0 + + +/* +@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for +** C89 ('long' and 'double'); Windows always has '__int64', so it does +** not need to use this case. +*/ +#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) +#define LUA_C89_NUMBERS 1 +#else +#define LUA_C89_NUMBERS 0 +#endif + + +#if LUA_32BITS /* { */ +/* +** 32-bit integers and 'float' +*/ +#if LUAI_IS32INT /* use 'int' if big enough */ +#define LUA_INT_TYPE LUA_INT_INT +#else /* otherwise use 'long' */ +#define LUA_INT_TYPE LUA_INT_LONG +#endif +#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT + +#elif LUA_C89_NUMBERS /* }{ */ +/* +** largest types available for C89 ('long' and 'double') +*/ +#define LUA_INT_TYPE LUA_INT_LONG +#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE + +#else /* }{ */ +/* use defaults */ + +#define LUA_INT_TYPE LUA_INT_DEFAULT +#define LUA_FLOAT_TYPE LUA_FLOAT_DEFAULT + +#endif /* } */ + + +/* }================================================================== */ + + + +/* +** {================================================================== +** Configuration for Paths. +** =================================================================== +*/ + +/* +** 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 +** C libraries. +** CHANGE them if your machine has a non-conventional directory +** hierarchy or if you want to install your libraries in +** non-conventional directories. +*/ + +#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#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. +*/ +#define LUA_LDIR "!\\lua\\" +#define LUA_CDIR "!\\" +#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\" + +#if !defined(LUA_PATH_DEFAULT) +#define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \ + LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \ + ".\\?.lua;" ".\\?\\init.lua" +#endif + +#if !defined(LUA_CPATH_DEFAULT) +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.dll;" \ + LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \ + LUA_CDIR"loadall.dll;" ".\\?.dll" +#endif + +#else /* }{ */ + +#define LUA_ROOT "/usr/local/" +#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/" +#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/" + +#if !defined(LUA_PATH_DEFAULT) +#define LUA_PATH_DEFAULT \ + LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \ + LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \ + "./?.lua;" "./?/init.lua" +#endif + +#if !defined(LUA_CPATH_DEFAULT) +#define LUA_CPATH_DEFAULT \ + LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so" +#endif + +#endif /* } */ + + +/* +@@ LUA_DIRSEP is the directory separator (for submodules). +** CHANGE it if your machine does not use "/" as the directory separator +** and is not Windows. (On Windows Lua automatically uses "\".) +*/ +#if !defined(LUA_DIRSEP) + +#if defined(_WIN32) +#define LUA_DIRSEP "\\" +#else +#define LUA_DIRSEP "/" +#endif + +#endif + +/* }================================================================== */ + + +/* +** {================================================================== +** Marks for exported symbols in the C code +** =================================================================== +*/ + +/* +@@ LUA_API is a mark for all core API functions. +@@ LUALIB_API is a mark for all auxiliary library functions. +@@ LUAMOD_API is a mark for all standard library opening functions. +** CHANGE them if you need to define those functions in some special way. +** For instance, if you want to create one Windows DLL with the core and +** the libraries, you may want to use the following definition (define +** LUA_BUILD_AS_DLL to get it). +*/ +#if defined(LUA_BUILD_AS_DLL) /* { */ + +#if defined(LUA_CORE) || defined(LUA_LIB) /* { */ +#define LUA_API __declspec(dllexport) +#else /* }{ */ +#define LUA_API __declspec(dllimport) +#endif /* } */ + +#else /* }{ */ + +#define LUA_API extern + +#endif /* } */ + + +/* +** More often than not the libs go together with the core. +*/ +#define LUALIB_API LUA_API +#define LUAMOD_API LUA_API + + +/* +@@ LUAI_FUNC is a mark for all extern functions that are not to be +** exported to outside modules. +@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables, +** none of which to be exported to outside modules (LUAI_DDEF for +** definitions and LUAI_DDEC for declarations). +** CHANGE them if you need to mark them in some special way. Elf/gcc +** (versions 3.2 and later) mark them as "hidden" to optimize access +** when Lua is compiled as a shared library. Not all elf targets support +** this attribute. Unfortunately, gcc does not offer a way to check +** whether the target offers that support, and those without support +** give a warning about it. To avoid these warnings, change to the +** default definition. +*/ +#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \ + defined(__ELF__) /* { */ +#define LUAI_FUNC __attribute__((visibility("internal"))) extern +#else /* }{ */ +#define LUAI_FUNC extern +#endif /* } */ + +#define LUAI_DDEC(dec) LUAI_FUNC dec +#define LUAI_DDEF /* empty */ + +/* }================================================================== */ + + +/* +** {================================================================== +** Compatibility with previous versions +** =================================================================== +*/ + +/* +@@ LUA_COMPAT_5_3 controls other macros for compatibility with Lua 5.3. +** You can define it to get all options, or change specific options +** to fit your specific needs. +*/ +#if defined(LUA_COMPAT_5_3) /* { */ + +/* +@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated +** functions in the mathematical library. +** (These functions were already officially removed in 5.3; +** nevertheless they are still available here.) +*/ +#define LUA_COMPAT_MATHLIB + +/* +@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for +** manipulating other integer types (lua_pushunsigned, lua_tounsigned, +** luaL_checkint, luaL_checklong, etc.) +** (These macros were also officially removed in 5.3, but they are still +** available here.) +*/ +#define LUA_COMPAT_APIINTCASTS + + +/* +@@ LUA_COMPAT_LT_LE controls the emulation of the '__le' metamethod +** using '__lt'. +*/ +#define LUA_COMPAT_LT_LE + + +/* +@@ The following macros supply trivial compatibility for some +** changes in the API. The macros themselves document how to +** change your code to avoid using them. +** (Once more, these macros were officially removed in 5.3, but they are +** still available here.) +*/ +#define lua_strlen(L,i) lua_rawlen(L, (i)) + +#define lua_objlen(L,i) lua_rawlen(L, (i)) + +#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ) +#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT) + +#endif /* } */ + +/* }================================================================== */ + + + +/* +** {================================================================== +** Configuration for Numbers (low-level part). +** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_* +** satisfy your needs. +** =================================================================== +*/ + +/* +@@ LUAI_UACNUMBER is the result of a 'default argument promotion' +@@ over a floating number. +@@ l_floatatt(x) corrects float attribute '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 numeral to a number. +*/ + + +/* 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 with an integral value +** 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_floatatt(n) (FLT_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.7g" + +#define l_mathop(op) op##f + +#define lua_str2number(s,p) strtof((s), (p)) + + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */ + +#define LUA_NUMBER long double + +#define l_floatatt(n) (LDBL_##n) + +#define LUAI_UACNUMBER long double + +#define LUA_NUMBER_FRMLEN "L" +#define LUA_NUMBER_FMT "%.19Lg" + +#define l_mathop(op) op##l + +#define lua_str2number(s,p) strtold((s), (p)) + +#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */ + +#define LUA_NUMBER double + +#define l_floatatt(n) (DBL_##n) + +#define LUAI_UACNUMBER double + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%.14g" + +#define l_mathop(op) op + +#define lua_str2number(s,p) strtod((s), (p)) + +#else /* }{ */ + +#error "numeric float type not defined" + +#endif /* } */ + + + +/* +@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. +@@ 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. +@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. +@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. +@@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED. +@@ lua_integer2str converts an integer to a string. +*/ + + +/* The following definitions are good for most cases here */ + +#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d" + +#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) +*/ +#define LUA_UNSIGNED unsigned LUAI_UACINT + + +/* now the variable definitions */ + +#if LUA_INT_TYPE == LUA_INT_INT /* { int */ + +#define LUA_INTEGER int +#define LUA_INTEGER_FRMLEN "" + +#define LUA_MAXINTEGER INT_MAX +#define LUA_MININTEGER INT_MIN + +#define LUA_MAXUNSIGNED UINT_MAX + +#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */ + +#define LUA_INTEGER long +#define LUA_INTEGER_FRMLEN "l" + +#define LUA_MAXINTEGER LONG_MAX +#define LUA_MININTEGER LONG_MIN + +#define LUA_MAXUNSIGNED ULONG_MAX + +#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 */ + +#define LUA_INTEGER long long +#define LUA_INTEGER_FRMLEN "ll" + +#define LUA_MAXINTEGER LLONG_MAX +#define LUA_MININTEGER LLONG_MIN + +#define LUA_MAXUNSIGNED ULLONG_MAX + +#elif defined(LUA_USE_WINDOWS) /* }{ */ +/* in Windows, can use specific Windows types */ + +#define LUA_INTEGER __int64 +#define LUA_INTEGER_FRMLEN "I64" + +#define LUA_MAXINTEGER _I64_MAX +#define LUA_MININTEGER _I64_MIN + +#define LUA_MAXUNSIGNED _UI64_MAX + +#else /* }{ */ + +#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \ + or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)" + +#endif /* } */ + +#else /* }{ */ + +#error "numeric integer type not defined" + +#endif /* } */ + +/* }================================================================== */ + + +/* +** {================================================================== +** 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 a hexadecimal numeral to a number. +** 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) +#endif + + +/* +@@ lua_pointer2str converts a pointer to a readable string in a +** non-specified way. +*/ +#define lua_pointer2str(buff,sz,p) l_sprintf(buff,sz,"%p",p) + + +/* +@@ lua_number2strx converts a float to a hexadecimal numeral. +** 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) +#define lua_number2strx(L,b,sz,f,n) \ + ((void)L, l_sprintf(b,sz,f,(LUAI_UACNUMBER)(n))) +#endif + + +/* +** 'strtof' and 'opf' variants for math functions are not valid in +** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the +** availability of these variants. ('math.h' is already included in +** all files that use these macros.) +*/ +#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF)) +#undef l_mathop /* variants not available */ +#undef lua_str2number +#define l_mathop(op) (lua_Number)op /* no variant */ +#define lua_str2number(s,p) ((lua_Number)strtod((s), (p))) +#endif + + +/* +@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation +** functions. It must be a numerical type; Lua will use 'intptr_t' if +** available, otherwise it will use 'ptrdiff_t' (the nearest thing to +** 'intptr_t' in C89) +*/ +#define LUA_KCONTEXT ptrdiff_t + +#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \ + __STDC_VERSION__ >= 199901L +#include +#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 the header 'locale.h'.) +*/ +#if !defined(lua_getlocaledecpoint) +#define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) +#endif + + +/* +** macros to improve jump prediction, used mostly for error handling +** and debug facilities. (Some macros in the Lua API use these macros. +** Define LUA_NOBUILTIN if you do not want '__builtin_expect' in your +** code.) +*/ +#if !defined(luai_likely) + +#if defined(__GNUC__) && !defined(LUA_NOBUILTIN) +#define luai_likely(x) (__builtin_expect(((x) != 0), 1)) +#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0)) +#else +#define luai_likely(x) (x) +#define luai_unlikely(x) (x) +#endif + +#endif + + +#if defined(LUA_CORE) || defined(LUA_LIB) +/* shorter names for Lua's own use */ +#define l_likely(x) luai_likely(x) +#define l_unlikely(x) luai_unlikely(x) +#endif + + + +/* }================================================================== */ + + +/* +** {================================================================== +** 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 +#define luai_apicheck(l,e) assert(e) +#endif + +/* }================================================================== */ + + +/* +** {================================================================== +** Macros that affect the API and must be stable (that is, must be the +** same when you compile Lua and when you compile code that links to +** Lua). +** ===================================================================== +*/ + +/* +@@ LUAI_MAXSTACK limits the size of the Lua stack. +** CHANGE it if you need a different limit. This limit is arbitrary; +** its only purpose is to stop Lua from consuming unlimited stack +** space (and to reserve some numbers for pseudo-indices). +** (It must fit into max(size_t)/32.) +*/ +#if LUAI_IS32INT +#define LUAI_MAXSTACK 1000000 +#else +#define LUAI_MAXSTACK 15000 +#endif + + +/* +@@ LUA_EXTRASPACE defines the size of a raw memory area associated with +** a Lua state with very fast access. +** CHANGE it if you need a different size. +*/ +#define LUA_EXTRASPACE (sizeof(void *)) + + +/* +@@ LUA_IDSIZE gives the maximum size for the description of the source +@@ of a function in debug information. +** CHANGE it if you want a different size. +*/ +#define LUA_IDSIZE 60 + + +/* +@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. +*/ +#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number))) + + +/* +@@ LUAI_MAXALIGN defines fields that, when used in a union, ensure +** maximum alignment for the other items in that union. +*/ +#define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l + +/* }================================================================== */ + + + + + +/* =================================================================== */ + +/* +** Local configuration. You can use this space to add your redefinitions +** without modifying the main part of the file. +*/ + + + +#include + +#endif + diff --git a/contrib/lua/src/luaconf.h.dist b/contrib/lua/src/luaconf.h.dist index b515396673d8..acb59c51f59c 100644 --- a/contrib/lua/src/luaconf.h.dist +++ b/contrib/lua/src/luaconf.h.dist @@ -16,13 +16,13 @@ ** =================================================================== ** General Configuration File for Lua ** -** Some definitions here can be changed externally, through the -** compiler (e.g., with '-D' options). Those are protected by -** '#if !defined' guards. However, several other definitions should -** be changed directly here, either because they affect the Lua -** ABI (by making the changes here, you ensure that all software -** connected to Lua, such as C libraries, will be compiled with the -** same configuration); or because they are seldom changed. +** Some definitions here can be changed externally, through the compiler +** (e.g., with '-D' options): They are commented out or protected +** by '#if !defined' guards. However, several other definitions +** should be changed directly here, either because they affect the +** Lua ABI (by making the changes here, you ensure that all software +** connected to Lua, such as C libraries, will be compiled with the same +** configuration); or because they are seldom changed. ** ** Search for "@@" to find all configurable definitions. ** =================================================================== @@ -81,26 +81,12 @@ /* ** {================================================================== -** Configuration for Number types. +** Configuration for Number types. These options should not be +** set externally, because any other code connected to Lua must +** use the same configuration. ** =================================================================== */ -/* -@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. -*/ -/* #define LUA_32BITS */ - - -/* -@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for -** C89 ('long' and 'double'); Windows always has '__int64', so it does -** not need to use this case. -*/ -#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) -#define LUA_C89_NUMBERS -#endif - - /* @@ LUA_INT_TYPE defines the type for Lua integers. @@ LUA_FLOAT_TYPE defines the type for Lua floats. @@ -122,7 +108,31 @@ #define LUA_FLOAT_LONGDOUBLE 3 #define LUA_FLOAT_INT64 4 -#if defined(LUA_32BITS) /* { */ + +/* Default configuration ('long long' and 'double', for 64-bit Lua) */ +#define LUA_INT_DEFAULT LUA_INT_LONGLONG +#define LUA_FLOAT_DEFAULT LUA_FLOAT_DOUBLE + + +/* +@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. +*/ +#define LUA_32BITS 0 + + +/* +@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for +** C89 ('long' and 'double'); Windows always has '__int64', so it does +** not need to use this case. +*/ +#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS) +#define LUA_C89_NUMBERS 1 +#else +#define LUA_C89_NUMBERS 0 +#endif + + +#if LUA_32BITS /* { */ /* ** 32-bit integers and 'float' */ @@ -133,27 +143,22 @@ #endif #define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT -#elif defined(LUA_C89_NUMBERS) /* }{ */ +#elif LUA_C89_NUMBERS /* }{ */ /* ** largest types available for C89 ('long' and 'double') */ #define LUA_INT_TYPE LUA_INT_LONG #define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE +#else /* }{ */ +/* use defaults */ + +#define LUA_INT_TYPE LUA_INT_DEFAULT +#define LUA_FLOAT_TYPE LUA_FLOAT_DEFAULT + #endif /* } */ -/* -** default configuration for 64-bit Lua ('long long' and 'double') -*/ -#if !defined(LUA_INT_TYPE) -#define LUA_INT_TYPE LUA_INT_LONGLONG -#endif - -#if !defined(LUA_FLOAT_TYPE) -#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE -#endif - /* }================================================================== */ @@ -374,14 +379,13 @@ /* ** {================================================================== -** Configuration for Numbers. +** Configuration for Numbers (low-level part). ** 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 a 'default argument promotion' @@ over a floating number. @@ l_floatatt(x) corrects float attribute 'x' to the proper float type @@ -474,10 +478,7 @@ /* -@@ LUA_INTEGER is the integer type used by Lua. -** @@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER. -** @@ 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. @@ -485,7 +486,6 @@ @@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER. @@ LUA_MININTEGER is the minimum value for a LUA_INTEGER. @@ LUA_MAXUNSIGNED is the maximum value for a LUA_UNSIGNED. -@@ LUA_UNSIGNEDBITS is the number of bits in a LUA_UNSIGNED. @@ lua_integer2str converts an integer to a string. */ @@ -506,9 +506,6 @@ #define LUA_UNSIGNED unsigned LUAI_UACINT -#define LUA_UNSIGNEDBITS (sizeof(LUA_UNSIGNED) * CHAR_BIT) - - /* now the variable definitions */ #if LUA_INT_TYPE == LUA_INT_INT /* { int */ @@ -660,6 +657,34 @@ #define lua_getlocaledecpoint() (localeconv()->decimal_point[0]) #endif + +/* +** macros to improve jump prediction, used mostly for error handling +** and debug facilities. (Some macros in the Lua API use these macros. +** Define LUA_NOBUILTIN if you do not want '__builtin_expect' in your +** code.) +*/ +#if !defined(luai_likely) + +#if defined(__GNUC__) && !defined(LUA_NOBUILTIN) +#define luai_likely(x) (__builtin_expect(((x) != 0), 1)) +#define luai_unlikely(x) (__builtin_expect(((x) != 0), 0)) +#else +#define luai_likely(x) (x) +#define luai_unlikely(x) (x) +#endif + +#endif + + +#if defined(LUA_CORE) || defined(LUA_LIB) +/* shorter names for Lua's own use */ +#define l_likely(x) luai_likely(x) +#define l_unlikely(x) luai_unlikely(x) +#endif + + + /* }================================================================== */ diff --git a/contrib/lua/src/lualib.h b/contrib/lua/src/lualib.h index eb08b530a60d..2625529076a8 100644 --- a/contrib/lua/src/lualib.h +++ b/contrib/lua/src/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/contrib/lua/src/lutf8lib.c b/contrib/lua/src/lutf8lib.c index 901d985f8d8c..e7bf098f6d04 100644 --- a/contrib/lua/src/lutf8lib.c +++ b/contrib/lua/src/lutf8lib.c @@ -224,14 +224,11 @@ static int byteoffset (lua_State *L) { static int iter_aux (lua_State *L, int strict) { size_t len; const char *s = luaL_checklstring(L, 1, &len); - lua_Integer n = lua_tointeger(L, 2) - 1; - if (n < 0) /* first iteration? */ - n = 0; /* start from here */ - else if (n < (lua_Integer)len) { - n++; /* skip current byte */ - while (iscont(s + n)) n++; /* and its continuations */ + lua_Unsigned n = (lua_Unsigned)lua_tointeger(L, 2); + if (n < len) { + while (iscont(s + n)) n++; /* skip continuation bytes */ } - if (n >= (lua_Integer)len) + if (n >= len) /* (also handles original 'n' being negative) */ return 0; /* no more codepoints */ else { utfint code; diff --git a/contrib/lua/src/lvm.c b/contrib/lua/src/lvm.c index 02c1b588a371..2da6b2c0e792 100644 --- a/contrib/lua/src/lvm.c +++ b/contrib/lua/src/lvm.c @@ -52,8 +52,10 @@ /* ** 'l_intfitsf' checks whether a given integer is in the range that ** can be converted to a float without rounding. Used in comparisons. +** May be defined in luaconf.h if this test is incorrect for custom +** LUA_FLOAT_TYPEs. */ -#if !defined(l_intfitsf) && LUA_FLOAT_TYPE != LUA_FLOAT_INT64 +#if !defined(l_intfitsf) /* number of bits in the mantissa of a float */ #define NBM (l_floatatt(MANT_DIG)) @@ -80,12 +82,7 @@ #endif -#endif /* !defined(l_intfitsf) && LUA_FLOAT_TYPE != LUA_FLOAT_INT64 */ - -#ifndef l_intfitsf -#define l_intfitsf(i) 1 -#endif - +#endif /* !defined(l_intfitsf) */ /* ** Try to convert a value from string to a number value. @@ -242,11 +239,11 @@ static int forprep (lua_State *L, StkId ra) { } else { /* try making all values floats */ lua_Number init; lua_Number limit; lua_Number step; - if (unlikely(!tonumber(plimit, &limit))) + if (l_unlikely(!tonumber(plimit, &limit))) luaG_forerror(L, plimit, "limit"); - if (unlikely(!tonumber(pstep, &step))) + if (l_unlikely(!tonumber(pstep, &step))) luaG_forerror(L, pstep, "step"); - if (unlikely(!tonumber(pinit, &init))) + if (l_unlikely(!tonumber(pinit, &init))) luaG_forerror(L, pinit, "initial value"); if (step == 0) luaG_runerror(L, "'for' step is zero"); @@ -299,7 +296,7 @@ void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val, if (slot == NULL) { /* 't' is not a table? */ lua_assert(!ttistable(t)); tm = luaT_gettmbyobj(L, t, TM_INDEX); - if (unlikely(notm(tm))) + if (l_unlikely(notm(tm))) luaG_typeerror(L, t, "index"); /* no metamethod */ /* else will try the metamethod */ } @@ -344,10 +341,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; @@ -356,7 +350,7 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, } else { /* not a table; check metamethod */ tm = luaT_gettmbyobj(L, t, TM_NEWINDEX); - if (unlikely(notm(tm))) + if (l_unlikely(notm(tm))) luaG_typeerror(L, t, "index"); } /* try the metamethod */ @@ -416,7 +410,7 @@ static int l_strcmp (const TString *ls, const TString *rs) { ** from float to int.) ** When 'f' is NaN, comparisons must result in false. */ -static int LTintfloat (lua_Integer i, lua_Number f) { +l_sinline int LTintfloat (lua_Integer i, lua_Number f) { if (l_intfitsf(i)) return luai_numlt(cast_num(i), f); /* compare them as floats */ else { /* i < f <=> i < ceil(f) */ @@ -433,7 +427,7 @@ static int LTintfloat (lua_Integer i, lua_Number f) { ** 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) { +l_sinline int LEintfloat (lua_Integer i, lua_Number f) { if (l_intfitsf(i)) return luai_numle(cast_num(i), f); /* compare them as floats */ else { /* i <= f <=> i <= floor(f) */ @@ -450,7 +444,7 @@ static int LEintfloat (lua_Integer i, lua_Number f) { ** Check whether float 'f' is less than integer 'i'. ** See comments on previous function. */ -static int LTfloatint (lua_Number f, lua_Integer i) { +l_sinline int LTfloatint (lua_Number f, lua_Integer i) { if (l_intfitsf(i)) return luai_numlt(f, cast_num(i)); /* compare them as floats */ else { /* f < i <=> floor(f) < i */ @@ -467,7 +461,7 @@ static int LTfloatint (lua_Number f, lua_Integer i) { ** Check whether float 'f' is less than or equal to integer 'i'. ** See comments on previous function. */ -static int LEfloatint (lua_Number f, lua_Integer i) { +l_sinline int LEfloatint (lua_Number f, lua_Integer i) { if (l_intfitsf(i)) return luai_numle(f, cast_num(i)); /* compare them as floats */ else { /* f <= i <=> ceil(f) <= i */ @@ -483,7 +477,7 @@ static int LEfloatint (lua_Number f, lua_Integer i) { /* ** Return 'l < r', for numbers. */ -static int LTnum (const TValue *l, const TValue *r) { +l_sinline int LTnum (const TValue *l, const TValue *r) { lua_assert(ttisnumber(l) && ttisnumber(r)); if (ttisinteger(l)) { lua_Integer li = ivalue(l); @@ -505,7 +499,7 @@ static int LTnum (const TValue *l, const TValue *r) { /* ** Return 'l <= r', for numbers. */ -static int LEnum (const TValue *l, const TValue *r) { +l_sinline int LEnum (const TValue *l, const TValue *r) { lua_assert(ttisnumber(l) && ttisnumber(r)); if (ttisinteger(l)) { lua_Integer li = ivalue(l); @@ -578,8 +572,13 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { if (ttype(t1) != ttype(t2) || ttype(t1) != LUA_TNUMBER) return 0; /* only numbers can be equal with different variants */ else { /* two numbers with different variants */ - lua_Integer i1, i2; /* compare them as integers */ - return (tointegerns(t1, &i1) && tointegerns(t2, &i2) && i1 == i2); + /* One of them is an integer. If the other does not have an + integer value, they cannot be equal; otherwise, compare their + integer values. */ + lua_Integer i1, i2; + return (luaV_tointegerns(t1, &i1, F2Ieq) && + luaV_tointegerns(t2, &i2, F2Ieq) && + i1 == i2); } } /* values have same type and same variant */ @@ -661,7 +660,7 @@ void luaV_concat (lua_State *L, int total) { /* collect total length and number of strings */ for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { size_t l = vslen(s2v(top - n - 1)); - if (unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) + if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) luaG_runerror(L, "string length overflow"); tl += l; } @@ -705,7 +704,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { } default: { /* try metamethod */ tm = luaT_gettmbyobj(L, rb, TM_LEN); - if (unlikely(notm(tm))) /* no metamethod? */ + if (l_unlikely(notm(tm))) /* no metamethod? */ luaG_typeerror(L, rb, "get length of"); break; } @@ -721,7 +720,7 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { ** otherwise 'floor(q) == trunc(q) - 1'. */ lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) { - if (unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ + if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ if (n == 0) luaG_runerror(L, "attempt to divide by zero"); return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ @@ -741,7 +740,7 @@ lua_Integer luaV_idiv (lua_State *L, lua_Integer m, lua_Integer n) { ** about luaV_idiv.) */ lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { - if (unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ + if (l_unlikely(l_castS2U(n) + 1u <= 1u)) { /* special cases: -1 or 0 */ if (n == 0) luaG_runerror(L, "attempt to perform 'n%%0'"); return 0; /* m % -1 == 0; avoid overflow with 0x80000...%-1 */ @@ -771,7 +770,8 @@ lua_Number luaV_modf (lua_State *L, lua_Number m, lua_Number n) { /* ** Shift left operation. (Shift right just negates 'y'.) */ -#define luaV_shiftr(x,y) luaV_shiftl(x,-(y)) +#define luaV_shiftr(x,y) luaV_shiftl(x,intop(-, 0, y)) + lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y) { if (y < 0) { /* shift right? */ @@ -852,6 +852,19 @@ void luaV_finishOp (lua_State *L) { luaV_concat(L, total); /* concat them (may yield again) */ break; } + case OP_CLOSE: { /* yielded closing variables */ + ci->u.l.savedpc--; /* repeat instruction to close other vars. */ + break; + } + case OP_RETURN: { /* yielded closing variables */ + StkId ra = base + GETARG_A(inst); + /* adjust top to signal correct number of returns, in case the + return is "up to top" ('isIT') */ + L->top = ra + ci->u2.nres; + /* repeat instruction to close other vars. and complete the return */ + ci->u.l.savedpc--; + break; + } default: { /* only these other opcodes can yield */ lua_assert(op == OP_TFORCALL || op == OP_CALL || @@ -927,7 +940,7 @@ void luaV_finishOp (lua_State *L) { */ #define op_arithfK(L,fop) { \ TValue *v1 = vRB(i); \ - TValue *v2 = KC(i); \ + TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ op_arithf_aux(L, v1, v2, fop); } @@ -956,7 +969,7 @@ void luaV_finishOp (lua_State *L) { */ #define op_arithK(L,iop,fop) { \ TValue *v1 = vRB(i); \ - TValue *v2 = KC(i); \ + TValue *v2 = KC(i); lua_assert(ttisnumber(v2)); \ op_arith_aux(L, v1, v2, iop, fop); } @@ -1055,7 +1068,8 @@ void luaV_finishOp (lua_State *L) { #define updatebase(ci) (base = ci->func + 1) -#define updatestack(ci) { if (trap) { updatebase(ci); ra = RA(i); } } +#define updatestack(ci) \ + { if (l_unlikely(trap)) { updatebase(ci); ra = RA(i); } } /* @@ -1099,7 +1113,7 @@ void luaV_finishOp (lua_State *L) { #define ProtectNT(exp) (savepc(L), (exp), updatetrap(ci)) /* -** Protect code that can only raise errors. (That is, it cannnot change +** Protect code that can only raise errors. (That is, it cannot change ** the stack or hooks.) */ #define halfProtect(exp) (savestate(L,ci), (exp)) @@ -1113,7 +1127,7 @@ void luaV_finishOp (lua_State *L) { /* fetch an instruction and prepare its execution */ #define vmfetch() { \ - if (trap) { /* stack reallocation or hooks? */ \ + if (l_unlikely(trap)) { /* stack reallocation or hooks? */ \ trap = luaG_traceexec(L, pc); /* handle hooks */ \ updatebase(ci); /* correct stack */ \ } \ @@ -1141,7 +1155,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { cl = clLvalue(s2v(ci->func)); k = cl->p->k; pc = ci->u.l.savedpc; - if (trap) { + if (l_unlikely(trap)) { if (pc == cl->p->code) { /* first instruction (not resuming)? */ if (cl->p->is_vararg) trap = 0; /* hooks will start after VARARGPREP instruction */ @@ -1156,6 +1170,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) { Instruction i; /* instruction being executed */ StkId ra; /* instruction's A register */ vmfetch(); + #if 0 + /* low-level line tracing for debugging Lua */ + printf("line: %d\n", luaG_getfuncline(cl->p, pcRel(pc, cl->p))); + #endif lua_assert(base == ci->func + 1); lua_assert(base <= L->top && L->top < L->stack_last); /* invalidate top for instructions not expecting it */ @@ -1534,7 +1552,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { vmbreak; } vmcase(OP_CLOSE) { - Protect(luaF_close(L, ra, LUA_OK)); + Protect(luaF_close(L, ra, LUA_OK, 1)); vmbreak; } vmcase(OP_TBC) { @@ -1623,13 +1641,13 @@ void luaV_execute (lua_State *L, CallInfo *ci) { updatetrap(ci); /* C call; nothing else to be done */ else { /* Lua call: run function in this same C frame */ ci = newci; - ci->callstatus = 0; /* call re-uses 'luaV_execute' */ goto startfunc; } vmbreak; } vmcase(OP_TAILCALL) { int b = GETARG_B(i); /* number of arguments + 1 (function) */ + int n; /* number of results when calling a C function */ int nparams1 = GETARG_C(i); /* delta is virtual 'func' - real 'func' (vararg functions) */ int delta = (nparams1) ? ci->u.l.nextraargs + nparams1 : 0; @@ -1639,29 +1657,18 @@ void luaV_execute (lua_State *L, CallInfo *ci) { b = cast_int(L->top - ra); savepc(ci); /* several calls here can raise errors */ if (TESTARG_k(i)) { - /* close upvalues from current call; the compiler ensures - that there are no to-be-closed variables here, so this - call cannot change the stack */ - luaF_close(L, base, NOCLOSINGMETH); + luaF_closeupval(L, base); /* close upvalues from current call */ + lua_assert(L->tbclist < base); /* no pending tbc variables */ lua_assert(base == ci->func + 1); } - while (!ttisfunction(s2v(ra))) { /* not a function? */ - luaD_tryfuncTM(L, ra); /* try '__call' metamethod */ - b++; /* there is now one extra argument */ - checkstackGCp(L, 1, ra); - } - if (!ttisLclosure(s2v(ra))) { /* C function? */ - luaD_precall(L, ra, LUA_MULTRET); /* call it */ - updatetrap(ci); - updatestack(ci); /* stack may have been relocated */ + if ((n = luaD_pretailcall(L, ci, ra, b, delta)) < 0) /* Lua function? */ + goto startfunc; /* execute the callee */ + else { /* C function? */ ci->func -= delta; /* restore 'func' (if vararg) */ - luaD_poscall(L, ci, cast_int(L->top - ra)); /* finish caller */ + luaD_poscall(L, ci, n); /* finish caller */ updatetrap(ci); /* 'luaD_poscall' can change hooks */ goto ret; /* caller returns after the tail call */ } - ci->func -= delta; /* restore 'func' (if vararg) */ - luaD_pretailcall(L, ci, ra, b); /* prepare call frame */ - goto startfunc; /* execute the callee */ } vmcase(OP_RETURN) { int n = GETARG_B(i) - 1; /* number of results */ @@ -1670,9 +1677,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) { n = cast_int(L->top - ra); /* get what is available */ savepc(ci); if (TESTARG_k(i)) { /* may there be open upvalues? */ + ci->u2.nres = n; /* save number of returns */ if (L->top < ci->top) L->top = ci->top; - luaF_close(L, base, LUA_OK); + luaF_close(L, base, CLOSEKTOP, 1); updatetrap(ci); updatestack(ci); } @@ -1684,23 +1692,23 @@ void luaV_execute (lua_State *L, CallInfo *ci) { goto ret; } vmcase(OP_RETURN0) { - if (L->hookmask) { + if (l_unlikely(L->hookmask)) { L->top = ra; savepc(ci); luaD_poscall(L, ci, 0); /* no hurry... */ trap = 1; } else { /* do the 'poscall' here */ - int nres = ci->nresults; + int nres; L->ci = ci->previous; /* back to caller */ L->top = base - 1; - while (nres-- > 0) + for (nres = ci->nresults; l_unlikely(nres > 0); nres--) setnilvalue(s2v(L->top++)); /* all results are nil */ } goto ret; } vmcase(OP_RETURN1) { - if (L->hookmask) { + if (l_unlikely(L->hookmask)) { L->top = ra + 1; savepc(ci); luaD_poscall(L, ci, 1); /* no hurry... */ @@ -1714,8 +1722,8 @@ void luaV_execute (lua_State *L, CallInfo *ci) { else { setobjs2s(L, base - 1, ra); /* at least this result */ L->top = base; - while (--nres > 0) /* complete missing results */ - setnilvalue(s2v(L->top++)); + for (; l_unlikely(nres > 1); nres--) + setnilvalue(s2v(L->top++)); /* complete missing results */ } } ret: /* return from a Lua function */ @@ -1818,7 +1826,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { } vmcase(OP_VARARGPREP) { ProtectNT(luaT_adjustvarargs(L, GETARG_A(i), ci, cl->p)); - if (trap) { + if (l_unlikely(trap)) { /* previous "Protect" updated trap */ luaD_hookcall(L, ci); L->oldpc = 1; /* next opcode will be seen as a "new" line */ } diff --git a/contrib/lua/src/lvm.h b/contrib/lua/src/lvm.h index 2d4ac160fefd..1bc16f3a50ba 100644 --- a/contrib/lua/src/lvm.h +++ b/contrib/lua/src/lvm.h @@ -60,12 +60,14 @@ typedef enum { /* convert an object to an integer (including string coercion) */ #define tointeger(o,i) \ - (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o,i,LUA_FLOORN2I)) + (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \ + : luaV_tointeger(o,i,LUA_FLOORN2I)) /* convert an object to an integer (without string coercion) */ #define tointegerns(o,i) \ - (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointegerns(o,i,LUA_FLOORN2I)) + (l_likely(ttisinteger(o)) ? (*(i) = ivalue(o), 1) \ + : luaV_tointegerns(o,i,LUA_FLOORN2I)) #define intop(op,v1,v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2)) diff --git a/lib/liblua/luaconf.local.h b/lib/liblua/luaconf.local.h new file mode 100644 index 000000000000..8f3fef15ddca --- /dev/null +++ b/lib/liblua/luaconf.local.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023, Netflix, Inc + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +/* + * We need to always define this. For the boot loader, we use it. For flua + * we don't, but it needs to be defined to keep some ifdefs happy. + */ +#define LUA_FLOAT_INT64 4 + +#define LUA_USE_POSIX +#ifndef BOOTSTRAPPING +#define LUA_USE_DLOPEN +#endif + +#undef LUA_ROOT +#undef LUA_LDIR +#undef LUA_CDIR +#define LUA_ROOT "/usr/" +#define LUA_LDIR LUA_ROOT "share/flua/" +#define LUA_CDIR LUA_ROOT "lib/flua/" diff --git a/stand/liblua/luaconf.local.h b/stand/liblua/luaconf.local.h new file mode 100644 index 000000000000..7da3d6bddc6e --- /dev/null +++ b/stand/liblua/luaconf.local.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023, Netflix, Inc + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once +/* + * We need to always define this. For the boot loader, we use it. For flua + * we don't, but it needs to be defined to keep some ifdefs happy. + */ +#define LUA_FLOAT_INT64 4 + +/* set the paths we want */ +#undef LUA_ROOT +#undef LUA_LDIR +#undef LUA_CDIR +#define LUA_ROOT LUA_PATH "/" LUA_VDIR "/" +#define LUA_LDIR LUA_ROOT "share/" +#define LUA_CDIR LUA_ROOT "lib/" + +/* Simplify this, since it's always an int */ +#undef lua_numbertointeger +#define lua_numbertointeger(n,p) \ + (*(p) = (LUA_INTEGER)(n), 1) + +/* Define our number type by brute force, but first undo the default defines */ +#undef panic +#undef LUA_NUMBER +#undef l_floatatt +#undef LUAI_UACNUMBER +#undef LUA_NUMBER_FRMLEN +#undef LUA_NUMBER_FMT +#undef l_mathop +#undef lua_str2number +#undef lua_getlocaledecpoint + +#undef LUA_FLOAT_TYPE +#define LUA_FLOAT_TYPE LUA_FLOAT_INT64 + +#include "lstd.h" + +#include + +#define panic lua_panic +/* Hack to use int64 as the LUA_NUMBER from ZFS code, kinda */ + +#define LUA_NUMBER int64_t + +#define l_floatatt(n) (LUA_FLOAT_INT_HACK_##n) +#define LUA_FLOAT_INT_HACK_MANT_DIG 32 +#define LUA_FLOAT_INT_HACK_MAX_10_EXP 32 + +#define LUAI_UACNUMBER int64_t + +#define LUA_NUMBER_FRMLEN "" +#define LUA_NUMBER_FMT "%" PRId64 + +#define l_mathop(x) (lstd_ ## x) + +#define lua_str2number(s,p) strtoll((s), (p), 0) + +#define lua_getlocaledecpoint() '.' + +/* Better buffer size */ +#undef LUAL_BUFFERSIZE +#define LUAL_BUFFERSIZE 128 + +/* Maxalign can't reference double */ +#undef LUAI_MAXALIGN +#define LUAI_MAXALIGN lua_Number n; void *s; lua_Integer i; long l + +#define LUA_AVOID_FLOAT diff --git a/stand/lua.mk b/stand/lua.mk index 711d95e48ba0..021ce73bd60f 100644 --- a/stand/lua.mk +++ b/stand/lua.mk @@ -3,4 +3,3 @@ # Common flags to build lua related files CFLAGS+= -I${LUASRC} -I${LDRSRC} -I${LIBLUASRC} -CFLAGS+= -DLUA_FLOAT_TYPE=LUA_FLOAT_INT64