diff -Nr lua-5.4.0/Makefile lua-5.4.1/Makefile 49c49 < R= $V.0 --- > R= $V.1 diff -Nr lua-5.4.0/README lua-5.4.1/README 2c2 < This is Lua 5.4.0, released on 18 Jun 2020. --- > This is Lua 5.4.1, released on 30 Sep 2020. diff -Nr lua-5.4.0/doc/contents.html lua-5.4.1/doc/contents.html 97a98 >
LUA_MINSTACK
extra slots.
---
> at least LUA_MINSTACK
extra elements;
> that is, you can safely push up to LUA_MINSTACK
values into it.
2987c2988
< So, before pushing anything in the stack after such a call
---
> So, before pushing anything on the stack after such a call
3046a3048,3089
>
> Several functions in the API return pointers (const char*
)
> to Lua strings in the stack.
> (See lua_pushfstring
, lua_pushlstring
,
> lua_pushstring
, and lua_tolstring
.
> See also luaL_checklstring
, luaL_checkstring
,
> and luaL_tolstring
in the auxiliary library.)
>
>
>
> In general, > Lua's garbage collection can free or move internal memory > and then invalidate pointers to internal strings. > To allow a safe use of these pointers, > The API guarantees that any pointer to a string in a stack index > is valid while the value at that index is neither modified nor popped. > When the index is a pseudo-index (referring to an upvalue), > the pointer is valid while the corresponding call is active and > the corresponding upvalue is not modified. > > >
> Some functions in the debug interface
> also return pointers to strings,
> namely lua_getlocal
, lua_getupvalue
,
> lua_setlocal
, and lua_setupvalue
.
> For these functions, the pointer is guaranteed to
> be valid while the caller function is active and
> the given closure (if one was given) is in the stack.
>
>
>
> Except for these guarantees,
> the garbage collector is free to invalidate
> any pointer to internal strings.
>
>
>
>
>
3392c3435
< (For instance, they may depend on what is on the stack.)
---
> (For instance, they may depend on what is in the stack.)
3681c3724
< Ensures that the stack has space for at least n
extra slots,
---
> Ensures that the stack has space for at least n
extra elements,
3689c3732
< if the stack already has space for the extra slots,
---
> if the stack already has space for the extra elements,
4445a4489,4492
> Lua ensures that this address is valid as long as
> the corresponding userdata is alive (see §2.5).
> Moreover, if the userdata is marked for finalization (see §2.5.3),
> its address is valid at least until the call to its finalizer.
4691c4738
< and returns a pointer to this string.
---
> and returns a pointer to this string (see §4.1.3).
4791c4838
< Returns a pointer to the internal copy of the string.
---
> Returns a pointer to the internal copy of the string (see §4.1.3).
4832c4879
< Returns a pointer to the internal copy of the string.
---
> Returns a pointer to the internal copy of the string (see §4.1.3).
5402c5449
< [-0, +0, v]
---
> [-0, +0, m]
5426,5427c5473,5474
< This function can raise an out-of-memory error.
< In that case, the value in the given index is immediately closed,
---
> In the case of an out-of-memory error,
> the value in the given index is immediately closed,
5430a5478,5485
>
> 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.
>
>
5485c5540
< to a string inside the Lua state.
---
> to a string inside the Lua state (see §4.1.3).
5491,5496d5545
<
< Because Lua has garbage collection,
< there is no guarantee that the pointer returned by lua_tolstring
< will be valid after the corresponding Lua value is removed from the stack.
<
<
5947c5996
< the index on the stack of the first value being "transferred",
---
> the index in the stack of the first value being "transferred",
6144c6193
< (except for tail calls, which do not count on the stack).
---
> (except for tail calls, which do not count in the stack).
6262,6263c6311
< The hook is called just after Lua enters the new function,
< before the function gets its arguments.
---
> The hook is called just after Lua enters the new function.
7576c7624
< returned by the function.
---
> returned by the function (see §4.1.3).
8004,8006c8052,8056
< Lua does not check the consistency of binary chunks.
< Maliciously crafted binary chunks can crash
< the interpreter.
---
> It is safe to load malformed binary chunks;
> load
signals an appropriate error.
> However,
> Lua does not check the consistency of the code inside binary chunks;
> running maliciously crafted bytecode can crash the interpreter.
8667a8718,8729
>
> This function is inherently insecure,
> as it allows Lua to call any function in any readable dynamic
> library in the system.
> (Lua calls any function assuming the function
> has a proper prototype and respects a proper protocol
> (see lua_CFunction
).
> Therefore,
> calling an arbitrary function in an arbitrary dynamic library
> more often than not results in an access violation.)
>
>
11087c11149
< (except for tail calls, which do not count on the stack);
---
> (except for tail calls, which do not count in the stack);
11889c11951
< Thu Jun 18 16:10:16 UTC 2020
---
> Wed Sep 30 09:46:30 UTC 2020
11892c11954
< Last change: revised for Lua 5.4.0 (final)
---
> Last change: revised for Lua 5.4.1
diff -Nr lua-5.4.0/doc/readme.html lua-5.4.1/doc/readme.html
113c113
< the top-level directory, which is named lua-5.4.0.
---
> the top-level directory, which is named lua-5.4.1.
333c333
< Fri May 1 19:33:31 UTC 2020
---
> Wed Sep 30 09:55:45 UTC 2020
336c336
< Last change: revised for Lua 5.4.0 (final)
---
> Last change: revised for Lua 5.4.1
diff -Nr lua-5.4.0/src/lapi.c lua-5.4.1/src/lapi.c
100c100
< CallInfo *ci = L->ci;
---
> CallInfo *ci;
101a102
> ci = L->ci;
173,174c174,175
< CallInfo *ci = L->ci;
< StkId func = ci->func;
---
> CallInfo *ci;
> StkId func;
176a178,179
> ci = L->ci;
> func = ci->func;
379c382,384
< TValue *o = index2value(L, idx);
---
> TValue *o;
> lua_lock(L);
> o = index2value(L, idx);
382a388
> lua_unlock(L);
385d390
< lua_lock(L); /* 'luaO_tostring' may create a new string */
389d393
< lua_unlock(L);
392a397
> lua_unlock(L);
565a571
> lua_assert(iswhite(cl));
627c633
< Table *reg = hvalue(&G(L)->l_registry);
---
> Table *reg;
628a635
> reg = hvalue(&G(L)->l_registry);
807c814
< Table *reg = hvalue(&G(L)->l_registry);
---
> Table *reg;
808a816
> reg = hvalue(&G(L)->l_registry);
1096c1104
< global_State *g = G(L);
---
> global_State *g;
1097a1106
> g = G(L);
1196a1206
> TValue *errobj;
1197a1208
> errobj = s2v(L->top - 1);
1199c1210,1214
< luaG_errormsg(L);
---
> /* error object is the memory error message? */
> if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
> luaM_error(L); /* raise a memory error */
> else
> luaG_errormsg(L); /* raise a regular error */
1241c1256
< if (n >= 2) {
---
> if (n > 0)
1243,1245c1258,1259
< }
< else if (n == 0) { /* push empty string */
< setsvalue2s(L, L->top, luaS_newlstr(L, "", 0));
---
> else { /* nothing to concatenate */
> setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */
1248d1261
< /* else n == 1; nothing to do */
diff -Nr lua-5.4.0/src/lauxlib.c lua-5.4.1/src/lauxlib.c
478,479c478,481
< if (temp == NULL && newsize > 0) /* allocation error? */
< luaL_error(L, "not enough memory");
---
> if (temp == NULL && newsize > 0) { /* allocation error? */
> lua_pushliteral(L, "not enough memory");
> lua_error(L); /* raise a memory error */
> }
diff -Nr lua-5.4.0/src/lcorolib.c lua-5.4.1/src/lcorolib.c
76c76
< if (r < 0) {
---
> if (r < 0) { /* error? */
78,80c78,81
< if (stat != LUA_OK && stat != LUA_YIELD)
< lua_resetthread(co); /* close variables in case of errors */
< if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
---
> if (stat != LUA_OK && stat != LUA_YIELD) /* error in the coroutine? */
> lua_resetthread(co); /* close its tbc variables */
> if (stat != LUA_ERRMEM && /* not a memory error and ... */
> lua_type(L, -1) == LUA_TSTRING) { /* ... error object is a string? */
diff -Nr lua-5.4.0/src/lctype.h lua-5.4.1/src/lctype.h
16c16
< ** optimized for the specific needs of Lua
---
> ** optimized for the specific needs of Lua.
63a64
>
65c66,69
< ** this 'ltolower' only works for alphabetic characters
---
> ** In ASCII, this 'ltolower' is correct for alphabetic characters and
> ** for '.'. That is enough for Lua needs. ('check_exp' ensures that
> ** the character either is an upper-case letter or is unchanged by
> ** the transformation, which holds for lower-case letters and '.'.)
67c71,73
< #define ltolower(c) ((c) | ('A' ^ 'a'))
---
> #define ltolower(c) \
> check_exp(('A' <= (c) && (c) <= 'Z') || (c) == ((c) | ('A' ^ 'a')), \
> (c) | ('A' ^ 'a'))
70c76
< /* two more entries for 0 and -1 (EOZ) */
---
> /* one entry for each character and for -1 (EOZ) */
diff -Nr lua-5.4.0/src/ldebug.c lua-5.4.1/src/ldebug.c
36,39c36,37
<
< /* Active Lua function (given call info) */
< #define ci_func(ci) (clLvalue(s2v((ci)->func)))
<
---
> /* inverse of 'pcRel' */
> #define invpcRel(pc, p) ((p)->code + (pc) + 1)
130,135c128,133
< ** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
< ** 'resethookcount') are for debug only, and it is no problem if they
< ** get arbitrary values (causes at most one wrong hook call). 'hookmask'
< ** is an atomic value. We assume that pointers are atomic too (e.g., gcc
< ** ensures that for all platforms where it runs). Moreover, 'hook' is
< ** always checked before being called (see 'luaD_hook').
---
> ** Fields 'basehookcount' and 'hookcount' (set by 'resethookcount')
> ** are for debug only, and it is no problem if they get arbitrary
> ** values (causes at most one wrong hook call). 'hookmask' is an atomic
> ** value. We assume that pointers are atomic too (e.g., gcc ensures that
> ** for all platforms where it runs). Moreover, 'hook' is always checked
> ** before being called (see 'luaD_hook').
142,143d139
< if (isLua(L->ci))
< L->oldpc = L->ci->u.l.savedpc;
195,196c191,192
< if (n <= nextra) {
< *pos = ci->func - nextra + (n - 1);
---
> if (n >= -nextra) { /* 'n' is negative */
> *pos = ci->func - nextra - (n + 1);
209c205
< return findvararg(ci, -n, pos);
---
> return findvararg(ci, n, pos);
789a786,787
> if (p->lineinfo == NULL) /* no debug information? */
> return 0;
794c792
< return 0; /* no line changes in the way */
---
> return 0; /* no line changes between positions */
797a796,806
> /*
> ** 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.)
> */
800a810
> const Proto *p = ci_func(ci)->p;
801a812,813
> /* 'L->oldpc' may be invalid; reset it in this case */
> int oldpc = (L->oldpc < p->sizecode) ? L->oldpc : 0;
822d833
< const Proto *p = ci_func(ci)->p;
825,826c836,837
< pc <= L->oldpc || /* when jump back (loop), or when */
< changedline(p, pcRel(L->oldpc, p), npci)) { /* enter new line */
---
> pc <= invpcRel(oldpc, p) || /* when jump back (loop), or when */
> changedline(p, oldpc, npci)) { /* enter new line */
830c841
< L->oldpc = pc; /* 'pc' of last call to line hook */
---
> L->oldpc = npci; /* 'pc' of last call to line hook */
diff -Nr lua-5.4.0/src/ldebug.h lua-5.4.1/src/ldebug.h
15a16,20
>
> /* Active Lua function (given call info) */
> #define ci_func(ci) (clLvalue(s2v((ci)->func)))
>
>
diff -Nr lua-5.4.0/src/ldo.c lua-5.4.1/src/ldo.c
248c248
< int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
---
> int goodsize = inuse + BASIC_STACK_SIZE;
253,254c253
< if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) &&
< goodsize < L->stacksize)
---
> if (inuse <= (LUAI_MAXSTACK - EXTRA_STACK) && goodsize < L->stacksize)
331c330
< Proto *p = clLvalue(s2v(ci->func))->p;
---
> Proto *p = ci_func(ci)->p;
344,345c343,344
< if (isLua(ci->previous))
< L->oldpc = ci->previous->u.l.savedpc; /* update 'oldpc' */
---
> if (isLua(ci = ci->previous))
> L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* update 'oldpc' */
469,470c468,470
< CallInfo *ci = next_ci(L);
< checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
---
> CallInfo *ci;
> checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
> L->ci = ci = next_ci(L);
475d474
< L->ci = ci;
489c488
< CallInfo *ci = next_ci(L);
---
> CallInfo *ci;
494c493,494
< checkstackp(L, fsize, func);
---
> checkstackGCp(L, fsize, func);
> L->ci = ci = next_ci(L);
508c508
< checkstackp(L, 1, func); /* space for metamethod */
---
> checkstackGCp(L, 1, func); /* space for metamethod */
518,520d517
< ** If there is a stack overflow, freeing all CI structures will
< ** force the subsequent call to invoke 'luaE_extendCI', which then
< ** will raise any errors.
524,525c521,524
< if (getCcalls(L) <= CSTACKERR) /* possible stack overflow? */
< luaE_freeCI(L);
---
> if (getCcalls(L) <= CSTACKERR) { /* possible C stack overflow? */
> luaE_exitCcall(L); /* to compensate decrement in next call */
> luaE_enterCcall(L); /* check properly */
> }
677c676
< L->nCcalls = getCcalls(from) + from->nci - L->nci - CSTACKCF;
---
> L->nCcalls = getCcalls(from) - L->nci - CSTACKCF;
709c708
< CallInfo *ci = L->ci;
---
> CallInfo *ci;
711a711
> ci = L->ci;
diff -Nr lua-5.4.0/src/ldo.h lua-5.4.1/src/ldo.h
19a20,21
> ** It also allows the running of one GC step when the stack is
> ** reallocated.
38c40
< #define checkstackp(L,n,p) \
---
> #define checkstackGCp(L,n,p) \
47c49
< luaD_checkstackaux(L, (fsize), (void)0, luaC_checkGC(L))
---
> luaD_checkstackaux(L, (fsize), luaC_checkGC(L), (void)0)
diff -Nr lua-5.4.0/src/lfunc.c lua-5.4.1/src/lfunc.c
237,239c237,240
< if (!iswhite(uv))
< gray2black(uv); /* closed upvalues cannot be gray */
< luaC_barrier(L, uv, slot);
---
> if (!iswhite(uv)) { /* neither white nor dead? */
> nw2black(uv); /* closed upvalues cannot be gray */
> luaC_barrier(L, uv, slot);
> }
diff -Nr lua-5.4.0/src/lgc.c lua-5.4.1/src/lgc.c
63,64c63,64
< /* mask to erase all color bits (plus gen. related stuff) */
< #define maskcolors (~(bitmask(BLACKBIT) | WHITEBITS | AGEBITS))
---
> /* mask with all color bits */
> #define maskcolors (bitmask(BLACKBIT) | WHITEBITS)
65a66,67
> /* mask with all GC bits */
> #define maskgcbits (maskcolors | AGEBITS)
67c69,70
< /* macro to erase all color bits then sets only the current white bit */
---
>
> /* macro to erase all color bits then set only the current white bit */
69c72,75
< (x->marked = cast_byte((x->marked & maskcolors) | luaC_white(g)))
---
> (x->marked = cast_byte((x->marked & ~maskcolors) | luaC_white(g)))
>
> /* make an object gray (neither white nor black) */
> #define set2gray(x) resetbits(x->marked, maskcolors)
71,72c77,80
< #define white2gray(x) resetbits(x->marked, WHITEBITS)
< #define black2gray(x) resetbit(x->marked, BLACKBIT)
---
>
> /* make an object black (coming from any color) */
> #define set2black(x) \
> (x->marked = cast_byte((x->marked & ~WHITEBITS) | bitmask(BLACKBIT)))
80,82d87
< #define checkconsistency(obj) \
< lua_longassert(!iscollectable(obj) || righttt(obj))
<
89c94
< #define markvalue(g,o) { checkconsistency(o); \
---
> #define markvalue(g,o) { checkliveness(g->mainthread,o); \
138c143,144
< ** Link a collectable object 'o' with a known type into list pointed by 'p'.
---
> ** Link a collectable object 'o' with a known type into the list 'p'.
> ** (Must be a macro to access the 'gclist' field in different types.)
140c146,153
< #define linkgclist(o,p) ((o)->gclist = (p), (p) = obj2gco(o))
---
> #define linkgclist(o,p) linkgclist_(obj2gco(o), &(o)->gclist, &(p))
>
> static void linkgclist_ (GCObject *o, GCObject **pnext, GCObject **list) {
> lua_assert(!isgray(o)); /* cannot be in a gray list */
> *pnext = *list;
> *list = o;
> set2gray(o); /* now it is */
> }
144c157
< ** Link a generic collectable object 'o' into list pointed by 'p'.
---
> ** Link a generic collectable object 'o' into the list 'p'.
146c159
< #define linkobjgclist(o,p) (*getgclist(o) = (p), (p) = obj2gco(o))
---
> #define linkobjgclist(o,p) linkgclist_(obj2gco(o), getgclist(o), &(p))
184,191c197,207
< ** barrier that moves collector forward, that is, mark the white object
< ** 'v' being pointed by the black object 'o'. (If in sweep phase, clear
< ** the black object to white [sweep it] to avoid other barrier calls for
< ** this same object.) In the generational mode, 'v' must also become
< ** old, if 'o' is old; however, it cannot be changed directly to OLD,
< ** because it may still point to non-old objects. So, it is marked as
< ** OLD0. In the next cycle it will become OLD1, and in the next it
< ** will finally become OLD (regular old).
---
> ** Barrier that moves collector forward, that is, marks the white object
> ** 'v' being pointed by the black object 'o'. In the generational
> ** mode, 'v' must also become old, if 'o' is old; however, it cannot
> ** be changed directly to OLD, because it may still point to non-old
> ** objects. So, it is marked as OLD0. In the next cycle it will become
> ** OLD1, and in the next it will finally become OLD (regular old). By
> ** then, any object it points to will also be old. If called in the
> ** incremental sweep phase, it clears the black object to white (sweep
> ** it) to avoid other barrier calls for this same object. (That cannot
> ** be done is generational mode, as its sweep does not distinguish
> ** whites from deads.)
205c221,222
< makewhite(g, o); /* mark main obj. as white to avoid other barriers */
---
> if (g->gckind == KGC_INC) /* incremental mode? */
> makewhite(g, o); /* mark 'o' as white to avoid other barriers */
217,221c234,240
< lua_assert(g->gckind != KGC_GEN || (isold(o) && getage(o) != G_TOUCHED1));
< if (getage(o) != G_TOUCHED2) /* not already in gray list? */
< linkobjgclist(o, g->grayagain); /* link it in 'grayagain' */
< black2gray(o); /* make object gray (again) */
< setage(o, G_TOUCHED1); /* touched in current cycle */
---
> lua_assert((g->gckind == KGC_GEN) == (isold(o) && getage(o) != G_TOUCHED1));
> if (getage(o) == G_TOUCHED2) /* already in gray list? */
> set2gray(o); /* make it gray to become touched1 */
> else /* link it in 'grayagain' and paint it gray */
> linkobjgclist(o, g->grayagain);
> if (isold(o)) /* generational mode? */
> setage(o, G_TOUCHED1); /* touched in current cycle */
228c247
< white2gray(o); /* they will be gray forever */
---
> set2gray(o); /* they will be gray forever */
262,266c281,290
< ** Mark an object. Userdata, strings, and closed upvalues are visited
< ** and turned black here. Other objects are marked gray and added
< ** to appropriate list to be visited (and turned black) later. (Open
< ** upvalues are already linked in 'headuv' list. They are kept gray
< ** to avoid barriers, as their values will be revisited by the thread.)
---
> ** Mark an object. Userdata with no user values, strings, and closed
> ** upvalues are visited and turned black here. Open upvalues are
> ** already indirectly linked through their respective threads in the
> ** 'twups' list, so they don't go to the gray list; nevertheless, they
> ** are kept gray to avoid barriers, as their values will be revisited
> ** by the thread or by 'remarkupvals'. Other objects are added to the
> ** gray list to be visited (and turned black) later. Both userdata and
> ** upvalues can call this function recursively, but this recursion goes
> ** for at most two levels: An upvalue cannot refer to another upvalue
> ** (only closures can), and a userdata's metatable must be a table.
269d292
< white2gray(o);
273c296
< gray2black(o);
---
> set2black(o); /* nothing to visit */
278,279c301,304
< if (!upisopen(uv)) /* open upvalues are kept gray */
< gray2black(o);
---
> if (upisopen(uv))
> set2gray(uv); /* open upvalues are kept gray */
> else
> set2black(o); /* closed upvalues are visited here */
287c312
< gray2black(o); /* nothing else to mark */
---
> set2black(o); /* nothing else to mark */
294c319
< linkobjgclist(o, g->gray);
---
> linkobjgclist(o, g->gray); /* to be visited later */
327,330c352,360
< ** Mark all values stored in marked open upvalues from non-marked threads.
< ** (Values from marked threads were already marked when traversing the
< ** thread.) Remove from the list threads that no longer have upvalues and
< ** not-marked threads.
---
> ** For each non-marked thread, simulates a barrier between each open
> ** upvalue and its value. (If the thread is collected, the value will be
> ** assigned to the upvalue, but then it can be too late for the barrier
> ** to act. The "barrier" does not need to check colors: A non-marked
> ** thread must be young; upvalues cannot be older than their threads; so
> ** any visited upvalue must be young too.) Also removes the thread from
> ** the list, as it was already visited. Removes also threads with no
> ** upvalues, as they have nothing to be checked. (If the thread gets an
> ** upvalue later, it will be linked in the list again.)
335c365
< int work = 0;
---
> int work = 0; /* estimate of how much work was done here */
338,339c368
< lua_assert(!isblack(thread)); /* threads are never black */
< if (isgray(thread) && thread->openupval != NULL)
---
> if (!iswhite(thread) && thread->openupval != NULL)
342a372
> lua_assert(!isold(thread) || thread->openupval == NULL);
345a376
> lua_assert(getage(uv) <= getage(thread));
347c378,379
< if (!iswhite(uv)) /* upvalue already visited? */
---
> if (!iswhite(uv)) { /* upvalue already visited? */
> lua_assert(upisopen(uv) && isgray(uv));
348a381
> }
355a389,394
> static void cleargraylists (global_State *g) {
> g->gray = g->grayagain = NULL;
> g->weak = g->allweak = g->ephemeron = NULL;
> }
>
>
360,361c399
< g->gray = g->grayagain = NULL;
< g->weak = g->allweak = g->ephemeron = NULL;
---
> cleargraylists(g);
376a415,434
>
> /*
> ** Check whether object 'o' should be kept in the 'grayagain' list for
> ** post-processing by 'correctgraylist'. (It could put all old objects
> ** in the list and leave all the work to 'correctgraylist', but it is
> ** more efficient to avoid adding elements that will be removed.) Only
> ** TOUCHED1 objects need to be in the list. TOUCHED2 doesn't need to go
> ** back to a gray list, but then it must become OLD. (That is what
> ** 'correctgraylist' does when it finds a TOUCHED2 object.)
> */
> static void genlink (global_State *g, GCObject *o) {
> lua_assert(isblack(o));
> if (getage(o) == G_TOUCHED1) { /* touched in this cycle? */
> linkobjgclist(o, g->grayagain); /* link it back in 'grayagain' */
> } /* everything else do not need to be linked back */
> else if (getage(o) == G_TOUCHED2)
> changeage(o, G_TOUCHED2, G_OLD); /* advance age */
> }
>
>
413,414c471,473
< ** (in the atomic phase). In generational mode, it (like all visited
< ** tables) must be kept in some gray list for post-processing.
---
> ** (in the atomic phase). In generational mode, some tables
> ** must be kept in some gray list for post-processing; this is done
> ** by 'genlink'.
453,454d511
< else if (g->gckind == KGC_GEN)
< linkgclist(h, g->grayagain); /* keep it in some list */
456c513
< gray2black(h);
---
> genlink(g, obj2gco(h)); /* check whether collector still needs to see it */
476,479c533
< if (g->gckind == KGC_GEN) {
< linkgclist(h, g->grayagain); /* keep it in some gray list */
< black2gray(h);
< }
---
> genlink(g, obj2gco(h));
491d544
< black2gray(h); /* keep table gray */
510,513c563
< if (g->gckind == KGC_GEN) {
< linkgclist(u, g->grayagain); /* keep it in some gray list */
< black2gray(u);
< }
---
> genlink(g, obj2gco(u));
562,563c612,620
< ** and cleaning the rest of the stack in the final traversal.
< ** That ensures that the entire stack have valid (non-dead) objects.
---
> ** and cleaning the rest of the stack in the final traversal. That
> ** ensures that the entire stack have valid (non-dead) objects.
> ** Threads have no barriers. In gen. mode, old threads must be visited
> ** at every cycle, because they might point to young objects. In inc.
> ** mode, the thread can still be modified before the end of the cycle,
> ** and therefore it must be visited again in the atomic phase. To ensure
> ** these visits, threads must return to a gray list if they are not new
> ** (which can only happen in generational mode) or if the traverse is in
> ** the propagate phase (which can only happen in incremental mode).
567a625,626
> if (isold(th) || g->gcstate == GCSpropagate)
> linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
593,594c652
< ** traverse one gray object, turning it to black (except for threads,
< ** which are always gray).
---
> ** traverse one gray object, turning it to black.
598c656
< gray2black(o);
---
> nw2black(o);
606,611c664
< case LUA_VTHREAD: {
< lua_State *th = gco2th(o);
< linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
< black2gray(o);
< return traversethread(g, th);
< }
---
> case LUA_VTHREAD: return traversethread(g, gco2th(o));
641,642c694,697
< next = gco2t(w)->gclist; /* list is rebuilt during loop */
< if (traverseephemeron(g, gco2t(w), dir)) { /* marked some value? */
---
> Table *h = gco2t(w);
> next = h->gclist; /* list is rebuilt during loop */
> nw2black(h); /* out of the list (for now) */
> if (traverseephemeron(g, h, dir)) { /* marked some value? */
769c824
< curr->marked = cast_byte((marked & maskcolors) | white);
---
> curr->marked = cast_byte((marked & ~maskgcbits) | white);
825a881,882
> else if (getage(o) == G_OLD1)
> g->firstold1 = o; /* it is the first OLD1 object in the list */
899,900c956,957
< ** (Note that objects after 'finobjold' cannot be white, so they
< ** don't need to be traversed. In incremental mode, 'finobjold' is NULL,
---
> ** (Note that objects after 'finobjold1' cannot be white, so they
> ** don't need to be traversed. In incremental mode, 'finobjold1' is NULL,
907c964
< while ((curr = *p) != g->finobjold) { /* traverse all finalizable objects */
---
> while ((curr = *p) != g->finobjold1) { /* traverse all finalizable objects */
923a981,1001
> ** If pointer 'p' points to 'o', move it to the next element.
> */
> static void checkpointer (GCObject **p, GCObject *o) {
> if (o == *p)
> *p = o->next;
> }
>
>
> /*
> ** Correct pointers to objects inside 'allgc' list when
> ** object 'o' is being removed from the list.
> */
> static void correctpointers (global_State *g, GCObject *o) {
> checkpointer(&g->survival, o);
> checkpointer(&g->old1, o);
> checkpointer(&g->reallyold, o);
> checkpointer(&g->firstold1, o);
> }
>
>
> /*
939,946c1017,1018
< else { /* correct pointers into 'allgc' list, if needed */
< if (o == g->survival)
< g->survival = o->next;
< if (o == g->old)
< g->old = o->next;
< if (o == g->reallyold)
< g->reallyold = o->next;
< }
---
> else
> correctpointers(g, o);
968,971d1039
< /* mask to erase all color bits, not changing gen-related stuff */
< #define maskgencolors (~(bitmask(BLACKBIT) | WHITEBITS))
<
<
973,974c1041,1044
< ** Sweep a list of objects, deleting dead ones and turning
< ** the non dead to old (without changing their colors).
---
> ** Sweep a list of objects to enter generational mode. Deletes dead
> ** objects and turns the non dead to old. All non-dead threads---which
> ** are now old---must be in a gray list. Everything else is not in a
> ** gray list. Open upvalues are also kept gray.
977a1048
> global_State *g = G(L);
980c1051
< lua_assert(isdead(G(L), curr));
---
> lua_assert(isdead(g, curr));
985a1057,1064
> if (curr->tt == LUA_VTHREAD) { /* threads must be watched */
> lua_State *th = gco2th(curr);
> linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
> }
> else if (curr->tt == LUA_VUPVAL && upisopen(gco2upv(curr)))
> set2gray(curr); /* open upvalues are always gray */
> else /* everything else is black */
> nw2black(curr);
997a1077,1080
> ** The ages of G_TOUCHED1 and G_TOUCHED2 objects cannot be advanced
> ** here, because these old-generation objects are usually not swept
> ** here. They will all be advanced in 'correctgraylist'. That function
> ** will also remove objects turned white here from any gray list.
1000c1083
< GCObject *limit) {
---
> GCObject *limit, GCObject **pfirstold1) {
1019,1021c1102,1110
< if (getage(curr) == G_NEW)
< curr->marked = cast_byte((curr->marked & maskgencolors) | white);
< setage(curr, nextage[getage(curr)]);
---
> if (getage(curr) == G_NEW) { /* new objects go back to white */
> int marked = curr->marked & ~maskgcbits; /* erase GC bits */
> curr->marked = cast_byte(marked | G_SURVIVAL | white);
> }
> else { /* all other objects will be old, and so keep their color */
> setage(curr, nextage[getage(curr)]);
> if (getage(curr) == G_OLD1 && *pfirstold1 == NULL)
> *pfirstold1 = curr; /* first OLD1 object in the list */
> }
1031c1120,1121
< ** age.
---
> ** age. In incremental mode, all objects are 'new' all the time,
> ** except for fixed strings (which are always old).
1036c1126
< p->marked = cast_byte((p->marked & maskcolors) | white);
---
> p->marked = cast_byte((p->marked & ~maskgcbits) | white);
1041c1131,1132
< ** Correct a list of gray objects.
---
> ** Correct a list of gray objects. Return pointer to where rest of the
> ** list should be linked.
1044,1046c1135,1137
< ** For tables and userdata, advance 'touched1' to 'touched2'; 'touched2'
< ** objects become regular old and are removed from the list.
< ** For threads, just remove white ones from the list.
---
> ** 'TOUCHED1' objects are advanced to 'TOUCHED2' and remain on the list;
> ** Non-white threads also remain on the list; 'TOUCHED2' objects become
> ** regular old; they and anything else are removed from the list.
1051,1081c1142,1160
< switch (curr->tt) {
< case LUA_VTABLE: case LUA_VUSERDATA: {
< GCObject **next = getgclist(curr);
< if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */
< lua_assert(isgray(curr));
< gray2black(curr); /* make it black, for next barrier */
< changeage(curr, G_TOUCHED1, G_TOUCHED2);
< p = next; /* go to next element */
< }
< else { /* not touched in this cycle */
< if (!iswhite(curr)) { /* not white? */
< lua_assert(isold(curr));
< if (getage(curr) == G_TOUCHED2) /* advance from G_TOUCHED2... */
< changeage(curr, G_TOUCHED2, G_OLD); /* ... to G_OLD */
< gray2black(curr); /* make it black */
< }
< /* else, object is white: just remove it from this list */
< *p = *next; /* remove 'curr' from gray list */
< }
< break;
< }
< case LUA_VTHREAD: {
< lua_State *th = gco2th(curr);
< lua_assert(!isblack(th));
< if (iswhite(th)) /* new object? */
< *p = th->gclist; /* remove from gray list */
< else /* old threads remain gray */
< p = &th->gclist; /* go to next element */
< break;
< }
< default: lua_assert(0); /* nothing more could be gray here */
---
> GCObject **next = getgclist(curr);
> if (iswhite(curr))
> goto remove; /* remove all white objects */
> else if (getage(curr) == G_TOUCHED1) { /* touched in this cycle? */
> lua_assert(isgray(curr));
> nw2black(curr); /* make it black, for next barrier */
> changeage(curr, G_TOUCHED1, G_TOUCHED2);
> goto remain; /* keep it in the list and go to next element */
> }
> else if (curr->tt == LUA_VTHREAD) {
> lua_assert(isgray(curr));
> goto remain; /* keep non-white threads on the list */
> }
> else { /* everything else is removed */
> lua_assert(isold(curr)); /* young objects should be white here */
> if (getage(curr) == G_TOUCHED2) /* advance from TOUCHED2... */
> changeage(curr, G_TOUCHED2, G_OLD); /* ... to OLD */
> nw2black(curr); /* make object black (to be removed) */
> goto remove;
1082a1162,1163
> remove: *p = *next; continue;
> remain: p = next; continue;
1103c1184
< ** Mark 'OLD1' objects when starting a new young collection.
---
> ** Mark black 'OLD1' objects when starting a new young collection.
1112,1113c1193,1194
< if (isblack(p)) {
< black2gray(p); /* should be '2white', but gray works too */
---
> changeage(p, G_OLD1, G_OLD); /* now they are old */
> if (isblack(p))
1115d1195
< }
1134,1138c1214,1216
< ** Does a young collection. First, mark 'OLD1' objects. (Only survival
< ** and "recent old" lists can contain 'OLD1' objects. New lists cannot
< ** contain 'OLD1' objects, at most 'OLD0' objects that were already
< ** visited when marked old.) Then does the atomic step. Then,
< ** sweep all lists and advance pointers. Finally, finish the collection.
---
> ** Does a young collection. First, mark 'OLD1' objects. Then does the
> ** atomic step. Then, sweep all lists and advance pointers. Finally,
> ** finish the collection.
1141a1220
> GCObject *dummy; /* dummy out parameter to 'sweepgen' */
1143c1222,1225
< markold(g, g->survival, g->reallyold);
---
> if (g->firstold1) { /* are there regular OLD1 objects? */
> markold(g, g->firstold1, g->reallyold); /* mark them */
> g->firstold1 = NULL; /* no more OLD1 objects (for now) */
> }
1144a1227
> markold(g, g->tobefnz, NULL);
1148,1152c1231,1236
< psurvival = sweepgen(L, g, &g->allgc, g->survival);
< /* sweep 'survival' and 'old' */
< sweepgen(L, g, psurvival, g->reallyold);
< g->reallyold = g->old;
< g->old = *psurvival; /* 'survival' survivals are old now */
---
> g->gcstate = GCSswpallgc;
> psurvival = sweepgen(L, g, &g->allgc, g->survival, &g->firstold1);
> /* sweep 'survival' */
> sweepgen(L, g, psurvival, g->old1, &g->firstold1);
> g->reallyold = g->old1;
> g->old1 = *psurvival; /* 'survival' survivals are old now */
1156,1160c1240,1245
< psurvival = sweepgen(L, g, &g->finobj, g->finobjsur);
< /* sweep 'survival' and 'old' */
< sweepgen(L, g, psurvival, g->finobjrold);
< g->finobjrold = g->finobjold;
< g->finobjold = *psurvival; /* 'survival' survivals are old now */
---
> dummy = NULL; /* no 'firstold1' optimization for 'finobj' lists */
> psurvival = sweepgen(L, g, &g->finobj, g->finobjsur, &dummy);
> /* sweep 'survival' */
> sweepgen(L, g, psurvival, g->finobjold1, &dummy);
> g->finobjrold = g->finobjold1;
> g->finobjold1 = *psurvival; /* 'survival' survivals are old now */
1163,1164c1248
< sweepgen(L, g, &g->tobefnz, NULL);
<
---
> sweepgen(L, g, &g->tobefnz, NULL, &dummy);
1168a1253,1258
> /*
> ** Clears all gray lists, sweeps objects, and prepare sublists to enter
> ** generational mode. The sweeps remove dead objects and turn all
> ** surviving objects to old. Threads go back to 'grayagain'; everything
> ** else is turned black (not in any gray list).
> */
1169a1260
> cleargraylists(g);
1170a1262
> g->gcstate = GCSswpallgc;
1173c1265,1266
< g->reallyold = g->old = g->survival = g->allgc;
---
> g->reallyold = g->old1 = g->survival = g->allgc;
> g->firstold1 = NULL; /* there are no OLD1 objects anywhere */
1177c1270
< g->finobjrold = g->finobjold = g->finobjsur = g->finobj;
---
> g->finobjrold = g->finobjold1 = g->finobjsur = g->finobj;
1190,1191c1283,1285
< ** to ensure that all threads and weak tables are in the gray lists.
< ** Then, turn all objects into old and finishes the collection.
---
> ** to ensure that all objects are correctly marked and weak tables
> ** are cleared. Then, turn all objects into old and finishes the
> ** collection.
1210c1304
< g->reallyold = g->old = g->survival = NULL;
---
> g->reallyold = g->old1 = g->survival = NULL;
1213c1307
< g->finobjrold = g->finobjold = g->finobjsur = NULL;
---
> g->finobjrold = g->finobjold1 = g->finobjsur = NULL;
diff -Nr lua-5.4.0/src/lgc.h lua-5.4.1/src/lgc.h
15,24c15,24
< ** Collectable objects may have one of three colors: white, which
< ** means the object is not marked; gray, which means the
< ** object is marked, but its references may be not marked; and
< ** black, which means that the object and all its references are marked.
< ** The main invariant of the garbage collector, while marking objects,
< ** is that a black object can never point to a white one. Moreover,
< ** any gray object must be in a "gray list" (gray, grayagain, weak,
< ** allweak, ephemeron) so that it can be visited again before finishing
< ** the collection cycle. These lists have no meaning when the invariant
< ** is not being enforced (e.g., sweep phase).
---
> ** Collectable objects may have one of three colors: white, which means
> ** the object is not marked; gray, which means the object is marked, but
> ** its references may be not marked; and black, which means that the
> ** object and all its references are marked. The main invariant of the
> ** garbage collector, while marking objects, is that a black object can
> ** never point to a white one. Moreover, any gray object must be in a
> ** "gray list" (gray, grayagain, weak, allweak, ephemeron) so that it
> ** can be visited again before finishing the collection cycle. (Open
> ** upvalues are an exception to this rule.) These lists have no meaning
> ** when the invariant is not being enforced (e.g., sweep phase).
72,73c72,73
< ** used for object "age" in generational mode. Last bit is free
< ** to be used by respective objects.
---
> ** used for object "age" in generational mode. Last bit is used
> ** by tests.
79a80,81
> #define TESTBIT 7
>
97c99,100
< #define gray2black(x) l_setbit((x)->marked, BLACKBIT)
---
> #define nw2black(x) \
> check_exp(!iswhite(x), l_setbit((x)->marked, BLACKBIT))
diff -Nr lua-5.4.0/src/liolib.c lua-5.4.1/src/liolib.c
54a55,60
> #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
>
>
281a288
> luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode");
diff -Nr lua-5.4.0/src/llex.c lua-5.4.1/src/llex.c
84d83
< lua_assert(token == cast_uchar(token));
diff -Nr lua-5.4.0/src/llex.h lua-5.4.1/src/llex.h
9a10,11
> #include