--- source: src/main.rs expression: compiled input_file: test-data/lua5.1-tests/gc.lua --- print('testing garbage collection'); collectgarbage(); _G[("while")] = 234 limit = 5000 contCreate = 0 print('tables'); while contCreate <= limit { local a = {} a = nil contCreate = contCreate + 1 } a = "a" contCreate = 0 print('strings'); while contCreate <= limit { a = contCreate .. "b" a = string.gsub(a, '(%d%d*)', string.upper) a = "a" contCreate = contCreate + 1 } contCreate = 0 a = {} print('functions'); method a::test() { while contCreate <= limit { loadstring(string.format("function temp(a) return 'a%d' end", contCreate))(); assert(temp() == string.format('a%d', contCreate)); contCreate = contCreate + 1 } } a::test(); { local f = fn () { } } print("functions with errors"); prog = ` do a = 10; function foo(x,y) a = sin(a+0.456-0.23e-12); return function (z) return sin(%x+z) end end local x = function (w) a=a+w; end end ` { local step = 1 if rawget(_G, "_soft") { step = 13 } for i = 1, string.len(prog), step { for j = i, string.len(prog), step { pcall(loadstring(string.sub(prog, i, j))); } } } print('long strings'); x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789" assert(string.len(x) == 80); s = '' n = 0 k = 300 while n < k { s = s .. x n = n + 1 j = tostring(n) } assert(string.len(s) == k * 80); s = string.sub(s, 1, 20000) s, i = string.gsub(s, '(%d%d%d%d)', math.sin) assert(i == 20000 / 4); s = nil x = nil assert(_G[("while")] == 234); local bytes = gcinfo() while 1 { local nbytes = gcinfo() if nbytes < bytes { break } bytes = nbytes a = {} } local fn dosteps(siz) { collectgarbage(); collectgarbage("stop"); local a = {} for i = 1, 100 { a[(i)] = { {} } local b = {} } local x = gcinfo() local i = 0 loop { i = i + 1 } until collectgarbage("step", siz) assert(gcinfo() < x); return i } assert(dosteps(0) > 10); assert(dosteps(6) < dosteps(2)); assert(dosteps(10000) == 1); assert(collectgarbage("step", 1000000) == true); assert(collectgarbage("step", 1000000)); { local x = gcinfo() collectgarbage(); collectgarbage("stop"); loop { local a = {} } until gcinfo() > 1000 collectgarbage("restart"); loop { local a = {} } until gcinfo() < 1000 } lim = 15 a = {} for i = 1, lim { a[({})] = i } b = {} for k, v with pairs(a) { b[(k)] = v } for n with pairs(b) { a[(n)] = nil assert(type(n) == 'table' && next(n) == nil); collectgarbage(); } b = nil collectgarbage(); for n with pairs(a) { error('cannot be here'); } for i = 1, lim { a[(i)] = i } for i = 1, lim { assert(a[(i)] == i); } print('weak tables'); a = {} setmetatable(a, { __mode = 'k' }); for i = 1, lim { a[({})] = i } for i = 1, lim { local t = {} a[(t)] = t } for i = 1, lim { a[(i)] = i } for i = 1, lim { local s = string.rep('@', i) a[(s)] = s .. '#' } collectgarbage(); local i = 0 for k, v with pairs(a) { assert(k == v || k .. '#' == v); i = i + 1 } assert(i == 3 * lim); a = {} setmetatable(a, { __mode = 'v' }); a[(1)] = string.rep('b', 21) collectgarbage(); assert(a[(1)]); a[(1)] = nil for i = 1, lim { a[(i)] = {} } for i = 1, lim { a[(i .. 'x')] = {} } for i = 1, lim { local t = {} a[(t)] = t } for i = 1, lim { a[(i + lim)] = i .. 'x' } collectgarbage(); local i = 0 for k, v with pairs(a) { assert(k == v || k - lim .. 'x' == v); i = i + 1 } assert(i == 2 * lim); a = {} setmetatable(a, { __mode = 'vk' }); local x, y, z = {}, {}, {} a[(1)], a[(2)], a[(3)] = x, y, z a[(string.rep('$', 11))] = string.rep('$', 11) for i = 4, lim { a[(i)] = {} } for i = 1, lim { a[({})] = i } for i = 1, lim { local t = {} a[(t)] = t } collectgarbage(); assert(next(a) != nil); local i = 0 for k, v with pairs(a) { assert((k == 1 && v == x) || (k == 2 && v == y) || (k == 3 && v == z) || k == v); i = i + 1 } assert(i == 4); x, y, z = nil collectgarbage(); assert(next(a) == string.rep('$', 11)); collectgarbage("stop"); local u = newproxy(true) local s = 0 local a = { u = 0 } setmetatable(a, { __mode = 'vk' }); for i = 1, 10 { a[(newproxy(u))] = i } for k with pairs(a) { assert(getmetatable(k) == getmetatable(u)); } local a1 = {} for k, v with pairs(a) { a1[(k)] = v } for k, v with pairs(a1) { a[(v)] = k } for i = 1, 10 { assert(a[(i)]); } getmetatable(u).a = a1 getmetatable(u).u = u { local u = u getmetatable(u).__gc = fn (o) { assert(a[(o)] == 10 - s); assert(a[(10 - s)] == nil); assert(getmetatable(o) == getmetatable(u)); assert(getmetatable(o).a[(o)] == 10 - s); s = s + 1 } } a1, u = nil assert(next(a) != nil); collectgarbage(); assert(s == 11); collectgarbage(); assert(next(a) == nil); local u = newproxy(true) setmetatable(getmetatable(u), { __mode = "v" }); getmetatable(u).__gc = fn (o) { os.exit(1); } collectgarbage(); local u = newproxy(true) local m = getmetatable(u) m.x = { { 0 } = 1, 0 = { 1 } } setmetatable(m.x, { __mode = "kv" }); m.__gc = fn (o) { assert(next(getmetatable(o).x) == nil); m = 10 } u, m = nil collectgarbage(); assert(m == 10); u = newproxy(true) getmetatable(u).__gc = fn () { error("!!!"); } u = nil assert(!pcall(collectgarbage)); if !rawget(_G, "_soft") { print("deep structures"); local a = {} for i = 1, 200000 { a = { next = a } } collectgarbage(); } local thread_id = 0 local threads = {} global fn fn(thread) { local x = {} threads[(thread_id)] = fn () { thread = x } coroutine.yield(); } while thread_id < 1000 { local thread = coroutine.create(fn) coroutine.resume(thread, thread); thread_id = thread_id + 1 } { local newproxy, assert, type, print, getmetatable = newproxy, assert, type, print, getmetatable local u = newproxy(true) local tt = getmetatable(u) ___Glob = { u } tt.__gc = fn (o) { assert(getmetatable(o) == tt); local a = 'xuxu' .. (10 + 3) .. 'joao', {} ___Glob = o newproxy(o); print(">>> closing state " .. "<<<\n"); } } { local u = newproxy(true) getmetatable(u).__gc = fn (o) { return o + 1 } table.insert(___Glob, u); for i = 1, 10 { table.insert(___Glob, newproxy(u)); } } print('OK');