mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 06:48:31 +00:00
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:
parent
3a599bfbe1
commit
0dbf01bf1d
90 changed files with 2741 additions and 1376 deletions
124
third_party/lua/lgc.c
vendored
124
third_party/lua/lgc.c
vendored
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue