diff options
Diffstat (limited to 'testes/gc.lua')
| -rw-r--r-- | testes/gc.lua | 624 |
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 | |||
| 4 | print('testing garbage collection') | ||
| 5 | |||
| 6 | local debug = require"debug" | ||
| 7 | |||
| 8 | collectgarbage() | ||
| 9 | |||
| 10 | assert(collectgarbage("isrunning")) | ||
| 11 | |||
| 12 | local function gcinfo () return collectgarbage"count" * 1024 end | ||
| 13 | |||
| 14 | |||
| 15 | -- test weird parameters | ||
| 16 | do | ||
| 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() | ||
| 35 | end | ||
| 36 | |||
| 37 | |||
| 38 | _G["while"] = 234 | ||
| 39 | |||
| 40 | limit = 5000 | ||
| 41 | |||
| 42 | |||
| 43 | local 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 | ||
| 61 | end | ||
| 62 | |||
| 63 | local 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 | ||
| 80 | end | ||
| 81 | |||
| 82 | local function GC() GC1(); GC2() end | ||
| 83 | |||
| 84 | |||
| 85 | contCreate = 0 | ||
| 86 | |||
| 87 | print('tables') | ||
| 88 | while contCreate <= limit do | ||
| 89 | local a = {}; a = nil | ||
| 90 | contCreate = contCreate+1 | ||
| 91 | end | ||
| 92 | |||
| 93 | a = "a" | ||
| 94 | |||
| 95 | contCreate = 0 | ||
| 96 | print('strings') | ||
| 97 | while contCreate <= limit do | ||
| 98 | a = contCreate .. "b"; | ||
| 99 | a = string.gsub(a, '(%d%d*)', string.upper) | ||
| 100 | a = "a" | ||
| 101 | contCreate = contCreate+1 | ||
| 102 | end | ||
| 103 | |||
| 104 | |||
| 105 | contCreate = 0 | ||
| 106 | |||
| 107 | a = {} | ||
| 108 | |||
| 109 | print('functions') | ||
| 110 | function 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 | ||
| 116 | end | ||
| 117 | |||
| 118 | a:test() | ||
| 119 | |||
| 120 | -- collection of functions without locals, globals, etc. | ||
| 121 | do local f = function () end end | ||
| 122 | |||
| 123 | |||
| 124 | print("functions with errors") | ||
| 125 | prog = [[ | ||
| 126 | do | ||
| 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 | ||
| 133 | end | ||
| 134 | ]] | ||
| 135 | do | ||
| 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 | ||
| 143 | end | ||
| 144 | |||
| 145 | foo = nil | ||
| 146 | print('long strings') | ||
| 147 | x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789" | ||
| 148 | assert(string.len(x)==80) | ||
| 149 | s = '' | ||
| 150 | n = 0 | ||
| 151 | k = math.min(300, (math.maxinteger // 80) // 2) | ||
| 152 | while n < k do s = s..x; n=n+1; j=tostring(n) end | ||
| 153 | assert(string.len(s) == k*80) | ||
| 154 | s = string.sub(s, 1, 10000) | ||
| 155 | s, i = string.gsub(s, '(%d%d%d%d)', '') | ||
| 156 | assert(i==10000 // 4) | ||
| 157 | s = nil | ||
| 158 | x = nil | ||
| 159 | |||
| 160 | assert(_G["while"] == 234) | ||
| 161 | |||
| 162 | |||
| 163 | print("steps") | ||
| 164 | |||
| 165 | print("steps (2)") | ||
| 166 | |||
| 167 | local 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 | ||
| 180 | end | ||
| 181 | |||
| 182 | collectgarbage"stop" | ||
| 183 | |||
| 184 | if 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)) | ||
| 188 | end | ||
| 189 | |||
| 190 | -- collector should do a full collection with so many steps | ||
| 191 | assert(dosteps(20000) == 1) | ||
| 192 | assert(collectgarbage("step", 20000) == true) | ||
| 193 | assert(collectgarbage("step", 20000) == true) | ||
| 194 | |||
| 195 | assert(not collectgarbage("isrunning")) | ||
| 196 | collectgarbage"restart" | ||
| 197 | assert(collectgarbage("isrunning")) | ||
| 198 | |||
| 199 | |||
| 200 | if 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 | ||
| 214 | end | ||
| 215 | |||
| 216 | |||
| 217 | print("clearing tables") | ||
| 218 | lim = 15 | ||
| 219 | a = {} | ||
| 220 | -- fill a with `collectable' indices | ||
| 221 | for i=1,lim do a[{}] = i end | ||
| 222 | b = {} | ||
| 223 | for k,v in pairs(a) do b[k]=v end | ||
| 224 | -- remove all indices and collect them | ||
| 225 | for n in pairs(b) do | ||
| 226 | a[n] = nil | ||
| 227 | assert(type(n) == 'table' and next(n) == nil) | ||
| 228 | collectgarbage() | ||
| 229 | end | ||
| 230 | b = nil | ||
| 231 | collectgarbage() | ||
| 232 | for n in pairs(a) do error'cannot be here' end | ||
| 233 | for i=1,lim do a[i] = i end | ||
| 234 | for i=1,lim do assert(a[i] == i) end | ||
| 235 | |||
| 236 | |||
| 237 | print('weak tables') | ||
| 238 | a = {}; setmetatable(a, {__mode = 'k'}); | ||
| 239 | -- fill a with some `collectable' indices | ||
| 240 | for i=1,lim do a[{}] = i end | ||
| 241 | -- and some non-collectable ones | ||
| 242 | for i=1,lim do a[i] = i end | ||
| 243 | for i=1,lim do local s=string.rep('@', i); a[s] = s..'#' end | ||
| 244 | collectgarbage() | ||
| 245 | local i = 0 | ||
| 246 | for k,v in pairs(a) do assert(k==v or k..'#'==v); i=i+1 end | ||
| 247 | assert(i == 2*lim) | ||
| 248 | |||
| 249 | a = {}; setmetatable(a, {__mode = 'v'}); | ||
| 250 | a[1] = string.rep('b', 21) | ||
| 251 | collectgarbage() | ||
| 252 | assert(a[1]) -- strings are *values* | ||
| 253 | a[1] = nil | ||
| 254 | -- fill a with some `collectable' values (in both parts of the table) | ||
| 255 | for i=1,lim do a[i] = {} end | ||
| 256 | for i=1,lim do a[i..'x'] = {} end | ||
| 257 | -- and some non-collectable ones | ||
| 258 | for i=1,lim do local t={}; a[t]=t end | ||
| 259 | for i=1,lim do a[i+lim]=i..'x' end | ||
| 260 | collectgarbage() | ||
| 261 | local i = 0 | ||
| 262 | for k,v in pairs(a) do assert(k==v or k-lim..'x' == v); i=i+1 end | ||
| 263 | assert(i == 2*lim) | ||
| 264 | |||
| 265 | a = {}; setmetatable(a, {__mode = 'vk'}); | ||
| 266 | local x, y, z = {}, {}, {} | ||
| 267 | -- keep only some items | ||
| 268 | a[1], a[2], a[3] = x, y, z | ||
| 269 | a[string.rep('$', 11)] = string.rep('$', 11) | ||
| 270 | -- fill a with some `collectable' values | ||
| 271 | for i=4,lim do a[i] = {} end | ||
| 272 | for i=1,lim do a[{}] = i end | ||
| 273 | for i=1,lim do local t={}; a[t]=t end | ||
| 274 | collectgarbage() | ||
| 275 | assert(next(a) ~= nil) | ||
| 276 | local i = 0 | ||
| 277 | for 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 | ||
| 282 | end | ||
| 283 | assert(i == 4) | ||
| 284 | x,y,z=nil | ||
| 285 | collectgarbage() | ||
| 286 | assert(next(a) == string.rep('$', 11)) | ||
| 287 | |||
| 288 | |||
| 289 | -- 'bug' in 5.1 | ||
| 290 | a = {} | ||
| 291 | local t = {x = 10} | ||
| 292 | local C = setmetatable({key = t}, {__mode = 'v'}) | ||
| 293 | local C1 = setmetatable({[t] = 1}, {__mode = 'k'}) | ||
| 294 | a.x = t -- this should not prevent 't' from being removed from | ||
| 295 | -- weak table 'C' by the time 'a' is finalized | ||
| 296 | |||
| 297 | setmetatable(a, {__gc = function (u) | ||
| 298 | assert(C.key == nil) | ||
| 299 | assert(type(next(C1)) == 'table') | ||
| 300 | end}) | ||
| 301 | |||
| 302 | a, t = nil | ||
| 303 | collectgarbage() | ||
| 304 | collectgarbage() | ||
| 305 | assert(next(C) == nil and next(C1) == nil) | ||
| 306 | C, C1 = nil | ||
| 307 | |||
| 308 | |||
| 309 | -- ephemerons | ||
| 310 | local mt = {__mode = 'k'} | ||
| 311 | a = {{10},{20},{30},{40}}; setmetatable(a, mt) | ||
| 312 | x = nil | ||
| 313 | for i = 1, 100 do local n = {}; a[n] = {k = {x}}; x = n end | ||
| 314 | GC() | ||
| 315 | local n = x | ||
| 316 | local i = 0 | ||
| 317 | while n do n = a[n].k[1]; i = i + 1 end | ||
| 318 | assert(i == 100) | ||
| 319 | x = nil | ||
| 320 | GC() | ||
| 321 | for i = 1, 4 do assert(a[i][1] == i * 10); a[i] = nil end | ||
| 322 | assert(next(a) == nil) | ||
| 323 | |||
| 324 | local K = {} | ||
| 325 | a[K] = {} | ||
| 326 | for i=1,10 do a[K][i] = {}; a[a[K][i]] = setmetatable({}, mt) end | ||
| 327 | x = nil | ||
| 328 | local k = 1 | ||
| 329 | for 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 | ||
| 332 | end | ||
| 333 | GC() | ||
| 334 | local n = x | ||
| 335 | local i = 0 | ||
| 336 | while n do local t = a[a[K][k]][n]; n = t[1]; k = t.k; i = i + 1 end | ||
| 337 | assert(i == 100) | ||
| 338 | K = nil | ||
| 339 | GC() | ||
| 340 | -- assert(next(a) == nil) | ||
| 341 | |||
| 342 | |||
| 343 | -- testing errors during GC | ||
| 344 | do | ||
| 345 | collectgarbage("stop") -- stop collection | ||
| 346 | local u = {} | ||
| 347 | local s = {}; setmetatable(s, {__mode = 'k'}) | ||
| 348 | setmetatable(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 | ||
| 353 | end}) | ||
| 354 | |||
| 355 | for i = 6, 10 do | ||
| 356 | local n = setmetatable({}, getmetatable(u)) | ||
| 357 | s[n] = i | ||
| 358 | end | ||
| 359 | |||
| 360 | assert(not pcall(collectgarbage)) | ||
| 361 | for i = 8, 10 do assert(s[i]) end | ||
| 362 | |||
| 363 | for i = 1, 5 do | ||
| 364 | local n = setmetatable({}, getmetatable(u)) | ||
| 365 | s[n] = i | ||
| 366 | end | ||
| 367 | |||
| 368 | collectgarbage() | ||
| 369 | for i = 1, 10 do assert(s[i]) end | ||
| 370 | |||
| 371 | getmetatable(u).__gc = false | ||
| 372 | |||
| 373 | |||
| 374 | -- __gc errors with non-string messages | ||
| 375 | setmetatable({}, {__gc = function () error{} end}) | ||
| 376 | local a, b = pcall(collectgarbage) | ||
| 377 | assert(not a and type(b) == "string" and string.find(b, "error in __gc")) | ||
| 378 | |||
| 379 | end | ||
| 380 | print '+' | ||
| 381 | |||
| 382 | |||
| 383 | -- testing userdata | ||
| 384 | if T==nil then | ||
| 385 | (Message or print)('\n >>> testC not active: skipping userdata GC tests <<<\n') | ||
| 386 | |||
| 387 | else | ||
| 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 | ||
| 421 | end | ||
| 422 | |||
| 423 | |||
| 424 | -- __gc x weak tables | ||
| 425 | local u = setmetatable({}, {__gc = true}) | ||
| 426 | -- __gc metamethod should be collected before running | ||
| 427 | setmetatable(getmetatable(u), {__mode = "v"}) | ||
| 428 | getmetatable(u).__gc = function (o) os.exit(1) end -- cannot happen | ||
| 429 | u = nil | ||
| 430 | collectgarbage() | ||
| 431 | |||
| 432 | local u = setmetatable({}, {__gc = true}) | ||
| 433 | local m = getmetatable(u) | ||
| 434 | m.x = {[{0}] = 1; [0] = {1}}; setmetatable(m.x, {__mode = "kv"}); | ||
| 435 | m.__gc = function (o) | ||
| 436 | assert(next(getmetatable(o).x) == nil) | ||
| 437 | m = 10 | ||
| 438 | end | ||
| 439 | u, m = nil | ||
| 440 | collectgarbage() | ||
| 441 | assert(m==10) | ||
| 442 | |||
| 443 | |||
| 444 | -- errors during collection | ||
| 445 | u = setmetatable({}, {__gc = function () error "!!!" end}) | ||
| 446 | u = nil | ||
| 447 | assert(not pcall(collectgarbage)) | ||
| 448 | |||
| 449 | |||
| 450 | if not _soft then | ||
| 451 | print("deep structures") | ||
| 452 | local a = {} | ||
| 453 | for i = 1,200000 do | ||
| 454 | a = {next = a} | ||
| 455 | end | ||
| 456 | collectgarbage() | ||
| 457 | end | ||
| 458 | |||
| 459 | -- create many threads with self-references and open upvalues | ||
| 460 | print("self-referenced threads") | ||
| 461 | local thread_id = 0 | ||
| 462 | local threads = {} | ||
| 463 | |||
| 464 | local function fn (thread) | ||
| 465 | local x = {} | ||
| 466 | threads[thread_id] = function() | ||
| 467 | thread = x | ||
| 468 | end | ||
| 469 | coroutine.yield() | ||
| 470 | end | ||
| 471 | |||
| 472 | while thread_id < 1000 do | ||
| 473 | local thread = coroutine.create(fn) | ||
| 474 | coroutine.resume(thread, thread) | ||
| 475 | thread_id = thread_id + 1 | ||
| 476 | end | ||
| 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. | ||
| 484 | do | ||
| 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") | ||
| 506 | end | ||
| 507 | |||
| 508 | |||
| 509 | do | ||
| 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" | ||
| 518 | end | ||
| 519 | |||
| 520 | |||
| 521 | if 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"+" | ||
| 560 | end | ||
| 561 | |||
| 562 | |||
| 563 | if 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") | ||
| 573 | end | ||
| 574 | |||
| 575 | |||
| 576 | if 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) | ||
| 593 | end | ||
| 594 | |||
| 595 | -- create an object to be collected when state is closed | ||
| 596 | do | ||
| 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 | ||
| 610 | end | ||
| 611 | |||
| 612 | -- create several objects to raise errors when collected while closing state | ||
| 613 | do | ||
| 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 | ||
| 619 | end | ||
| 620 | |||
| 621 | -- just to make sure | ||
| 622 | assert(collectgarbage'isrunning') | ||
| 623 | |||
| 624 | print('OK') | ||
