Every call of a LuaClosure issues creation of a new stack frame for the function execution. Since this stack is usually thrown away after execution pooling them can help to reduce garbage collection overhead (there's one exception to this: the stack can be used as part of the returned varargs object, in that case it cannot be reused since that could cause conflicts). In my use case this change was a useful for calling a lot of Lua functions on a mobile device.
```
for _, m in ipairs({'', 'k', 'kv', 'v'}) do
print('test', m)
a = {}; setmetatable(a, {__mode = m});
a[1], a[2], a[3] = {}, {}, {};
for k, v in pairs(a) do
print(k, v)
end
end
print('ok')
```
```
t = {}
t.__lt = function (a,b,c)
collectgarbage()
assert(c == nil)
if type(a) == 'table' then a = a.x end
if type(b) == 'table' then b = b.x end
return a<b, "dummy"
end
function Op(x) return setmetatable({x=x}, t) end
local function test ()
assert(not(Op(1)<Op(1)) and (Op(1)<Op(2)) and not(Op(2)<Op(1)))
assert(not(1 < Op(1)) and (Op(1) < 2) and not(2 < Op(1)))
assert(not(Op('a')<Op('a')) and (Op('a')<Op('b')) and not(Op('b')<Op('a')))
assert(not('a' < Op('a')) and (Op('a') < 'b') and not(Op('b') < Op('a')))
assert((Op(1)<=Op(1)) and (Op(1)<=Op(2)) and not(Op(2)<=Op(1)))
assert((Op('a')<=Op('a')) and (Op('a')<=Op('b')) and not(Op('b')<=Op('a')))
assert(not(Op(1)>Op(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1)))
assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a')))
assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1)))
assert((1 >= Op(1)) and not(1 >= Op(2)) and (Op(2) >= 1))
assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a')))
assert(('a' >= Op('a')) and not(Op('a') >= 'b') and (Op('b') >= Op('a')))
end
test()
```
```
-- bug since 2.5 (C-stack overflow)
do
local function f (size)
local s = string.rep("a", size)
local p = string.rep(".?", size)
return pcall(string.match, s, p)
end
local r, m = f(80)
assert(r and #m == 80)
r, m = f(200000)
assert(not r and string.find(m, "too complex"), tostring(r)..", "..tostring(m))
end
```
```
do -- new (5.3.3) semantics for empty matches
assert(string.gsub("a b cd", " *", "-") == "-a-b-c-d-")
local res = ""
local sub = "a \nbc\t\td"
local i = 1
for p, e in string.gmatch(sub, "()%s*()") do
res = res .. string.sub(sub, i, p - 1) .. "-"
i = e
end
assert(res == "-a-b-c-d-")
end
```
```
do -- testing table library with metamethods
local function test (proxy, t)
for i = 1, 10 do
table.insert(proxy, 1, i)
end
assert(#proxy == 10 and #t == 10, tostring(#proxy)..'; '..tostring(#t))
for i = 1, 10 do
assert(t[i] == 11 - i)
end
table.sort(proxy)
for i = 1, 10 do
assert(t[i] == i and proxy[i] == i, i..': '..tostring(proxy[i])..'; '..tostring(t[i]))
end
assert(table.concat(proxy, ",") == "1,2,3,4,5,6,7,8,9,10")
for i = 1, 8 do
assert(table.remove(proxy, 1) == i)
end
assert(#proxy == 2 and #t == 2)
local a, b, c = table.unpack(proxy)
assert(a == 9 and b == 10 and c == nil)
end
-- all virtual
local t = {}
local proxy = setmetatable({}, {
__len = function () return #t end,
__index = t,
__newindex = t,
})
test(proxy, t)
-- only __newindex
local count = 0
t = setmetatable({}, {
__newindex = function (t,k,v) count = count + 1; rawset(t,k,v) end})
test(t, t)
assert(count == 10) -- after first 10, all other sets are not new
-- no __newindex
t = setmetatable({}, {
__index = function (_,k) return k + 1 end,
__len = function (_) return 5 end})
assert(table.concat(t, ";") == "2;3;4;5;6")
end
function check (a, f)
f = f or function (x,y) return x<y end;
for n = #a, 2, -1 do
local cmp = f(a[n], a[n-1])
if cmp then print(tostring(a)..'\n'..n..': "'..tostring(a[n])..'" < "'..tostring(a[n-1])..'"') end
assert(not cmp)
end
end
for b = 1, 2 do
a = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"}
if b == 2 then a[15] = 'Aaa' a[14] = 'Iii' a[13] = 'Mmm' end
print(#a)
table.sort(a)
check(a)
end
```
what = [[label between local definitions can mix-up their initializations]],
report = [[Karel Tuma, 2016/03/01]],
since = [[5.2]],
fix = nil,
example = [[
do
local k = 0
local x
::foo::
local y -- should be reset to nil after goto, but it is not
assert(not y)
y = true
k = k + 1
if k < 2 then goto foo end
end
]],
patch = [[
--- lparser.c 2015/11/02 16:09:30 2.149
+++ lparser.c 2016/03/03 12:03:37
@@ -1226,7 +1226,7 @@
checkrepeated(fs, ll, label); /* check for repeated labels */
checknext(ls, TK_DBCOLON); /* skip double colon */
/* create new entry for this label */
- l = newlabelentry(ls, ll, label, line, fs->pc);
+ l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
skipnoopstat(ls); /* skip other no-op statements */
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
]]
}
```
local ref = {
}
for cl in string.gmatch('acdglpsuwxACDGLPSUWX', '.') do
local list = ''
for i = 0, 255 do
if string.match(string.char(i), '%'..cl) then
list = list..i..','
end
end
if ref[cl] then
assert(ref[cl] == list, cl..':\n'..list..'\n'..ref[cl])
else
print(cl..' = "'..list..'",')
end
end
print('+')
```