summaryrefslogtreecommitdiff
path: root/testes/gc.lua
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-12-17 14:46:37 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2018-12-17 14:46:37 -0200
commit063d4e4543088e7a21965bda8ee5a0f952a9029e (patch)
tree6c3f2f8e98c26f071a94a32f9f2754396a66a9de /testes/gc.lua
parente354c6355e7f48e087678ec49e340ca0696725b1 (diff)
downloadlua-5.3.5.tar.gz
lua-5.3.5.tar.bz2
lua-5.3.5.zip
Lua 5.3.5 ported to gitv5.3.5
This is the first commit for the branch Lua 5.3. All source files were copied from the official distribution of 5.3.5 in the Lua site. The test files are the same of 5.3.4. The manual came from the previous RCS repository, revision 1.167.1.2.
Diffstat (limited to '')
-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')