Lua 5.4.3 defer statement patch

master
Dibyendu Majumdar 3 years ago
parent 2c81edafa0
commit bbf2c29077

@ -2,5 +2,10 @@ These patches are for Lua 5.3 and 5.4.
The 'defer' patch adds the defer statement to Lua. The 'defer' patch adds the defer statement to Lua.
Note that in Lua 5.4 a deferred closure may be called more than once just as the close method of a to-be-closed variable Note that in Lua 5.4 versions prior to 5.4.3 a deferred closure may be called more than once
may be called more than once, when exiting the scope. I am checking why Lua 5.4 behaves this way. just as the close method of a to-be-closed variable may be called more than once, when exiting the scope.
I think this is fixed in Lua 5.4.3.
The original patch for 5.4 is applicable to versions prior to 5.4.3.
The 5.4.3 version has a new approach to the implementation of toclose values, hence a new patch had to be created.

@ -0,0 +1,709 @@
Index: llex.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/llex.h b/llex.h
--- a/llex.h (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/llex.h (date 1620514343391)
@@ -33,7 +33,7 @@
/* terminal symbols denoted by reserved words */
TK_AND = FIRST_RESERVED, TK_BREAK,
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
- TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
+ TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_DEFER, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
TK_IDIV, TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE,
Index: lobject.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lobject.h b/lobject.h
--- a/lobject.h (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/lobject.h (date 1620514343399)
@@ -147,6 +147,7 @@
TValue val;
struct {
TValuefields;
+ lu_byte is_deferred;
unsigned short delta;
} tbclist;
} StackValue;
@@ -609,6 +610,10 @@
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_VCCL)); \
checkliveness(L,io); }
+enum {
+ UV_FLAG_TBC = 1,
+ UV_FLAG_DEFER = 3
+};
/*
** Upvalues for Lua closures
Index: ljumptab.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/ljumptab.h b/ljumptab.h
--- a/ljumptab.h (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/ljumptab.h (date 1620514343380)
@@ -105,6 +105,7 @@
&&L_OP_TFORLOOP,
&&L_OP_SETLIST,
&&L_OP_CLOSURE,
+&&L_OP_DEFER,
&&L_OP_VARARG,
&&L_OP_VARARGPREP,
&&L_OP_EXTRAARG
Index: lfunc.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lfunc.h b/lfunc.h
--- a/lfunc.h (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/lfunc.h (date 1620514343371)
@@ -52,7 +52,7 @@
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 void luaF_newtbcupval (lua_State *L, StkId level, int deferred);
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);
Index: lopcodes.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lopcodes.h b/lopcodes.h
--- a/lopcodes.h (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/lopcodes.h (date 1620514343412)
@@ -300,6 +300,7 @@
OP_SETLIST,/* A B C k R[A][C+i] := R[A+i], 1 <= i <= B */
OP_CLOSURE,/* A Bx R[A] := closure(KPROTO[Bx]) */
+OP_DEFER,
OP_VARARG,/* A C R[A], R[A+1], ..., R[A+C-2] = vararg */
Index: lopcodes.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lopcodes.c b/lopcodes.c
--- a/lopcodes.c (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/lopcodes.c (date 1620514343404)
@@ -97,6 +97,7 @@
,opmode(0, 0, 0, 0, 1, iABx) /* OP_TFORLOOP */
,opmode(0, 0, 1, 0, 0, iABC) /* OP_SETLIST */
,opmode(0, 0, 0, 0, 1, iABx) /* OP_CLOSURE */
+ ,opmode(0, 0, 0, 0, 1, iABC) /* OP_DEFER */
,opmode(0, 1, 0, 0, 1, iABC) /* OP_VARARG */
,opmode(0, 0, 1, 0, 1, iABC) /* OP_VARARGPREP */
,opmode(0, 0, 0, 0, 0, iAx) /* OP_EXTRAARG */
Index: llex.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/llex.c b/llex.c
--- a/llex.c (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/llex.c (date 1620514343386)
@@ -40,7 +40,7 @@
static const char *const luaX_tokens [] = {
"and", "break", "do", "else", "elseif",
"end", "false", "for", "function", "goto", "if",
- "in", "local", "nil", "not", "or", "repeat",
+ "in", "local", "defer", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
"//", "..", "...", "==", ">=", "<=", "~=",
"<<", ">>", "::", "<eof>",
Index: lparser.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lparser.c b/lparser.c
--- a/lparser.c (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/lparser.c (date 1620514343432)
@@ -707,10 +707,17 @@
** are in use at that time.
*/
-static void codeclosure (LexState *ls, expdesc *v) {
+static void codeclosure (LexState *ls, expdesc *v, int deferred) {
FuncState *fs = ls->fs->prev;
+ int pc = -1;
+ if (deferred) {
+ pc = luaK_codeABC(fs, OP_DEFER, 0, 0, 0);
+ }
init_exp(v, VRELOC, luaK_codeABx(fs, OP_CLOSURE, 0, fs->np - 1));
luaK_exp2nextreg(fs, v); /* fix it at the last register */
+ if (deferred) {
+ SETARG_A(fs->f->code[pc], v->u.info);
+ }
}
@@ -975,24 +982,26 @@
}
-static void body (LexState *ls, expdesc *e, int ismethod, int line) {
+static void body (LexState *ls, expdesc *e, int ismethod, int line, int deferred) {
/* body -> '(' parlist ')' block END */
FuncState new_fs;
BlockCnt bl;
new_fs.f = addprototype(ls);
new_fs.f->linedefined = line;
open_func(ls, &new_fs, &bl);
- checknext(ls, '(');
- if (ismethod) {
- new_localvarliteral(ls, "self"); /* create 'self' parameter */
- adjustlocalvars(ls, 1);
- }
- parlist(ls);
- checknext(ls, ')');
+ if (!deferred) {
+ checknext(ls, '(');
+ if (ismethod) {
+ new_localvarliteral(ls, "self"); /* create 'self' parameter */
+ adjustlocalvars(ls, 1);
+ }
+ parlist(ls);
+ checknext(ls, ')');
+ }
statlist(ls);
new_fs.f->lastlinedefined = ls->linenumber;
check_match(ls, TK_END, TK_FUNCTION, line);
- codeclosure(ls, e);
+ codeclosure(ls, e, deferred);
close_func(ls);
}
@@ -1168,7 +1177,7 @@
}
case TK_FUNCTION: {
luaX_next(ls);
- body(ls, v, 0, ls->linenumber);
+ body(ls, v, 0, ls->linenumber, 0);
return;
}
default: {
@@ -1674,13 +1683,21 @@
}
-static void localfunc (LexState *ls) {
+static void localfunc (LexState *ls, int defer) {
expdesc b;
FuncState *fs = ls->fs;
int fvar = fs->nactvar; /* function's variable index */
- new_localvar(ls, str_checkname(ls)); /* new local variable */
+ if (defer) {
+ static const char funcname[] = "(deferred function)";
+ new_localvar(ls, luaX_newstring(ls, funcname, sizeof funcname-1)); /* new local variable */
+ markupval(fs, fs->nactvar);
+ fs->bl->insidetbc = 1; /* in the scope of a defer closure variable */
+ }
+ else {
+ new_localvar(ls, str_checkname(ls)); /* new local variable */
+ }
adjustlocalvars(ls, 1); /* enter its scope */
- body(ls, &b, 0, ls->linenumber); /* function created in next register */
+ body(ls, &b, 0, ls->linenumber, defer); /* function created in next register */
/* debug information will only see the variable after this point! */
localdebuginfo(fs, fvar)->startpc = fs->pc;
}
@@ -1775,7 +1792,7 @@
expdesc v, b;
luaX_next(ls); /* skip FUNCTION */
ismethod = funcname(ls, &v);
- body(ls, &b, ismethod, line);
+ body(ls, &b, ismethod, line, 0);
luaK_storevar(ls->fs, &v, &b);
luaK_fixline(ls->fs, line); /* definition "happens" in the first line */
}
@@ -1868,10 +1885,15 @@
case TK_LOCAL: { /* stat -> localstat */
luaX_next(ls); /* skip LOCAL */
if (testnext(ls, TK_FUNCTION)) /* local function? */
- localfunc(ls);
+ localfunc(ls, 0);
else
localstat(ls);
break;
+ }
+ case TK_DEFER: { /* stat -> deferstat */
+ luaX_next(ls); /* skip DEFER */
+ localfunc(ls, 1);
+ break;
}
case TK_DBCOLON: { /* stat -> label */
luaX_next(ls); /* skip double colon */
Index: lvm.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lvm.c b/lvm.c
--- a/lvm.c (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/lvm.c (date 1620514343445)
@@ -1541,7 +1541,7 @@
}
vmcase(OP_TBC) {
/* create new to-be-closed upvalue */
- halfProtect(luaF_newtbcupval(L, ra));
+ halfProtect(luaF_newtbcupval(L, ra, 0));
vmbreak;
}
vmcase(OP_JMP) {
@@ -1752,7 +1752,7 @@
}
vmcase(OP_TFORPREP) {
/* create to-be-closed upvalue (if needed) */
- halfProtect(luaF_newtbcupval(L, ra + 3));
+ halfProtect(luaF_newtbcupval(L, ra + 3, 0));
pc += GETARG_Bx(i);
i = *(pc++); /* go to next instruction */
lua_assert(GET_OPCODE(i) == OP_TFORCALL && ra == RA(i));
@@ -1810,6 +1810,10 @@
halfProtect(pushclosure(L, p, cl->upvals, base, ra));
checkGC(L, ra + 1);
vmbreak;
+ }
+ vmcase(OP_DEFER) {
+ halfProtect(luaF_newtbcupval(L, ra, 1));
+ vmbreak;
}
vmcase(OP_VARARG) {
int n = GETARG_C(i) - 1; /* required results */
Index: testes/defer.lua
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/testes/defer.lua b/testes/defer.lua
new file mode 100644
--- /dev/null (date 1620514917535)
+++ b/testes/defer.lua (date 1620514917535)
@@ -0,0 +1,318 @@
+-- ================================================================
+-- Following section is an extract from the code.lua test
+-- These functions test bytecode generation, and also provide
+-- helper routines that we use later on in other test cases
+
+-- testing opcodes
+function check (f, ...)
+ if not T then
+ return true
+ end
+ local arg = {...}
+ local c = T.listcode(f)
+ for i=1, #arg do
+ --print(arg[i], c[i])
+ opcodes_coverage[arg[i]] = opcodes_coverage[arg[i]]+1
+ assert(string.find(c[i], '- '..arg[i]..' *[AB][xs]?=%d'))
+ end
+ assert(c[#arg+2] == nil)
+end
+
+-- Test defer statement
+do
+ local y = 0
+ local function x()
+ defer y = y + 1 end
+ defer y = y + 1 end
+ end
+ check(x, 'DEFER', 'CLOSURE', 'DEFER', 'CLOSURE', 'RETURN')
+ x()
+ assert(y == 2)
+ print 'Test 1 OK'
+end
+
+-- Test defer statement
+do
+ local y = 0
+ local function x()
+ defer y = y + 1 end
+ error('raise error')
+ defer y = y + 2 end -- will not be called
+ end
+ pcall(x)
+ assert(y == 1)
+ print 'Test 2 OK'
+end
+
+-- Test defer statement
+do
+ local y = 0
+ local function x()
+ defer y = y + 1 end
+ defer y = y + 2; error('err') end
+ defer y = y + 3 end
+ end
+ pcall(x)
+ assert(y == 6)
+ -- Seems the defer closure that errored is called twice
+ -- FIXME why? See also test 12 below - same issue I think
+ -- This appears to be a feature of Lua 5.4
+ --assert(y == 8)
+ print 'Test 3 OK'
+end
+
+-- Test defer statement in tailcalls
+do
+ local y = 0
+ local function x (n)
+ defer y = y + 1 end
+ if n > 0 then return x(n - 1) end
+ end
+ pcall(x, 3)
+ assert(y == 4)
+ print 'Test 4 OK'
+end
+
+-- Simulate a test of resource closure with defer
+do
+ local y = 0
+ local z = { count = 0 }
+ z.__index = z;
+ function z:new()
+ local object = {}
+ setmetatable(object, z)
+ return object
+ end
+ function z:open(arg)
+ if (arg) then
+ z.count = z.count + 1
+ return
+ end
+ y = 1
+ error('error opening')
+ end
+ function z.close()
+ z.count = z.count - 1
+ end
+ local function x(arg)
+ local f = z:new()
+ f:open(arg)
+ assert(z.count == 1)
+ defer f:close() end
+ end
+ x('filename')
+ assert(y == 0)
+ assert(z.count == 0)
+ pcall(x, false)
+ assert(z.count == 0)
+ assert(y == 1)
+ print 'Test 5 OK'
+end
+
+--- Test stack reallocation in defer statement
+do
+ local function x(a) if a <= 0 then return else x(a-1) end end
+ local y = 100
+ local function z(...)
+ -- recursive call to make stack
+ defer x(y) end
+ return ...
+ end
+ do
+ local a,b,c = z(1,2,3)
+ assert(a == 1 and b == 2 and c == 3)
+ a,b,c = z(3,2,1)
+ assert(a == 3 and b == 2 and c == 1)
+ end
+ print 'Test 6 OK'
+end
+
+-- Adapted from Lua 5.4
+local function stack(n) n = ((n == 0) or stack(n - 1)) end
+
+local function func2close (f, x, y)
+ local obj = setmetatable({}, {__close = f})
+ if x then
+ return x, obj, y
+ else
+ return obj
+ end
+end
+
+do
+ local function t()
+ local a = {}
+ do
+ local b = false -- not to be closed
+ -- x is <close>
+ local x = setmetatable({"x"}, {__close = function (self)
+ a[#a + 1] = self[1] end})
+ defer getmetatable(x).__close(x) end
+ -- y is <close>
+ local w, y, z = func2close(function (self, err)
+ assert(err == nil); a[#a + 1] = "y"
+ end, 10, 20)
+ defer getmetatable(y).__close(y) end
+ local c = nil -- not to be closed
+ a[#a + 1] = "in"
+ assert(w == 10 and z == 20)
+ end
+ a[#a + 1] = "out"
+ assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out")
+ end
+ t()
+ print 'Test 7 OK'
+end
+
+do
+ local function t()
+ local X = false
+
+ local x, closescope = func2close(function () stack(10); X = true end, 100)
+ assert(x == 100); x = 101; -- 'x' is not read-only
+
+ -- closing functions do not corrupt returning values
+ local function foo (x)
+ local _ = closescope
+ defer getmetatable(_).__close(_) end
+ return x, X, 23
+ end
+
+ local a, b, c = foo(1.5)
+ assert(a == 1.5 and b == false and c == 23 and X == true)
+
+ X = false
+ foo = function (x)
+ local _ = closescope
+ defer getmetatable(_).__close(_) end
+ local y = 15
+ return y
+ end
+
+ assert(foo() == 15 and X == true)
+
+ X = false
+ foo = function ()
+ local x = closescope
+ defer getmetatable(x).__close(x) end
+ return x
+ end
+
+ assert(foo() == closescope and X == true)
+ end
+ t()
+ print 'Test 8 OK'
+end
+
+do
+ local function t()
+ -- calls cannot be tail in the scope of to-be-closed variables
+ local X, Y
+ local function foo ()
+ local _ = func2close(function () Y = 10 end)
+ defer getmetatable(_).__close(_) end
+ assert(X == true and Y == nil) -- 'X' not closed yet
+ return 1,2,3
+ end
+
+ local function bar ()
+ local _ = func2close(function () X = false end)
+ defer getmetatable(_).__close(_) end
+ X = true
+ do
+ return foo() -- not a tail call!
+ end
+ end
+
+ local a, b, c, d = bar()
+ assert(a == 1 and b == 2 and c == 3 and X == false and Y == 10 and d == nil)
+ return foo, bar
+ end
+ local f,b = t()
+ print 'Test 9 OK'
+end
+
+do
+ local function t()
+ -- an error in a wrapped coroutine closes variables
+ local x = false
+ local y = false
+ local co = coroutine.wrap(function ()
+ local xv = func2close(function () x = true end)
+ defer getmetatable(xv).__close(xv) end
+ do
+ local yv = func2close(function () y = true end)
+ defer getmetatable(yv).__close(yv) end
+ coroutine.yield(100) -- yield doesn't close variable
+ end
+ coroutine.yield(200) -- yield doesn't close variable
+ error(23) -- error does
+ end)
+
+ local b = co()
+ assert(b == 100 and not x and not y)
+ b = co()
+ assert(b == 200 and not x and y)
+ local a, b = pcall(co)
+ assert(not a and b == 23 and x and y)
+ end
+ t()
+ print 'Test 10 OK'
+end
+
+-- a suspended coroutine should not close its variables when collected
+do
+ function t()
+ local co
+ co = coroutine.wrap(function()
+ -- should not run
+ local x = func2close(function () os.exit(false) end)
+ defer getmetatable(x).__close(x) end
+ co = nil
+ coroutine.yield()
+ end)
+ co() -- start coroutine
+ assert(co == nil) -- eventually it will be collected
+ collectgarbage()
+ end
+ t()
+ print 'Test 11 OK'
+end
+
+do
+ local function t()
+ -- error in a wrapped coroutine raising errors when closing a variable
+ local x = 0
+ local co = coroutine.wrap(function ()
+ local xx = func2close(function () x = x + 1; error("@YYY") end)
+ defer getmetatable(xx).__close(xx) end
+ local xv = func2close(function () x = x + 1; error("@XXX") end)
+ defer getmetatable(xv).__close(xv) end
+ coroutine.yield(100)
+ error(200)
+ end)
+ assert(co() == 100); assert(x == 0)
+ local st, msg = pcall(co); assert(x == 2)
+ assert(not st and string.find(msg, "@YYY")) -- should get first error raised
+
+ local x = 0
+ local y = 0
+ co = coroutine.wrap(function ()
+ local xx = func2close(function () y = y + 1; error("YYY") end)
+ defer getmetatable(xx).__close(xx) end
+ local xv = func2close(function () x = x + 1; error("XXX") end)
+ defer getmetatable(xv).__close(xv) end
+ coroutine.yield(100)
+ return 200
+ end)
+ assert(co() == 100); assert(x == 0)
+ local st, msg = pcall(co)
+ assert(x == 1 and y == 1)
+ -- should get first error raised
+ assert(not st and string.find(msg, "%w+%.%w+:%d+: YYY"))
+ end
+ t()
+ print 'Test 12 OK'
+end
+
+print 'OK'
Index: lopnames.h
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lopnames.h b/lopnames.h
--- a/lopnames.h (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/lopnames.h (date 1620514343417)
@@ -93,6 +93,7 @@
"TFORLOOP",
"SETLIST",
"CLOSURE",
+ "DEFER",
"VARARG",
"VARARGPREP",
"EXTRAARG",
Index: lapi.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lapi.c b/lapi.c
--- a/lapi.c (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/lapi.c (date 1620514343354)
@@ -1266,7 +1266,7 @@
o = index2stack(L, idx);
nresults = L->ci->nresults;
api_check(L, L->tbclist < o, "given index below or equal a marked one");
- luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
+ luaF_newtbcupval(L, o, 0); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */
lua_assert(hastocloseCfunc(L->ci->nresults));
Index: lfunc.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/lfunc.c b/lfunc.c
--- a/lfunc.c (revision a03ceb4b47666501369a6b300e00f57c1dc1c708)
+++ b/lfunc.c (date 1620514658224)
@@ -99,6 +99,16 @@
return newupval(L, 0, level, pp);
}
+/* DEFER patch */
+static void calldefermethod (lua_State *L, TValue *func, TValue *err) {
+ if (!ttisfunction(func))
+ return;
+ StkId top = L->top;
+ setobj2s(L, top, func); /* will call defer function */
+ setobj2s(L, top + 1, err); /* and error msg. as 1st argument */
+ L->top = top + 2; /* add function and arguments */
+ luaD_callnoyield(L, top, 0);
+}
/*
** Call closing method for object 'obj' with error message 'err'. The
@@ -150,7 +160,10 @@
errobj = s2v(level + 1); /* error object goes after 'uv' */
luaD_seterrorobj(L, status, level + 1); /* set error object */
}
- callclosemethod(L, uv, errobj, yy);
+ if (level->tbclist.is_deferred)
+ calldefermethod(L, uv, errobj);
+ else
+ callclosemethod(L, uv, errobj, yy);
}
@@ -166,16 +179,20 @@
/*
** Insert a variable in the list of to-be-closed variables.
*/
-void luaF_newtbcupval (lua_State *L, StkId level) {
+void luaF_newtbcupval (lua_State *L, StkId level, int deferred) {
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 */
+ if (!deferred) {
+ 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;
+ L->tbclist->tbclist.is_deferred = 0;
}
level->tbclist.delta = cast(unsigned short, level - L->tbclist);
+ level->tbclist.is_deferred = deferred ? 1 : 0;
L->tbclist = level;
}
Loading…
Cancel
Save