Bring Lua to 5.4.6. (#1214)

This essentially re-does the work of #875 on top of master.

This is what I did to check that Cosmo's Lua extensions still worked:

```
$ build/bootstrap/make MODE=aarch64 o/aarch64/third_party/lua/lua
$ ape o/aarch64/third_party/lua/lua
>: 10
10
>: 010
8
>: 0b10
2
>: string.byte("\e")
27
>: "Hello, %s" % {"world"}
Hello, world
>: "*" * 3
***
```

`luaL_traceback2` was used to show the stack trace with parameter
values; it's used in `LuaCallWithTrace`, which is used in Redbean to run
Lua code. You should be able to see the extended stack trace by running
something like this: `redbean -e "function a(b)c()end a(2)"` (with
"params" indicating the extended stack trace):

```
stack traceback:
 [string "function a(b)c()end a(2)"]:1: in function 'a', params: b = 2;
 [string "function a(b)c()end a(2)"]:1: in main chunk
```
@pkulchenko confirmed that I get the expected result with the updated
code.

This is what I did to check that Lua itself still worked:

```
$ cd third_party/lua/test/
$ ape ../../../o/aarch64/third_party/lua/lua all.lua
```

There's one test failure, in `files.lua`:

```
***** FILE 'files.lua'*****
testing i/o
../../../o/aarch64/third_party/lua/lua: files.lua:84: assertion failed!
stack traceback:
[C]: in function 'assert'
files.lua:84: in main chunk
(...tail calls...)
all.lua:195: in main chunk
[C]: in ?
.>>> closing state <<<
```

That isn't a result of these changes; the same test is failing in
master.

The failure is here:

```lua
if not _port then   -- invalid seek
  local status, msg, code = io.stdin:seek("set", 1000)
  assert(not status and type(msg) == "string" and type(code) == "number")
end
```

The test expects a seek to offset 1,000 on stdin to fail — but it
doesn't. `status` ends up being the new offset rather than `nil`.

If I comment out that one test, the remaining tests succeed.
This commit is contained in:
Michael Lenaghan 2024-06-15 20:13:08 -04:00 committed by GitHub
parent 3a599bfbe1
commit 0dbf01bf1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
90 changed files with 2741 additions and 1376 deletions

124
third_party/lua/lgc.c vendored
View file

@ -3,7 +3,7 @@
Lua
Copyright © 2004-2021 Lua.org, PUC-Rio.
Copyright © 2004-2023 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
@ -27,6 +27,7 @@
*/
#define lgc_c
#define LUA_CORE
#include "libc/str/str.h"
#include "third_party/lua/ldebug.h"
#include "third_party/lua/ldo.h"
@ -268,12 +269,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
/*
** create a new collectable object (with given type and size) and link
** it to 'allgc' list.
** create a new collectable object (with given type, size, and offset)
** and link it to 'allgc' list.
*/
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
global_State *g = G(L);
GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz));
char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
GCObject *o = cast(GCObject *, p + offset);
o->marked = luaC_white(g);
o->tt = tt;
o->next = g->allgc;
@ -281,6 +283,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return o;
}
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return luaC_newobjdt(L, tt, sz, 0);
}
/* }====================================================== */
@ -317,7 +324,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
set2gray(uv); /* open upvalues are kept gray */
else
set2black(uv); /* closed upvalues are visited here */
markvalue(g, uv->v); /* mark its content */
markvalue(g, uv->v.p); /* mark its content */
break;
}
case LUA_VUSERDATA: {
@ -392,7 +399,7 @@ static int remarkupvals (global_State *g) {
work++;
if (!iswhite(uv)) { /* upvalue already visited? */
lua_assert(upisopen(uv) && isgray(uv));
markvalue(g, uv->v); /* mark its value */
markvalue(g, uv->v.p); /* mark its value */
}
}
}
@ -636,19 +643,19 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
*/
static int traversethread (global_State *g, lua_State *th) {
UpVal *uv;
StkId o = th->stack;
StkId o = th->stack.p;
if (isold(th) || g->gcstate == GCSpropagate)
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
if (o == NULL)
return 1; /* stack not completely built yet */
lua_assert(g->gcstate == GCSatomic ||
th->openupval == NULL || isintwups(th));
for (; o < th->top; o++) /* mark live elements in the stack */
for (; o < th->top.p; o++) /* mark live elements in the stack */
markvalue(g, s2v(o));
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markobject(g, uv); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */
for (; o < th->stack_last + EXTRA_STACK; o++)
for (; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) {
@ -908,7 +915,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) {
UNUSED(ud);
luaD_callnoyield(L, L->top - 2, 0);
luaD_callnoyield(L, L->top.p - 2, 0);
}
@ -922,19 +929,19 @@ 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 */
setobj2s(L, L->top.p++, tm); /* push finalizer... */
setobj2s(L, L->top.p++, &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);
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */
g->gcrunning = running; /* restore state */
g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc metamethod");
L->top--; /* pops error object */
luaE_warnerror(L, "__gc");
L->top.p--; /* pops error object */
}
}
}
@ -1027,7 +1034,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;
@ -1056,7 +1064,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** =======================================================
*/
static void setpause (global_State *g);
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/*
@ -1300,6 +1326,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
}
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/*
** Enter generational mode. Must go until the end of an atomic cycle
** to ensure that all objects are correctly marked and weak tables
@ -1312,6 +1347,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
numobjs = atomic(L); /* propagates all and then do the atomic stuff */
atomic2gen(L, g);
setminordebt(g); /* set debt assuming next cycle will be minor */
return numobjs;
}
@ -1357,15 +1393,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
}
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/*
** Does a major collection after last collection was a "bad collection".
**
@ -1437,8 +1464,8 @@ static void genstep (lua_State *L, global_State *g) {
lu_mem numobjs = fullgen(L, g); /* do a major collection */
if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
/* collected at least half of memory growth since last major
collection; keep doing minor collections */
setminordebt(g);
collection; keep doing minor collections. */
lua_assert(g->lastatomic == 0);
}
else { /* bad collection */
g->lastatomic = numobjs; /* signal that last collection was bad */
@ -1464,26 +1491,6 @@ static void genstep (lua_State *L, global_State *g) {
*/
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/*
** Enter first sweep phase.
** The call to 'sweeptolive' makes the pointer point to an object
@ -1518,12 +1525,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);
}
@ -1663,6 +1671,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
@ -1689,12 +1698,15 @@ static void incstep (lua_State *L, global_State *g) {
}
/*
** performs a basic GC step if collector is running
** Performs a basic GC step if collector is running. (If collector is
** not running, set a reasonable debt to avoid it being called at
** every single check.)
*/
void luaC_step (lua_State *L) {
global_State *g = G(L);
lua_assert(!g->gcemergency);
if (g->gcrunning) { /* running? */
if (!gcrunning(g)) /* not running? */
luaE_setdebt(g, -2000);
else {
if(isdecGCmodegen(g))
genstep(L, g);
else