summaryrefslogtreecommitdiff
path: root/testes/gc.lua
diff options
context:
space:
mode:
Diffstat (limited to 'testes/gc.lua')
-rw-r--r--testes/gc.lua624
1 files changed, 624 insertions, 0 deletions
diff --git a/testes/gc.lua b/testes/gc.lua
new file mode 100644
index 00000000..93fd6d69
--- /dev/null
+++ b/testes/gc.lua
@@ -0,0 +1,624 @@
1-- $Id: gc.lua,v 1.72 2016/11/07 13:11:28 roberto Exp $
2-- See Copyright Notice in file all.lua
3
4print('testing garbage collection')
5
6local debug = require"debug"
7
8collectgarbage()
9
10assert(collectgarbage("isrunning"))
11
12local function gcinfo () return collectgarbage"count" * 1024 end
13
14
15-- test weird parameters
16do
17 -- save original parameters
18 local a = collectgarbage("setpause", 200)
19 local b = collectgarbage("setstepmul", 200)
20 local t = {0, 2, 10, 90, 500, 5000, 30000, 0x7ffffffe}
21 for i = 1, #t do
22 local p = t[i]
23 for j = 1, #t do
24 local m = t[j]
25 collectgarbage("setpause", p)
26 collectgarbage("setstepmul", m)
27 collectgarbage("step", 0)
28 collectgarbage("step", 10000)
29 end
30 end
31 -- restore original parameters
32 collectgarbage("setpause", a)
33 collectgarbage("setstepmul", b)
34 collectgarbage()
35end
36
37
38_G["while"] = 234
39
40limit = 5000
41
42
43local function GC1 ()
44 local u
45 local b -- must be declared after 'u' (to be above it in the stack)
46 local finish = false
47 u = setmetatable({}, {__gc = function () finish = true end})
48 b = {34}
49 repeat u = {} until finish
50 assert(b[1] == 34) -- 'u' was collected, but 'b' was not
51
52 finish = false; local i = 1
53 u = setmetatable({}, {__gc = function () finish = true end})
54 repeat i = i + 1; u = tostring(i) .. tostring(i) until finish
55 assert(b[1] == 34) -- 'u' was collected, but 'b' was not
56
57 finish = false
58 u = setmetatable({}, {__gc = function () finish = true end})
59 repeat local i; u = function () return i end until finish
60 assert(b[1] == 34) -- 'u' was collected, but 'b' was not
61end
62
63local function GC2 ()
64 local u
65 local finish = false
66 u = {setmetatable({}, {__gc = function () finish = true end})}
67 b = {34}
68 repeat u = {{}} until finish
69 assert(b[1] == 34) -- 'u' was collected, but 'b' was not
70
71 finish = false; local i = 1
72 u = {setmetatable({}, {__gc = function () finish = true end})}
73 repeat i = i + 1; u = {tostring(i) .. tostring(i)} until finish
74 assert(b[1] == 34) -- 'u' was collected, but 'b' was not
75
76 finish = false
77 u = {setmetatable({}, {__gc = function () finish = true end})}
78 repeat local i; u = {function () return i end} until finish
79 assert(b[1] == 34) -- 'u' was collected, but 'b' was not
80end
81
82local function GC() GC1(); GC2() end
83
84
85contCreate = 0
86
87print('tables')
88while contCreate <= limit do
89 local a = {}; a = nil
90 contCreate = contCreate+1
91end
92
93a = "a"
94
95contCreate = 0
96print('strings')
97while contCreate <= limit do
98 a = contCreate .. "b";
99 a = string.gsub(a, '(%d%d*)', string.upper)
100 a = "a"
101 contCreate = contCreate+1
102end
103
104
105contCreate = 0
106
107a = {}
108
109print('functions')
110function a:test ()
111 while contCreate <= limit do
112 load(string.format("function temp(a) return 'a%d' end", contCreate), "")()
113 assert(temp() == string.format('a%d', contCreate))
114 contCreate = contCreate+1
115 end
116end
117
118a:test()
119
120-- collection of functions without locals, globals, etc.
121do local f = function () end end
122
123
124print("functions with errors")
125prog = [[
126do
127 a = 10;
128 function foo(x,y)
129 a = sin(a+0.456-0.23e-12);
130 return function (z) return sin(%x+z) end
131 end
132 local x = function (w) a=a+w; end
133end
134]]
135do
136 local step = 1
137 if _soft then step = 13 end
138 for i=1, string.len(prog), step do
139 for j=i, string.len(prog), step do
140 pcall(load(string.sub(prog, i, j), ""))
141 end
142 end
143end
144
145foo = nil
146print('long strings')
147x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
148assert(string.len(x)==80)
149s = ''
150n = 0
151k = math.min(300, (math.maxinteger // 80) // 2)
152while n < k do s = s..x; n=n+1; j=tostring(n) end
153assert(string.len(s) == k*80)
154s = string.sub(s, 1, 10000)
155s, i = string.gsub(s, '(%d%d%d%d)', '')
156assert(i==10000 // 4)
157s = nil
158x = nil
159
160assert(_G["while"] == 234)
161
162
163print("steps")
164
165print("steps (2)")
166
167local function dosteps (siz)
168 assert(not collectgarbage("isrunning"))
169 collectgarbage()
170 assert(not collectgarbage("isrunning"))
171 local a = {}
172 for i=1,100 do a[i] = {{}}; local b = {} end
173 local x = gcinfo()
174 local i = 0
175 repeat -- do steps until it completes a collection cycle
176 i = i+1
177 until collectgarbage("step", siz)
178 assert(gcinfo() < x)
179 return i
180end
181
182collectgarbage"stop"
183
184if not _port then
185 -- test the "size" of basic GC steps (whatever they mean...)
186 assert(dosteps(0) > 10)
187 assert(dosteps(10) < dosteps(2))
188end
189
190-- collector should do a full collection with so many steps
191assert(dosteps(20000) == 1)
192assert(collectgarbage("step", 20000) == true)
193assert(collectgarbage("step", 20000) == true)
194
195assert(not collectgarbage("isrunning"))
196collectgarbage"restart"
197assert(collectgarbage("isrunning"))
198
199
200if not _port then
201 -- test the pace of the collector
202 collectgarbage(); collectgarbage()
203 local x = gcinfo()
204 collectgarbage"stop"
205 assert(not collectgarbage("isrunning"))
206 repeat
207 local a = {}
208 until gcinfo() > 3 * x
209 collectgarbage"restart"
210 assert(collectgarbage("isrunning"))
211 repeat
212 local a = {}
213 until gcinfo() <= x * 2
214end
215
216
217print("clearing tables")
218lim = 15
219a = {}
220-- fill a with `collectable' indices
221for i=1,lim do a[{}] = i end
222b = {}
223for k,v in pairs(a) do b[k]=v end
224-- remove all indices and collect them
225for n in pairs(b) do
226 a[n] = nil
227 assert(type(n) == 'table' and next(n) == nil)
228 collectgarbage()
229end
230b = nil
231collectgarbage()
232for n in pairs(a) do error'cannot be here' end
233for i=1,lim do a[i] = i end
234for i=1,lim do assert(a[i] == i) end
235
236
237print('weak tables')
238a = {}; setmetatable(a, {__mode = 'k'});
239-- fill a with some `collectable' indices
240for i=1,lim do a[{}] = i end
241-- and some non-collectable ones
242for i=1,lim do a[i] = i end
243for i=1,lim do local s=string.rep('@', i); a[s] = s..'#' end
244collectgarbage()
245local i = 0
246for k,v in pairs(a) do assert(k==v or k..'#'==v); i=i+1 end
247assert(i == 2*lim)
248
249a = {}; setmetatable(a, {__mode = 'v'});
250a[1] = string.rep('b', 21)
251collectgarbage()
252assert(a[1]) -- strings are *values*
253a[1] = nil
254-- fill a with some `collectable' values (in both parts of the table)
255for i=1,lim do a[i] = {} end
256for i=1,lim do a[i..'x'] = {} end
257-- and some non-collectable ones
258for i=1,lim do local t={}; a[t]=t end
259for i=1,lim do a[i+lim]=i..'x' end
260collectgarbage()
261local i = 0
262for k,v in pairs(a) do assert(k==v or k-lim..'x' == v); i=i+1 end
263assert(i == 2*lim)
264
265a = {}; setmetatable(a, {__mode = 'vk'});
266local x, y, z = {}, {}, {}
267-- keep only some items
268a[1], a[2], a[3] = x, y, z
269a[string.rep('$', 11)] = string.rep('$', 11)
270-- fill a with some `collectable' values
271for i=4,lim do a[i] = {} end
272for i=1,lim do a[{}] = i end
273for i=1,lim do local t={}; a[t]=t end
274collectgarbage()
275assert(next(a) ~= nil)
276local i = 0
277for k,v in pairs(a) do
278 assert((k == 1 and v == x) or
279 (k == 2 and v == y) or
280 (k == 3 and v == z) or k==v);
281 i = i+1
282end
283assert(i == 4)
284x,y,z=nil
285collectgarbage()
286assert(next(a) == string.rep('$', 11))
287
288
289-- 'bug' in 5.1
290a = {}
291local t = {x = 10}
292local C = setmetatable({key = t}, {__mode = 'v'})
293local C1 = setmetatable({[t] = 1}, {__mode = 'k'})
294a.x = t -- this should not prevent 't' from being removed from
295 -- weak table 'C' by the time 'a' is finalized
296
297setmetatable(a, {__gc = function (u)
298 assert(C.key == nil)
299 assert(type(next(C1)) == 'table')
300 end})
301
302a, t = nil
303collectgarbage()
304collectgarbage()
305assert(next(C) == nil and next(C1) == nil)
306C, C1 = nil
307
308
309-- ephemerons
310local mt = {__mode = 'k'}
311a = {{10},{20},{30},{40}}; setmetatable(a, mt)
312x = nil
313for i = 1, 100 do local n = {}; a[n] = {k = {x}}; x = n end
314GC()
315local n = x
316local i = 0
317while n do n = a[n].k[1]; i = i + 1 end
318assert(i == 100)
319x = nil
320GC()
321for i = 1, 4 do assert(a[i][1] == i * 10); a[i] = nil end
322assert(next(a) == nil)
323
324local K = {}
325a[K] = {}
326for i=1,10 do a[K][i] = {}; a[a[K][i]] = setmetatable({}, mt) end
327x = nil
328local k = 1
329for j = 1,100 do
330 local n = {}; local nk = k%10 + 1
331 a[a[K][nk]][n] = {x, k = k}; x = n; k = nk
332end
333GC()
334local n = x
335local i = 0
336while n do local t = a[a[K][k]][n]; n = t[1]; k = t.k; i = i + 1 end
337assert(i == 100)
338K = nil
339GC()
340-- assert(next(a) == nil)
341
342
343-- testing errors during GC
344do
345collectgarbage("stop") -- stop collection
346local u = {}
347local s = {}; setmetatable(s, {__mode = 'k'})
348setmetatable(u, {__gc = function (o)
349 local i = s[o]
350 s[i] = true
351 assert(not s[i - 1]) -- check proper finalization order
352 if i == 8 then error("here") end -- error during GC
353end})
354
355for i = 6, 10 do
356 local n = setmetatable({}, getmetatable(u))
357 s[n] = i
358end
359
360assert(not pcall(collectgarbage))
361for i = 8, 10 do assert(s[i]) end
362
363for i = 1, 5 do
364 local n = setmetatable({}, getmetatable(u))
365 s[n] = i
366end
367
368collectgarbage()
369for i = 1, 10 do assert(s[i]) end
370
371getmetatable(u).__gc = false
372
373
374-- __gc errors with non-string messages
375setmetatable({}, {__gc = function () error{} end})
376local a, b = pcall(collectgarbage)
377assert(not a and type(b) == "string" and string.find(b, "error in __gc"))
378
379end
380print '+'
381
382
383-- testing userdata
384if T==nil then
385 (Message or print)('\n >>> testC not active: skipping userdata GC tests <<<\n')
386
387else
388
389 local function newproxy(u)
390 return debug.setmetatable(T.newuserdata(0), debug.getmetatable(u))
391 end
392
393 collectgarbage("stop") -- stop collection
394 local u = newproxy(nil)
395 debug.setmetatable(u, {__gc = true})
396 local s = 0
397 local a = {[u] = 0}; setmetatable(a, {__mode = 'vk'})
398 for i=1,10 do a[newproxy(u)] = i end
399 for k in pairs(a) do assert(getmetatable(k) == getmetatable(u)) end
400 local a1 = {}; for k,v in pairs(a) do a1[k] = v end
401 for k,v in pairs(a1) do a[v] = k end
402 for i =1,10 do assert(a[i]) end
403 getmetatable(u).a = a1
404 getmetatable(u).u = u
405 do
406 local u = u
407 getmetatable(u).__gc = function (o)
408 assert(a[o] == 10-s)
409 assert(a[10-s] == nil) -- udata already removed from weak table
410 assert(getmetatable(o) == getmetatable(u))
411 assert(getmetatable(o).a[o] == 10-s)
412 s=s+1
413 end
414 end
415 a1, u = nil
416 assert(next(a) ~= nil)
417 collectgarbage()
418 assert(s==11)
419 collectgarbage()
420 assert(next(a) == nil) -- finalized keys are removed in two cycles
421end
422
423
424-- __gc x weak tables
425local u = setmetatable({}, {__gc = true})
426-- __gc metamethod should be collected before running
427setmetatable(getmetatable(u), {__mode = "v"})
428getmetatable(u).__gc = function (o) os.exit(1) end -- cannot happen
429u = nil
430collectgarbage()
431
432local u = setmetatable({}, {__gc = true})
433local m = getmetatable(u)
434m.x = {[{0}] = 1; [0] = {1}}; setmetatable(m.x, {__mode = "kv"});
435m.__gc = function (o)
436 assert(next(getmetatable(o).x) == nil)
437 m = 10
438end
439u, m = nil
440collectgarbage()
441assert(m==10)
442
443
444-- errors during collection
445u = setmetatable({}, {__gc = function () error "!!!" end})
446u = nil
447assert(not pcall(collectgarbage))
448
449
450if not _soft then
451 print("deep structures")
452 local a = {}
453 for i = 1,200000 do
454 a = {next = a}
455 end
456 collectgarbage()
457end
458
459-- create many threads with self-references and open upvalues
460print("self-referenced threads")
461local thread_id = 0
462local threads = {}
463
464local function fn (thread)
465 local x = {}
466 threads[thread_id] = function()
467 thread = x
468 end
469 coroutine.yield()
470end
471
472while thread_id < 1000 do
473 local thread = coroutine.create(fn)
474 coroutine.resume(thread, thread)
475 thread_id = thread_id + 1
476end
477
478
479-- Create a closure (function inside 'f') with an upvalue ('param') that
480-- points (through a table) to the closure itself and to the thread
481-- ('co' and the initial value of 'param') where closure is running.
482-- Then, assert that table (and therefore everything else) will be
483-- collected.
484do
485 local collected = false -- to detect collection
486 collectgarbage(); collectgarbage("stop")
487 do
488 local function f (param)
489 ;(function ()
490 assert(type(f) == 'function' and type(param) == 'thread')
491 param = {param, f}
492 setmetatable(param, {__gc = function () collected = true end})
493 coroutine.yield(100)
494 end)()
495 end
496 local co = coroutine.create(f)
497 assert(coroutine.resume(co, co))
498 end
499 -- Now, thread and closure are not reacheable any more;
500 -- two collections are needed to break cycle
501 collectgarbage()
502 assert(not collected)
503 collectgarbage()
504 assert(collected)
505 collectgarbage("restart")
506end
507
508
509do
510 collectgarbage()
511 collectgarbage"stop"
512 local x = gcinfo()
513 repeat
514 for i=1,1000 do _ENV.a = {} end
515 collectgarbage("step", 0) -- steps should not unblock the collector
516 until gcinfo() > 2 * x
517 collectgarbage"restart"
518end
519
520
521if T then -- tests for weird cases collecting upvalues
522
523 local function foo ()
524 local a = {x = 20}
525 coroutine.yield(function () return a.x end) -- will run collector
526 assert(a.x == 20) -- 'a' is 'ok'
527 a = {x = 30} -- create a new object
528 assert(T.gccolor(a) == "white") -- of course it is new...
529 coroutine.yield(100) -- 'a' is still local to this thread
530 end
531
532 local t = setmetatable({}, {__mode = "kv"})
533 collectgarbage(); collectgarbage('stop')
534 -- create coroutine in a weak table, so it will never be marked
535 t.co = coroutine.wrap(foo)
536 local f = t.co() -- create function to access local 'a'
537 T.gcstate("atomic") -- ensure all objects are traversed
538 assert(T.gcstate() == "atomic")
539 assert(t.co() == 100) -- resume coroutine, creating new table for 'a'
540 assert(T.gccolor(t.co) == "white") -- thread was not traversed
541 T.gcstate("pause") -- collect thread, but should mark 'a' before that
542 assert(t.co == nil and f() == 30) -- ensure correct access to 'a'
543
544 collectgarbage("restart")
545
546 -- test barrier in sweep phase (advance cleaning of upvalue to white)
547 local u = T.newuserdata(0) -- create a userdata
548 collectgarbage()
549 collectgarbage"stop"
550 T.gcstate"atomic"
551 T.gcstate"sweepallgc"
552 local x = {}
553 assert(T.gccolor(u) == "black") -- upvalue is "old" (black)
554 assert(T.gccolor(x) == "white") -- table is "new" (white)
555 debug.setuservalue(u, x) -- trigger barrier
556 assert(T.gccolor(u) == "white") -- upvalue changed to white
557 collectgarbage"restart"
558
559 print"+"
560end
561
562
563if T then
564 local debug = require "debug"
565 collectgarbage("stop")
566 local x = T.newuserdata(0)
567 local y = T.newuserdata(0)
568 debug.setmetatable(y, {__gc = true}) -- bless the new udata before...
569 debug.setmetatable(x, {__gc = true}) -- ...the old one
570 assert(T.gccolor(y) == "white")
571 T.checkmemory()
572 collectgarbage("restart")
573end
574
575
576if T then
577 print("emergency collections")
578 collectgarbage()
579 collectgarbage()
580 T.totalmem(T.totalmem() + 200)
581 for i=1,200 do local a = {} end
582 T.totalmem(0)
583 collectgarbage()
584 local t = T.totalmem("table")
585 local a = {{}, {}, {}} -- create 4 new tables
586 assert(T.totalmem("table") == t + 4)
587 t = T.totalmem("function")
588 a = function () end -- create 1 new closure
589 assert(T.totalmem("function") == t + 1)
590 t = T.totalmem("thread")
591 a = coroutine.create(function () end) -- create 1 new coroutine
592 assert(T.totalmem("thread") == t + 1)
593end
594
595-- create an object to be collected when state is closed
596do
597 local setmetatable,assert,type,print,getmetatable =
598 setmetatable,assert,type,print,getmetatable
599 local tt = {}
600 tt.__gc = function (o)
601 assert(getmetatable(o) == tt)
602 -- create new objects during GC
603 local a = 'xuxu'..(10+3)..'joao', {}
604 ___Glob = o -- ressurect object!
605 setmetatable({}, tt) -- creates a new one with same metatable
606 print(">>> closing state " .. "<<<\n")
607 end
608 local u = setmetatable({}, tt)
609 ___Glob = {u} -- avoid object being collected before program end
610end
611
612-- create several objects to raise errors when collected while closing state
613do
614 local mt = {__gc = function (o) return o + 1 end}
615 for i = 1,10 do
616 -- create object and preserve it until the end
617 table.insert(___Glob, setmetatable({}, mt))
618 end
619end
620
621-- just to make sure
622assert(collectgarbage'isrunning')
623
624print('OK')