-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
issue #163 Split out defer tests to a separate file. Also backport a …
…few tests from Lua 5.4
- Loading branch information
1 parent
bf2f55e
commit d8a60dd
Showing
3 changed files
with
401 additions
and
116 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,398 @@ | ||
if ravi then | ||
ravi.auto(true) | ||
end | ||
|
||
print "testing code generation and optimizations" | ||
T = ravi | ||
|
||
local opcodes_coverage = {} | ||
opcodes_coverage.MOVE = 0 | ||
opcodes_coverage.LOADK = 0 | ||
opcodes_coverage.LOADKX = 0 | ||
opcodes_coverage.LOADBOOL = 0 | ||
opcodes_coverage.LOADNIL = 0 | ||
opcodes_coverage.GETUPVAL = 0 | ||
opcodes_coverage.GETTABUP = 0 | ||
opcodes_coverage.GETTABUP_SK = 0 | ||
opcodes_coverage.GETTABLE = 0 | ||
opcodes_coverage.SETTABUP = 0 | ||
opcodes_coverage.SETTABUP_SK = 0 | ||
opcodes_coverage.SETUPVAL = 0 | ||
opcodes_coverage.SETTABLE = 0 | ||
opcodes_coverage.NEWTABLE = 0 | ||
opcodes_coverage.SELF = 0 | ||
opcodes_coverage.ADD = 0 | ||
opcodes_coverage.SUB = 0 | ||
opcodes_coverage.MUL = 0 | ||
opcodes_coverage.MOD = 0 | ||
opcodes_coverage.POW = 0 | ||
opcodes_coverage.DIV = 0 | ||
opcodes_coverage.IDIV = 0 | ||
opcodes_coverage.BAND = 0 | ||
opcodes_coverage.BOR = 0 | ||
opcodes_coverage.BXOR = 0 | ||
opcodes_coverage.SHL = 0 | ||
opcodes_coverage.SHR = 0 | ||
opcodes_coverage.UNM = 0 | ||
opcodes_coverage.BNOT = 0 | ||
opcodes_coverage.NOT = 0 | ||
opcodes_coverage.LEN = 0 | ||
opcodes_coverage.CONCAT = 0 | ||
opcodes_coverage.JMP = 0 | ||
opcodes_coverage.EQ = 0 | ||
opcodes_coverage.LT = 0 | ||
opcodes_coverage.LE = 0 | ||
opcodes_coverage.TEST = 0 | ||
opcodes_coverage.TESTSET = 0 | ||
opcodes_coverage.CALL = 0 | ||
opcodes_coverage.TAILCALL = 0 | ||
opcodes_coverage.RETURN = 0 | ||
opcodes_coverage.FORLOOP = 0 | ||
opcodes_coverage.FORPREP = 0 | ||
opcodes_coverage.TFORCALL = 0 | ||
opcodes_coverage.TFORLOOP = 0 | ||
opcodes_coverage.SETLIST = 0 | ||
opcodes_coverage.CLOSURE = 0 | ||
opcodes_coverage.VARARG = 0 | ||
opcodes_coverage.EXTRAARG = 0 | ||
opcodes_coverage.NEW_IARRAY = 0 | ||
opcodes_coverage.NEW_FARRAY = 0 | ||
opcodes_coverage.LOADIZ = 0 | ||
opcodes_coverage.LOADFZ = 0 | ||
opcodes_coverage.UNMF = 0 | ||
opcodes_coverage.UNMI = 0 | ||
opcodes_coverage.ADDFF = 0 | ||
opcodes_coverage.ADDFI = 0 | ||
opcodes_coverage.ADDII = 0 | ||
opcodes_coverage.SUBFF = 0 | ||
opcodes_coverage.SUBFI = 0 | ||
opcodes_coverage.SUBIF = 0 | ||
opcodes_coverage.SUBII = 0 | ||
opcodes_coverage.MULFF = 0 | ||
opcodes_coverage.MULFI = 0 | ||
opcodes_coverage.MULII = 0 | ||
opcodes_coverage.DIVFF = 0 | ||
opcodes_coverage.DIVFI = 0 | ||
opcodes_coverage.DIVIF = 0 | ||
opcodes_coverage.DIVII = 0 | ||
opcodes_coverage.TOINT = 0 | ||
opcodes_coverage.TOFLT = 0 | ||
opcodes_coverage.TOIARRAY = 0 | ||
opcodes_coverage.TOFARRAY = 0 | ||
opcodes_coverage.MOVEI = 0 | ||
opcodes_coverage.MOVEF = 0 | ||
opcodes_coverage.MOVEIARRAY = 0 | ||
opcodes_coverage.MOVEFARRAY = 0 | ||
opcodes_coverage.IARRAY_GET = 0 | ||
opcodes_coverage.FARRAY_GET = 0 | ||
opcodes_coverage.IARRAY_SET = 0 | ||
opcodes_coverage.FARRAY_SET = 0 | ||
opcodes_coverage.FORLOOP_IP = 0 | ||
opcodes_coverage.FORLOOP_I1 = 0 | ||
opcodes_coverage.FORPREP_IP = 0 | ||
opcodes_coverage.FORPREP_I1 = 0 | ||
opcodes_coverage.SETUPVALI = 0 | ||
opcodes_coverage.SETUPVALF = 0 | ||
opcodes_coverage.SETUPVAL_IARRAY = 0 | ||
opcodes_coverage.SETUPVAL_FARRAY = 0 | ||
opcodes_coverage.IARRAY_SETI = 0 | ||
opcodes_coverage.FARRAY_SETF = 0 | ||
opcodes_coverage.BAND_II = 0 | ||
opcodes_coverage.BOR_II = 0 | ||
opcodes_coverage.BXOR_II = 0 | ||
opcodes_coverage.SHL_II = 0 | ||
opcodes_coverage.SHR_II = 0 | ||
opcodes_coverage.BNOT_I = 0 | ||
opcodes_coverage.EQ_II = 0 | ||
opcodes_coverage.EQ_FF = 0 | ||
opcodes_coverage.LT_II = 0 | ||
opcodes_coverage.LT_FF = 0 | ||
opcodes_coverage.LE_II = 0 | ||
opcodes_coverage.LE_FF = 0 | ||
opcodes_coverage.GETI = 0 | ||
opcodes_coverage.TABLE_GETFIELD = 0 | ||
opcodes_coverage.SETI = 0 | ||
opcodes_coverage.TABLE_SETFIELD = 0 | ||
opcodes_coverage.SETFIELD = 0 | ||
opcodes_coverage.GETFIELD = 0 | ||
opcodes_coverage.TOTAB = 0 | ||
opcodes_coverage.MOVETAB = 0 | ||
opcodes_coverage.SETUPVALT = 0 | ||
opcodes_coverage.TABLE_SELF_SK = 0 | ||
opcodes_coverage.TOTYPE = 0 | ||
opcodes_coverage.TOSTRING = 0 | ||
opcodes_coverage.TOCLOSURE = 0 | ||
opcodes_coverage.SELF_SK = 0 | ||
opcodes_coverage.DEFER = 0 | ||
|
||
local compile = function(f) | ||
if ravi and ravi.jit() then | ||
assert(ravi.compile(f)) | ||
end | ||
return true | ||
end | ||
|
||
-- ================================================================ | ||
-- Following section is an extract from the code.lua test | ||
-- These functions test bytecode generation, and also provide | ||
-- helper routines that we use later on in other test cases | ||
|
||
-- testing opcodes | ||
function check (f, ...) | ||
if not T then | ||
return true | ||
end | ||
local arg = {...} | ||
local c = T.listcode(f) | ||
for i=1, #arg do | ||
--print(arg[i], c[i]) | ||
opcodes_coverage[arg[i]] = opcodes_coverage[arg[i]]+1 | ||
assert(string.find(c[i], '- '..arg[i]..' *[AB][xs]?=%d')) | ||
end | ||
assert(c[#arg+2] == nil) | ||
end | ||
|
||
-- Test defer statement | ||
do | ||
local y = 0 | ||
local function x() | ||
defer y = y + 1 end | ||
defer y = y + 1 end | ||
end | ||
check(x, 'DEFER', 'CLOSURE', 'DEFER', 'CLOSURE', 'RETURN') | ||
x() | ||
assert(y == 2) | ||
compile(x) | ||
x() | ||
assert(y == 4) | ||
print 'Test 1 OK' | ||
end | ||
|
||
-- Test defer statement | ||
do | ||
local y = 0 | ||
local function x() | ||
defer y = y + 1 end | ||
error('raise error') | ||
defer y = y + 2 end -- will not be called | ||
end | ||
pcall(x) | ||
assert(y == 1) | ||
compile(x) | ||
pcall(x) | ||
assert(y == 2) | ||
print 'Test 2 OK' | ||
end | ||
|
||
-- Test defer statement | ||
do | ||
local y = 0 | ||
local function x() | ||
defer y = y + 1 end | ||
defer y = y + 2; error('err') end | ||
defer y = y + 3 end | ||
end | ||
pcall(x) | ||
assert(y == 6) | ||
compile(x) | ||
pcall(x) | ||
assert(y == 12) | ||
print 'Test 3 OK' | ||
end | ||
|
||
-- Test defer statement in tailcalls | ||
do | ||
local y = 0 | ||
local function x (n) | ||
defer y = y + 1 end | ||
if n > 0 then return x(n - 1) end | ||
end | ||
pcall(x, 3) | ||
assert(y == 4) | ||
compile(x) | ||
pcall(x, 3) | ||
assert(y == 8) | ||
print 'Test 4 OK' | ||
end | ||
|
||
-- Simulate a test of resource closure with defer | ||
do | ||
local y = 0 | ||
local z = { count = 0 } | ||
z.__index = z; | ||
function z:new() | ||
local object = {} | ||
setmetatable(object, z) | ||
return object | ||
end | ||
function z:open(arg) | ||
if (arg) then | ||
z.count = z.count + 1 | ||
return | ||
end | ||
y = 1 | ||
error('error opening') | ||
end | ||
function z.close() | ||
z.count = z.count - 1 | ||
end | ||
local function x(arg) | ||
local f = z:new() | ||
f:open(arg) | ||
assert(z.count == 1) | ||
defer f:close() end | ||
end | ||
x('filename') | ||
assert(y == 0) | ||
assert(z.count == 0) | ||
pcall(x, false) | ||
assert(z.count == 0) | ||
assert(y == 1) | ||
y = 0 | ||
compile(x) | ||
compile(z.new) | ||
compile(z.open) | ||
compile(z.close) | ||
x('filename') | ||
assert(y == 0) | ||
assert(z.count == 0) | ||
pcall(x, false) | ||
assert(z.count == 0) | ||
assert(y == 1) | ||
print 'Test 5 OK' | ||
end | ||
|
||
--- Test stack reallocation in defer statement | ||
do | ||
local function x(a) if a <= 0 then return else x(a-1) end end | ||
local y = ravi.jit and 100 or 1000 | ||
local function z(...) | ||
-- recursive call to make stack | ||
defer x(y) end | ||
return ... | ||
end | ||
do | ||
local a,b,c = z(1,2,3) | ||
assert(a == 1 and b == 2 and c == 3) | ||
compile(x) | ||
compile(z) | ||
a,b,c = z(3,2,1) | ||
assert(a == 3 and b == 2 and c == 1) | ||
end | ||
print 'Test 6 OK' | ||
end | ||
|
||
-- Adapted from Lua 5.4 | ||
local function stack(n) n = ((n == 0) or stack(n - 1)) end | ||
|
||
local function func2close (f, x, y) | ||
local obj = setmetatable({}, {__close = f}) | ||
if x then | ||
return x, obj, y | ||
else | ||
return obj | ||
end | ||
end | ||
|
||
do | ||
local function t() | ||
local a = {} | ||
do | ||
local b = false -- not to be closed | ||
-- x is <close> | ||
local x = setmetatable({"x"}, {__close = function (self) | ||
a[#a + 1] = self[1] end}) | ||
defer getmetatable(x).__close(x) end | ||
-- y is <close> | ||
local w, y, z = func2close(function (self, err) | ||
assert(err == nil); a[#a + 1] = "y" | ||
end, 10, 20) | ||
defer getmetatable(y).__close(y) end | ||
local c = nil -- not to be closed | ||
a[#a + 1] = "in" | ||
assert(w == 10 and z == 20) | ||
end | ||
a[#a + 1] = "out" | ||
assert(a[1] == "in" and a[2] == "y" and a[3] == "x" and a[4] == "out") | ||
end | ||
t() | ||
compile(t) | ||
t() | ||
print 'Test 7 OK' | ||
end | ||
|
||
do | ||
local function t() | ||
local X = false | ||
|
||
local x, closescope = func2close(function () stack(10); X = true end, 100) | ||
assert(x == 100); x = 101; -- 'x' is not read-only | ||
|
||
-- closing functions do not corrupt returning values | ||
local function foo (x) | ||
local _ = closescope | ||
defer getmetatable(_).__close(_) end | ||
return x, X, 23 | ||
end | ||
|
||
local a, b, c = foo(1.5) | ||
assert(a == 1.5 and b == false and c == 23 and X == true) | ||
|
||
X = false | ||
foo = function (x) | ||
local _ = closescope | ||
defer getmetatable(_).__close(_) end | ||
local y = 15 | ||
return y | ||
end | ||
|
||
assert(foo() == 15 and X == true) | ||
|
||
X = false | ||
foo = function () | ||
local x = closescope | ||
defer getmetatable(x).__close(x) end | ||
return x | ||
end | ||
|
||
assert(foo() == closescope and X == true) | ||
end | ||
t() | ||
compile(t) | ||
t() | ||
print 'Test 8 OK' | ||
end | ||
|
||
do | ||
local function t() | ||
-- calls cannot be tail in the scope of to-be-closed variables | ||
local X, Y | ||
local function foo () | ||
local _ = func2close(function () Y = 10 end) | ||
defer getmetatable(_).__close(_) end | ||
assert(X == true and Y == nil) -- 'X' not closed yet | ||
return 1,2,3 | ||
end | ||
|
||
local function bar () | ||
local _ = func2close(function () X = false end) | ||
defer getmetatable(_).__close(_) end | ||
X = true | ||
do | ||
return foo() -- not a tail call! | ||
end | ||
end | ||
|
||
local a, b, c, d = bar() | ||
assert(a == 1 and b == 2 and c == 3 and X == false and Y == 10 and d == nil) | ||
return foo, bar | ||
end | ||
local f,b = t() | ||
compile(f) | ||
compile(b) | ||
compile(t) | ||
t() | ||
print 'Test 9 OK' | ||
end | ||
|
||
print 'OK' |
Oops, something went wrong.