github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/testdata/lua-5.3.3-tests/gc.lua (about)

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