|
@@ -11,9 +11,6 @@ local debug = require "debug"
|
|
|
local pack = table.pack
|
|
|
|
|
|
|
|
|
--- standard error message for memory errors
|
|
|
-local MEMERRMSG = "not enough memory"
|
|
|
-
|
|
|
local function tcheck (t1, t2)
|
|
|
assert(t1.n == (t2.n or #t2) + 1)
|
|
|
for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end
|
|
@@ -432,11 +429,6 @@ do
|
|
|
"bad argument #4 (string expected, got no value)")
|
|
|
|
|
|
|
|
|
- -- memory error
|
|
|
- T.totalmem(T.totalmem()+10000) -- set low memory limit (+10k)
|
|
|
- assert(T.checkpanic("newuserdata 20000") == MEMERRMSG)
|
|
|
- T.totalmem(0) -- restore high limit
|
|
|
-
|
|
|
-- memory error + thread status
|
|
|
local x = T.checkpanic(
|
|
|
[[ alloccount 0 # force a memory error in next line
|
|
@@ -1306,241 +1298,6 @@ do
|
|
|
end
|
|
|
|
|
|
|
|
|
---[[
|
|
|
-** {==================================================================
|
|
|
-** Testing memory limits
|
|
|
-** ===================================================================
|
|
|
---]]
|
|
|
-
|
|
|
-print("memory-allocation errors")
|
|
|
-
|
|
|
-checkerr("block too big", T.newuserdata, math.maxinteger)
|
|
|
-collectgarbage()
|
|
|
-local f = load"local a={}; for i=1,100000 do a[i]=i end"
|
|
|
-T.alloccount(10)
|
|
|
-checkerr(MEMERRMSG, f)
|
|
|
-T.alloccount() -- remove limit
|
|
|
-
|
|
|
-
|
|
|
--- test memory errors; increase limit for maximum memory by steps,
|
|
|
--- o that we get memory errors in all allocations of a given
|
|
|
--- task, until there is enough memory to complete the task without
|
|
|
--- errors.
|
|
|
-local function testbytes (s, f)
|
|
|
- collectgarbage()
|
|
|
- local M = T.totalmem()
|
|
|
- local oldM = M
|
|
|
- local a,b = nil
|
|
|
- while true do
|
|
|
- collectgarbage(); collectgarbage()
|
|
|
- T.totalmem(M)
|
|
|
- a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
|
|
|
- T.totalmem(0) -- remove limit
|
|
|
- if a and b == "OK" then break end -- stop when no more errors
|
|
|
- if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
|
|
|
- error(a, 0) -- propagate it
|
|
|
- end
|
|
|
- M = M + 7 -- increase memory limit
|
|
|
- end
|
|
|
- print(string.format("minimum memory for %s: %d bytes", s, M - oldM))
|
|
|
- return a
|
|
|
-end
|
|
|
-
|
|
|
--- test memory errors; increase limit for number of allocations one
|
|
|
--- by one, so that we get memory errors in all allocations of a given
|
|
|
--- task, until there is enough allocations to complete the task without
|
|
|
--- errors.
|
|
|
-
|
|
|
-local function testalloc (s, f)
|
|
|
- collectgarbage()
|
|
|
- local M = 0
|
|
|
- local a,b = nil
|
|
|
- while true do
|
|
|
- collectgarbage(); collectgarbage()
|
|
|
- T.alloccount(M)
|
|
|
- a, b = T.testC("pcall 0 1 0; pushstatus; return 2", f)
|
|
|
- T.alloccount() -- remove limit
|
|
|
- if a and b == "OK" then break end -- stop when no more errors
|
|
|
- if b ~= "OK" and b ~= MEMERRMSG then -- not a memory error?
|
|
|
- error(a, 0) -- propagate it
|
|
|
- end
|
|
|
- M = M + 1 -- increase allocation limit
|
|
|
- end
|
|
|
- print(string.format("minimum allocations for %s: %d allocations", s, M))
|
|
|
- return a
|
|
|
-end
|
|
|
-
|
|
|
-
|
|
|
-local function testamem (s, f)
|
|
|
- testalloc(s, f)
|
|
|
- return testbytes(s, f)
|
|
|
-end
|
|
|
-
|
|
|
-
|
|
|
--- doing nothing
|
|
|
-b = testamem("doing nothing", function () return 10 end)
|
|
|
-assert(b == 10)
|
|
|
-
|
|
|
--- testing memory errors when creating a new state
|
|
|
-
|
|
|
-testamem("state creation", function ()
|
|
|
- local st = T.newstate()
|
|
|
- if st then T.closestate(st) end -- close new state
|
|
|
- return st
|
|
|
-end)
|
|
|
-
|
|
|
-testamem("empty-table creation", function ()
|
|
|
- return {}
|
|
|
-end)
|
|
|
-
|
|
|
-testamem("string creation", function ()
|
|
|
- return "XXX" .. "YYY"
|
|
|
-end)
|
|
|
-
|
|
|
-testamem("coroutine creation", function()
|
|
|
- return coroutine.create(print)
|
|
|
-end)
|
|
|
-
|
|
|
-
|
|
|
--- testing to-be-closed variables
|
|
|
-testamem("to-be-closed variables", function()
|
|
|
- local flag
|
|
|
- do
|
|
|
- local x <close> =
|
|
|
- setmetatable({}, {__close = function () flag = true end})
|
|
|
- flag = false
|
|
|
- local x = {}
|
|
|
- end
|
|
|
- return flag
|
|
|
-end)
|
|
|
-
|
|
|
-
|
|
|
--- testing threads
|
|
|
-
|
|
|
--- get main thread from registry
|
|
|
-local mt = T.testC("rawgeti R !M; return 1")
|
|
|
-assert(type(mt) == "thread" and coroutine.running() == mt)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-local function expand (n,s)
|
|
|
- if n==0 then return "" end
|
|
|
- local e = string.rep("=", n)
|
|
|
- return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
|
|
|
- e, s, expand(n-1,s), e)
|
|
|
-end
|
|
|
-
|
|
|
-G=0; collectgarbage(); a =collectgarbage("count")
|
|
|
-load(expand(20,"G=G+1"))()
|
|
|
-assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1)
|
|
|
-G = nil
|
|
|
-
|
|
|
-testamem("running code on new thread", function ()
|
|
|
- return T.doonnewstack("local x=1") == 0 -- try to create thread
|
|
|
-end)
|
|
|
-
|
|
|
-
|
|
|
--- testing memory x compiler
|
|
|
-
|
|
|
-testamem("loadstring", function ()
|
|
|
- return load("x=1") -- try to do load a string
|
|
|
-end)
|
|
|
-
|
|
|
-
|
|
|
-local testprog = [[
|
|
|
-local function foo () return end
|
|
|
-local t = {"x"}
|
|
|
-AA = "aaa"
|
|
|
-for i = 1, #t do AA = AA .. t[i] end
|
|
|
-return true
|
|
|
-]]
|
|
|
-
|
|
|
--- testing memory x dofile
|
|
|
-_G.AA = nil
|
|
|
-local t =os.tmpname()
|
|
|
-local f = assert(io.open(t, "w"))
|
|
|
-f:write(testprog)
|
|
|
-f:close()
|
|
|
-testamem("dofile", function ()
|
|
|
- local a = loadfile(t)
|
|
|
- return a and a()
|
|
|
-end)
|
|
|
-assert(os.remove(t))
|
|
|
-assert(_G.AA == "aaax")
|
|
|
-
|
|
|
-
|
|
|
--- other generic tests
|
|
|
-
|
|
|
-testamem("gsub", function ()
|
|
|
- local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end)
|
|
|
- return (a == 'ablo ablo')
|
|
|
-end)
|
|
|
-
|
|
|
-testamem("dump/undump", function ()
|
|
|
- local a = load(testprog)
|
|
|
- local b = a and string.dump(a)
|
|
|
- a = b and load(b)
|
|
|
- return a and a()
|
|
|
-end)
|
|
|
-
|
|
|
-_G.AA = nil
|
|
|
-
|
|
|
-local t = os.tmpname()
|
|
|
-testamem("file creation", function ()
|
|
|
- local f = assert(io.open(t, 'w'))
|
|
|
- assert (not io.open"nomenaoexistente")
|
|
|
- io.close(f);
|
|
|
- return not loadfile'nomenaoexistente'
|
|
|
-end)
|
|
|
-assert(os.remove(t))
|
|
|
-
|
|
|
-testamem("table creation", function ()
|
|
|
- local a, lim = {}, 10
|
|
|
- for i=1,lim do a[i] = i; a[i..'a'] = {} end
|
|
|
- return (type(a[lim..'a']) == 'table' and a[lim] == lim)
|
|
|
-end)
|
|
|
-
|
|
|
-testamem("constructors", function ()
|
|
|
- local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5}
|
|
|
- return (type(a) == 'table' and a.e == 5)
|
|
|
-end)
|
|
|
-
|
|
|
-local a = 1
|
|
|
-local close = nil
|
|
|
-testamem("closure creation", function ()
|
|
|
- function close (b)
|
|
|
- return function (x) return b + x end
|
|
|
- end
|
|
|
- return (close(2)(4) == 6)
|
|
|
-end)
|
|
|
-
|
|
|
-testamem("using coroutines", function ()
|
|
|
- local a = coroutine.wrap(function ()
|
|
|
- coroutine.yield(string.rep("a", 10))
|
|
|
- return {}
|
|
|
- end)
|
|
|
- assert(string.len(a()) == 10)
|
|
|
- return a()
|
|
|
-end)
|
|
|
-
|
|
|
-do -- auxiliary buffer
|
|
|
- local lim = 100
|
|
|
- local a = {}; for i = 1, lim do a[i] = "01234567890123456789" end
|
|
|
- testamem("auxiliary buffer", function ()
|
|
|
- return (#table.concat(a, ",") == 20*lim + lim - 1)
|
|
|
- end)
|
|
|
-end
|
|
|
-
|
|
|
-testamem("growing stack", function ()
|
|
|
- local function foo (n)
|
|
|
- if n == 0 then return 1 else return 1 + foo(n - 1) end
|
|
|
- end
|
|
|
- return foo(100)
|
|
|
-end)
|
|
|
-
|
|
|
--- }==================================================================
|
|
|
-
|
|
|
-
|
|
|
do -- testing failing in 'lua_checkstack'
|
|
|
local res = T.testC([[rawcheckstack 500000; return 1]])
|
|
|
assert(res == false)
|