First "complete" implementation of to-be-closed variables · lua/lua@bd96330 · GitHub
Skip to content

Commit bd96330

Browse files
committed
First "complete" implementation of to-be-closed variables
Still missing: - handling of memory errors when creating upvalue (must run closing method all the same) - interaction with coroutines
1 parent 4cd1f4a commit bd96330

13 files changed

Lines changed: 145 additions & 26 deletions

File tree

‎ldo.c‎

Lines changed: 13 additions & 7 deletions

‎ldo.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
/* type of protected functions, to be ran by 'runprotected' */
5151
typedef void (*Pfunc) (lua_State *L, void *ud);
5252

53+
LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop);
5354
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
5455
const char *mode);
5556
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,

‎lfunc.c‎

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "lua.h"
1616

17+
#include "ldo.h"
1718
#include "lfunc.h"
1819
#include "lgc.h"
1920
#include "lmem.h"
@@ -83,6 +84,40 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
8384
}
8485

8586

87+
static void callclose (lua_State *L, void *ud) {
88+
luaD_callnoyield(L, cast(StkId, ud), 0);
89+
}
90+
91+
92+
static int closeupval (lua_State *L, UpVal *uv, StkId level, int status) {
93+
StkId func = level + 1; /* save slot for old error message */
94+
if (status != LUA_OK) /* was there an error? */
95+
luaD_seterrorobj(L, status, level); /* save error message */
96+
else
97+
setnilvalue(s2v(level));
98+
if (ttisfunction(uv->v)) { /* object to-be-closed is a function? */
99+
setobj2s(L, func, uv->v); /* will call it */
100+
setobjs2s(L, func + 1, level); /* error msg. as argument */
101+
}
102+
else { /* try '__close' metamethod */
103+
const TValue *tm = luaT_gettmbyobj(L, uv->v, TM_CLOSE);
104+
if (ttisnil(tm))
105+
return status; /* no metamethod */
106+
setobj2s(L, func, tm); /* will call metamethod */
107+
setobj2s(L, func + 1, uv->v); /* with 'self' as argument */
108+
}
109+
L->top = func + 2; /* add function and argument */
110+
if (status == LUA_OK) /* not in "error mode"? */
111+
callclose(L, func); /* call closing method */
112+
else { /* already inside error handler; cannot raise another error */
113+
int newstatus = luaD_pcall(L, callclose, func, savestack(L, level), 0);
114+
if (newstatus != LUA_OK) /* error when closing? */
115+
status = newstatus; /* this will be the new error */
116+
}
117+
return status;
118+
}
119+
120+
86121
void luaF_unlinkupval (UpVal *uv) {
87122
lua_assert(upisopen(uv));
88123
*uv->u.open.previous = uv->u.open.next;
@@ -91,18 +126,24 @@ void luaF_unlinkupval (UpVal *uv) {
91126
}
92127

93128

94-
void luaF_close (lua_State *L, StkId level) {
129+
int luaF_close (lua_State *L, StkId level, int status) {
95130
UpVal *uv;
96-
while (L->openupval != NULL &&
97-
(uv = L->openupval, uplevel(uv) >= level)) {
131+
while ((uv = L->openupval) != NULL && uplevel(uv) >= level) {
132+
StkId upl = uplevel(uv);
98133
TValue *slot = &uv->u.value; /* new position for value */
99134
luaF_unlinkupval(uv);
100135
setobj(L, slot, uv->v); /* move value to upvalue slot */
101136
uv->v = slot; /* now current value lives here */
102137
if (!iswhite(uv))
103138
gray2black(uv); /* closed upvalues cannot be gray */
104139
luaC_barrier(L, uv, slot);
140+
if (status >= 0 && uv->tt == LUA_TUPVALTBC) { /* must be closed? */
141+
ptrdiff_t levelrel = savestack(L, level);
142+
status = closeupval(L, uv, upl, status); /* may reallocate the stack */
143+
level = restorestack(L, levelrel);
144+
}
105145
}
146+
return status;
106147
}
107148

108149

‎lfunc.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ LUAI_FUNC CClosure *luaF_newCclosure (lua_State *L, int nelems);
4747
LUAI_FUNC LClosure *luaF_newLclosure (lua_State *L, int nelems);
4848
LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
4949
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
50-
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
50+
LUAI_FUNC int luaF_close (lua_State *L, StkId level, int status);
5151
LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
5252
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
5353
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,

‎lgc.c‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,13 +609,18 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
609609
** That ensures that the entire stack have valid (non-dead) objects.
610610
*/
611611
static int traversethread (global_State *g, lua_State *th) {
612+
UpVal *uv;
612613
StkId o = th->stack;
613614
if (o == NULL)
614615
return 1; /* stack not completely built yet */
615616
lua_assert(g->gcstate == GCSatomic ||
616617
th->openupval == NULL || isintwups(th));
617618
for (; o < th->top; o++) /* mark live elements in the stack */
618619
markvalue(g, s2v(o));
620+
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) {
621+
if (uv->tt == LUA_TUPVALTBC) /* to be closed? */
622+
markobject(g, uv); /* cannot be collected */
623+
}
619624
if (g->gcstate == GCSatomic) { /* final traversal? */
620625
StkId lim = th->stack + th->stacksize; /* real end of stack */
621626
for (; o < lim; o++) /* clear not-marked stack slice */

‎lparser.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1536,9 +1536,9 @@ static void scopedlocalstat (LexState *ls) {
15361536
FuncState *fs = ls->fs;
15371537
new_localvar(ls, str_checkname(ls));
15381538
checknext(ls, '=');
1539+
exp1(ls, 0);
15391540
luaK_codeABC(fs, OP_TBC, fs->nactvar, 0, 0);
15401541
markupval(fs, fs->nactvar);
1541-
exp1(ls, 0);
15421542
adjustlocalvars(ls, 1);
15431543
}
15441544

‎lstate.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ static void preinit_thread (lua_State *L, global_State *g) {
258258

259259
static void close_state (lua_State *L) {
260260
global_State *g = G(L);
261-
luaF_close(L, L->stack); /* close all upvalues for this thread */
261+
luaF_close(L, L->stack, -1); /* close all upvalues for this thread */
262262
luaC_freeallobjects(L); /* collect all objects */
263263
if (ttisnil(&g->nilvalue)) /* closing a fully built state? */
264264
luai_userstateclose(L);
@@ -301,7 +301,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
301301

302302
void luaE_freethread (lua_State *L, lua_State *L1) {
303303
LX *l = fromstate(L1);
304-
luaF_close(L1, L1->stack); /* close all upvalues for this thread */
304+
luaF_close(L1, L1->stack, -1); /* close all upvalues for this thread */
305305
lua_assert(L1->openupval == NULL);
306306
luai_userstatefree(L, L1);
307307
freestack(L1);

‎ltests.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,7 @@ static int getindex_aux (lua_State *L, lua_State *L1, const char **pc) {
12081208

12091209
static void pushcode (lua_State *L, int code) {
12101210
static const char *const codes[] = {"OK", "YIELD", "ERRRUN",
1211-
"ERRSYNTAX", "ERRMEM", "ERRGCMM", "ERRERR"};
1211+
"ERRSYNTAX", MEMERRMSG, "ERRGCMM", "ERRERR"};
12121212
lua_pushstring(L, codes[code]);
12131213
}
12141214

‎ltm.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void luaT_init (lua_State *L) {
4343
"__div", "__idiv",
4444
"__band", "__bor", "__bxor", "__shl", "__shr",
4545
"__unm", "__bnot", "__lt", "__le",
46-
"__concat", "__call"
46+
"__concat", "__call", "__close"
4747
};
4848
int i;
4949
for (i=0; i<TM_N; i++) {

‎ltm.h‎

Lines changed: 1 addition & 0 deletions

0 commit comments

Comments
 (0)