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.
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
may be called more than once, when exiting the scope. I am checking why Lua 5.4 behaves this way.
Note that in Lua 5.4 versions prior to 5.4.3 a deferred closure may be called more than once
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