diff --git a/experimental/test.lua b/experimental/test.lua deleted file mode 100644 index 9ea05ed462..0000000000 --- a/experimental/test.lua +++ /dev/null @@ -1,86 +0,0 @@ --- test.lua --- --- Recursively run tests in the given paths, filtered by the given tags. --- Failed tests are extracted to the directory "failed_tests", and error --- details are appended. - -local t = require("tester") -local tconcat, iowrite = table.concat, io.write -local tagpat_inc = "^%+([_%a][_%w]*)$" -local tagpat_exc = "^%-([_%a][_%w]*)$" -local paths, tags_inc, tags_exc = {}, {}, {} -local verbose = false -local arg = arg or {...} -local runcmd -local function print_help() - io.write[[ -Usage: luajit test.lua path1 path2 +tagtofilter +orthistag -tagtoexclude -andthistag -Options: - path Recursively include tests in path. Default: test - +tag_inc Include only tests with tag tag_inc. Multiple include tags are ORed. - -tag_exc Exclude tests with tag tag_exc. - --help Print this help message. - --verbose Explicitly list all tests. - --runcmd='cmd' - If runcmd is defined, Command to run the tests with, externally, e.g. - --runcmd="luajit -joff" -]] -end - -for _,a in ipairs(arg) do - if not a:match("^[+-]") then - paths[#paths+1]=a - elseif a:match(tagpat_inc) then - tags_inc[#tags_inc+1]=a:match(tagpat_inc) - elseif a:match(tagpat_exc) then - tags_exc[#tags_exc+1]=a:match(tagpat_exc) - elseif a:match("%-%-verbose") then - verbose = true - elseif a:match("%-%-help") then - print_help() - return - elseif a:match("%-%-runcmd") then - runcmd = a:match("%-%-runcmd=(.*)") - end -end - -if #paths==0 then paths[1]="test" end -iowrite("Running tests in \"",tconcat(paths,"\",\""),"\"") -if #tags_inc > 0 then - iowrite(" with tags ",tconcat(tags_inc,",")) -end -if #tags_exc > 0 then - iowrite(" but without tags ",tconcat(tags_exc,",")) -end -iowrite("\n") - -local index = t.index(paths) -index = t.filter(index,tags_inc,tags_exc) -local pass, fail, failed_tests, errors = t.run(index,verbose,runcmd) - -iowrite("Passed ",pass,"/",pass+fail," tests.\n") -if fail==0 then return end - -local function report_fail(test,err) - local extfn = t.extract(test,"failed_tests") - iowrite("----------------------------------------------------------", - "\nname: ",test.name, - "\nerror: ",err or "(no error message)", - "\nsource file: ",test.fn, - "\nextracted to file: ",extfn, - "\n") - -- Append error message for completeness - local extf = io.open(extfn,"a") - if extf then - extf:write("\n--[===[\nTest failed at ",os.date(), - "\nruncmd: ",runcmd or "(internal pcall)", - "\nerror:\n",err or "(no error message)", - "\n]===]\n") - end -end - -iowrite("Failed tests:\n") -for i,failed_test in ipairs(failed_tests) do - report_fail(failed_test,errors[i]) -end - diff --git a/experimental/test/libs_ext/table.lua b/experimental/test/libs_ext/table.lua deleted file mode 100644 index 03c221912d..0000000000 --- a/experimental/test/libs_ext/table.lua +++ /dev/null @@ -1,37 +0,0 @@ ---- table.new -do - local tnew = require("table.new") - local x, y - for i=1,100 do - x = tnew(100, 30) - if i == 90 then y = x end - end - assert(x ~= y) -end - ---- table.pack() --- +lua52 -do - if os.getenv("LUA52") then - local t = table.pack() - assert(t.n == 0 and t[0] == nil and t[1] == nil) - end -end - ---- table.pack(99) --- +lua52 -do - if os.getenv("LUA52") then - local t = table.pack(99) - assert(t.n == 1 and t[0] == nil and t[1] == 99 and t[2] == nil) - end -end - ---- table.pack(nils) --- +lua52 -do - if os.getenv("LUA52") then - local t = table.pack(nil, nil, nil) - assert(t.n == 3 and t[0] == nil and t[1] == nil and t[2] == nil and t[3] == nil and t[4] == nil) - end -end diff --git a/experimental/tester.lua b/experimental/tester.lua deleted file mode 100644 index 77b61164fa..0000000000 --- a/experimental/tester.lua +++ /dev/null @@ -1,274 +0,0 @@ -local lfs = require("lfs") -local tconcat = table.concat - ---- Shallow table copy -local function cp(t) - local t1 = {} - for k,v in pairs(t) do t1[k]=v end - return t1 -end - ---- Path tokenizer, builds a table t for which t.token=true --- @param fn string containing a filename (fullpath) --- @return table for which keys token = true -local function tags_from_path(fn) - local tags = {} - for token in fn:gmatch("[^\\/]+") do - local token_lua = token:match("(.*)%.lua$") - tags[token_lua or token] = true - end - return tags -end - --- Patterns for parsing out test data. -local identifier_pat = "([_%a][_%w]*)" -local delim_pat = "^%-%-%-" -local name_pat = delim_pat.."%s*(.*)" -local desc_pat = "^%-%-(.*)" -local tag_pat = "%+"..identifier_pat -local attrib_pat = "@"..identifier_pat.."%s*:%s*([^@]*)" - ---- Parser for the tests. --- @param fn string containing a filename (fullpath) --- @return array containing test specs (name, code, description, tags) -local function parse_test(fn) - local tests = {} - local lookup = {} - local prelude = { - name = "prelude of "..fn, - fn = fn, - description = {}, - code = {}, - tags = tags_from_path(fn), - attributes = {}, - } - local current_test = prelude - local function store_test() - tests[#tests+1] = current_test - lookup[current_test.name] = #tests - end - for line in io.lines(fn) do - if line:match(delim_pat) then - -- Next test is reached - store_test() - local testname = line:match(name_pat) - if lookup[testname] then - error("Test "..testname.." is defined twice in the same file. Please give the tests unique names.") - end - -- Add current test to the tests table and start new current test table. - current_test = { - name = testname, - fn = fn, - description = cp(prelude.description), - tags = cp(prelude.tags), - code = cp(prelude.code), - attributes = cp(prelude.attributes), - } - elseif line:match(desc_pat) and #current_test.code==#prelude.code then - -- Continue building current test description, and possibly extract tags and key-value pairs - current_test.description[#current_test.description+1] = line:match(desc_pat) - for tag in line:gmatch(tag_pat) do - current_test.tags[tag] = true - end - for key,value in line:gmatch(attrib_pat) do - current_test.attributes[key] = value:gsub("%s*$","") - end - else - current_test.code[#current_test.code+1] = line - end - end - store_test() - return tests -end - --- Recursively parse the path and store the tests in test_index --- @param path string containing a path to a file or directory --- @param test_index array containing the tables with tests per file -local function recursive_parse(path,test_index) - local att, err = lfs.attributes(path) - if not att then - error("Could not parse "..path..": "..err) - end - if att.mode=="directory" then - for path2 in lfs.dir(path) do - if path2~=".." and path2~="." then - recursive_parse(path.."/"..path2,test_index) - end - end - elseif att.mode=="file" and path:match("%.lua$") then - test_index[#test_index+1] = parse_test(path) - end -end - ---- Walk the directory tree and index tests. --- @param paths array of paths that should be indexed. --- @return array of tables containing tests returned by parse -local function index_tests(paths) - local test_index = {} - for _,path in ipairs(paths) do - recursive_parse(path,test_index) - end - return test_index -end - ---- Build the string containing the chunk of a single test, including name and --- description. --- @param test table containing a test's name, description and code --- @return string containing the code snippet for the test, including comments. -local function build_codestring(test) - return tconcat({ - "--- ", test.name, - #test.description>0 and "\n--" or "", - tconcat(test.description,"\n--"), "\n", - tconcat(test.code,"\n") - }) -end - ---- Extract a test to a file. --- @param test the test table returned by parse, containing name, description, --- tags, code and attributes --- @param workdir string containing the directory where the test is extracted; --- the directory is created if needed (default: ".") --- @param fn string containing filename where the test should be extracted --- (default: test_fn__test_name.lua) --- @return filename to where the test was extracted -local function extract_test(test,workdir,fn) - fn = fn or (test.fn:gsub("%.lua$","").."__"..test.name):gsub("[^%a]","_")..".lua" - if workdir then - lfs.mkdir(workdir) - fn = workdir.."/"..fn - end - local f = io.open(fn,"w") - if not f then - error("Could not write to file "..fn) - end - f:write(build_codestring(test)) - f:close() - return fn -end - ---- Run a single test, possibly externally with runcmd. --- @param test single test object containing name, description, tags, code. --- @param verbose boolean indicating verbosity --- @param runcmd string containing the luajit command to run external tests. --- If runcmd is defined, the test is extracted into a file and run externally. --- If left empty, the test is run internally with pcall. --- @param workdir string containing the directory where runcmd is run and --- the test is extracted. --- @return true (pass) or false (fail) --- @return msg error message in case of failure -local function run_single_test(test,verbose,runcmd,workdir) - local ok, res - if runcmd then - workdir = workdir or "." - local fn = extract_test(test,workdir,"current_test.lua") - local fnerr = fn:gsub("%.lua$",".err") - local status = os.execute(runcmd.." "..fn.." 2> "..fnerr) - ok = status==0 - if not ok then - local ferr = io.open(fnerr) - if ferr then - res = ferr:read("*a") - ferr:close() - end - end - else - local code = build_codestring(test) - local load_ok, load_res = pcall(loadstring,code) - if not load_ok then - if verbose then - io.write("SYNT ",test.name,"\n ",load_res or "(no error message)","\n") - end - return load_ok, load_res - else - ok, res = pcall(load_res) - end - end - if verbose then - io.write(ok and "PASS " or "FAIL ",test.name,"\n") - if not ok then io.write(" "..(res or "(no error message)"),"\n") end - end - return ok, res -end - ---- Recursively run tests in paths. --- @param paths array of paths to recursively run tests in. --- @param verbose boolean indicating verbosity --- @param runcmd string containing the luajit command to run external tests. --- If runcmd is defined, the test is extracted into a file and run externally. --- If left empty, the test is run internally with pcall. --- @return number of passed tests --- @return number of failed tests --- @return array of failed tests --- @return array of corresponding error messages -local function run_tests(test_index,verbose,runcmd) - local pass, fail = 0,0 - local failed_tests = {} - local errors = {} - for i,test_block in ipairs(test_index) do - for j,test in ipairs(test_block) do - local ok, res = run_single_test(test,verbose,runcmd) - if ok then - pass = pass+1 - else - fail = fail+1 - failed_tests[#failed_tests+1] = test - errors[#errors+1] = res - end - end - end - return pass, fail, failed_tests, errors -end - ---- Check whether tags are in tags_inc and none are in tags_exc. --- If tags_inc is empty, default inclusion is true. --- @param tags Array of tags to test --- @param tags_inc Array of tags to include --- @param tags_exc Array of tags to exclude --- @return boolean indicating inclusion -local function check_tags(tags,tags_inc,tags_exc) - local include = false - if #tags_inc==0 then include = true end - for _,tag_inc in ipairs(tags_inc) do - if tags[tag_inc] then - include = true - break - end - end - if not include then return false end - for _,tag_exc in ipairs(tags_exc) do - if tags[tag_exc] then - return false - end - end - return true -end - ---- Select tests with tags_inc without tags_exc. --- If tags_inc is empty, select all tests by default. --- @param test_index array of test_blocks --- @param tags_inc array of tags to include --- @param tags_exc array of tags to exclude -local function filter_tests(test_index,tags_inc,tags_exc) - local tests_filtered = {} - for i,test_block in ipairs(test_index) do - local tests_i - for j, test in ipairs(test_block) do - if check_tags(test.tags,tags_inc,tags_exc) then - tests_i = tests_i or {} - tests_i[#tests_i+1]= test - end - end - tests_filtered[#tests_filtered+1] = tests_i - end - return tests_filtered -end - -return { - parse = parse_test, - index = index_tests, - extract = extract_test, - run_single = run_single_test, - run = run_tests, - filter = filter_tests, -} diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000000..f72290f225 --- /dev/null +++ b/test/README.md @@ -0,0 +1,110 @@ +This directory contains the LuaJIT test suite, or at least something which +will evolve into the LuaJIT test suite. Large chunks of the suite can also +be run with any other Lua 5.1 or 5.2 interpreter. + +## Running the test suite ## + +To run the default test suite, run `test.lua` using the Lua interpreter you +wish to test, for example: + + $ ~/luajit-2.0/src/luajit test.lua + +If the test suite passes, the final line printed to stdout will be +`NNN passed`, and the exit code of the process will be zero. If any tests +fail, the exit code will be non-zero. If the failures caused catastrophic +termination of the entire process (such as a segmentation fault or assertion +failure), the last line of output will be number and name of the test which +caused the catastrophe. If the failures weren't catastrophic, the penultimate +line of output will be `NNN passed, MMM failed`, and the last line will say +how to re-run just the failing tests. + +Various flags and options can be passed to `test.lua` to control which tests +are run, and in which order. Run `lua test.lua --help` for details. + +## Structure of the test suite ## + +The test suite consists of a directory tree. Within said tree there are various +`.lua` files, and within every `.lua` file there are one or more tests. Every +directory in the tree contains a file called `index`, which enumerates the +members of the directory which contribute to the test suite (this is done to +avoid an external dependency for directory iteration, and to allow metadata to +be specified at the file/directory level). Every `.lua` file is structured as: + + << local definitions >> + << test 1 >> + ... + << test N >> + +Where `<< local definitions >>` consists of Lua code to act as a common prefix +for every test in the file, and each `<< test >>` looks like: + + do --- <> <> + << code >> + end + +Where `<>` is (almost) free-form, and `<< code >>` is Lua code which +performs some actions and probably calls `assert` alot. The `<>` +fragment can be used to specify the conditions under which the test should +or should not run, to adjust the environment in which the test is run, and to +allow key/value pairs to be specified in a standard place/format. + +Some common pieces of metadata are: + * `+luajit>=2.1` - The test requires LuaJIT 2.1 or later to run. + * `+lua<5.2` - The test requires Lua 5.1 or earlier to run (all versions of + LuaJIT report themselves as 5.1). + * `+ffi` - The test requires the `ffi` library to be present. + * `+bit` - The test requires the `bit` library to be present. + * `+jit` - The test requires JIT compilation be available and turned on. + * `+slow` - The test is too slow to run as part of the default suite, and + thus requires `+slow` to be specified on the command line. + * `!private_G` - The test modifies globals, and thus needs to be run with a + private (shallow) copy of `_G`. + +Lua code which is common across all (or some) tests in a single file can be +written at the top of the file as part of `<< local definitions >>`. Code +which is common across multiple files lives in the `common` directory, and +is pulled into applicable tests by means of `local x = require"common.x"`. + +It is intended that most `.lua` files in the test suite can be exercised +without the test runner by just passing them to a Lua interpreter. In such +cases, metadata is ignored, the tests are executed from top to bottom, and +any failure results in later tests not running. Also note that the test +runner converts every test into a separate function, which causes references +to local definitions to become upvalue accesses rather than local variable +accesses - in some cases this can cause differences in behaviour. + +## Extending the test suite ## + +First of all, decide where your new test(s) should live. This might be within +an existing `.lua` file, or might involve creating new files and/or directories. +If new files are created, remember to add them to the `index` file of the +enclosing directory. If new directories are created, remember to create an +`index` file in said directory, and add the new directory to the `index` file +in the parent directory. + +Once you've decided in which file the test(s) should live, you're ready to add +your test(s) to said file. Each test should be wrapped in a `do`/`end` block, +and given some kind of name (after the `do` keyword, as in `do --- <>`). +The test should call `assert` to confirm whether the thing under test is +behaving, or otherwise raise an error if the thing under test is misbehaving. +Your test(s) should not write to stdout or stderr, nor should they mutate +global state. After your test(s) are written, you should be able to determine +which features they require, and put on metadata appropriately. + +## Completing the tidy-up of the test suite ## + +Some files/directories in this directory need some thought: + + * `common/ffi_util.inc` - Needs renaming and being made `require`-able. + * `lib/ffi` - Tests need converting to structure described in this document. + * `lib/table/misc.lua` - Tests need organising and converting to structure + described in this document. + * `misc` - Tests need organising and converting to structure described in + this document. + * `src` - C/C++ source which needs to be compiled into a dynamic library and + loaded for certain tests. Need to figure out a good way of handling + C/C++ source. + * `sysdep` - Need to figure out a good way of handling these. + * `unportable` - Need to figure out a good way of handling these. + +After that, consult the README file by Mike in the directory above this one. diff --git a/test/misc/constov.lua b/test/bc/constov.lua similarity index 87% rename from test/misc/constov.lua rename to test/bc/constov.lua index 341cf32930..de1e2a6d5d 100644 --- a/test/misc/constov.lua +++ b/test/bc/constov.lua @@ -1,19 +1,16 @@ - -if not os.getenv("SLOWTEST") then return end - -do - local t = { "local x\n" } - for i=2,65537 do t[i] = "x="..i..".5\n" end - assert(loadstring(table.concat(t)) ~= nil) - t[65538] = "x=65538.5" - assert(loadstring(table.concat(t)) == nil) -end - -do - local t = { "local x\n" } - for i=2,65537 do t[i] = "x='"..i.."'\n" end - assert(loadstring(table.concat(t)) ~= nil) - t[65538] = "x='65538'" - assert(loadstring(table.concat(t)) == nil) -end - + +do --- float + local t = { "local x\n" } + for i=2,65537 do t[i] = "x="..i..".5\n" end + assert(loadstring(table.concat(t)) ~= nil) + t[65538] = "x=65538.5" + assert(loadstring(table.concat(t)) == nil) +end + +do --- int + local t = { "local x\n" } + for i=2,65537 do t[i] = "x='"..i.."'\n" end + assert(loadstring(table.concat(t)) ~= nil) + t[65538] = "x='65538'" + assert(loadstring(table.concat(t)) == nil) +end diff --git a/test/bc/index b/test/bc/index new file mode 100644 index 0000000000..3954d57600 --- /dev/null +++ b/test/bc/index @@ -0,0 +1 @@ +constov.lua +slow diff --git a/test/common/expect_error.lua b/test/common/expect_error.lua new file mode 100644 index 0000000000..7643416720 --- /dev/null +++ b/test/common/expect_error.lua @@ -0,0 +1,16 @@ +return function(f, msg) + local ok, err = pcall(f) + if ok then error("error check unexpectedly succeeded", 2) end + if msg then + if type(err) ~= "string" then + error("error check failed with "..tostring(err), 2) + end + local line, err2 = string.match(err, ":(%d*): (.*)") + if err2 ~= msg then + if err2:gsub(" got no value", " got nil") == msg then + return + end + error("error check failed with "..err, 2) + end + end +end diff --git a/test/common/test_runner_canary.lua b/test/common/test_runner_canary.lua new file mode 100644 index 0000000000..138ad84c9e --- /dev/null +++ b/test/common/test_runner_canary.lua @@ -0,0 +1 @@ +return "canary is alive" diff --git a/test/computations.lua b/test/computations.lua new file mode 100644 index 0000000000..439febee7e --- /dev/null +++ b/test/computations.lua @@ -0,0 +1,113 @@ +do --- ack + local function Ack(m, n) + if m == 0 then return n+1 end + if n == 0 then return Ack(m-1, 1) end + return Ack(m-1, (Ack(m, n-1))) -- The parentheses are deliberate. + end + + assert(Ack(3,5) == 253) +end + +do --- ack notail + local function Ack(m, n) + if m == 0 then return n+1 end + if n == 0 then return Ack(m-1, 1) end + return (Ack(m-1, (Ack(m, n-1)))) -- The parentheses are deliberate. + end + + assert(Ack(3,5) == 253) +end + +do --- fac + local function fac(n) + local x = 1 + for i=2,n do + x = x * i + end + return x + end + + assert(fac(10) == 3628800) +end + +do --- ffib + local function ffib(n) + if n <= 2 then return n,1 end + if n % 2 == 1 then + local a,b = ffib((n-1)/2) + local aa = a*a + return aa+a*(b+b), aa+b*b + else + local a,b = ffib(n/2-1) + local ab = a+b + return ab*ab+a*a, (ab+b)*a + end + end + + local function fib(n) + return (ffib(n)) + end + + assert(fib(40) == 165580141) + assert(fib(39) == 102334155) + assert(fib(77) == 8944394323791464) +end + +do --- fib + local function fib(n) + if n < 2 then return 1 end + return fib(n-2) + fib(n-1) + end + + assert(fib(27) == 317811) +end + +do --- nsieve + local function nsieve(m) + local isPrime = {} + for i=2,m do isPrime[i] = true end + local count = 0 + for i=2,m do + if isPrime[i] then + for k=i+i,m,i do isPrime[k] = false end + count = count + 1 + end + end + return count + end + + assert(nsieve(100) == 25) + assert(nsieve(12345) == 1474) +end + +do --- recsum + local function sum(n) + if n == 1 then return 1 end + return n + sum(n-1) + end + + for i=1, 100 do + assert(sum(i) == i*(i+1)/2) + end +end + +do --- recsump + local abs = math.abs + local function sum(n) + if n == 1 then return 1 end + return abs(n + sum(n-1)) + end + + for i=1, 100 do + assert(sum(i) == i*(i+1)/2) + end +end + +do --- tak + local function tak(x, y, z) + if y >= x then return z end + return tak(tak(x-1, y, z), tak(y-1, z, x), (tak(z-1, x, y))) + end + + assert(tak(21, 14, 7) == 14) +end diff --git a/test/index b/test/index new file mode 100644 index 0000000000..256118eb9b --- /dev/null +++ b/test/index @@ -0,0 +1,6 @@ +lang +lib +bc +luajit>=2 +computations.lua +trace +jit +opt +jit diff --git a/test/lang/andor.lua b/test/lang/andor.lua new file mode 100644 index 0000000000..dc4296faa3 --- /dev/null +++ b/test/lang/andor.lua @@ -0,0 +1,61 @@ +do --- smoke + local x = ((1 or false) and true) or false + assert(x == true) +end + +do --- allcases + local basiccases = { + {"nil", nil}, + {"false", false}, + {"true", true}, + {"10", 10}, + } + + local mem = {basiccases} -- for memoization + + local function allcases (n) + if mem[n] then return mem[n] end + local res = {} + -- include all smaller cases + for _, v in ipairs(allcases(n - 1)) do + res[#res + 1] = v + end + for i = 1, n - 1 do + for _, v1 in ipairs(allcases(i)) do + for _, v2 in ipairs(allcases(n - i)) do + res[#res + 1] = { + "(" .. v1[1] .. " and " .. v2[1] .. ")", + v1[2] and v2[2] + } + res[#res + 1] = { + "(" .. v1[1] .. " or " .. v2[1] .. ")", + v1[2] or v2[2] + } + end + end + end + mem[n] = res -- memoize + return res + end + + for _, v in pairs(allcases(4)) do + local res = (loadstring or load)("return " .. v[1])() + if res ~= v[2] then + error(string.format("bad conditional eval\n%s\nexpected: %s\ngot: %s", + v[1], tostring(v[2]), tostring(res))) + end + end +end + +do --- tracefib + -- 0001 KSHORT 1 2 + -- 0002 ISGE 0 1 + -- 0003 JMP 1 => 0006 + -- 0004 KSHORT 1 1 + -- 0005 JMP 1 => 0013 + -- ^^^ must be 2 + -- fix in jmp_patchtestreg + local function fib(n) return (n < 2) and 1 or fib(n-1)+fib(n-2) end + assert(fib(5) == 8) + assert(fib(10) == 89) +end diff --git a/test/lang/assignment.lua b/test/lang/assignment.lua new file mode 100644 index 0000000000..34c7b52df7 --- /dev/null +++ b/test/lang/assignment.lua @@ -0,0 +1,46 @@ +local assert = assert + +do --- local + local a, b, c + a, b, c = 0, 1 + assert(a == 0) + assert(b == 1) + assert(c == nil) + a, b = a+1, b+1, a+b + assert(a == 1) + assert(b == 2) + a, b, c = 0 + assert(a == 0) + assert(b == nil) + assert(c == nil) +end + +do --- global !private_G + a, b, c = 0, 1 + assert(a == 0) + assert(b == 1) + assert(c == nil) + a, b = a+1, b+1, a+b + assert(a == 1) + assert(b == 2) + a, b, c = 0 + assert(a == 0) + assert(b == nil) + assert(c == nil) +end + +do --- local lhs in key on lhs + local a = {} + local i = 3 + i, a[i] = i+1, 20 + assert(i == 4) + assert(a[3] == 20) +end + +do --- global lhs in key on lhs !private_G + a = {} + i = 3 + i, a[i] = i+1, 20 + assert(i == 4) + assert(a[3] == 20) +end diff --git a/test/lang/compare.lua b/test/lang/compare.lua new file mode 100644 index 0000000000..fdabef5e8d --- /dev/null +++ b/test/lang/compare.lua @@ -0,0 +1,249 @@ +local function lt(x, y) + if x < y then return true else return false end +end + +local function le(x, y) + if x <= y then return true else return false end +end + +local function gt(x, y) + if x > y then return true else return false end +end + +local function ge(x, y) + if x >= y then return true else return false end +end + +local function eq(x, y) + if x == y then return true else return false end +end + +local function ne(x, y) + if x ~= y then return true else return false end +end + + +local function ltx1(x) + if x < 1 then return true else return false end +end + +local function lex1(x) + if x <= 1 then return true else return false end +end + +local function gtx1(x) + if x > 1 then return true else return false end +end + +local function gex1(x) + if x >= 1 then return true else return false end +end + +local function eqx1(x) + if x == 1 then return true else return false end +end + +local function nex1(x) + if x ~= 1 then return true else return false end +end + + +local function lt1x(x) + if 1 < x then return true else return false end +end + +local function le1x(x) + if 1 <= x then return true else return false end +end + +local function gt1x(x) + if 1 > x then return true else return false end +end + +local function ge1x(x) + if 1 >= x then return true else return false end +end + +local function eq1x(x) + if 1 == x then return true else return false end +end + +local function ne1x(x) + if 1 ~= x then return true else return false end +end + +local function check(a, b) + if a ~= b then + error("check failed with "..tostring(a).." ~= "..tostring(b), 2) + end +end + +do --- 1,2 + local x,y = 1,2 + + check(xy, false) + check(x>=y, false) + check(x==y, false) + check(x~=y, true) + + check(1y, false) + check(1>=y, false) + check(1==y, false) + check(1~=y, true) + + check(x<2, true) + check(x<=2, true) + check(x>2, false) + check(x>=2, false) + check(x==2, false) + check(x~=2, true) + + check(lt(x,y), true) + check(le(x,y), true) + check(gt(x,y), false) + check(ge(x,y), false) + check(eq(y,x), false) + check(ne(y,x), true) +end + +do --- 2,1 + local x,y = 2,1 + + check(xy, true) + check(x>=y, true) + check(x==y, false) + check(x~=y, true) + + check(2y, true) + check(2>=y, true) + check(2==y, false) + check(2~=y, true) + + check(x<1, false) + check(x<=1, false) + check(x>1, true) + check(x>=1, true) + check(x==1, false) + check(x~=1, true) + + check(lt(x,y), false) + check(le(x,y), false) + check(gt(x,y), true) + check(ge(x,y), true) + check(eq(y,x), false) + check(ne(y,x), true) +end + +do --- 1,1 + local x,y = 1,1 + + check(xy, false) + check(x>=y, true) + check(x==y, true) + check(x~=y, false) + + check(1y, false) + check(1>=y, true) + check(1==y, true) + check(1~=y, false) + + check(x<1, false) + check(x<=1, true) + check(x>1, false) + check(x>=1, true) + check(x==1, true) + check(x~=1, false) + + check(lt(x,y), false) + check(le(x,y), true) + check(gt(x,y), false) + check(ge(x,y), true) + check(eq(y,x), true) + check(ne(y,x), false) +end + +do --- 2 + check(lt1x(2), true) + check(le1x(2), true) + check(gt1x(2), false) + check(ge1x(2), false) + check(eq1x(2), false) + check(ne1x(2), true) + + check(ltx1(2), false) + check(lex1(2), false) + check(gtx1(2), true) + check(gex1(2), true) + check(eqx1(2), false) + check(nex1(2), true) +end + +do --- 1 + check(lt1x(1), false) + check(le1x(1), true) + check(gt1x(1), false) + check(ge1x(1), true) + check(eq1x(1), true) + check(ne1x(1), false) + + check(ltx1(1), false) + check(lex1(1), true) + check(gtx1(1), false) + check(gex1(1), true) + check(eqx1(1), true) + check(nex1(1), false) +end + +do --- 0 + check(lt1x(0), false) + check(le1x(0), false) + check(gt1x(0), true) + check(ge1x(0), true) + check(eq1x(0), false) + check(ne1x(0), true) + + check(ltx1(0), true) + check(lex1(0), true) + check(gtx1(0), false) + check(gex1(0), false) + check(eqx1(0), false) + check(nex1(0), true) +end + +do --- pcall + assert(not pcall(function() + local a, b = 10.5, nil + return a < b + end)) +end + +do --- bit +bit + for i=1,100 do + assert(bit.tobit(i+0x7fffffff) < 0) + end + for i=1,100 do + assert(bit.tobit(i+0x7fffffff) <= 0) + end +end + +do --- string 1 255 + local a = "\255\255\255\255" + local b = "\1\1\1\1" + + assert(a > b) + assert(a > b) + assert(a >= b) + assert(b <= a) +end diff --git a/test/misc/cat_jit.lua b/test/lang/concat.lua similarity index 79% rename from test/misc/cat_jit.lua rename to test/lang/concat.lua index 858a15bf45..c7af134f92 100644 --- a/test/misc/cat_jit.lua +++ b/test/lang/concat.lua @@ -1,113 +1,101 @@ - --- Constant folding -do - local y - for i=1,100 do y = "a".."b" end - assert(y == "ab") - for i=1,100 do y = "ab"..(1).."cd"..(1.5) end - assert(y == "ab1cd1.5") -end - --- Fuse conversions to strings -do - local y - local x = "a" - for i=1,100 do y = x..i end - assert(y == "a100") - x = "a" - for i=1.5,100.5 do y = x..i end - assert(y == "a100.5") -end - --- Fuse string construction -do - local y - local x = "abc" - for i=1,100 do y = "x"..string.sub(x, 2) end - assert(y == "xbc") -end - --- CSE, sink -do - local y - local x = "a" - for i=1,100 do y = x.."b" end - assert(y == "ab") -end - --- CSE, two buffers in parallel, no sink -do - local y, z - local x1, x2 = "xx", "yy" - for i=1,100 do y = x1.."a"..x1; z = x1.."a"..x2 end - assert(y == "xxaxx") - assert(z == "xxayy") - x1 = "xx" - for i=1,100 do y = x1.."a"..x1; z = x1.."b"..x1 end - assert(y == "xxaxx") - assert(z == "xxbxx") -end - --- Append, CSE -do - local y, z - local x = "a" - for i=1,100 do - y = x.."b" - y = y.."c" - end - assert(y == "abc") - x = "a" - for i=1,100 do - y = x.."b" - z = y.."c" - end - assert(y == "ab") - assert(z == "abc") - x = "a" - for i=1,100 do - y = x.."b" - z = y..i - end - assert(y == "ab") - assert(z == "ab100") -end - --- Append, FOLD -do - local a, b = "x" - for i=1,100 do b = (a.."y").."" end - assert(b == "xy") -end - --- Append to buffer, sink -do - local x = "a" - for i=1,100 do x = x.."b" end - assert(x == "a"..string.rep("b", 100)) - x = "a" - for i=1,100 do x = x.."bc" end - assert(x == "a"..string.rep("bc", 100)) -end - --- Append to two buffers in parallel, no append, no sink -do - local y, z = "xx", "yy" - for i=1,100 do y = y.."a"; z = z.."b" end - assert(y == "xx"..string.rep("a", 100)) - assert(z == "yy"..string.rep("b", 100)) -end - --- Sink into side-exit -do - local x = "a" - local z - for i=1,200 do - local y = x.."b" - if i > 100 then - z = y..i - end - end - assert(z == "ab200") -end - +do --- Constant folding + local y + for i=1,100 do y = "a".."b" end + assert(y == "ab") + for i=1,100 do y = "ab"..(1).."cd"..(1.5) end + assert(y == "ab1cd1.5") +end + +do --- Fuse conversions to strings + local y + local x = "a" + for i=1,100 do y = x..i end + assert(y == "a100") + x = "a" + for i=1.5,100.5 do y = x..i end + assert(y == "a100.5") +end + +do --- Fuse string construction + local y + local x = "abc" + for i=1,100 do y = "x"..string.sub(x, 2) end + assert(y == "xbc") +end + +do --- CSE, sink + local y + local x = "a" + for i=1,100 do y = x.."b" end + assert(y == "ab") +end + +do --- CSE, two buffers in parallel, no sink + local y, z + local x1, x2 = "xx", "yy" + for i=1,100 do y = x1.."a"..x1; z = x1.."a"..x2 end + assert(y == "xxaxx") + assert(z == "xxayy") + x1 = "xx" + for i=1,100 do y = x1.."a"..x1; z = x1.."b"..x1 end + assert(y == "xxaxx") + assert(z == "xxbxx") +end + +do --- Append, CSE + local y, z + local x = "a" + for i=1,100 do + y = x.."b" + y = y.."c" + end + assert(y == "abc") + x = "a" + for i=1,100 do + y = x.."b" + z = y.."c" + end + assert(y == "ab") + assert(z == "abc") + x = "a" + for i=1,100 do + y = x.."b" + z = y..i + end + assert(y == "ab") + assert(z == "ab100") +end + +do --- Append, FOLD + local a, b = "x" + for i=1,100 do b = (a.."y").."" end + assert(b == "xy") +end + +do --- Append to buffer, sink + local x = "a" + for i=1,100 do x = x.."b" end + assert(x == "a"..string.rep("b", 100)) + x = "a" + for i=1,100 do x = x.."bc" end + assert(x == "a"..string.rep("bc", 100)) +end + +do --- Append to two buffers in parallel, no append, no sink + local y, z = "xx", "yy" + for i=1,100 do y = y.."a"; z = z.."b" end + assert(y == "xx"..string.rep("a", 100)) + assert(z == "yy"..string.rep("b", 100)) +end + +do --- Sink into side-exit + local x = "a" + local z + for i=1,200 do + local y = x.."b" + if i > 100 then + z = y..i + end + end + assert(z == "ab200") +end diff --git a/test/lang/constant/index b/test/lang/constant/index new file mode 100644 index 0000000000..05bc1edb01 --- /dev/null +++ b/test/lang/constant/index @@ -0,0 +1 @@ +number.lua diff --git a/test/lang/constant/number.lua b/test/lang/constant/number.lua new file mode 100644 index 0000000000..c0514e7389 --- /dev/null +++ b/test/lang/constant/number.lua @@ -0,0 +1,12 @@ +do --- exp + assert(1e5 == 100000) + assert(1e+5 == 100000) + assert(1e-5 == 0.00001) +end + +do --- hex exp +hexfloat !lex + assert(0xe+9 == 23) + assert(0xep9 == 7168) + assert(0xep+9 == 7168) + assert(0xep-9 == 0.02734375) +end diff --git a/test/lang/coroutine.lua b/test/lang/coroutine.lua new file mode 100644 index 0000000000..769e64ffab --- /dev/null +++ b/test/lang/coroutine.lua @@ -0,0 +1,8 @@ +do --- traceback + local co = coroutine.create(function() + local x = nil + local y = x.x + end) + assert(coroutine.resume(co) == false) + debug.traceback(co) +end diff --git a/test/lang/for.lua b/test/lang/for.lua new file mode 100644 index 0000000000..b16508e1d3 --- /dev/null +++ b/test/lang/for.lua @@ -0,0 +1,45 @@ +do --- direction + local a,b,c = 10,1,-1 + for i=1,20 do + if c == -1 then + a,b,c = 1,10,1 + else + a,b,c = 10,1,-1 + end + local x = 0 + for i=a,b,c do for j=1,10 do end x=x+1 end + assert(x == 10) + end +end + +do --- coerce to integer at 13 + local n = 1 + local x = 0 + for i=1,20 do + for j=n,100 do x = x + 1 end + if i == 13 then n = "2" end + end + assert(x == 1993) +end + +do --- coerce to integer at 10 + local n = 1 + local x = 0 + for i=1,20 do + for j=n,100 do x = x + 1 end + if i == 10 then n = "2" end + end + assert(x == 1990) +end + +do --- cannot coerce to integer at 10 + local function f() + local n = 1 + local x = 0 + for i=1,20 do + for j=n,100 do x = x + 1 end + if i == 10 then n = "x" end + end + end + assert(not pcall(f)) +end diff --git a/test/lang/gc.lua b/test/lang/gc.lua new file mode 100644 index 0000000000..0c50450646 --- /dev/null +++ b/test/lang/gc.lua @@ -0,0 +1,30 @@ +do --- rechain + local k + + collectgarbage() + + local t = {} + t.ac = 1 + + t.nn = 1 + t.mm = 1 + t.nn = nil + t.mm = nil + + k = "a".."i" + t[k] = 2 + + t.ad = 3 + + t[k] = nil + k = nil + + collectgarbage() + + k = "a".."f" + t[k] = 4 + + t.ak = 5 + + assert(t[k] == 4) +end diff --git a/test/lang/index b/test/lang/index new file mode 100644 index 0000000000..743c5bce9e --- /dev/null +++ b/test/lang/index @@ -0,0 +1,12 @@ +andor.lua +assignment.lua +compare.lua +constant +for.lua +modulo.lua +concat.lua +self.lua +upvalue +coroutine.lua +tail_recursion.lua +gc.lua diff --git a/test/lang/modulo.lua b/test/lang/modulo.lua new file mode 100644 index 0000000000..eddaea77fa --- /dev/null +++ b/test/lang/modulo.lua @@ -0,0 +1,46 @@ +local assert, floor = assert, math.floor + +do --- integer equivalence + for x=-5,5 do + for y=-5,5 do + if y ~= 0 then + assert(x%y == x-floor(x/y)*y) + end + end + end +end + +do --- fractional equivalence + for x=-5,5,0.25 do + for y=-5,5,0.25 do + if y ~= 0 then + assert(x%y == x-floor(x/y)*y) + end + end + end +end + +do --- jit constant RHS + local y = 0 + for x=-100,123 do + y = y + x%17 + end + assert(y == 1777) +end + +do --- jit constant LHS, with exit + local y = 0 + for x=-100,123 do + if x ~= 0 then + y = y + 85%x + end + end + assert(y == 2059) +end + +do --- divide by zero + local x = 1%0 + assert(x ~= x) + x = floor(0/0) + assert(x ~= x) +end diff --git a/test/lang/self.lua b/test/lang/self.lua new file mode 100644 index 0000000000..48f58d30c8 --- /dev/null +++ b/test/lang/self.lua @@ -0,0 +1,19 @@ +do --- trivial setget + local t = {} + + function t:set(x) + self.a=x + end + + function t:get() + return self.a + end + + t:set("foo") + assert(t:get() == "foo") + assert(t.a == "foo") + + t:set(42) + assert(t:get() == 42) + assert(t.a == 42) +end diff --git a/test/lang/tail_recursion.lua b/test/lang/tail_recursion.lua new file mode 100644 index 0000000000..22bab72f95 --- /dev/null +++ b/test/lang/tail_recursion.lua @@ -0,0 +1,20 @@ +do --- self + local tr1 + function tr1(n) + if n <= 0 then return 0 end + return tr1(n-1) + end + assert(tr1(200) == 0) +end + +do --- mutual + local tr1, tr2 + function tr1(n) + if n <= 0 then return 0 end + return tr2(n-1) + end + function tr2(n) + return tr1(n) + end + assert(tr2(200) == 0) +end diff --git a/test/lang/upvalue/closure.lua b/test/lang/upvalue/closure.lua new file mode 100644 index 0000000000..34083223c7 --- /dev/null +++ b/test/lang/upvalue/closure.lua @@ -0,0 +1,84 @@ +do --- for + local z1, z2 + for i=1,10 do + local function f() return i end + if z1 then z2 = f else z1 = f end + end + assert(z1() == 1) + assert(z2() == 10) +end + +do --- while + local z1, z2 + local i = 1 + while i <= 10 do + local j = i + local function f() return j end + if z1 then z2 = f else z1 = f end + i = i + 1 + end + assert(z1() == 1) + assert(z2() == 10) +end + +do --- repeat + local z1, z2 + local i = 1 + repeat + local j = i + local function f() return j end + if z1 then z2 = f else z1 = f end + i = i + 1 + until i > 10 + assert(z1() == 1) + assert(z2() == 10) +end + +do --- func + local function ff(x) + return function() return x end + end + local z1, z2 + for i=1,10 do + local f = ff(i) + if z1 then z2 = f else z1 = f end + end + assert(z1() == 1) + assert(z2() == 10) +end + +do --- recursive type change + local function f1(a) + if a > 0 then + local b = f1(a - 1) + return function() + if type(b) == "function" then + return a + b() + end + return a + b + end + end + return a + end + + local function f2(a) + return f1(a)() + end + + for i = 1, 41 do + local r = f2(4) + f2(4) + assert(r == 20) + end +end + +do --- Don't mark upvalue as immutable if written to after prototype definition + local x = 1 + local function f() + local y = 0 + for i=1,100 do y=y+x end + return y + end + assert(f() == 100) + x = 2 + assert(f() == 200) +end diff --git a/test/lang/upvalue/index b/test/lang/upvalue/index new file mode 100644 index 0000000000..58931de651 --- /dev/null +++ b/test/lang/upvalue/index @@ -0,0 +1 @@ +closure.lua diff --git a/test/lib/base/assert.lua b/test/lib/base/assert.lua new file mode 100644 index 0000000000..6f1ef548c1 --- /dev/null +++ b/test/lib/base/assert.lua @@ -0,0 +1,33 @@ +do --- pass through one + assert(assert(true) == true) + assert(assert(3) == 3) + assert(assert(1.5) == 1.5) + assert(assert("x") == "x") + local f = function() end + assert(assert(f) == f) + local t = {} + assert(assert(t) == t) +end + +do --- pass through many + local b, c = assert("b", "c") + assert(b == "b") + assert(c == "c") + local d, e, f, g = assert("d", 5, true, false) + assert(d == "d") + assert(e == 5) + assert(f == true) + assert(g == false) +end + +do --- raise on nil + local ok, err = pcall(assert, nil) + assert(ok == false) + assert(err == "assertion failed!") +end + +do --- raise on false + local ok, err = pcall(assert, false, "msg") + assert(ok == false) + assert(err == "msg") +end diff --git a/test/lib/base/error.lua b/test/lib/base/error.lua new file mode 100644 index 0000000000..74aac75437 --- /dev/null +++ b/test/lib/base/error.lua @@ -0,0 +1,43 @@ +do --- no message + local ok, msg = pcall(error) + assert(ok == false) + assert(msg == nil) +end + +do --- level 0 + local ok, msg = pcall(error, "emsg", 0) + assert(ok == false) + assert(msg == "emsg") +end + +do --- default level + local ok, msg = pcall(error, "emsg") + assert(ok == false) + assert(msg == "emsg") +end + +do --- default level in xpcall + local line + local ok, msg = xpcall(function() + local x + line = debug.getinfo(1, "l").currentline; error("emsg") + end, function(m) + assert(debug.getlocal(3, 1) == "x") + return m .."xp" + end) + assert(ok == false) + assert(msg:find("^.-:".. line ..": emsgxp$")) +end + +do --- level 2 in xpcall + local line + local ok, msg = xpcall(function() + local function f() error("emsg", 2) end + line = debug.getinfo(1, "l").currentline; f() + end, function(m) + assert(debug.getlocal(4, 1) == "f") + return m .."xp2" + end) + assert(ok == false) + assert(msg:find("^.-:".. line ..": emsgxp2$")) +end diff --git a/test/lib/base/getfenv.lua b/test/lib/base/getfenv.lua new file mode 100644 index 0000000000..29e288c13f --- /dev/null +++ b/test/lib/base/getfenv.lua @@ -0,0 +1,13 @@ +do --- untitled + local x + local function f() + x = getfenv(0) + end + local co = coroutine.create(f) + local t = {} + debug.setfenv(co, t) + for i=1,50 do f() f() f() end + assert(x == getfenv(0)) + coroutine.resume(co) + assert(x == t) +end diff --git a/test/lib/base/index b/test/lib/base/index new file mode 100644 index 0000000000..16adea05e2 --- /dev/null +++ b/test/lib/base/index @@ -0,0 +1,5 @@ +assert.lua +error.lua +getfenv.lua +lua<5.2 +select.lua +xpcall_jit.lua +compat5.2 diff --git a/experimental/test/libs/core/select.lua b/test/lib/base/select.lua similarity index 71% rename from experimental/test/libs/core/select.lua rename to test/lib/base/select.lua index 5431609072..5c8ac55170 100644 --- a/experimental/test/libs/core/select.lua +++ b/test/lib/base/select.lua @@ -1,99 +1,105 @@ --- Tests for the basic function select(). --- +select +fast - ---- select # --- Test whether select("#", 3, 4) returns the correct number of arguments. -do - local x = 0 - for i=1,100 do - x = x + select("#", 3, 4) - end - assert(x == 200) -end - ---- select modf --- Test whether select("#", func()) also works with func returning multiple values -do - local x = 0 - for i=1,100 do - x = x + select("#", math.modf(i)) - end - assert(x == 200) -end - ---- select 1 -do - local x = 0 - for i=1,100 do - x = x + select(1, i) - end - assert(x == 5050) -end - ---- select 2 -do - local x, y = 0, 0 - for i=1,100 do - local a, b = select(2, 1, i, i+10) - x = x + a - y = y + b - end - assert(x == 5050 and y == 6050) -end - ---- select vararg # -do - local function f(a, ...) - local x = 0 - for i=1,select('#', ...) do - x = x + select(i, ...) - end - assert(x == a) - end - for i=1,100 do - f(1, 1) - f(3, 1, 2) - f(15, 1, 2, 3, 4, 5) - f(0) - f(3200, string.byte(string.rep(" ", 100), 1, 100)) - end -end - ---- select vararg i -do - local function f(a, ...) - local x = 0 - for i=1,20 do - local b = select(i, ...) - if b then x = x + b else x = x + 9 end - end - assert(x == a) - end - for i=1,100 do - f(172, 1) - f(165, 1, 2) - f(150, 1, 2, 3, 4, 5) - f(180) - f(640, string.byte(string.rep(" ", 100), 1, 100)) - end -end - ---- select vararg 4 -do - local function f(a, ...) - local x = 0 - for i=1,20 do - local b = select(4, ...) - if b then x = x + b else x = x + 9 end - end - assert(x == a) - end - for i=1,100 do - f(180, 1) - f(180, 1, 2) - f(80, 1, 2, 3, 4, 5) - f(180) - f(640, string.byte(string.rep(" ", 100), 1, 100)) - end -end - + +do --- select # +-- Test whether select("#", 3, 4) returns the correct number of arguments. + local x = 0 + for i=1,100 do + x = x + select("#", 3, 4) + end + assert(x == 200) +end + +do --- select modf +-- Test whether select("#", func()) also works with func returning multiple values + local x = 0 + math.frexp(3) + for i=1,100 do + x = x + select("#", math.modf(i)) + end + assert(x == 200) +end + +do --- select 1 + local x = 0 + for i=1,100 do + x = x + select(1, i) + end + assert(x == 5050) +end + +do --- select 2 + local x, y = 0, 0 + for i=1,100 do + local a, b = select(2, 1, i, i+10) + x = x + a + y = y + b + end + assert(x == 5050 and y == 6050) +end + +do --- select vararg # + local function f(a, ...) + local x = 0 + for i=1,select('#', ...) do + x = x + select(i, ...) + end + assert(x == a) + end + for i=1,100 do + f(1, 1) + f(3, 1, 2) + f(15, 1, 2, 3, 4, 5) + f(0) + f(3200, string.byte(string.rep(" ", 100), 1, 100)) + end +end + +do --- select vararg i + local function f(a, ...) + local x = 0 + for i=1,20 do + local b = select(i, ...) + if b then x = x + b else x = x + 9 end + end + assert(x == a) + end + for i=1,100 do + f(172, 1) + f(165, 1, 2) + f(150, 1, 2, 3, 4, 5) + f(180) + f(640, string.byte(string.rep(" ", 100), 1, 100)) + end +end + +do --- select vararg 4 + local function f(a, ...) + local x = 0 + for i=1,20 do + local b = select(4, ...) + if b then x = x + b else x = x + 9 end + end + assert(x == a) + end + for i=1,100 do + f(180, 1) + f(180, 1, 2) + f(80, 1, 2, 3, 4, 5) + f(180) + f(640, string.byte(string.rep(" ", 100), 1, 100)) + end +end + +do --- varg-select specialisation requires guard against select + local select = select + local exptyp = "number" + local function f(...) + for i = 1, 100 do + assert(type((select('#', ...))) == exptyp) + if i == 75 then + select = function() return "" end + exptyp = "string" + end + end + end + f(1) +end diff --git a/test/misc/xpcall_jit.lua b/test/lib/base/xpcall_jit.lua similarity index 87% rename from test/misc/xpcall_jit.lua rename to test/lib/base/xpcall_jit.lua index 61ffc8e64c..32c8e1c472 100644 --- a/test/misc/xpcall_jit.lua +++ b/test/lib/base/xpcall_jit.lua @@ -1,86 +1,83 @@ - -local function tr(err) return "tr"..err end - -do - local function f(x) return x*x end - local x = 0 - for i=1,100 do - local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i) - if not ok1 or not ok2 or not ok3 then break end - x = x + y - end - assert(x == 338350) -end - -do - local x = 0 - for i=1,100 do - local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, math.sqrt, tr, i*i) - if not ok1 or not ok2 or not ok3 then break end - x = x + y - end - assert(x == 5050) -end - -do - local function f(x) - if x >= 150 then error("test", 0) end - return x end - local x = 0 - for i=1,200 do - local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i) - if not ok1 or not ok2 or not ok3 then - assert(ok1 and ok2 and not ok3) - assert(y == "trtest") - break - end - x = x + y - end - assert(x == 11175) -end - -do - local function f(x) - if x >= 150 then return x*x end - return x - end - local x = 0 - for i=1,200 do - local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i) - if not ok1 or not ok2 or not ok3 then break end - x = x + y - end - assert(x == 1584100) -end - -do - local function f(x) - if x >= 150 then - if x >= 175 then error("test", 0) end - return x*x - end - return x - end - local x = 0 - for i=1,200 do - local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i) - if not ok1 or not ok2 or not ok3 then - assert(ok1 and ok2 and not ok3) - assert(y == "trtest") - -- note: no break, so we get an exit to interpreter - else - x = x + y - end - end - assert(x == 668575) -end - -do - local x = 0 - for i=1,100 do - -- Test xpcall swap after recorder error. - local ok1, ok2, ok3, err = xpcall(xpcall, tr, xpcall, tr, error, tr, "test", 0) - assert(ok1 and ok2 and not ok3 and err == "trtest") - end -end - +local function tr(err) return "tr"..err end + +do --- square sum + local function f(x) return x*x end + local x = 0 + for i=1,100 do + local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i) + if not ok1 or not ok2 or not ok3 then break end + x = x + y + end + assert(x == 338350) +end + +do --- sqrt square sum + local x = 0 + for i=1,100 do + local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, math.sqrt, tr, i*i) + if not ok1 or not ok2 or not ok3 then break end + x = x + y + end + assert(x == 5050) +end + +do --- sum with error + local function f(x) + if x >= 150 then error("test", 0) end + return x end + local x = 0 + for i=1,200 do + local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i) + if not ok1 or not ok2 or not ok3 then + assert(ok1 and ok2 and not ok3) + assert(y == "trtest") + break + end + x = x + y + end + assert(x == 11175) +end + +do --- square with error + local function f(x) + if x >= 150 then return x*x end + return x + end + local x = 0 + for i=1,200 do + local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i) + if not ok1 or not ok2 or not ok3 then break end + x = x + y + end + assert(x == 1584100) +end + +do --- sum or square with error + local function f(x) + if x >= 150 then + if x >= 175 then error("test", 0) end + return x*x + end + return x + end + local x = 0 + for i=1,200 do + local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i) + if not ok1 or not ok2 or not ok3 then + assert(ok1 and ok2 and not ok3) + assert(y == "trtest") + -- note: no break, so we get an exit to interpreter + else + x = x + y + end + end + assert(x == 668575) +end + +do --- xpcall swap after recorder error + local x = 0 + for i=1,100 do + local ok1, ok2, ok3, err = xpcall(xpcall, tr, xpcall, tr, error, tr, "test", 0) + assert(ok1 and ok2 and not ok3 and err == "trtest") + end +end diff --git a/test/lib/bit.lua b/test/lib/bit.lua new file mode 100644 index 0000000000..a37b28a37e --- /dev/null +++ b/test/lib/bit.lua @@ -0,0 +1,98 @@ +local bit = require"bit" +local byte, ipairs, tostring, pcall = string.byte, ipairs, tostring, pcall + +local vb = { + 0, 1, -1, 2, -2, 0x12345678, 0x87654321, + 0x33333333, 0x77777777, 0x55aa55aa, 0xaa55aa55, + 0x7fffffff, 0x80000000, 0xffffffff +} + +local function cksum(name, s, r) + local z = 0 + for i=1,#s do z = (z + byte(s, i)*i) % 2147483629 end + if z ~= r then + error("bit."..name.." test failed (got "..z..", expected "..r..")", 0) + end +end + +local function check_unop(name, r) + local f = bit[name] + local s = "" + if pcall(f) or pcall(f, "z") or pcall(f, true) then + error("bit."..name.." fails to detect argument errors", 0) + end + for _,x in ipairs(vb) do s = s..","..tostring(f(x)) end + cksum(name, s, r) +end + +local function check_binop(name, r) + local f = bit[name] + local s = "" + if pcall(f) or pcall(f, "z") or pcall(f, true) then + error("bit."..name.." fails to detect argument errors", 0) + end + for _,x in ipairs(vb) do + for _2,y in ipairs(vb) do s = s..","..tostring(f(x, y)) --[[io.write(_, " ", _2, " ", x, " ", y, " ", f(x, y), "\n")]] end + end + cksum(name, s, r) +end + +local function check_binop_range(name, r, yb, ye) + local f = bit[name] + local s = "" + if pcall(f) or pcall(f, "z") or pcall(f, true) or pcall(f, 1, true) then + error("bit."..name.." fails to detect argument errors", 0) + end + for _,x in ipairs(vb) do + for y=yb,ye do s = s..","..tostring(f(x, y)) end + end + cksum(name, s, r) +end + +local function check_shift(name, r) + check_binop_range(name, r, 0, 31) +end + +do --- Minimal sanity checks. + assert(0x7fffffff == 2147483647, "broken hex literals") + assert(0xffffffff == -1 or 0xffffffff == 2^32-1, "broken hex literals") + assert(tostring(-1) == "-1", "broken tostring()") + assert(tostring(0xffffffff) == "-1" or tostring(0xffffffff) == "4294967295", "broken tostring()") +end + +do --- Basic argument processing. + assert(bit.tobit(1) == 1) + assert(bit.band(1) == 1) + assert(bit.bxor(1,2) == 3) + assert(bit.bor(1,2,4,8,16,32,64,128) == 255) +end + +do --- unop test vectors + check_unop("tobit", 277312) + check_unop("bnot", 287870) + check_unop("bswap", 307611) +end + +do --- binop test vectors + check_binop("band", 41206764) + check_binop("bor", 51253663) + check_binop("bxor", 79322427) +end + +do --- shift test vectors + check_shift("lshift", 325260344) + check_shift("rshift", 139061800) + check_shift("arshift", 111364720) + check_shift("rol", 302401155) + check_shift("ror", 302316761) +end + +do --- tohex test vectors + check_binop_range("tohex", 47880306, -8, 8) +end + +do --- Don't propagate TOBIT narrowing across two conversions. + local tobit = bit.tobit + local k = 0x8000000000003 + for i=1,100 do assert(tobit(k % (2^32)) == 3) end +end diff --git a/test/lib/contents.lua b/test/lib/contents.lua new file mode 100644 index 0000000000..bb9f2cf79f --- /dev/null +++ b/test/lib/contents.lua @@ -0,0 +1,151 @@ +local function check(m, expected, exclude) + local t = {} + local ex = {} + if exclude then + for k in exclude:gmatch"[^:]+" do + ex[k] = true + end + end + for k in pairs(m) do + if not ex[k] then + t[#t+1] = tostring(k) + end + end + table.sort(t) + local got = table.concat(t, ":") + if got ~= expected then + error("got: \""..got.."\"\nexpected: \""..expected.."\"", 2) + end +end + +do --- base + check(_G, "_G:_VERSION:arg:assert:collectgarbage:coroutine:debug:dofile:error:getmetatable:io:ipairs:load:loadfile:math:next:os:package:pairs:pcall:print:rawequal:rawget:rawset:require:select:setmetatable:string:table:tonumber:tostring:type:xpcall", "rawlen:bit:bit32:jit:gcinfo:setfenv:getfenv:loadstring:unpack:module:newproxy") +end + +do --- pre-5.2 base +lua<5.2 + assert(gcinfo) + assert(setfenv) + assert(getfenv) + assert(loadstring) + assert(unpack) + assert(module) + assert(newproxy) +end + +do --- 5.2 base +lua>=5.2 + assert(not gcinfo) + assert(not setfenv) + assert(not getfenv) + assert(not loadstring) + assert(not unpack) + assert(not module) + assert(not newproxy) +end + +do --- pre-5.2 base rawlen -compat5.2 + assert(not rawlen) +end + +do --- 5.2 base rawlen +compat5.2 + assert(rawlen) +end + +do --- math + check(math, "abs:acos:asin:atan:atan2:ceil:cos:cosh:deg:exp:floor:fmod:frexp:huge:ldexp:log:max:min:modf:pi:pow:rad:random:randomseed:sin:sinh:sqrt:tan:tanh", "log10:mod") +end + +do --- pre-5.2 math +lua<5.2 + assert(math.mod) + assert(math.log10) +end + +do --- 5.2 math +lua>=5.2 + assert(not math.mod) + assert(not math.log10) +end + +do --- string + check(string, "byte:char:dump:find:format:gmatch:gsub:len:lower:match:rep:reverse:sub:upper", "gfind") +end + +do --- pre-5.2 string +lua<5.2 + assert(string.gfind) +end + +do --- 5.2 string +lua>=5.2 + assert(not string.gfind) +end + +do --- pre-5.2 table +lua<5.2 + check(table, "concat:foreach:foreachi:getn:insert:maxn:remove:sort", "pack:unpack:setn:new") +end + +do --- 5.2 table +lua>=5.2 + check(table, "concat:insert:pack:remove:sort:unpack") +end + +do --- pre-5.2 table.pack -compat5.2 + assert(not table.pack) + assert(not table.unpack) +end + +do --- 5.2 table.pack +compat5.2 + assert(table.pack) + assert(table.unpack) +end + +do --- io + check(io, "close:flush:input:lines:open:output:popen:read:stderr:stdin:stdout:tmpfile:type:write") +end + +do --- io file + check(debug.getmetatable(io.stdin), "__gc:__index:__tostring:close:flush:lines:read:seek:setvbuf:write") +end + +do --- os + check(os, "clock:date:difftime:execute:exit:getenv:remove:rename:setlocale:time:tmpname") +end + +do --- debug + check(debug, "debug:gethook:getinfo:getlocal:getmetatable:getregistry:getupvalue:sethook:setlocal:setmetatable:setupvalue:traceback", "getfenv:setfenv:upvalueid:upvaluejoin:getuservalue:setuservalue") +end + +-- TODO: Check versional differences in debug library + +do --- package + check(package, "config:cpath:loaded:loadlib:path:preload", "searchpath:loaders:searchers:seeall") +end + +do --- pre-5.2 package +lua<5.2 + assert(package.loaders) + assert(not package.searchers) + assert(package.seeall) +end + +do --- 5.2 package +lua>=5.2 + assert(not package.loaders) + assert(package.searchers) + assert(not package.seeall) +end + +do --- package.loaders + check(package.loaders or package.searchers, "1:2:3:4") +end + +do --- package.loaded + local loaded = {} + for k, v in pairs(package.loaded) do + if type(k) ~= "string" or (k:sub(1, 7) ~= "common." and k:sub(1, 4) ~= "jit.") then + loaded[k] = v + end + end + check(loaded, "_G:coroutine:debug:io:math:os:package:string:table", "bit:bit32:common:ffi:jit:table.new") +end + +do --- bit +bit + check(bit, "arshift:band:bnot:bor:bswap:bxor:lshift:rol:ror:rshift:tobit:tohex") +end + +do --- ffi +ffi + check(require"ffi", "C:abi:alignof:arch:cast:cdef:copy:errno:fill:gc:istype:load:metatype:new:offsetof:os:sizeof:string:typeinfo:typeof") +end diff --git a/test/lib/coroutine/index b/test/lib/coroutine/index new file mode 100644 index 0000000000..4c9e320b48 --- /dev/null +++ b/test/lib/coroutine/index @@ -0,0 +1 @@ +yield.lua diff --git a/test/lib/coroutine/yield.lua b/test/lib/coroutine/yield.lua new file mode 100644 index 0000000000..4cc98de9c5 --- /dev/null +++ b/test/lib/coroutine/yield.lua @@ -0,0 +1,109 @@ +local create = coroutine.create +local wrap = coroutine.wrap +local resume = coroutine.resume +local yield = coroutine.yield + +do --- Stack overflow on return (create) + wrap(function() + local co = create(function() + yield(string.byte(string.rep(" ", 100), 1, 100)) + end) + assert(select('#', resume(co)) == 101) + end)() +end + +do --- Stack overflow on return (wrap) + wrap(function() + local f = wrap(function() + yield(string.byte(string.rep(" ", 100), 1, 100)) + end) + assert(select('#', f()) == 100) + end)() +end + +do --- cogen + local function cogen(x) + return wrap(function(n) repeat x = x+n; n = yield(x) until false end), + wrap(function(n) repeat x = x*n; n = yield(x) until false end) + end + + local a,b=cogen(3) + local c,d=cogen(5) + assert(d(b(c(a(d(b(c(a(1)))))))) == 168428160) +end + +do --- cofunc +luajit + local function verify(what, expect, ...) + local got = {...} + for i=1,100 do + if expect[i] ~= got[i] then + error("FAIL " .. what) + end + if expect[i] == nil then + break + end + end + end + + local function cofunc(...) + verify("call", { 1, "foo" }, ...) + verify("yield", { "bar" }, yield(2, "test")) + verify("pcall yield", { true, "again" }, pcall(yield, "from pcall")) + return "end" + end + + local co = create(cofunc) + verify("resume", { true, 2, "test" }, resume(co, 1, "foo")) + verify("resume pcall", { true, "from pcall" }, resume(co, "bar")) + verify("resume end", { true, "end" }, resume(co, "again")) +end + +do --- assorted +luajit + local function verify(expect, func, ...) + local co = create(func) + for i=1,100 do + local ok, res = resume(co, ...) + if not ok then + if expect[i] ~= nil then + error("too few results: ["..i.."] = "..tostring(expect[i]).." (got: "..tostring(res)..")") + end + break + end + if expect[i] ~= res then + error("bad result: ["..i.."] = "..tostring(res).." (should be: "..tostring(expect[i])..")") + end + end + end + + verify({ 42, 99 }, + function(x) pcall(yield, x) return 99 end, + 42) + + verify({ 42, 99 }, + function(x) pcall(function(y) yield(y) end, x) return 99 end, + 42) + + verify({ 42, 99 }, + function(x) xpcall(yield, debug.traceback, x) return 99 end, + 42) + + verify({ 45, 44, 43, 42, 99 }, + function(x, y) + for i in + function(o, k) + yield(o+k) + if k ~= 0 then return k-1 end + end,x,y do + end + return 99 + end, + 42, 3) + + verify({ 84, 99 }, + function(x) + local o = setmetatable({ x }, + {__add = function(a, b) yield(a[1]+b[1]) return 99 end }) + return o+o + end, + 42) +end diff --git a/test/ffi/ffi_arith_ptr.lua b/test/lib/ffi/ffi_arith_ptr.lua similarity index 100% rename from test/ffi/ffi_arith_ptr.lua rename to test/lib/ffi/ffi_arith_ptr.lua diff --git a/test/ffi/ffi_bit64.lua b/test/lib/ffi/ffi_bit64.lua similarity index 100% rename from test/ffi/ffi_bit64.lua rename to test/lib/ffi/ffi_bit64.lua diff --git a/test/ffi/ffi_bitfield.lua b/test/lib/ffi/ffi_bitfield.lua similarity index 100% rename from test/ffi/ffi_bitfield.lua rename to test/lib/ffi/ffi_bitfield.lua diff --git a/test/ffi/ffi_call.lua b/test/lib/ffi/ffi_call.lua similarity index 100% rename from test/ffi/ffi_call.lua rename to test/lib/ffi/ffi_call.lua diff --git a/test/ffi/ffi_callback.lua b/test/lib/ffi/ffi_callback.lua similarity index 100% rename from test/ffi/ffi_callback.lua rename to test/lib/ffi/ffi_callback.lua diff --git a/test/ffi/ffi_const.lua b/test/lib/ffi/ffi_const.lua similarity index 100% rename from test/ffi/ffi_const.lua rename to test/lib/ffi/ffi_const.lua diff --git a/test/ffi/ffi_convert.lua b/test/lib/ffi/ffi_convert.lua similarity index 100% rename from test/ffi/ffi_convert.lua rename to test/lib/ffi/ffi_convert.lua diff --git a/test/ffi/ffi_copy_fill.lua b/test/lib/ffi/ffi_copy_fill.lua similarity index 100% rename from test/ffi/ffi_copy_fill.lua rename to test/lib/ffi/ffi_copy_fill.lua diff --git a/test/ffi/ffi_enum.lua b/test/lib/ffi/ffi_enum.lua similarity index 100% rename from test/ffi/ffi_enum.lua rename to test/lib/ffi/ffi_enum.lua diff --git a/test/ffi/ffi_err.lua b/test/lib/ffi/ffi_err.lua similarity index 100% rename from test/ffi/ffi_err.lua rename to test/lib/ffi/ffi_err.lua diff --git a/test/ffi/ffi_gcstep_recursive.lua b/test/lib/ffi/ffi_gcstep_recursive.lua similarity index 100% rename from test/ffi/ffi_gcstep_recursive.lua rename to test/lib/ffi/ffi_gcstep_recursive.lua diff --git a/test/ffi/ffi_istype.lua b/test/lib/ffi/ffi_istype.lua similarity index 100% rename from test/ffi/ffi_istype.lua rename to test/lib/ffi/ffi_istype.lua diff --git a/test/ffi/ffi_jit_arith.lua b/test/lib/ffi/ffi_jit_arith.lua similarity index 100% rename from test/ffi/ffi_jit_arith.lua rename to test/lib/ffi/ffi_jit_arith.lua diff --git a/test/ffi/ffi_jit_array.lua b/test/lib/ffi/ffi_jit_array.lua similarity index 100% rename from test/ffi/ffi_jit_array.lua rename to test/lib/ffi/ffi_jit_array.lua diff --git a/test/ffi/ffi_jit_call.lua b/test/lib/ffi/ffi_jit_call.lua similarity index 100% rename from test/ffi/ffi_jit_call.lua rename to test/lib/ffi/ffi_jit_call.lua diff --git a/test/ffi/ffi_jit_complex.lua b/test/lib/ffi/ffi_jit_complex.lua similarity index 100% rename from test/ffi/ffi_jit_complex.lua rename to test/lib/ffi/ffi_jit_complex.lua diff --git a/test/ffi/ffi_jit_conv.lua b/test/lib/ffi/ffi_jit_conv.lua similarity index 100% rename from test/ffi/ffi_jit_conv.lua rename to test/lib/ffi/ffi_jit_conv.lua diff --git a/test/ffi/ffi_jit_misc.lua b/test/lib/ffi/ffi_jit_misc.lua similarity index 100% rename from test/ffi/ffi_jit_misc.lua rename to test/lib/ffi/ffi_jit_misc.lua diff --git a/test/ffi/ffi_jit_struct.lua b/test/lib/ffi/ffi_jit_struct.lua similarity index 100% rename from test/ffi/ffi_jit_struct.lua rename to test/lib/ffi/ffi_jit_struct.lua diff --git a/test/ffi/ffi_lex_number.lua b/test/lib/ffi/ffi_lex_number.lua similarity index 100% rename from test/ffi/ffi_lex_number.lua rename to test/lib/ffi/ffi_lex_number.lua diff --git a/test/ffi/ffi_meta_tostring.lua b/test/lib/ffi/ffi_meta_tostring.lua similarity index 100% rename from test/ffi/ffi_meta_tostring.lua rename to test/lib/ffi/ffi_meta_tostring.lua diff --git a/test/ffi/ffi_metatype.lua b/test/lib/ffi/ffi_metatype.lua similarity index 100% rename from test/ffi/ffi_metatype.lua rename to test/lib/ffi/ffi_metatype.lua diff --git a/test/ffi/ffi_new.lua b/test/lib/ffi/ffi_new.lua similarity index 100% rename from test/ffi/ffi_new.lua rename to test/lib/ffi/ffi_new.lua diff --git a/test/ffi/ffi_nosink.lua b/test/lib/ffi/ffi_nosink.lua similarity index 100% rename from test/ffi/ffi_nosink.lua rename to test/lib/ffi/ffi_nosink.lua diff --git a/test/ffi/ffi_parse_array.lua b/test/lib/ffi/ffi_parse_array.lua similarity index 100% rename from test/ffi/ffi_parse_array.lua rename to test/lib/ffi/ffi_parse_array.lua diff --git a/test/ffi/ffi_parse_basic.lua b/test/lib/ffi/ffi_parse_basic.lua similarity index 100% rename from test/ffi/ffi_parse_basic.lua rename to test/lib/ffi/ffi_parse_basic.lua diff --git a/test/ffi/ffi_parse_cdef.lua b/test/lib/ffi/ffi_parse_cdef.lua similarity index 100% rename from test/ffi/ffi_parse_cdef.lua rename to test/lib/ffi/ffi_parse_cdef.lua diff --git a/test/ffi/ffi_parse_struct.lua b/test/lib/ffi/ffi_parse_struct.lua similarity index 100% rename from test/ffi/ffi_parse_struct.lua rename to test/lib/ffi/ffi_parse_struct.lua diff --git a/test/ffi/ffi_redir.lua b/test/lib/ffi/ffi_redir.lua similarity index 100% rename from test/ffi/ffi_redir.lua rename to test/lib/ffi/ffi_redir.lua diff --git a/test/ffi/ffi_sink.lua b/test/lib/ffi/ffi_sink.lua similarity index 100% rename from test/ffi/ffi_sink.lua rename to test/lib/ffi/ffi_sink.lua diff --git a/test/ffi/ffi_tabov.lua b/test/lib/ffi/ffi_tabov.lua similarity index 100% rename from test/ffi/ffi_tabov.lua rename to test/lib/ffi/ffi_tabov.lua diff --git a/test/ffi/ffi_type_punning.lua b/test/lib/ffi/ffi_type_punning.lua similarity index 100% rename from test/ffi/ffi_type_punning.lua rename to test/lib/ffi/ffi_type_punning.lua diff --git a/test/lib/index b/test/lib/index new file mode 100644 index 0000000000..c15ccfd6a6 --- /dev/null +++ b/test/lib/index @@ -0,0 +1,8 @@ +base +bit.lua +bit +math +string +table +coroutine + +contents.lua \ No newline at end of file diff --git a/test/lib/math/abs.lua b/test/lib/math/abs.lua new file mode 100644 index 0000000000..660a6cc37d --- /dev/null +++ b/test/lib/math/abs.lua @@ -0,0 +1,16 @@ +local abs = math.abs +local expect_error = require"common.expect_error" + +do --- smoke + assert(abs(-1.5) == 1.5) + assert(abs("-1.5") == 1.5) +end + +do --- argcheck + expect_error(function() abs() end, + "bad argument #1 to 'abs' (number expected, got no value)") + expect_error(function() abs(false) end, + "bad argument #1 to 'abs' (number expected, got boolean)") + expect_error(function() abs("a") end, + "bad argument #1 to 'abs' (number expected, got string)") +end diff --git a/test/lib/math/constants.lua b/test/lib/math/constants.lua new file mode 100644 index 0000000000..5f8a4f79d8 --- /dev/null +++ b/test/lib/math/constants.lua @@ -0,0 +1,8 @@ +do --- pi + assert(math.pi == 3.141592653589793) +end + +do --- huge + assert(math.huge > 0) + assert(1/math.huge == 0) +end diff --git a/test/lib/math/index b/test/lib/math/index new file mode 100644 index 0000000000..f17d52e780 --- /dev/null +++ b/test/lib/math/index @@ -0,0 +1,3 @@ +abs.lua +constants.lua +random.lua diff --git a/test/lib/math/random.lua b/test/lib/math/random.lua new file mode 100644 index 0000000000..4ee799b2e2 --- /dev/null +++ b/test/lib/math/random.lua @@ -0,0 +1,47 @@ +local random = math.random +local MAX_SEED = 10 + +do --- generally uniform in range [0, 1) + local N = 100 + local min, max = math.min, math.max + for j=1,MAX_SEED do + math.randomseed(j) + local lo, hi, sum = math.huge, -math.huge, 0 + for i=1,N do + local x = random() + assert(0 <= x and x < 1) + sum = sum + x + lo = min(lo, x) + hi = max(hi, x) + end + assert(lo*N < 15 and (1-hi)*N < 15) + assert(sum > N*0.45 and sum < N*0.55) + end +end + +do --- all in range [1, 10] + math.randomseed(1) + local counts = setmetatable({}, {__index = function() return 0 end}) + for i = 1, 100 do + local n = random(10) + counts[n] = counts[n] + 1 + end + for i = 1, 10 do + assert(counts[i]) + counts[i] = nil + end + assert(not next(counts)) +end + +do --- all in range [-3, 11] + math.randomseed(1) + local seen = setmetatable({}, {__index = function() return false end}) + for i = 1, 120 do + seen[random(-3, 11)] = true + end + for i = -3, 11 do + assert(seen[i]) + seen[i] = nil + end + assert(not next(seen)) +end diff --git a/test/misc/string_byte.lua b/test/lib/string/byte.lua similarity index 76% rename from test/misc/string_byte.lua rename to test/lib/string/byte.lua index cd565ecb48..21b1231737 100644 --- a/test/misc/string_byte.lua +++ b/test/lib/string/byte.lua @@ -1,90 +1,92 @@ - -local band, bor = bit.band, bit.bor -local byte = string.byte - --- Fixed slice [i,i+k] or overflow -do - local s = "abcdefg" - local x,y,z - for j=100,107 do - for i=1,j do x,y,z = byte("abcdefg", band(i, 7), band(i+2, 7)) end - local a,b,c = byte("abcdefg", band(j, 7), band(j+2, 7)) - assert(x == a and y == b and z == c) - end - for j=100,107 do - for i=1,j do x,y,z = byte(s, band(i, 7), band(i+2, 7)) end - local a,b,c = byte(s, band(j, 7), band(j+2, 7)) - assert(x == a and y == b and z == c) - end -end - --- Positive slice [i,len] or overflow -do - local s = "abc" - local x,y,z - for j=100,107 do - for i=1,j do x,y,z = byte("abc", band(i, 7), -1) end - local a,b,c = byte("abc", band(j, 7), -1) - assert(x == a and y == b and z == c) - end - for j=100,107 do - for i=1,j do x,y,z = byte(s, band(i, 7), -1) end - local a,b,c = byte(s, band(j, 7), -1) - assert(x == a and y == b and z == c) - end -end - --- Negative slice [-i,len] or underflow -do - local s = "abc" - local x,y,z - for j=-100,-107,-1 do - for i=-1,j,-1 do x,y,z = byte("abc", bor(i, -8), -1) end - local a,b,c = byte("abc", bor(j, -8), -1) - assert(x == a and y == b and z == c) - end - for j=-100,-107,-1 do - for i=-1,j,-1 do x,y,z = byte(s, bor(i, -8), -1) end - local a,b,c = byte(s, bor(j, -8), -1) - assert(x == a and y == b and z == c) - end -end - --- Positive slice [1,i] or overflow -do - local s = "abc" - local x,y,z - for j=100,107 do - for i=1,j do x,y,z = byte("abc", 1, band(i, 7)) end - local a,b,c = byte("abc", 1, band(j, 7)) - assert(x == a and y == b and z == c) - end - for j=100,107 do - for i=1,j do x,y,z = byte(s, 1, band(i, 7)) end - local a,b,c = byte(s, 1, band(j, 7)) - assert(x == a and y == b and z == c) - end -end - --- Negative slice [1,-i] or underflow -do - local s = "abc" - local x,y,z - for j=-100,-107,-1 do - for i=-1,j,-1 do x,y,z = byte("abc", 1, bor(i, -8)) end - local a,b,c = byte("abc", 1, bor(j, -8)) - assert(x == a and y == b and z == c) - end - for j=-100,-107,-1 do - for i=-1,j,-1 do x,y,z = byte(s, 1, bor(i, -8)) end - local a,b,c = byte(s, 1, bor(j, -8)) - assert(x == a and y == b and z == c) - end -end - --- Check for slot stack overflow -do - local s = string.rep("x", 500) - for i=1,100 do byte(s, 1, 500) end -end - +local band, bor = bit and bit.band, bit and bit.bor +local byte = string.byte + +do --- simple + local a, b = ("foo"):byte(1) + assert(type(a) == "number") + assert(b == nil) + local c, d = ("foo"):byte(2, 3) + assert(type(c) == "number") + assert(c == d) + assert(c ~= a) +end + +do --- Fixed slice [i,i+k] or overflow +bit + local s = "abcdefg" + local x,y,z + for j=100,107 do + for i=1,j do x,y,z = byte("abcdefg", band(i, 7), band(i+2, 7)) end + local a,b,c = byte("abcdefg", band(j, 7), band(j+2, 7)) + assert(x == a and y == b and z == c) + end + for j=100,107 do + for i=1,j do x,y,z = byte(s, band(i, 7), band(i+2, 7)) end + local a,b,c = byte(s, band(j, 7), band(j+2, 7)) + assert(x == a and y == b and z == c) + end +end + +do --- Positive slice [i,len] or overflow +bit + local s = "abc" + local x,y,z + for j=100,107 do + for i=1,j do x,y,z = byte("abc", band(i, 7), -1) end + local a,b,c = byte("abc", band(j, 7), -1) + assert(x == a and y == b and z == c) + end + for j=100,107 do + for i=1,j do x,y,z = byte(s, band(i, 7), -1) end + local a,b,c = byte(s, band(j, 7), -1) + assert(x == a and y == b and z == c) + end +end + +do --- Negative slice [-i,len] or underflow +bit + local s = "abc" + local x,y,z + for j=-100,-107,-1 do + for i=-1,j,-1 do x,y,z = byte("abc", bor(i, -8), -1) end + local a,b,c = byte("abc", bor(j, -8), -1) + assert(x == a and y == b and z == c) + end + for j=-100,-107,-1 do + for i=-1,j,-1 do x,y,z = byte(s, bor(i, -8), -1) end + local a,b,c = byte(s, bor(j, -8), -1) + assert(x == a and y == b and z == c) + end +end + +do --- Positive slice [1,i] or overflow +bit + local s = "abc" + local x,y,z + for j=100,107 do + for i=1,j do x,y,z = byte("abc", 1, band(i, 7)) end + local a,b,c = byte("abc", 1, band(j, 7)) + assert(x == a and y == b and z == c) + end + for j=100,107 do + for i=1,j do x,y,z = byte(s, 1, band(i, 7)) end + local a,b,c = byte(s, 1, band(j, 7)) + assert(x == a and y == b and z == c) + end +end + +do --- Negative slice [1,-i] or underflow +bit + local s = "abc" + local x,y,z + for j=-100,-107,-1 do + for i=-1,j,-1 do x,y,z = byte("abc", 1, bor(i, -8)) end + local a,b,c = byte("abc", 1, bor(j, -8)) + assert(x == a and y == b and z == c) + end + for j=-100,-107,-1 do + for i=-1,j,-1 do x,y,z = byte(s, 1, bor(i, -8)) end + local a,b,c = byte(s, 1, bor(j, -8)) + assert(x == a and y == b and z == c) + end +end + +do --- Check for slot stack overflow + local s = string.rep("x", 500) + for i=1,100 do byte(s, 1, 500) end +end diff --git a/test/lib/string/char.lua b/test/lib/string/char.lua new file mode 100644 index 0000000000..dff92e3202 --- /dev/null +++ b/test/lib/string/char.lua @@ -0,0 +1,29 @@ +local char = string.char + +do --- jit one char + local y + for i=1,100 do y = char(65) end + assert(y == "A") + local x = 97 + for i=1,100 do y = char(x) end + assert(y == "a") + x = "98" + for i=1,100 do y = char(x) end + assert(y == "b") + for i=1,100 do y = char(32+i) end + assert(y == "\132") +end + +do --- jit until out of bounds + local y + assert(not pcall(function() + for i=1,200 do y = char(100+i) end + end)) + assert(y == "\255") +end + +do --- jit five chars + local y + for i=1,100 do y = char(65, 66, i, 67, 68) end + assert(y == "ABdCD") +end diff --git a/test/misc/string_dump.lua b/test/lib/string/dump.lua similarity index 83% rename from test/misc/string_dump.lua rename to test/lib/string/dump.lua index a255b8a895..075e37e5d6 100644 --- a/test/misc/string_dump.lua +++ b/test/lib/string/dump.lua @@ -1,31 +1,29 @@ - --- Must unpatch modified bytecode with ILOOP/JLOOP etc. -do - local function foo() - local t = {} - for i=1,100 do t[i] = i end - for a,b in ipairs(t) do end - local m = 0 - while m < 100 do m = m + 1 end - end - - local d1 = string.dump(foo) - foo() - assert(string.dump(foo) == d1) - jit.off(foo) - foo() - assert(string.dump(foo) == d1) - local d2 = string.dump(loadstring(d1, ""), true) - local d3 = string.dump(assert(loadstring(d2, "")), true) - assert(d2 == d3) - assert(loadstring(string.dump(assert(loadstring(d2, ""))))) -end - -do - local function f1() return -0x80000000 end - local function f2() return 0.971234567 end - assert(f1() == -0x80000000) - assert(loadstring(string.dump(f1), "")() == -0x80000000) - assert(f2() == 0.971234567) - assert(loadstring(string.dump(f2), "")() == 0.971234567) -end +do --- Must unpatch modified bytecode with ILOOP/JLOOP etc. + local function foo() + local t = {} + for i=1,100 do t[i] = i end + for a,b in ipairs(t) do end + local m = 0 + while m < 100 do m = m + 1 end + end + + local d1 = string.dump(foo) + foo() + assert(string.dump(foo) == d1) + if jit then jit.off(foo) end + foo() + assert(string.dump(foo) == d1) + local d2 = string.dump(loadstring(d1, ""), true) + local d3 = string.dump(assert(loadstring(d2, "")), true) + assert(d2 == d3) + assert(loadstring(string.dump(assert(loadstring(d2, ""))))) +end + +do --- roundtrip constants + local function f1() return -0x80000000 end + local function f2() return 0.971234567 end + assert(f1() == -0x80000000) + assert(loadstring(string.dump(f1), "")() == -0x80000000) + assert(f2() == 0.971234567) + assert(loadstring(string.dump(f2), "")() == 0.971234567) +end diff --git a/test/lib/string/format/index b/test/lib/string/format/index new file mode 100644 index 0000000000..682f3b8ebe --- /dev/null +++ b/test/lib/string/format/index @@ -0,0 +1 @@ +num.lua diff --git a/test/lib/string/format/num.lua b/test/lib/string/format/num.lua new file mode 100644 index 0000000000..279f3c2304 --- /dev/null +++ b/test/lib/string/format/num.lua @@ -0,0 +1,184 @@ +local format, type, tonumber = string.format, type, tonumber + +local function check(input, fstr, output, inputN) + local actual = format(fstr, inputN or tonumber(input)) + if actual == output then return end + local t = type(output) + if t == "string" then + if output:find"[[%]]" then + local s, e = actual:find((output:gsub("%.", "%%."))) + if s == 1 and e == #actual then return end + end + end + error(format("expected string.format(%q, %q) == %q, but got %q", + fstr, input, output, actual)) +end + +do --- small denormals at low precision +hexfloat !lex + assert(("%.9e"):format(0x1.0E00D1p-1050) == "8.742456525e-317") + assert(("%.13e"):format(0x1.1Cp-1068) == "3.5078660854729e-322") +end + +do --- smoke + local cases = { + -- input, %e, %f, %g + { "0", "0.000000e+00", "0.000000", "0"}, + { "1", "1.000000e+00", "1.000000", "1"}, + { "0.5", "5.000000e-01", "0.500000", "0.5"}, + { "123", "1.230000e+02", "123.000000", "123"}, + {"0.0078125", "7.812500e-03", "0.00781[23]", "0.0078125"}, + { "1.109375", "1.109375e+00", "1.109375", "1.1093[78]"}, + { "0.999995", "9.999950e-01", "0.999995", "0.999995"}, + {"0.9999995", "9.999995e-01", "1.000000", "1"}, + { "99999.95", "9.999995e+04", "99999.950000", "99999.9"}, + {"999999.95", "9.999999e+05", "999999.950000", "1e+06"}, + {"123456978", "1.234570e+08", "123456978.000000", "1.23457e+08"}, + { "33.3", "3.330000e+01", "33.300000", "33.3"}, + } + for _, t in ipairs(cases) do + local n = tonumber(t[1]) + check(t[1], "%e", t[2], n) + check(t[1], "%f", t[3], n) + check(t[1], "%g", t[4], n) + end +end + +do --- easily enumerable cases of %a, %A +hexfloat + for i = 1, 16 do + check(1+(i-1)/16, "%.1a", "0x1.".. ("0123456789abcdef"):sub(i,i) .."p+0") + check(16+(i-1), "%.1A", "0X1.".. ("0123456789ABCDEF"):sub(i,i) .."P+4") + end +end + +do --- easily enumerable cases of %f + for i = 1, 16 do + check(("1"):rep(i), "%#2.0f", ("1"):rep(i)..".") + end +end + +do --- easily enumerable cases of %e + local z, f, c = ("0"):byte(), math.floor, string.char + for p = 0, 14 do + local head = "1.".. ("0"):rep(p) + local fmt = "%#.".. c(z + f(p / 10), z + (p % 10)) .."e" + for i = 1, 99 do + local istr = c(z + f(i / 10), z + (i % 10)) + check("1e-".. istr, fmt, head .."e-".. istr) + check("1e+".. istr, fmt, head .."e+".. istr) + end + for i = 100, 308 do + local istr = c(z + f(i / 100), z + f(i / 10) % 10, z + (i % 10)) + check("1e-".. istr, fmt, head .."e-".. istr) + check("1e+".. istr, fmt, head .."e+".. istr) + end + end +end + +do --- assorted + check("0", "%.14g", "0") + check("1e-310", "%.0g", "1e-310") + check("1e8", "%010.5g", "000001e+08") + check("1e8", "% -10.5g", " 1e+08 ") + check("4e123", "%+#.0e", "+4.e+123") + check("1e49", "%.0f", "9999999999999999464902769475481793196872414789632") + check("1e50", "%.0f", "100000000000000007629769841091887003294964970946560") + check("1e50", "%.35g", "1.00000000000000007629769841091887e+50") + check("1e50", "%40.35g", " 1.00000000000000007629769841091887e+50") + check("1e50", "%#+40.34g", "+1.000000000000000076297698410918870e+50") + check("1e50", "%-40.35g", "1.00000000000000007629769841091887e+50 ") + check("0.5", "%.0f", "[01]") + check("0.25", "%.1f", "0.[23]") + check("999999.95", "%.7g", "999999.9") + check("999.99995", "%.7g", "1000") + check("6.9039613742e-314", "%.3e", "6.904e-314") + + check(1e-323, "%.99g", "9.8813129168249308835313758573644274473011960522864".. + "9528851171365001351014540417503730599672723271985e-324") + check(1e308, "%.99f", "1000000000000000010979063629440455417404923096773118".. + "463368106829031575854049114915371633289784946888990612496697211725".. + "156115902837431400883283070091981460460312716645029330271856974896".. + "995885590433383844661650011784268976262129451776280911957867074581".. + "22783970171784415105291802893207873272974885715430223118336.000000".. + "000000000000000000000000000000000000000000000000000000000000000000".. + "000000000000000000000000000") + check("1", "%.99f", "1."..("0"):rep(99)) + check("5", "%99g", (" "):rep(98).."5") + check("5", "%099g", ("0"):rep(98).."5") + check("5", "%-99g", "5".. (" "):rep(98)) + check("5", "%0-99g", "5".. (" "):rep(98)) + + check((2^53-1)*2^971, "%e", "1.797693e+308") + check((2^53-1)*2^971, "%.0e", "2e+308") + + check("0", "%.14g", "0") + + check("0.15", "%.1f", "0.1") + check("0.45", "%.1f", "0.5") + check("0.55", "%.1f", "0.6") + check("0.85", "%.1f", "0.8") +end + +do --- assorted %a +luajit>=2.1 + check((2^53-1)*2^971, "%a", "0x1.fffffffffffffp+1023") + check((2^53-1)*2^971, "%.0a", "0x2p+1023") + check("0", "%a", "0x0p+0") + check("1.53173828125", "%1.8a", "0x1.88200000p+0") + check("1.53173828125", "%8.1a", "0x1.9p+0") -- libc on OSX gets this wrong + check("1.5317", "%8.1a", "0x1.9p+0") + check("1.53", "%8.1a", "0x1.8p+0") + check("-1.5", "%11.2a", " -0x1.80p+0") + check("3.14159265358", "%a", "0x1.921fb5443d6f4p+1") + check("3.14159265358", "%A", "0X1.921FB5443D6F4P+1") +end + +do --- Cases where inprecision can easily affect rounding + check("2.28579528986935e-262", "%.14g", "2.2857952898694e-262") + check("4.86009084710405e+243", "%.14g", "4.8600908471041e+243") + check("6.28108398359615e+258", "%.14g", "6.2810839835962e+258") + check("4.29911075733405e+250", "%.14g", "4.2991107573341e+250") + check("8.5068432121065e+244", "% .13g", " 8.506843212107e+244") + check("8.1919113161235899e+233", "%.40g", "8.191911316123589934222156598061".. + "949037266e+233") + check("7.1022381748280933e+272", "%.40g", "7.102238174828093393858336547341".. + "897013319e+272") + check("5.8018368514358030e+261", "%.67g", "5.801836851435803025936253580958".. + "042578728799220447411839451694590343e+261") + check("7.9225909325493999e-199", "%.26g", "7.922590932549399935196127e-199") + check("2.4976643533685383e-153", "%.43g", "2.497664353368538321643894302495".. + "469512999562e-153") + check("9.796500001282779e+222", "%.4g", "9.797e+222") + check("7.7169235e-227", "%e", "7.716923e-227") + check("7.7169235000000044e-227", "%e", "7.716924e-227") + check("5.3996444915000004e+87", "%.9e", "5.399644492e+87") + check("2.03037546395e-49", "%.10e", "2.0303754640e-49") + check("3.38759425741500027e+65", "%.11e", "3.38759425742e+65") + check("1.013960434983135e-66", "%.0e", "1e-66") + check("1.32423054454835e-204", "%.13e", "1.3242305445484e-204") + check("5.9005060812045502e+100", "%.13e", "5.9005060812046e+100") +end + +do --- ExploringBinary.com/print-precision-of-dyadic-fractions-varies-by-language/ + check(5404319552844595/2^53, "%.53g", "0.5999999999999999777955395074968691".. + "9152736663818359375") + check(2^-1074, "%.99e", "4.940656458412465441765687928682213723650598026143".. + "247644255856825006755072702087518652998363616359924e-324") + check(1-2^-53, "%1.53f", "0.99999999999999988897769753748434595763683319091".. + "796875") +end + +do --- ExploringBinary.com/incorrect-floating-point-to-decimal-conversions/ + check("1.0551955", "%.7g", "1.055195") + check("8.330400913327153", "%.15f", "8.330400913327153") + check("9194.25055964485", "%.14g", "9194.2505596449") + check("816.2665949149578", "%.16g", "816.2665949149578") + check("95.47149571505499", "%.16g", "95.47149571505498") +end + +do --- big f +luajit>=2.1 + check("9.522938016739373", "%.15F", "9.522938016739372") +end + +do --- RandomASCII.wordpress.com/2013/02/07/ + check("6.10351562e-05", "%1.8e", "6.1035156[23]e%-05") + check("4.3037358649999999e-15", "%1.8e", "4.30373586e-15") +end diff --git a/test/lib/string/index b/test/lib/string/index new file mode 100644 index 0000000000..a51f80651c --- /dev/null +++ b/test/lib/string/index @@ -0,0 +1,9 @@ +metatable.lua +byte.lua +char.lua +dump.lua +format +len.lua +lower_upper.lua +rep.lua +sub.lua diff --git a/test/lib/string/len.lua b/test/lib/string/len.lua new file mode 100644 index 0000000000..8d9c7e57a6 --- /dev/null +++ b/test/lib/string/len.lua @@ -0,0 +1,14 @@ +local len = string.len +local expect_error = require"common.expect_error" + +do --- smoke + assert(len("abc") == 3) + assert(len(123) == 3) +end + +do --- argcheck + expect_error(function() len() end, + "bad argument #1 to 'len' (string expected, got nil)") + expect_error(function() len(false) end, + "bad argument #1 to 'len' (string expected, got boolean)") +end diff --git a/test/lib/string/lower_upper.lua b/test/lib/string/lower_upper.lua new file mode 100644 index 0000000000..52c5739706 --- /dev/null +++ b/test/lib/string/lower_upper.lua @@ -0,0 +1,16 @@ +do --- smoke + assert(("abc123DEF_<>"):lower() == "abc123def_<>") + assert(("abc123DEF_<>"):upper() == "ABC123DEF_<>") +end + +do --- repeated + local l = "the quick brown fox..." + local u = "THE QUICK BROWN FOX..." + local s = l + for i = 1, 75 do + s = s:upper() + assert(s == u) + s = s:lower() + assert(s == l) + end +end diff --git a/test/lib/string/metatable.lua b/test/lib/string/metatable.lua new file mode 100644 index 0000000000..9861ee7e3c --- /dev/null +++ b/test/lib/string/metatable.lua @@ -0,0 +1,3 @@ +do --- __index metamethod is string library + assert(debug.getmetatable("").__index == string) +end diff --git a/test/lib/string/rep.lua b/test/lib/string/rep.lua new file mode 100644 index 0000000000..d06b4ee4ed --- /dev/null +++ b/test/lib/string/rep.lua @@ -0,0 +1,13 @@ +do --- smoke + assert(("p"):rep(0) == "") + assert(("a"):rep(3) == "aaa") + assert(("x\0z"):rep(4) == "x\0zx\0zx\0zx\0z") +end + +do --- versus concat + local s = "" + for i = 1, 75 do + s = s .. "{}" + assert(s == ("{}"):rep(i)) + end +end diff --git a/test/lib/string/sub.lua b/test/lib/string/sub.lua new file mode 100644 index 0000000000..981f2924a0 --- /dev/null +++ b/test/lib/string/sub.lua @@ -0,0 +1,189 @@ +local band, bor = bit and bit.band, bit and bit.bor +local sub = string.sub +local expect_error = require"common.expect_error" + +do --- smoke + assert(sub("abc", 2) == "bc") + assert(sub(123, "2") == "23") +end + +do --- argcheck + expect_error(function() sub("abc", false) end, + "bad argument #2 to 'sub' (number expected, got boolean)") + expect_error(function() ("abc"):sub(false) end, + "bad argument #1 to 'sub' (number expected, got boolean)") +end + +do --- all bar substrings + local subs = { + {"b", "ba", "bar"}, + { "", "a", "ar"}, + { "", "", "r"} + } + for i = 1, 3 do + for j = 1, 3 do + assert(sub("bar", i, j) == subs[i][j]) + assert(sub("bar", -4+i, j) == subs[i][j]) + assert(sub("bar", i, -4+j) == subs[i][j]) + assert(sub("bar", -4+i, -4+j) == subs[i][j]) + end + end +end + +do --- Positive slice [i,len] or overflow +bit + local s = "abc" + local x + for j=100,107 do + for i=1,j do x = sub("abc", band(i, 7)) end + assert(x == sub("abc", band(j, 7))) + end + for j=100,107 do + for i=1,j do x = sub(s, band(i, 7)) end + assert(x == sub(s, band(j, 7))) + end +end + +do --- Negative slice [-i,len] or underflow +bit + local s = "abc" + local x + for j=-100,-107,-1 do + for i=-1,j,-1 do x = sub("abc", bor(i, -8)) end + assert(x == sub("abc", bor(j, -8))) + end + for j=-100,-107,-1 do + for i=-1,j,-1 do x = sub(s, bor(i, -8)) end + assert(x == sub(s, bor(j, -8))) + end +end + +do --- Positive slice [1,i] or overflow +bit + local s = "abc" + local x + for j=100,107 do + for i=1,j do x = sub("abc", 1, band(i, 7)) end + assert(x == sub("abc", 1, band(j, 7))) + end + for j=100,107 do + for i=1,j do x = sub(s, 1, band(i, 7)) end + assert(x == sub(s, 1, band(j, 7))) + end +end + +do --- Negative slice [1,-i] or underflow +bit + local s = "abc" + local x + for j=-100,-107,-1 do + for i=-1,j,-1 do x = sub("abc", 1, bor(i, -8)) end + assert(x == sub("abc", 1, bor(j, -8))) + end + for j=-100,-107,-1 do + for i=-1,j,-1 do x = sub(s, 1, bor(i, -8)) end + assert(x == sub(s, 1, bor(j, -8))) + end +end + +do --- jit sub 1 eq + local s = "abcde" + local x = 0 + for i=1,100 do + if sub(s, 1, 1) == "a" then x = x + 1 end + end + assert(x == 100) +end + +do --- jit sub 1 ne (contents) + local s = "abcde" + local x = 0 + for i=1,100 do + if sub(s, 1, 1) == "b" then x = x + 1 end + end + assert(x == 0) +end + +do --- jit sub 1 ne (rhs too long) + local s = "abcde" + local x = 0 + for i=1,100 do + if sub(s, 1, 1) == "ab" then x = x + 1 end + end + assert(x == 0) +end + +do --- jit sub 1,2 ne + local s = "abcde" + local x = 0 + for i=1,100 do + if sub(s, 1, 2) == "a" then x = x + 1 end + end + assert(x == 0) +end + +do --- jit sub 1,k eq + local s = "abcde" + local x = 0 + local k = 1 + for i=1,100 do + if sub(s, 1, k) == "a" then x = x + 1 end + end + assert(x == 100) +end + +do --- jit sub 1,k ne (contents) + local s = "abcde" + local x = 0 + local k = 1 + for i=1,100 do + if sub(s, 1, k) == "b" then x = x + 1 end + end + assert(x == 0) +end + +do --- jit sub 1,k ne (rhs too long) + local s = "abcde" + local x = 0 + local k = 1 + for i=1,100 do + if sub(s, 1, k) == "ab" then x = x + 1 end + end + assert(x == 0) +end + +do --- jit sub 1,2 eq + local s = "abcde" + local x = 0 + for i=1,100 do + if sub(s, 1, 2) == "ab" then x = x + 1 end + end + assert(x == 100) +end + +do --- jit sub 1,3 eq + local s = "abcde" + local x = 0 + for i=1,100 do + if sub(s, 1, 3) == "abc" then x = x + 1 end + end + assert(x == 100) +end + +do --- jit sub 1,4 eq + local s = "abcde" + local x = 0 + for i=1,100 do + if sub(s, 1, 4) == "abcd" then x = x + 1 end + end + assert(x == 100) +end + +do --- jit sub i,i + local t = {} + local line = string.rep("..XX", 100) + local i = 1 + local c = line:sub(i, i) + while c ~= "" and c ~= "Z" do + t[i] = c == "X" and "Y" or c + i = i + 1 + c = line:sub(i, i) + end + assert(table.concat(t) == string.rep("..YY", 100)) +end diff --git a/test/lib/table/concat.lua b/test/lib/table/concat.lua new file mode 100644 index 0000000000..514a883fc6 --- /dev/null +++ b/test/lib/table/concat.lua @@ -0,0 +1,55 @@ +local concat, assert, pcall = table.concat, assert, pcall + +do --- table.concat + local t = {a=1,b=2,c=3,d=4,e=5} + t[1] = 4 + t[3] = 6 + local ok, err = pcall(concat, t, "", 1, 3) + assert(not ok and err:match("index 2 ")) + local q = {} + for i=1,100 do q[i] = {9,8,7} end + q[90] = t + for i=1,100 do + assert(pcall(concat, q[i], "", 1, 3) == (i ~= 90)) + end + t[2] = 5 -- index 1 - 3 in hash part + q[91] = {} + q[92] = {9} + for i=1,100 do q[i] = concat(q[i], "x") end + assert(q[90] == "4x5x6") + assert(q[91] == "") + assert(q[92] == "9") + assert(q[93] == "9x8x7") +end + +do --- table.concat must inhibit CSE and DSE + local t = {1,2,3} + local y, z + for i=1,100 do + y = concat(t, "x", 1, 3) + t[2] = i + z = concat(t, "x", 1, 3) + end + assert(y == "1x99x3") + assert(z == "1x100x3") +end + +do --- table.concat must inhibit CSE and DSE 2 + local y + for i=1,100 do + local t = {1,2,3} + t[2] = 4 + y = concat(t, "x") + t[2] = 9 + end + assert(y == "1x4x3") +end + +do --- table.concat must inhibit CSE and DSE 3 + local t = {[0]={}, {}, {}, {}} + for i=1,30 do + for j=3,0,-1 do + t[j].x = t[j-1] + end + end +end diff --git a/test/lib/table/index b/test/lib/table/index new file mode 100644 index 0000000000..e400606b0d --- /dev/null +++ b/test/lib/table/index @@ -0,0 +1,6 @@ +concat.lua +insert.lua +new.lua +table.new +pack.lua +compat5.2 +remove.lua +sort.lua diff --git a/experimental/test/libs/table/insert.lua b/test/lib/table/insert.lua similarity index 87% rename from experimental/test/libs/table/insert.lua rename to test/lib/table/insert.lua index d4d617cc83..91d4dd8767 100644 --- a/experimental/test/libs/table/insert.lua +++ b/test/lib/table/insert.lua @@ -1,17 +1,14 @@ - local tinsert = table.insert local assert = assert ---- table.insert(t,i) -do +do --- table.insert(t,i) local t = {} for i=1,100 do t[i] = i end for i=1,100 do tinsert(t, i) end assert(#t == 200 and t[100] == 100 and t[200] == 100) end ---- table.insert(t,i,i) -do +do --- table.insert(t,i,i) local t = {} for i=1,200 do t[i] = i end for i=101,200 do tinsert(t, i, i) end diff --git a/experimental/test/libs/table/misc.lua b/test/lib/table/misc.lua similarity index 57% rename from experimental/test/libs/table/misc.lua rename to test/lib/table/misc.lua index ba6375172f..e0e2fc592f 100644 --- a/experimental/test/libs/table/misc.lua +++ b/test/lib/table/misc.lua @@ -1,4 +1,6 @@ --- ABC elim +-- TODO: Organise + +-- ABC elim -- +opt +abc do local s, t = {}, {} @@ -52,61 +54,5 @@ do t[6] == nil) end ---- table.concat -do - local t = {a=1,b=2,c=3,d=4,e=5} - t[1] = 4 - t[3] = 6 - local ok, err = pcall(table.concat, t, "", 1, 3) - assert(not ok and err:match("index 2 ")) - local q = {} - for i=1,100 do q[i] = {9,8,7} end - q[90] = t - for i=1,100 do - assert(pcall(table.concat, q[i], "", 1, 3) == (i ~= 90)) - end - t[2] = 5 -- index 1 - 3 in hash part - q[91] = {} - q[92] = {9} - for i=1,100 do q[i] = table.concat(q[i], "x") end - assert(q[90] == "4x5x6") - assert(q[91] == "") - assert(q[92] == "9") - assert(q[93] == "9x8x7") -end - ---- table.concat must inhibit CSE and DSE -do - local t = {1,2,3} - local y, z - for i=1,100 do - y = table.concat(t, "x", 1, 3) - t[2] = i - z = table.concat(t, "x", 1, 3) - end - assert(y == "1x99x3") - assert(z == "1x100x3") -end ---- table.concat must inhibit CSE and DSE 2 -do - local y - for i=1,100 do - local t = {1,2,3} - t[2] = 4 - y = table.concat(t, "x") - t[2] = 9 - end - assert(y == "1x4x3") -end - ---- table.concat must inhibit CSE and DSE 3 -do - local t = {[0]={}, {}, {}, {}} - for i=1,30 do - for j=3,0,-1 do - t[j].x = t[j-1] - end - end -end diff --git a/test/lib/table/new.lua b/test/lib/table/new.lua new file mode 100644 index 0000000000..8e422477cc --- /dev/null +++ b/test/lib/table/new.lua @@ -0,0 +1,11 @@ +local tnew = require"table.new" + +do --- table.new + local x, y + for i=1,100 do + x = tnew(100, 30) + assert(type(x) == "table") + if i == 90 then y = x end + end + assert(x ~= y) +end diff --git a/test/lib/table/pack.lua b/test/lib/table/pack.lua new file mode 100644 index 0000000000..b76e22fd51 --- /dev/null +++ b/test/lib/table/pack.lua @@ -0,0 +1,7 @@ +do --- empty + local t = table.pack() + assert(type(t) == "table") + assert(t.n == 0) + assert(t[0] == nil) + assert(t[1] == nil) +end diff --git a/experimental/test/libs/table/remove.lua b/test/lib/table/remove.lua similarity index 73% rename from experimental/test/libs/table/remove.lua rename to test/lib/table/remove.lua index 67a594b206..604f588ab5 100644 --- a/experimental/test/libs/table/remove.lua +++ b/test/lib/table/remove.lua @@ -1,28 +1,23 @@ - local tremove = table.remove local assert = assert ---- table.remove(t) removes correct entries -do +do --- table.remove(t) removes correct entries local t = {} for i=1,200 do t[i] = i end for i=1,100 do tremove(t) end assert(#t == 100 and t[100] == 100) end ---- table.remove(t) returns the removed entry -do +do --- table.remove(t) returns the removed entry local t = {} for i=1,200 do t[i] = i end for i=1,100 do assert(tremove(t) == 201-i) end assert(#t == 100 and t[100] == 100) end ---- table.remove(t, 1) removes and returns the first entry -do +do --- table.remove(t, 1) removes and returns the first entry local t = {} for i=1,200 do t[i] = i end for i=1,100 do assert(tremove(t, 1) == i) end assert(#t == 100 and t[100] == 200) end - diff --git a/test/lib/table/sort.lua b/test/lib/table/sort.lua new file mode 100644 index 0000000000..c95a895e10 --- /dev/null +++ b/test/lib/table/sort.lua @@ -0,0 +1,27 @@ +-- Really a test for lua_lessthan() +local N = 1000 + +do --- numbers + math.randomseed(42) + local t = {} + for i=1,N do t[i] = math.random(N) end + table.sort(t) + for i=2,N do assert(t[i-1] <= t[i]) end +end + +do --- strings + math.randomseed(42) + local t = {} + for i=1,N do t[i] = math.random(1, N/10).."" end + table.sort(t) + for i=2,N do assert(t[i-1] <= t[i]) end +end + +do --- tables + math.randomseed(42) + local mt = { __lt = function(a,b) return a[1] < b[1] end } + local t = {} + for i=1,N do t[i] = setmetatable({ math.random(N) }, mt) end + table.sort(t) + for i=2,N do assert(t[i-1][1] <= t[i][1]) end +end diff --git a/test/misc/ack.lua b/test/misc/ack.lua deleted file mode 100644 index bcc1316e1e..0000000000 --- a/test/misc/ack.lua +++ /dev/null @@ -1,12 +0,0 @@ -local function Ack(m, n) - if m == 0 then return n+1 end - if n == 0 then return Ack(m-1, 1) end - return Ack(m-1, (Ack(m, n-1))) -- The parentheses are deliberate. -end - -if arg and arg[1] then - local N = tonumber(arg and arg[1]) - io.write("Ack(3,", N ,"): ", Ack(3,N), "\n") -else - assert(Ack(3,5) == 253) -end diff --git a/test/misc/ack_notail.lua b/test/misc/ack_notail.lua deleted file mode 100644 index e14c003afd..0000000000 --- a/test/misc/ack_notail.lua +++ /dev/null @@ -1,12 +0,0 @@ -local function Ack(m, n) - if m == 0 then return n+1 end - if n == 0 then return (Ack(m-1, 1)) end - return (Ack(m-1, (Ack(m, n-1)))) -- The parentheses are deliberate. -end - -if arg and arg[1] then - local N = tonumber(arg and arg[1]) - io.write("Ack(3,", N ,"): ", Ack(3,N), "\n") -else - assert(Ack(3,5) == 253) -end diff --git a/test/misc/argcheck.lua b/test/misc/argcheck.lua deleted file mode 100644 index de3cb70ad7..0000000000 --- a/test/misc/argcheck.lua +++ /dev/null @@ -1,40 +0,0 @@ - -local function check(f, msg) - local ok, err = pcall(f) - if ok then error("error check unexpectedly succeeded", 2) end - if type(err) ~= "string" then - error("error check failed with "..tostring(err), 2) - end - local line, err2 = string.match(err, ":(%d*): (.*)") - if err2 ~= msg then error("error check failed with "..err, 2) end -end - -assert(math.abs(-1.5) == 1.5) -assert(math.abs("-1.5") == 1.5) - -check(function() math.abs() end, - "bad argument #1 to 'abs' (number expected, got no value)") -check(function() math.abs(false) end, - "bad argument #1 to 'abs' (number expected, got boolean)") -check(function() math.abs("a") end, - "bad argument #1 to 'abs' (number expected, got string)") -string.abs = math.abs -check(function() ("a"):abs() end, - "calling 'abs' on bad self (number expected, got string)") - -assert(string.len("abc") == 3) -assert(string.len(123) == 3) - -check(function() string.len() end, - "bad argument #1 to 'len' (string expected, got nil)") -check(function() string.len(false) end, - "bad argument #1 to 'len' (string expected, got boolean)") - -assert(string.sub("abc", 2) == "bc") -assert(string.sub(123, "2") == "23") - -check(function() string.sub("abc", false) end, - "bad argument #2 to 'sub' (number expected, got boolean)") -check(function() ("abc"):sub(false) end, - "bad argument #1 to 'sub' (number expected, got boolean)") - diff --git a/test/misc/assign_tset_prevnil.lua b/test/misc/assign_tset_prevnil.lua deleted file mode 100644 index 202153c612..0000000000 --- a/test/misc/assign_tset_prevnil.lua +++ /dev/null @@ -1,11 +0,0 @@ -a, b, c = 0, 1 -assert(a == 0) -assert(b == 1) -assert(c == nil) -a, b = a+1, b+1, a+b -assert(a == 1) -assert(b == 2) -a, b, c = 0 -assert(a == 0) -assert(b == nil) -assert(c == nil) diff --git a/test/misc/assign_tset_tmp.lua b/test/misc/assign_tset_tmp.lua deleted file mode 100644 index 909d5aadaa..0000000000 --- a/test/misc/assign_tset_tmp.lua +++ /dev/null @@ -1,5 +0,0 @@ -a = {} -i = 3 -i, a[i] = i+1, 20 -assert(i == 4) -assert(a[3] == 20) diff --git a/test/misc/bit_op.lua b/test/misc/bit_op.lua deleted file mode 100644 index 4bab240c03..0000000000 --- a/test/misc/bit_op.lua +++ /dev/null @@ -1,90 +0,0 @@ --- Test cases for bit operations library. Public domain. - -local bit = require"bit" - -local vb = { - 0, 1, -1, 2, -2, 0x12345678, 0x87654321, - 0x33333333, 0x77777777, 0x55aa55aa, 0xaa55aa55, - 0x7fffffff, 0x80000000, 0xffffffff -} - -local function cksum(name, s, r) - local z = 0 - for i=1,#s do z = (z + string.byte(s, i)*i) % 2147483629 end - if z ~= r then - error("bit."..name.." test failed (got "..z..", expected "..r..")", 0) - end -end - -local function check_unop(name, r) - local f = bit[name] - local s = "" - if pcall(f) or pcall(f, "z") or pcall(f, true) then - error("bit."..name.." fails to detect argument errors", 0) - end - for _,x in ipairs(vb) do s = s..","..tostring(f(x)) end - cksum(name, s, r) -end - -local function check_binop(name, r) - local f = bit[name] - local s = "" - if pcall(f) or pcall(f, "z") or pcall(f, true) then - error("bit."..name.." fails to detect argument errors", 0) - end - for _,x in ipairs(vb) do - for _,y in ipairs(vb) do s = s..","..tostring(f(x, y)) end - end - cksum(name, s, r) -end - -local function check_binop_range(name, r, yb, ye) - local f = bit[name] - local s = "" - if pcall(f) or pcall(f, "z") or pcall(f, true) or pcall(f, 1, true) then - error("bit."..name.." fails to detect argument errors", 0) - end - for _,x in ipairs(vb) do - for y=yb,ye do s = s..","..tostring(f(x, y)) end - end - cksum(name, s, r) -end - -local function check_shift(name, r) - check_binop_range(name, r, 0, 31) -end - --- Minimal sanity checks. -assert(0x7fffffff == 2147483647, "broken hex literals") -assert(0xffffffff == -1 or 0xffffffff == 2^32-1, "broken hex literals") -assert(tostring(-1) == "-1", "broken tostring()") -assert(tostring(0xffffffff) == "-1" or tostring(0xffffffff) == "4294967295", "broken tostring()") - --- Basic argument processing. -assert(bit.tobit(1) == 1) -assert(bit.band(1) == 1) -assert(bit.bxor(1,2) == 3) -assert(bit.bor(1,2,4,8,16,32,64,128) == 255) - --- Apply operations to test vectors and compare checksums. -check_unop("tobit", 277312) -check_unop("bnot", 287870) -check_unop("bswap", 307611) - -check_binop("band", 41206764) -check_binop("bor", 51253663) -check_binop("bxor", 79322427) - -check_shift("lshift", 325260344) -check_shift("rshift", 139061800) -check_shift("arshift", 111364720) -check_shift("rol", 302401155) -check_shift("ror", 302316761) - -check_binop_range("tohex", 47880306, -8, 8) - --- Don't propagate TOBIT narrowing across two conversions. -local tobit = bit.tobit -local k = 0x8000000000003 -for i=1,100 do assert(tobit(k % (2^32)) == 3) end - diff --git a/test/misc/compare.lua b/test/misc/compare.lua deleted file mode 100644 index 96a52d90d2..0000000000 --- a/test/misc/compare.lua +++ /dev/null @@ -1,232 +0,0 @@ -local function lt(x, y) - if x < y then return true else return false end -end - -local function le(x, y) - if x <= y then return true else return false end -end - -local function gt(x, y) - if x > y then return true else return false end -end - -local function ge(x, y) - if x >= y then return true else return false end -end - -local function eq(x, y) - if x == y then return true else return false end -end - -local function ne(x, y) - if x ~= y then return true else return false end -end - - -local function ltx1(x) - if x < 1 then return true else return false end -end - -local function lex1(x) - if x <= 1 then return true else return false end -end - -local function gtx1(x) - if x > 1 then return true else return false end -end - -local function gex1(x) - if x >= 1 then return true else return false end -end - -local function eqx1(x) - if x == 1 then return true else return false end -end - -local function nex1(x) - if x ~= 1 then return true else return false end -end - - -local function lt1x(x) - if 1 < x then return true else return false end -end - -local function le1x(x) - if 1 <= x then return true else return false end -end - -local function gt1x(x) - if 1 > x then return true else return false end -end - -local function ge1x(x) - if 1 >= x then return true else return false end -end - -local function eq1x(x) - if 1 == x then return true else return false end -end - -local function ne1x(x) - if 1 ~= x then return true else return false end -end - - -local function check(a, b) - if a ~= b then - error("check failed with "..tostring(a).." ~= "..tostring(b), 2) - end -end - -local x,y = 1,2 - -check(xy, false) -check(x>=y, false) -check(x==y, false) -check(x~=y, true) - -check(1y, false) -check(1>=y, false) -check(1==y, false) -check(1~=y, true) - -check(x<2, true) -check(x<=2, true) -check(x>2, false) -check(x>=2, false) -check(x==2, false) -check(x~=2, true) - -check(lt(x,y), true) -check(le(x,y), true) -check(gt(x,y), false) -check(ge(x,y), false) -check(eq(y,x), false) -check(ne(y,x), true) - -local x,y = 2,1 - -check(xy, true) -check(x>=y, true) -check(x==y, false) -check(x~=y, true) - -check(2y, true) -check(2>=y, true) -check(2==y, false) -check(2~=y, true) - -check(x<1, false) -check(x<=1, false) -check(x>1, true) -check(x>=1, true) -check(x==1, false) -check(x~=1, true) - -check(lt(x,y), false) -check(le(x,y), false) -check(gt(x,y), true) -check(ge(x,y), true) -check(eq(y,x), false) -check(ne(y,x), true) - -local x,y = 1,1 - -check(xy, false) -check(x>=y, true) -check(x==y, true) -check(x~=y, false) - -check(1y, false) -check(1>=y, true) -check(1==y, true) -check(1~=y, false) - -check(x<1, false) -check(x<=1, true) -check(x>1, false) -check(x>=1, true) -check(x==1, true) -check(x~=1, false) - -check(lt(x,y), false) -check(le(x,y), true) -check(gt(x,y), false) -check(ge(x,y), true) -check(eq(y,x), true) -check(ne(y,x), false) - - -check(lt1x(2), true) -check(le1x(2), true) -check(gt1x(2), false) -check(ge1x(2), false) -check(eq1x(2), false) -check(ne1x(2), true) - -check(ltx1(2), false) -check(lex1(2), false) -check(gtx1(2), true) -check(gex1(2), true) -check(eqx1(2), false) -check(nex1(2), true) - - -check(lt1x(1), false) -check(le1x(1), true) -check(gt1x(1), false) -check(ge1x(1), true) -check(eq1x(1), true) -check(ne1x(1), false) - -check(ltx1(1), false) -check(lex1(1), true) -check(gtx1(1), false) -check(gex1(1), true) -check(eqx1(1), true) -check(nex1(1), false) - - -check(lt1x(0), false) -check(le1x(0), false) -check(gt1x(0), true) -check(ge1x(0), true) -check(eq1x(0), false) -check(ne1x(0), true) - -check(ltx1(0), true) -check(lex1(0), true) -check(gtx1(0), false) -check(gex1(0), false) -check(eqx1(0), false) -check(nex1(0), true) - -do - assert(not pcall(function() - local a, b = 10.5, nil - return a < b - end)) -end - -do - for i=1,100 do - assert(bit.tobit(i+0x7fffffff) < 0) - end - for i=1,100 do - assert(bit.tobit(i+0x7fffffff) <= 0) - end -end - diff --git a/test/misc/exit_growstack.lua b/test/misc/exit_growstack.lua deleted file mode 100644 index 548b55565a..0000000000 --- a/test/misc/exit_growstack.lua +++ /dev/null @@ -1,24 +0,0 @@ -local function f(i) - local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; - local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; - local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; - if i==90 then return end -- Exit needs to grow stack before slot fill. -end -for j=1,5 do - collectgarbage() -- Shrink stack. - for i=1,100 do f(i) end -end - -local function g(i) - if i==90 then return end -- Exit needs to grow stack after slot fill. - do return end - do - local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; - local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; - local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; - end -end -for j=1,5 do - collectgarbage() -- Shrink stack. - for i=1,100 do g(i) end -end diff --git a/test/misc/exit_jfuncf.lua b/test/misc/exit_jfuncf.lua deleted file mode 100644 index 7e452ef44f..0000000000 --- a/test/misc/exit_jfuncf.lua +++ /dev/null @@ -1,30 +0,0 @@ - -local assert = assert - -local function rec(a, b, c, d, e, f) - assert(f == a+1) - if b == 0 then return 7 end - do local x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, x32, x33, x34, x35, x36, x37, x38, x39, x40, x41, x42, x43, x44, x45, x46, x47, x48, x49, x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x60, x61, x62, x63, x64, x65, x66, x67, x68, x69, x70, x71, x72, x73, x74, x75, x76, x77, x78, x79, x80, x81, x82, x83, x84, x85, x86, x87, x88, x89, x90, x91, x92, x93, x94, x95, x96, x97, x98, x99, x100 end - return rec(a, b-1, c, d, e, f)+1 -end - --- Compile recursive function. -assert(rec(42, 200, 1, 2, 3, 43) == 207) - -local function trec() - return rec(42, 0, 1, 2, 3, 43) -end - --- Compile function jumping to JFUNCF. -for i=1,200 do - gcinfo() - assert(trec() == 7) -end - --- Shrink stack. -for j=1,10 do collectgarbage() end - --- Cause an exit due to stack growth with PC pointing to JFUNCF. --- Needs to load RD with nres+1 and not with the bytecode RD. -assert(trec() == 7) - diff --git a/test/misc/fac.lua b/test/misc/fac.lua deleted file mode 100644 index 86dc427070..0000000000 --- a/test/misc/fac.lua +++ /dev/null @@ -1,13 +0,0 @@ -local function fac(n) - local x = 1 - for i=2,n do - x = x * i - end - return x -end - -if arg and arg[1] then - print(fac(tonumber(arg[1]))) -else - assert(fac(10) == 3628800) -end diff --git a/test/misc/fastfib.lua b/test/misc/fastfib.lua deleted file mode 100644 index 80394bdd08..0000000000 --- a/test/misc/fastfib.lua +++ /dev/null @@ -1,26 +0,0 @@ - -local function ffib(n) - if n <= 2 then return n,1 end - if n % 2 == 1 then - local a,b = ffib((n-1)/2) - local aa = a*a - return aa+a*(b+b), aa+b*b - else - local a,b = ffib(n/2-1) - local ab = a+b - return ab*ab+a*a, (ab+b)*a - end -end - -local function fib(n) - return (ffib(n)) -end - -if arg and arg[1] then - local n = tonumber(arg and arg[1]) or 10 - io.write(string.format("Fib(%d): %.0f\n", n, fib(n))) -else - assert(fib(40) == 165580141) - assert(fib(39) == 102334155) - assert(fib(77) == 8944394323791464) -end diff --git a/test/misc/fib.lua b/test/misc/fib.lua deleted file mode 100644 index 74eb046496..0000000000 --- a/test/misc/fib.lua +++ /dev/null @@ -1,11 +0,0 @@ -local function fib(n) - if n < 2 then return 1 end - return fib(n-2) + fib(n-1) -end - -if arg and arg[1] then - local n = tonumber(arg[1]) or 10 - io.write(string.format("Fib(%d): %d\n", n, fib(n))) -else - assert(fib(27) == 317811) -end diff --git a/test/misc/fuse.lua b/test/misc/fuse.lua deleted file mode 100644 index c4e077c87d..0000000000 --- a/test/misc/fuse.lua +++ /dev/null @@ -1,8 +0,0 @@ - --- Don't fuse i+101 on x64. --- Except if i is sign-extended to 64 bit or addressing is limited to 32 bit. -do - local t = {} - for i=-100,-1 do t[i+101] = 1 end -end - diff --git a/test/misc/fwd_hrefk_rollback.lua b/test/misc/fwd_hrefk_rollback.lua deleted file mode 100644 index 1c4d597923..0000000000 --- a/test/misc/fwd_hrefk_rollback.lua +++ /dev/null @@ -1,34 +0,0 @@ - --- https://github.com/LuaJIT/LuaJIT/issues/124 - -local function foo(a, b, f) - return f and (a.f0 < b.f1 and - b.f0 < a.f1 and - a.f2 < b.f3 and - b.f2 < a.f3) -end - -local function bar(f0, f1, f2, f3, X, f) - for _, v in ipairs(X) do - local b = {} - b.f0 = 0 - b.f2 = v - b.f1 = b.f0 + 1 - b.f3 = b.f2 + 1 - - if foo({f0 = f0, f1 = f1, f2 = f2, f3 = f3}, b, f) then - return false - end - end - - return true -end - -local X = { 0, 1, 0, 0 } - -for i = 1, 20 do - assert(bar(0, 1, 2, 3, X, true)) -end - -assert(not bar(0, 1, 1, 2, X, true)) - diff --git a/test/misc/libfuncs.lua b/test/misc/libfuncs.lua deleted file mode 100644 index d0cf42ff07..0000000000 --- a/test/misc/libfuncs.lua +++ /dev/null @@ -1,63 +0,0 @@ - -local function check(m, expected) - local t = {} - for k in pairs(m) do t[#t+1] = tostring(k) end - table.sort(t) - local got = table.concat(t, ":") - if got ~= expected then - error("got: \""..got.."\"\nexpected: \""..expected.."\"", 2) - end -end - -local bit = bit -_G.bit = nil -_G.jit = nil -table.setn = nil -package.searchpath = nil - -if os.getenv("LUA52") then - check(_G, "_G:_VERSION:arg:assert:collectgarbage:coroutine:debug:dofile:error:gcinfo:getfenv:getmetatable:io:ipairs:load:loadfile:loadstring:math:module:newproxy:next:os:package:pairs:pcall:print:rawequal:rawget:rawlen:rawset:require:select:setfenv:setmetatable:string:table:tonumber:tostring:type:unpack:xpcall") - check(math, "abs:acos:asin:atan:atan2:ceil:cos:cosh:deg:exp:floor:fmod:frexp:huge:ldexp:log:log10:max:min:modf:pi:pow:rad:random:randomseed:sin:sinh:sqrt:tan:tanh") - check(string, "byte:char:dump:find:format:gmatch:gsub:len:lower:match:rep:reverse:sub:upper") - check(table, "concat:foreach:foreachi:getn:insert:maxn:pack:remove:sort:unpack") -else - check(_G, "_G:_VERSION:arg:assert:collectgarbage:coroutine:debug:dofile:error:gcinfo:getfenv:getmetatable:io:ipairs:load:loadfile:loadstring:math:module:newproxy:next:os:package:pairs:pcall:print:rawequal:rawget:rawset:require:select:setfenv:setmetatable:string:table:tonumber:tostring:type:unpack:xpcall") - check(math, "abs:acos:asin:atan:atan2:ceil:cos:cosh:deg:exp:floor:fmod:frexp:huge:ldexp:log:log10:max:min:mod:modf:pi:pow:rad:random:randomseed:sin:sinh:sqrt:tan:tanh") - check(string, "byte:char:dump:find:format:gfind:gmatch:gsub:len:lower:match:rep:reverse:sub:upper") - check(table, "concat:foreach:foreachi:getn:insert:maxn:remove:sort") -end - -check(io, "close:flush:input:lines:open:output:popen:read:stderr:stdin:stdout:tmpfile:type:write") - -check(debug.getmetatable(io.stdin), "__gc:__index:__tostring:close:flush:lines:read:seek:setvbuf:write") - -check(os, "clock:date:difftime:execute:exit:getenv:remove:rename:setlocale:time:tmpname") - -if os.getenv("LUA52") then - check(debug, "debug:getfenv:gethook:getinfo:getlocal:getmetatable:getregistry:getupvalue:getuservalue:setfenv:sethook:setlocal:setmetatable:setupvalue:setuservalue:traceback:upvalueid:upvaluejoin") -else - check(debug, "debug:getfenv:gethook:getinfo:getlocal:getmetatable:getregistry:getupvalue:setfenv:sethook:setlocal:setmetatable:setupvalue:traceback:upvalueid:upvaluejoin") -end - -check(package, "config:cpath:loaded:loaders:loadlib:path:preload:seeall") - -check(package.loaders, "1:2:3:4") -package.loaded.bit = nil -package.loaded.jit = nil -package.loaded["jit.util"] = nil -package.loaded["jit.opt"] = nil -check(package.loaded, "_G:coroutine:debug:io:math:os:package:string:table") - -if bit then - check(bit, "arshift:band:bnot:bor:bswap:bxor:lshift:rol:ror:rshift:tobit:tohex") -end - -local ok, ffi = pcall(require, "ffi") -if ok then - check(ffi, "C:abi:alignof:arch:cast:cdef:copy:errno:fill:gc:istype:load:metatype:new:offsetof:os:sizeof:string:typeinfo:typeof") -end - -assert(math.pi == 3.141592653589793) -assert(math.huge > 0 and 1/math.huge == 0) -assert(debug.getmetatable("").__index == string) - diff --git a/test/misc/math_random.lua b/test/misc/math_random.lua deleted file mode 100644 index 391ee2d901..0000000000 --- a/test/misc/math_random.lua +++ /dev/null @@ -1,21 +0,0 @@ - -local random = math.random -local randomseed = math.randomseed - -do - local N = 1000 - local min, max = math.min, math.max - for j=1,100 do - randomseed(j) - local lo, hi, sum = math.huge, -math.huge, 0 - for i=1,N do - local x = random() - sum = sum + x - lo = min(lo, x) - hi = max(hi, x) - end - assert(lo*N < 15 and (1-hi)*N < 15) - assert(sum > N*0.45 and sum < N*0.55) - end -end - diff --git a/test/misc/modulo.lua b/test/misc/modulo.lua deleted file mode 100644 index fefb02cf1e..0000000000 --- a/test/misc/modulo.lua +++ /dev/null @@ -1,42 +0,0 @@ - -for x=-5,5 do - for y=-5,5 do - if y ~= 0 then - assert(x%y == x-math.floor(x/y)*y) - end - end -end - -for x=-5,5,0.25 do - for y=-5,5,0.25 do - if y ~= 0 then - assert(x%y == x-math.floor(x/y)*y) - end - end -end - -do - local y = 0 - for x=-100,123 do - y = y + x%17 - end - assert(y == 1777) -end - -do - local y = 0 - for x=-100,123 do - if x ~= 0 then - y = y + 85%x - end - end - assert(y == 2059) -end - -do - local x = 1%0 - assert(x ~= x) - x = math.floor(0/0) - assert(x ~= x) -end - diff --git a/test/misc/nsieve.lua b/test/misc/nsieve.lua deleted file mode 100644 index 49dc1c8df7..0000000000 --- a/test/misc/nsieve.lua +++ /dev/null @@ -1,20 +0,0 @@ -local function nsieve(m, isPrime) - for i=2,m do isPrime[i] = true end - local count = 0 - for i=2,m do - if isPrime[i] then - for k=i+i,m,i do isPrime[k] = false end - count = count + 1 - end - end - return count -end - -local flags = {} -if arg and arg[1] then - local N = tonumber(arg and arg[1]) - io.write(string.format("Primes up to %8d %8d", N, nsieve(N,flags)), "\n") -else - assert(nsieve(100, flags) == 25) - assert(nsieve(12345, flags) == 1474) -end diff --git a/test/misc/parse_andor.lua b/test/misc/parse_andor.lua deleted file mode 100644 index 2c796cb375..0000000000 --- a/test/misc/parse_andor.lua +++ /dev/null @@ -1,58 +0,0 @@ -local x = ((1 or false) and true) or false -assert(x == true) - -local basiccases = { - {"nil", nil}, - {"false", false}, - {"true", true}, - {"10", 10}, -} - -local mem = {basiccases} -- for memoization - -local function allcases (n) - if mem[n] then return mem[n] end - local res = {} - -- include all smaller cases - for _, v in ipairs(allcases(n - 1)) do - res[#res + 1] = v - end - for i = 1, n - 1 do - for _, v1 in ipairs(allcases(i)) do - for _, v2 in ipairs(allcases(n - i)) do - res[#res + 1] = { - "(" .. v1[1] .. " and " .. v2[1] .. ")", - v1[2] and v2[2] - } - res[#res + 1] = { - "(" .. v1[1] .. " or " .. v2[1] .. ")", - v1[2] or v2[2] - } - end - end - end - mem[n] = res -- memoize - return res -end - -for _, v in pairs(allcases(4)) do - local res = loadstring("return " .. v[1])() - if res ~= v[2] then - error(string.format("bad conditional eval\n%s\nexpected: %s\ngot: %s", - v[1], tostring(v[2]), tostring(res))) - end -end - -do - -- 0001 KSHORT 1 2 - -- 0002 ISGE 0 1 - -- 0003 JMP 1 => 0006 - -- 0004 KSHORT 1 1 - -- 0005 JMP 1 => 0013 - -- ^^^ must be 2 - -- fix in jmp_patchtestreg - local function fib(n) return (n < 2) and 1 or fib(n-1)+fib(n-2) end - assert(fib(5) == 8) - assert(fib(10) == 89) -end - diff --git a/test/misc/recsum.lua b/test/misc/recsum.lua deleted file mode 100644 index a25336d1c3..0000000000 --- a/test/misc/recsum.lua +++ /dev/null @@ -1,11 +0,0 @@ - -do - local function sum(n) - if n == 1 then return 1 end - return n + sum(n-1) - end - for i=1,tonumber(arg and arg[1]) or 100 do - assert(sum(100) == 5050) - end -end - diff --git a/test/misc/recsump.lua b/test/misc/recsump.lua deleted file mode 100644 index 2285018180..0000000000 --- a/test/misc/recsump.lua +++ /dev/null @@ -1,11 +0,0 @@ - -do - local abs = math.abs - local function sum(n) - if n == 1 then return 1 end - return abs(n + sum(n-1)) - end - for i=1,tonumber(arg and arg[1]) or 100 do - assert(sum(100) == 5050) - end -end diff --git a/test/misc/self.lua b/test/misc/self.lua deleted file mode 100644 index afb95ce041..0000000000 --- a/test/misc/self.lua +++ /dev/null @@ -1,18 +0,0 @@ -local t={} - -function t:set(x) - self.a=x -end - -function t:get() - return self.a -end - -t:set("foo") -assert(t:get() == "foo") -assert(t.a == "foo") - -t:set(42) -assert(t:get() == 42) -assert(t.a == 42) - diff --git a/test/misc/snap_gcexit.lua b/test/misc/snap_gcexit.lua deleted file mode 100644 index 37fce65ae4..0000000000 --- a/test/misc/snap_gcexit.lua +++ /dev/null @@ -1,16 +0,0 @@ - -do - local x = 0 - local t - for i=1,1000 do - if i >= 100 then - -- causes an exit for atomic phase - -- must not merge snapshot #0 with comparison since it has the wrong PC - if i < 150 then x=x+1 end - t = {i} - end - end - assert(x == 50) - assert(t[1] == 1000) -end - diff --git a/test/misc/snap_top.lua b/test/misc/snap_top.lua deleted file mode 100644 index a717a15989..0000000000 --- a/test/misc/snap_top.lua +++ /dev/null @@ -1,16 +0,0 @@ - -do - function randomtable(entries, depth) - if depth == 0 then - return tostring(math.random(2)) -- snapshot between return and CALLMT - end - local t = {} - for k=1,entries do - t[k] = randomtable(entries, depth-1) - end - return t - end - - local t = randomtable(10, 2) -end - diff --git a/test/misc/snap_top2.lua b/test/misc/snap_top2.lua deleted file mode 100644 index 4504dc3e23..0000000000 --- a/test/misc/snap_top2.lua +++ /dev/null @@ -1,15 +0,0 @@ - -local function f() - gcinfo() - local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ - local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ - local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ - local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ - local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ - local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ -end - -for i=1,100 do - f() - if i % 3 == 0 then collectgarbage() end -end diff --git a/test/misc/sort.lua b/test/misc/sort.lua deleted file mode 100644 index 4b2e40129e..0000000000 --- a/test/misc/sort.lua +++ /dev/null @@ -1,23 +0,0 @@ --- Really a test for lua_lessthan() - -local N = 1000 - -math.randomseed(42) -local t = {} -for i=1,N do t[i] = math.random(N) end -table.sort(t) -for i=2,N do assert(t[i-1] <= t[i]) end - -math.randomseed(42) -local t = {} -for i=1,N do t[i] = math.random(N).."" end -table.sort(t) -for i=2,N do assert(t[i-1] <= t[i]) end - -math.randomseed(42) -local mt = { __lt = function(a,b) return a[1] < b[1] end } -local t = {} -for i=1,N do t[i] = setmetatable({ math.random(N) }, mt) end -table.sort(t) -for i=2,N do assert(t[i-1][1] <= t[i][1]) end - diff --git a/test/misc/string_char.lua b/test/misc/string_char.lua deleted file mode 100644 index 3920c3a4c2..0000000000 --- a/test/misc/string_char.lua +++ /dev/null @@ -1,28 +0,0 @@ - -do - local y - for i=1,100 do y = string.char(65) end - assert(y == "A") - local x = 97 - for i=1,100 do y = string.char(x) end - assert(y == "a") - x = "98" - for i=1,100 do y = string.char(x) end - assert(y == "b") - for i=1,100 do y = string.char(32+i) end - assert(y == "\132") -end - -do - local y - assert(not pcall(function() - for i=1,200 do y = string.char(100+i) end - end)) - assert(y == "\255") -end - -do - local y - for i=1,100 do y = string.char(65, 66, i, 67, 68) end - assert(y == "ABdCD") -end diff --git a/test/misc/string_sub.lua b/test/misc/string_sub.lua deleted file mode 100644 index 2cdfac766a..0000000000 --- a/test/misc/string_sub.lua +++ /dev/null @@ -1,60 +0,0 @@ - -local band, bor = bit.band, bit.bor -local sub = string.sub - --- Positive slice [i,len] or overflow -do - local s = "abc" - local x - for j=100,107 do - for i=1,j do x = sub("abc", band(i, 7)) end - assert(x == sub("abc", band(j, 7))) - end - for j=100,107 do - for i=1,j do x = sub(s, band(i, 7)) end - assert(x == sub(s, band(j, 7))) - end -end - --- Negative slice [-i,len] or underflow -do - local s = "abc" - local x - for j=-100,-107,-1 do - for i=-1,j,-1 do x = sub("abc", bor(i, -8)) end - assert(x == sub("abc", bor(j, -8))) - end - for j=-100,-107,-1 do - for i=-1,j,-1 do x = sub(s, bor(i, -8)) end - assert(x == sub(s, bor(j, -8))) - end -end - --- Positive slice [1,i] or overflow -do - local s = "abc" - local x - for j=100,107 do - for i=1,j do x = sub("abc", 1, band(i, 7)) end - assert(x == sub("abc", 1, band(j, 7))) - end - for j=100,107 do - for i=1,j do x = sub(s, 1, band(i, 7)) end - assert(x == sub(s, 1, band(j, 7))) - end -end - --- Negative slice [1,-i] or underflow -do - local s = "abc" - local x - for j=-100,-107,-1 do - for i=-1,j,-1 do x = sub("abc", 1, bor(i, -8)) end - assert(x == sub("abc", 1, bor(j, -8))) - end - for j=-100,-107,-1 do - for i=-1,j,-1 do x = sub(s, 1, bor(i, -8)) end - assert(x == sub(s, 1, bor(j, -8))) - end -end - diff --git a/test/misc/string_sub_opt.lua b/test/misc/string_sub_opt.lua deleted file mode 100644 index 235767aff8..0000000000 --- a/test/misc/string_sub_opt.lua +++ /dev/null @@ -1,109 +0,0 @@ - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 1) == "a" then x = x + 1 end - end - assert(x == 100) -end - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 1) == "b" then x = x + 1 end - end - assert(x == 0) -end - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 1) == "ab" then x = x + 1 end - end - assert(x == 0) -end - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 2) == "a" then x = x + 1 end - end - assert(x == 0) -end - -do - local s = "abcde" - local x = 0 - local k = 1 - for i=1,100 do - if string.sub(s, 1, k) == "a" then x = x + 1 end - end - assert(x == 100) -end - -do - local s = "abcde" - local x = 0 - local k = 1 - for i=1,100 do - if string.sub(s, 1, k) == "b" then x = x + 1 end - end - assert(x == 0) -end - -do - local s = "abcde" - local x = 0 - local k = 1 - for i=1,100 do - if string.sub(s, 1, k) == "ab" then x = x + 1 end - end - assert(x == 0) -end - ----- - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 2) == "ab" then x = x + 1 end - end - assert(x == 100) -end - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 3) == "abc" then x = x + 1 end - end - assert(x == 100) -end - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 4) == "abcd" then x = x + 1 end - end - assert(x == 100) -end - -do - local t = {} - local line = string.rep("..XX", 100) - local i = 1 - local c = line:sub(i, i) - while c ~= "" and c ~= "Z" do - t[i] = c == "X" and "Y" or c - i = i + 1 - c = line:sub(i, i) - end - assert(table.concat(t) == string.rep("..YY", 100)) -end - diff --git a/test/misc/tak.lua b/test/misc/tak.lua deleted file mode 100644 index a67478350c..0000000000 --- a/test/misc/tak.lua +++ /dev/null @@ -1,12 +0,0 @@ - -local function tak(x, y, z) - if y >= x then return z end - return tak(tak(x-1, y, z), tak(y-1, z, x), (tak(z-1, x, y))) -end - -if arg and arg[1] then - local N = tonumber(arg and arg[1]) or 7 - print(tak(3*N, 2*N, N)) -else - assert(tak(21, 14, 7) == 14) -end diff --git a/test/misc/dse_array.lua b/test/opt/dse/array.lua similarity index 59% rename from test/misc/dse_array.lua rename to test/opt/dse/array.lua index af1725fe20..867a7372c7 100644 --- a/test/misc/dse_array.lua +++ b/test/opt/dse/array.lua @@ -1,200 +1,197 @@ - -local assert = assert - --- Same value ---------------------------------------------------------------- - --- 1. Store with same ref and same value. --- 2nd store eliminated. All stores in loop eliminated. -do - local t = { 1, 2 } - for i=1,100 do - t[1] = 11 - assert(t[1] == 11) - t[1] = 11 - assert(t[1] == 11) - end - assert(t[1] == 11) -end - --- 2. Store with different tab, same idx and same value. --- All stores in loop eliminated. -do - local t1 = { 1, 2 } - local t2 = { 1, 2 } - for i=1,100 do - t1[1] = 11 - assert(t1[1] == 11) - t2[1] = 11 - assert(t2[1] == 11) - end - assert(t1[1] == 11) - assert(t2[1] == 11) -end - --- 3. Store with same tab, different const idx and same value. --- All stores in loop eliminated. Also disambiguated. -do - local t = { 1, 2 } - for i=1,100 do - t[1] = 11 - assert(t[1] == 11) - t[2] = 11 - assert(t[2] == 11) - end - assert(t[1] == 11) - assert(t[2] == 11) -end - --- 4. Store with different tab, different const idx and same value. --- All stores in loop eliminated. Also disambiguated. -do - local t1 = { 1, 2 } - local t2 = { 1, 2 } - for i=1,100 do - t1[1] = 11 - assert(t1[1] == 11) - t2[2] = 11 - assert(t2[2] == 11) - end - assert(t1[1] == 11) - assert(t2[2] == 11) -end - --- 5. Store with different tab, different non-const idx and same value. --- All stores in loop eliminated. Not disambiguated (but not needed). -do - local t1 = { 1, 2 } - local t2 = { 1, 2 } - local k = 1 - for i=1,100 do - t1[k] = 11 - assert(t1[k] == 11) - t2[2] = 11 - assert(t2[2] == 11) - end - assert(t1[1] == 11) - assert(t2[2] == 11) -end - --- 6. Store with same ref, same value and aliased loads. --- 2nd store eliminated. Not disambiguated (but not needed). -do - local t1 = { 1, 2 } - local t2 = t1 - for i=1,100 do - t1[1] = 11 - assert(t2[1] == 11) - t1[1] = 11 - assert(t2[1] == 11) - end - assert(t1[1] == 11) -end - --- Different value ----------------------------------------------------------- - --- 7. Store with same ref and different value. --- 1st store eliminated. All stores in loop eliminated. -do - local t = { 1, 2 } - for i=1,100 do - assert(true) - t[1] = 11 - assert(t[1] == 11) - t[1] = 22 - assert(t[1] == 22) - end - assert(t[1] == 22) -end - --- 8. Store with different tab, same idx and different value. --- Cannot eliminate any stores (would need dynamic disambiguation). -do - local t1 = { 1, 2 } - local t2 = { 1, 2 } - for i=1,100 do - assert(true) - t1[1] = 11 - assert(t1[1] == 11) - t2[1] = 22 - assert(t2[1] == 22) - end - assert(t1[1] == 11) - assert(t2[1] == 22) -end - --- 9. Store with same tab, different const idx and different value. --- Disambiguated. All stores in loop eliminated. -do - local t = { 1, 2 } - for i=1,100 do - assert(true) - t[1] = 11 - assert(t[1] == 11) - t[2] = 22 - assert(t[2] == 22) - end - assert(t[1] == 11) - assert(t[2] == 22) -end - --- 10. Store with different tab, different const idx and different value. --- Disambiguated. All stores in loop eliminated. -do - local t1 = { 1, 2 } - local t2 = { 1, 2 } - for i=1,100 do - assert(true) - t1[1] = 11 - assert(t1[1] == 11) - t2[2] = 22 - assert(t2[2] == 22) - end - assert(t1[1] == 11) - assert(t2[2] == 22) -end - --- 11. Store with different tab, different non-const idx and different value. --- Cannot eliminate any stores (would need dynamic disambiguation). -do - local t1 = { 1, 2 } - local t2 = { 1, 2 } - local k = 1 - for i=1,100 do - assert(true) - t1[k] = 11 - assert(t1[k] == 11) - t2[2] = 22 - assert(t2[2] == 22) - end - assert(t1[1] == 11) - assert(t2[2] == 22) -end - --- 12. Store with same ref, different value and aliased loads. --- Cannot eliminate any stores (would need dynamic disambiguation). -do - local t1 = { 1, 2 } - local t2 = t1 - for i=1,100 do - assert(true) - t1[1] = 11 - assert(t2[1] == 11) - t1[1] = 22 - assert(t2[1] == 22) - end - assert(t1[1] == 22) -end - --- CALLL must inhibit DSE. -do - local a,b - local t = {1,2} - for i=1,100 do - t[2]=nil - a=#t - t[2]=2 - b=#t - end - assert(a == 1 and b == 2) -end - +local assert = assert + +-- Same value ---------------------------------------------------------------- + +do --- 1 +-- Store with same ref and same value. +-- 2nd store eliminated. All stores in loop eliminated. + local t = { 1, 2 } + for i=1,100 do + t[1] = 11 + assert(t[1] == 11) + t[1] = 11 + assert(t[1] == 11) + end + assert(t[1] == 11) +end + +do --- 2 +-- Store with different tab, same idx and same value. +-- All stores in loop eliminated. + local t1 = { 1, 2 } + local t2 = { 1, 2 } + for i=1,100 do + t1[1] = 11 + assert(t1[1] == 11) + t2[1] = 11 + assert(t2[1] == 11) + end + assert(t1[1] == 11) + assert(t2[1] == 11) +end + +do --- 3 +-- Store with same tab, different const idx and same value. +-- All stores in loop eliminated. Also disambiguated. + local t = { 1, 2 } + for i=1,100 do + t[1] = 11 + assert(t[1] == 11) + t[2] = 11 + assert(t[2] == 11) + end + assert(t[1] == 11) + assert(t[2] == 11) +end + +do --- 4 +-- Store with different tab, different const idx and same value. +-- All stores in loop eliminated. Also disambiguated. + local t1 = { 1, 2 } + local t2 = { 1, 2 } + for i=1,100 do + t1[1] = 11 + assert(t1[1] == 11) + t2[2] = 11 + assert(t2[2] == 11) + end + assert(t1[1] == 11) + assert(t2[2] == 11) +end + +do --- 5 +-- Store with different tab, different non-const idx and same value. +-- All stores in loop eliminated. Not disambiguated (but not needed). + local t1 = { 1, 2 } + local t2 = { 1, 2 } + local k = 1 + for i=1,100 do + t1[k] = 11 + assert(t1[k] == 11) + t2[2] = 11 + assert(t2[2] == 11) + end + assert(t1[1] == 11) + assert(t2[2] == 11) +end + +do --- 6 +-- Store with same ref, same value and aliased loads. +-- 2nd store eliminated. Not disambiguated (but not needed). + local t1 = { 1, 2 } + local t2 = t1 + for i=1,100 do + t1[1] = 11 + assert(t2[1] == 11) + t1[1] = 11 + assert(t2[1] == 11) + end + assert(t1[1] == 11) +end + +-- Different value ----------------------------------------------------------- + +do --- 7 +-- Store with same ref and different value. +-- 1st store eliminated. All stores in loop eliminated. + local t = { 1, 2 } + for i=1,100 do + assert(true) + t[1] = 11 + assert(t[1] == 11) + t[1] = 22 + assert(t[1] == 22) + end + assert(t[1] == 22) +end + +do --- 8 +-- Store with different tab, same idx and different value. +-- Cannot eliminate any stores (would need dynamic disambiguation). + local t1 = { 1, 2 } + local t2 = { 1, 2 } + for i=1,100 do + assert(true) + t1[1] = 11 + assert(t1[1] == 11) + t2[1] = 22 + assert(t2[1] == 22) + end + assert(t1[1] == 11) + assert(t2[1] == 22) +end + +do --- 9 +-- Store with same tab, different const idx and different value. +-- Disambiguated. All stores in loop eliminated. + local t = { 1, 2 } + for i=1,100 do + assert(true) + t[1] = 11 + assert(t[1] == 11) + t[2] = 22 + assert(t[2] == 22) + end + assert(t[1] == 11) + assert(t[2] == 22) +end + +do --- 10 +-- Store with different tab, different const idx and different value. +-- Disambiguated. All stores in loop eliminated. + local t1 = { 1, 2 } + local t2 = { 1, 2 } + for i=1,100 do + assert(true) + t1[1] = 11 + assert(t1[1] == 11) + t2[2] = 22 + assert(t2[2] == 22) + end + assert(t1[1] == 11) + assert(t2[2] == 22) +end + +do --- 11 +-- Store with different tab, different non-const idx and different value. +-- Cannot eliminate any stores (would need dynamic disambiguation). + local t1 = { 1, 2 } + local t2 = { 1, 2 } + local k = 1 + for i=1,100 do + assert(true) + t1[k] = 11 + assert(t1[k] == 11) + t2[2] = 22 + assert(t2[2] == 22) + end + assert(t1[1] == 11) + assert(t2[2] == 22) +end + +do --- 12 +-- Store with same ref, different value and aliased loads. +-- Cannot eliminate any stores (would need dynamic disambiguation). + local t1 = { 1, 2 } + local t2 = t1 + for i=1,100 do + assert(true) + t1[1] = 11 + assert(t2[1] == 11) + t1[1] = 22 + assert(t2[1] == 22) + end + assert(t1[1] == 22) +end + +do --- CALLL must inhibit DSE. + local a,b + local t = {1,2} + for i=1,100 do + t[2]=nil + a=#t + t[2]=2 + b=#t + end + assert(a == 1 and b == 2) +end diff --git a/test/misc/dse_field.lua b/test/opt/dse/field.lua similarity index 72% rename from test/misc/dse_field.lua rename to test/opt/dse/field.lua index 497cd9ecfe..9b544577fb 100644 --- a/test/misc/dse_field.lua +++ b/test/opt/dse/field.lua @@ -1,77 +1,70 @@ - -local getmetatable, setmetatable = getmetatable, setmetatable - --- 1. Store with same ref and same value. All stores in loop eliminated. -do - local mt = {} - local t = {} - for i=1,100 do - setmetatable(t, mt) - assert(getmetatable(t) == mt) - setmetatable(t, mt) - assert(getmetatable(t) == mt) - end - assert(getmetatable(t) == mt) -end - --- 2. Store with different ref and same value. All stores in loop eliminated. -do - local mt = {} - local t1 = {} - local t2 = {} - for i=1,100 do - setmetatable(t1, mt) - assert(getmetatable(t1) == mt) - setmetatable(t2, mt) - assert(getmetatable(t2) == mt) - end - assert(getmetatable(t1) == mt) - assert(getmetatable(t2) == mt) -end - --- 3. Store with different ref and different value. Cannot eliminate any stores. -do - local mt1 = {} - local mt2 = {} - local t1 = {} - local t2 = {} - for i=1,100 do - setmetatable(t1, mt1) - assert(getmetatable(t1) == mt1) - setmetatable(t2, mt2) - assert(getmetatable(t2) == mt2) - end - assert(getmetatable(t1) == mt1) - assert(getmetatable(t2) == mt2) -end - --- 4. Store with same ref and different value. 2nd store remains in loop. -do - local mt1 = {} - local mt2 = {} - local t = {} - for i=1,100 do - setmetatable(t, mt1) - assert(getmetatable(t) == mt1) - setmetatable(t, mt2) - assert(getmetatable(t) == mt2) - end - assert(getmetatable(t) == mt2) -end - --- 5. Store with same ref, different value and aliased loads. --- Cannot eliminate any stores. -do - local mt1 = {} - local mt2 = {} - local t1 = {} - local t2 = t1 - for i=1,100 do - setmetatable(t1, mt1) - assert(getmetatable(t2) == mt1) - setmetatable(t1, mt2) - assert(getmetatable(t2) == mt2) - end - assert(getmetatable(t1) == mt2) -end - +local getmetatable, setmetatable = getmetatable, setmetatable + +do --- 1. Store with same ref and same value. All stores in loop eliminated. + local mt = {} + local t = {} + for i=1,100 do + setmetatable(t, mt) + assert(getmetatable(t) == mt) + setmetatable(t, mt) + assert(getmetatable(t) == mt) + end + assert(getmetatable(t) == mt) +end + +do --- 2. Store with different ref and same value. All stores in loop eliminated. + local mt = {} + local t1 = {} + local t2 = {} + for i=1,100 do + setmetatable(t1, mt) + assert(getmetatable(t1) == mt) + setmetatable(t2, mt) + assert(getmetatable(t2) == mt) + end + assert(getmetatable(t1) == mt) + assert(getmetatable(t2) == mt) +end + +do --- 3. Store with different ref and different value. Cannot eliminate any stores. + local mt1 = {} + local mt2 = {} + local t1 = {} + local t2 = {} + for i=1,100 do + setmetatable(t1, mt1) + assert(getmetatable(t1) == mt1) + setmetatable(t2, mt2) + assert(getmetatable(t2) == mt2) + end + assert(getmetatable(t1) == mt1) + assert(getmetatable(t2) == mt2) +end + +do --- 4. Store with same ref and different value. 2nd store remains in loop. + local mt1 = {} + local mt2 = {} + local t = {} + for i=1,100 do + setmetatable(t, mt1) + assert(getmetatable(t) == mt1) + setmetatable(t, mt2) + assert(getmetatable(t) == mt2) + end + assert(getmetatable(t) == mt2) +end + +do --- 5. Store with same ref, different value and aliased loads. +-- Cannot eliminate any stores. + local mt1 = {} + local mt2 = {} + local t1 = {} + local t2 = t1 + for i=1,100 do + setmetatable(t1, mt1) + assert(getmetatable(t2) == mt1) + setmetatable(t1, mt2) + assert(getmetatable(t2) == mt2) + end + assert(getmetatable(t1) == mt2) +end diff --git a/test/opt/dse/index b/test/opt/dse/index new file mode 100644 index 0000000000..6d9d9478ec --- /dev/null +++ b/test/opt/dse/index @@ -0,0 +1,2 @@ +array.lua +field.lua diff --git a/test/opt/fold/index b/test/opt/fold/index new file mode 100644 index 0000000000..3bc303fd0c --- /dev/null +++ b/test/opt/fold/index @@ -0,0 +1 @@ +kfold.lua diff --git a/test/misc/kfold.lua b/test/opt/fold/kfold.lua similarity index 93% rename from test/misc/kfold.lua rename to test/opt/fold/kfold.lua index 1a532f16d8..1db29084db 100644 --- a/test/misc/kfold.lua +++ b/test/opt/fold/kfold.lua @@ -1,81 +1,81 @@ - -do - local y = 0 - for i=1,100 do local a, b = 23, 11; y = a+b end; assert(y == 23+11) - for i=1,100 do local a, b = 23, 11; y = a-b end; assert(y == 23-11) - for i=1,100 do local a, b = 23, 11; y = a*b end; assert(y == 23*11) - for i=1,100 do local a, b = 23, 11; y = a/b end; assert(y == 23/11) - for i=1,100 do local a, b = 23, 11; y = a%b end; assert(y == 23%11) - for i=1,100 do local a, b = 23, 11; y = a^b end; assert(y == 23^11) - - for i=1,100 do local a, b = 23.5, 11.5; y = a+b end; assert(y == 23.5+11.5) - for i=1,100 do local a, b = 23.5, 11.5; y = a-b end; assert(y == 23.5-11.5) - for i=1,100 do local a, b = 23.5, 11.5; y = a*b end; assert(y == 23.5*11.5) - for i=1,100 do local a, b = 23.5, 11.5; y = a/b end; assert(y == 23.5/11.5) - for i=1,100 do local a, b = 23.5, 11.5; y = a%b end; assert(y == 23.5%11.5) - for i=1,100 do local a, b = 8, 11.5; y = a^b end; assert(y == 8^11.5) -end - -do - local y = 0 - for i=1,100 do local a=23; y = math.abs(a) end; assert(y == math.abs(23)) - for i=1,100 do local a=-23; y = math.abs(a) end; assert(y == math.abs(-23)) - for i=1,100 do local a=23.5; y = math.abs(a) end; assert(y == math.abs(23.5)) - for i=1,100 do local a=-23.5; y = math.abs(a) end; assert(y==math.abs(-23.5)) - for i=1,100 do local a=-2^31; y = math.abs(a) end; assert(y==math.abs(-2^31)) -end - -do - local y = 0 - for i=1,100 do local a, b = 23, 11; y = math.atan2(a, b) end - assert(y == math.atan2(23, 11)) - for i=1,100 do local a, b = 23, 11; y = math.ldexp(a, b) end - assert(y == math.ldexp(23, 11)) -end - -do - local y = 0 - for i=1,100 do local a, b = 23, 11; y = math.min(a, b) end - assert(y == math.min(23, 11)) - for i=1,100 do local a, b = 23, 11; y = math.max(a, b) end - assert(y == math.max(23, 11)) - for i=1,100 do local a, b = 23.5, 11.5; y = math.min(a, b) end - assert(y == math.min(23.5, 11.5)) - for i=1,100 do local a, b = 23.5, 11.5; y = math.max(a, b) end - assert(y == math.max(23.5, 11.5)) - for i=1,100 do local a, b = 11, 23; y = math.min(a, b) end - assert(y == math.min(11, 23)) - for i=1,100 do local a, b = 11, 23; y = math.max(a, b) end - assert(y == math.max(11, 23)) - for i=1,100 do local a, b = 11.5, 23.5; y = math.min(a, b) end - assert(y == math.min(11.5, 23.5)) - for i=1,100 do local a, b = 11.5, 23.5; y = math.max(a, b) end - assert(y == math.max(11.5, 23.5)) -end - -do - local y = 0 - for i=1,100 do local a=23; y=math.floor(a) end assert(y==math.floor(23)) - for i=1,100 do local a=23.5; y=math.floor(a) end assert(y==math.floor(23.5)) - for i=1,100 do local a=-23; y=math.floor(a) end assert(y==math.floor(-23)) - for i=1,100 do local a=-23.5; y=math.floor(a) end assert(y==math.floor(-23.5)) - for i=1,100 do local a=-0; y=math.floor(a) end assert(y==math.floor(-0)) - for i=1,100 do local a=23; y=math.ceil(a) end assert(y==math.ceil(23)) - for i=1,100 do local a=23.5; y=math.ceil(a) end assert(y==math.ceil(23.5)) - for i=1,100 do local a=-23; y=math.ceil(a) end assert(y==math.ceil(-23)) - for i=1,100 do local a=-23.5; y=math.ceil(a) end assert(y==math.ceil(-23.5)) - for i=1,100 do local a=-0; y=math.ceil(a) end assert(y==math.ceil(-0)) -end - -do - local y = 0 - for i=1,100 do local a=23; y=math.sqrt(a) end assert(y==math.sqrt(23)) - for i=1,100 do local a=23; y=math.exp(a) end assert(y==math.exp(23)) - for i=1,100 do local a=23; y=math.log(a) end assert(y==math.log(23)) - for i=1,100 do local a=23; y=math.log10(a) end assert(y==math.log10(23)) - for i=1,100 do local a=23; y=math.sin(a) end assert(y==math.sin(23)) - for i=1,100 do local a=23; y=math.cos(a) end assert(y==math.cos(23)) - for i=1,100 do local a=23; y=math.tan(a) end assert(y==math.tan(23)) -end - -assert((10^-2 - 0.01) == 0) +do --- operators + local y = 0 + for i=1,100 do local a, b = 23, 11; y = a+b end; assert(y == 23+11) + for i=1,100 do local a, b = 23, 11; y = a-b end; assert(y == 23-11) + for i=1,100 do local a, b = 23, 11; y = a*b end; assert(y == 23*11) + for i=1,100 do local a, b = 23, 11; y = a/b end; assert(y == 23/11) + for i=1,100 do local a, b = 23, 11; y = a%b end; assert(y == 23%11) + for i=1,100 do local a, b = 23, 11; y = a^b end; assert(y == 23^11) + + for i=1,100 do local a, b = 23.5, 11.5; y = a+b end; assert(y == 23.5+11.5) + for i=1,100 do local a, b = 23.5, 11.5; y = a-b end; assert(y == 23.5-11.5) + for i=1,100 do local a, b = 23.5, 11.5; y = a*b end; assert(y == 23.5*11.5) + for i=1,100 do local a, b = 23.5, 11.5; y = a/b end; assert(y == 23.5/11.5) + for i=1,100 do local a, b = 23.5, 11.5; y = a%b end; assert(y == 23.5%11.5) +end + +do --- abs + local y = 0 + for i=1,100 do local a=23; y = math.abs(a) end; assert(y == math.abs(23)) + for i=1,100 do local a=-23; y = math.abs(a) end; assert(y == math.abs(-23)) + for i=1,100 do local a=23.5; y = math.abs(a) end; assert(y == math.abs(23.5)) + for i=1,100 do local a=-23.5; y = math.abs(a) end; assert(y==math.abs(-23.5)) + for i=1,100 do local a=-2^31; y = math.abs(a) end; assert(y==math.abs(-2^31)) +end + +do --- atan2 ldexp + local y = 0 + for i=1,100 do local a, b = 23, 11; y = math.atan2(a, b) end + assert(y == math.atan2(23, 11)) + for i=1,100 do local a, b = 23, 11; y = math.ldexp(a, b) end + assert(y == math.ldexp(23, 11)) +end + +do --- minmax + local y = 0 + for i=1,100 do local a, b = 23, 11; y = math.min(a, b) end + assert(y == math.min(23, 11)) + for i=1,100 do local a, b = 23, 11; y = math.max(a, b) end + assert(y == math.max(23, 11)) + for i=1,100 do local a, b = 23.5, 11.5; y = math.min(a, b) end + assert(y == math.min(23.5, 11.5)) + for i=1,100 do local a, b = 23.5, 11.5; y = math.max(a, b) end + assert(y == math.max(23.5, 11.5)) + for i=1,100 do local a, b = 11, 23; y = math.min(a, b) end + assert(y == math.min(11, 23)) + for i=1,100 do local a, b = 11, 23; y = math.max(a, b) end + assert(y == math.max(11, 23)) + for i=1,100 do local a, b = 11.5, 23.5; y = math.min(a, b) end + assert(y == math.min(11.5, 23.5)) + for i=1,100 do local a, b = 11.5, 23.5; y = math.max(a, b) end + assert(y == math.max(11.5, 23.5)) +end + +do --- floorceil + local y = 0 + for i=1,100 do local a=23; y=math.floor(a) end assert(y==math.floor(23)) + for i=1,100 do local a=23.5; y=math.floor(a) end assert(y==math.floor(23.5)) + for i=1,100 do local a=-23; y=math.floor(a) end assert(y==math.floor(-23)) + for i=1,100 do local a=-23.5; y=math.floor(a) end assert(y==math.floor(-23.5)) + for i=1,100 do local a=-0; y=math.floor(a) end assert(y==math.floor(-0)) + for i=1,100 do local a=23; y=math.ceil(a) end assert(y==math.ceil(23)) + for i=1,100 do local a=23.5; y=math.ceil(a) end assert(y==math.ceil(23.5)) + for i=1,100 do local a=-23; y=math.ceil(a) end assert(y==math.ceil(-23)) + for i=1,100 do local a=-23.5; y=math.ceil(a) end assert(y==math.ceil(-23.5)) + for i=1,100 do local a=-0; y=math.ceil(a) end assert(y==math.ceil(-0)) +end + +do --- sqrt exp log trig + local y = 0 + for i=1,100 do local a=23; y=math.sqrt(a) end assert(y==math.sqrt(23)) + for i=1,100 do local a=23; y=math.exp(a) end assert(y==math.exp(23)) + for i=1,100 do local a=23; y=math.log(a) end assert(y==math.log(23)) + for i=1,100 do local a=23; y=math.log10(a) end assert(y==math.log10(23)) + for i=1,100 do local a=23; y=math.sin(a) end assert(y==math.sin(23)) + for i=1,100 do local a=23; y=math.cos(a) end assert(y==math.cos(23)) + for i=1,100 do local a=23; y=math.tan(a) end assert(y==math.tan(23)) +end + +do --- exp + assert((10^-2 - 0.01) == 0) +end diff --git a/test/opt/fuse.lua b/test/opt/fuse.lua new file mode 100644 index 0000000000..57c5c9df03 --- /dev/null +++ b/test/opt/fuse.lua @@ -0,0 +1,5 @@ +do --- Don't fuse i+101 on x64. +-- (except if i is sign-extended to 64 bit or addressing is limited to 32 bit) + local t = {} + for i=-100,-1 do t[i+101] = 1 end +end diff --git a/test/opt/fwd/hrefk_rollback.lua b/test/opt/fwd/hrefk_rollback.lua new file mode 100644 index 0000000000..32ba95d28c --- /dev/null +++ b/test/opt/fwd/hrefk_rollback.lua @@ -0,0 +1,32 @@ +do --- https://github.com/LuaJIT/LuaJIT/issues/124 + local function foo(a, b, f) + return f and (a.f0 < b.f1 and + b.f0 < a.f1 and + a.f2 < b.f3 and + b.f2 < a.f3) + end + + local function bar(f0, f1, f2, f3, X, f) + for _, v in ipairs(X) do + local b = {} + b.f0 = 0 + b.f2 = v + b.f1 = b.f0 + 1 + b.f3 = b.f2 + 1 + + if foo({f0 = f0, f1 = f1, f2 = f2, f3 = f3}, b, f) then + return false + end + end + + return true + end + + local X = { 0, 1, 0, 0 } + + for i = 1, 20 do + assert(bar(0, 1, 2, 3, X, true)) + end + + assert(not bar(0, 1, 1, 2, X, true)) +end diff --git a/test/opt/fwd/index b/test/opt/fwd/index new file mode 100644 index 0000000000..74d3bdbd69 --- /dev/null +++ b/test/opt/fwd/index @@ -0,0 +1,3 @@ +hrefk_rollback.lua +tnew_tdup.lua +upval.lua diff --git a/test/misc/fwd_tnew_tdup.lua b/test/opt/fwd/tnew_tdup.lua similarity index 80% rename from test/misc/fwd_tnew_tdup.lua rename to test/opt/fwd/tnew_tdup.lua index 105263ca08..375863f69f 100644 --- a/test/misc/fwd_tnew_tdup.lua +++ b/test/opt/fwd/tnew_tdup.lua @@ -1,78 +1,69 @@ - --- 1. -do - local x = 2 - for i=1,100 do - local t = {} -- TNEW: DCE - x = t.foo -- HREF -> niltv: folded - end - assert(x == nil) -end - --- 2. -do - local x = 2 - for i=1,100 do - local t = {1} -- TDUP: DCE - x = t.foo -- HREF -> niltv: folded - end - assert(x == nil) -end - --- 3. -do - local x = 2 - for i=1,100 do - local t = {} - t[1] = 11 -- NEWREF + HSTORE - x = t[1] -- AREF + ALOAD, no forwarding, no fold - end - assert(x == 11) -end - --- 4. HREFK not eliminated. Ditto for the EQ(FLOAD(t, #tab.hmask), k). -do - local x = 2 - for i=1,100 do - local t = {} - t.foo = 11 -- NEWREF + HSTORE - x = t.foo -- HREFK + HLOAD: store forwarding - end - assert(x == 11) -end - --- 5. HREFK not eliminated. Ditto for the EQ(FLOAD(t, #tab.hmask), k). -do - local x = 2 - for i=1,100 do - local t = {foo=11} -- TDUP - x = t.foo -- HREFK + non-nil HLOAD: folded - end - assert(x == 11) -end - --- 6. -do - local x = 2 - local k = 1 - for i=1,100 do - local t = {[0]=11} -- TDUP - t[k] = 22 -- AREF + ASTORE aliasing - x = t[0] -- AREF + ALOAD, no fold - end - assert(x == 11) -end - --- 7. -do - local setmetatable = setmetatable - local mt = { __newindex = function(t, k, v) - assert(k == "foo") - assert(v == 11) - end } - for i=1,100 do - local t = setmetatable({}, mt) - t.foo = 11 - end -end - +do --- 1. + local x = 2 + for i=1,100 do + local t = {} -- TNEW: DCE + x = t.foo -- HREF -> niltv: folded + end + assert(x == nil) +end + +do --- 2. + local x = 2 + for i=1,100 do + local t = {1} -- TDUP: DCE + x = t.foo -- HREF -> niltv: folded + end + assert(x == nil) +end + +do --- 3. + local x = 2 + for i=1,100 do + local t = {} + t[1] = 11 -- NEWREF + HSTORE + x = t[1] -- AREF + ALOAD, no forwarding, no fold + end + assert(x == 11) +end + +do --- 4. HREFK not eliminated. Ditto for the EQ(FLOAD(t, #tab.hmask), k). + local x = 2 + for i=1,100 do + local t = {} + t.foo = 11 -- NEWREF + HSTORE + x = t.foo -- HREFK + HLOAD: store forwarding + end + assert(x == 11) +end + +do --- 5. HREFK not eliminated. Ditto for the EQ(FLOAD(t, #tab.hmask), k). + local x = 2 + for i=1,100 do + local t = {foo=11} -- TDUP + x = t.foo -- HREFK + non-nil HLOAD: folded + end + assert(x == 11) +end + +do --- 6. + local x = 2 + local k = 1 + for i=1,100 do + local t = {[0]=11} -- TDUP + t[k] = 22 -- AREF + ASTORE aliasing + x = t[0] -- AREF + ALOAD, no fold + end + assert(x == 11) +end + +do --- 7. + local setmetatable = setmetatable + local mt = { __newindex = function(t, k, v) + assert(k == "foo") + assert(v == 11) + end } + for i=1,100 do + local t = setmetatable({}, mt) + t.foo = 11 + end +end diff --git a/test/misc/fwd_upval.lua b/test/opt/fwd/upval.lua similarity index 60% rename from test/misc/fwd_upval.lua rename to test/opt/fwd/upval.lua index 7fb360d2d3..5bc1cc96cb 100644 --- a/test/misc/fwd_upval.lua +++ b/test/opt/fwd/upval.lua @@ -1,57 +1,50 @@ - --- 1. Open upvalue above base slot, aliasing an SSA value. -do - local x = 7 - local function a() x = x + 1 end - local function b() x = x + 2 end - for i=1,100 do a(); b(); x = x + 5 end - assert(x == 807) -end - --- 2. Open upvalue below base slot. UREFO CSE for a.x + b.x, but not x in loop. --- ULOAD not disambiguated. 2x ULOAD + 2x USTORE (+ 1x DSE USTORE). -do - local x = 7 - (function() - local function a() x = x + 1 end - local function b() x = x + 2 end - for i=1,100 do a(); b(); x = x + 5 end - end)() - assert(x == 807) -end - --- 3. Closed upvalue. UREFC CSE for a.x + b.x, but not x in loop. --- ULOAD not disambiguated. 2x ULOAD + 2x USTORE (+ 1x DSE for USTORE). -do - local xx = (function() - local x = 7 - local function a() x = x + 1 end - local function b() x = x + 2 end - return function() for i=1,100 do a(); b(); x = x + 5 end; return x end - end)()() - assert(xx == 807) -end - --- 4. Open upvalue below base slot. Forwarded. 1x USTORE (+ 1x DSE USTORE). -do - local x = 7 - (function() - local function a() x = x + 1 end - for i=1,100 do a(); a() end - end)() - assert(x == 207) -end - --- 5. Closed upvalue. Forwarded. 1x USTORE (+ 1x DSE USTORE). -do - local xx = (function() - local x = 7 - return function() - local function a() x = x + 1 end - for i=1,100 do a(); a() end - return x - end - end)()() - assert(xx == 207) -end - +do --- 1. Open upvalue above base slot, aliasing an SSA value. + local x = 7 + local function a() x = x + 1 end + local function b() x = x + 2 end + for i=1,100 do a(); b(); x = x + 5 end + assert(x == 807) +end + +do --- 2. Open upvalue below base slot. UREFO CSE for a.x + b.x, but not x in loop. + -- ULOAD not disambiguated. 2x ULOAD + 2x USTORE (+ 1x DSE USTORE). + local x = 7 + (function() + local function a() x = x + 1 end + local function b() x = x + 2 end + for i=1,100 do a(); b(); x = x + 5 end + end)() + assert(x == 807) +end + +do --- 3. Closed upvalue. UREFC CSE for a.x + b.x, but not x in loop. + -- ULOAD not disambiguated. 2x ULOAD + 2x USTORE (+ 1x DSE for USTORE). + local xx = (function() + local x = 7 + local function a() x = x + 1 end + local function b() x = x + 2 end + return function() for i=1,100 do a(); b(); x = x + 5 end; return x end + end)()() + assert(xx == 807) +end + +do --- 4. Open upvalue below base slot. Forwarded. 1x USTORE (+ 1x DSE USTORE). + local x = 7 + (function() + local function a() x = x + 1 end + for i=1,100 do a(); a() end + end)() + assert(x == 207) +end + +do --- 5. Closed upvalue. Forwarded. 1x USTORE (+ 1x DSE USTORE). + local xx = (function() + local x = 7 + return function() + local function a() x = x + 1 end + for i=1,100 do a(); a() end + return x + end + end)()() + assert(xx == 207) +end diff --git a/test/opt/index b/test/opt/index new file mode 100644 index 0000000000..2aeaa8f16d --- /dev/null +++ b/test/opt/index @@ -0,0 +1,6 @@ +dse +dse +fold +fold +fwd +fwd +fuse.lua +fuse +loop +loop +sink +sink diff --git a/test/opt/loop/index b/test/opt/loop/index new file mode 100644 index 0000000000..321efe23fb --- /dev/null +++ b/test/opt/loop/index @@ -0,0 +1 @@ +unroll.lua diff --git a/test/opt/loop/unroll.lua b/test/opt/loop/unroll.lua new file mode 100644 index 0000000000..4c856a5813 --- /dev/null +++ b/test/opt/loop/unroll.lua @@ -0,0 +1,32 @@ +do --- type instability on loop unroll -> record unroll + local flip = true + for i=1,100 do flip = not flip end + assert(flip == true) +end + +do --- untitled + local t = {} + local a, b, c = 1, "", t + for i=1,100 do a,b,c=b,c,a end + assert(c == 1 and a == "" and b == t) +end + +do --- FAILFOLD on loop unroll -> LJ_TRERR_GFAIL -> record unroll + local t = { 1, 2 } + local k = 2 + local x = 0 + for i=1,200 do + x = x + t[k] + k = k == 1 and 2 or 1 + end + assert(x == 300 and k == 2) +end + +do --- Unroll if inner loop aborts. + local j = 0 + for i = 1,100 do + repeat + j = j+1 + until true + end +end diff --git a/test/misc/sink_alloc.lua b/test/opt/sink/alloc.lua similarity index 76% rename from test/misc/sink_alloc.lua rename to test/opt/sink/alloc.lua index 55f4218e63..a83e8f05ac 100644 --- a/test/misc/sink_alloc.lua +++ b/test/opt/sink/alloc.lua @@ -1,140 +1,126 @@ - -local assert = assert - --- DCE or sink trivial TNEW or TDUP. -do - for i=1,100 do local t={} end - for i=1,100 do local t={1} end -end - --- Sink TNEW/TDUP + ASTORE/HSTORE. -do - for i=1,100 do local t={i}; assert(t[1] == i) end - for i=1,100 do local t={foo=i}; assert(t.foo == i) end - for i=1,100 do local t={1,i}; assert(t[2] == i) end - for i=1,100 do local t={bar=1,foo=i}; assert(t.foo == i) end -end - --- Sink outermost table of nested TNEW. -do - local x - for i=1,100 do - local t = {[0]={{1,i}}} - if i == 90 then x = t end - assert(t[0][1][2] == i) - end - assert(x[0][1][2] == 90) - for i=1,100 do - local t = {foo={bar={baz=i}}} - if i == 90 then x = t end - assert(t.foo.bar.baz == i) - end - assert(x.foo.bar.baz == 90) -end - --- Sink one TNEW + FSTORE. -do - for i=1,100 do local t = setmetatable({}, {}) end -end - --- Sink TDUP or TDUP + HSTORE. Guard of HREFK eliminated. -do - local x - for i=1,100 do local t = { foo = 1 }; x = t.foo; end - assert(x == 1) - for i=1,100 do local t = { foo = i }; x = t.foo; end - assert(x == 100) -end - --- Sink of simplified complex add, unused in next iteration, drop PHI. -do - local x={1,2} - for i=1,100 do x = {x[1]+3, x[2]+4} end - assert(x[1] == 301) - assert(x[2] == 402) -end - --- Sink of complex add, unused in next iteration, drop PHI. -do - local x,k={1.5,2.5},{3.5,4.5} - for i=1,100 do x = {x[1]+k[1], x[2]+k[2]} end - assert(x[1] == 351.5) - assert(x[2] == 452.5) -end - --- Sink of TDUP with stored values that are both PHI and non-PHI. -do - local x,k={1,2},{3,4} - for i=1,100 do x = {x[1]+k[1], k[2]} end - assert(x[1] == 301) - assert(x[2] == 4) -end - --- Sink of CONV. -do - local t = {1} - local x,y - for i=1,200 do - local v = {i} - local w = {i+1} - x = v[1] - y = w[1] - if i > 100 then end - end - assert(x == 200 and y == 201) -end - --- Sink of stores with numbers. -do - local x = {1.5, 0} - for i=1,200 do x = {x[1]+1, 99.5}; x[2]=4.5; if i > 100 then end end - assert(x[1] == 201.5) - assert(x[2] == 4.5) -end - --- Sink of stores with constants. -do - for i=1,100 do local t = {false}; t[1] = true; if i > 100 then g=t end end -end - --- Sink with two references to the same table. -do - for i=1,200 do - local t = {i} - local q = t - if i > 100 then assert(t == q) end - end -end - -do - local point - point = { - new = function(self, x, y) - return setmetatable({x=x, y=y}, self) - end, - __add = function(a, b) - return point:new(a.x + b.x, a.y + b.y) - end, - } - point.__index = point - local a, b = point:new(1, 1), point:new(2, 2) - for i=1,100 do a = (a + b) + b end - assert(a.x == 401) - assert(a.y == 401) - assert(getmetatable(a) == point) - for i=1,200 do a = (a + b) + b; if i > 100 then end end - assert(a.x == 1201) - assert(a.y == 1201) - assert(getmetatable(a) == point) -end - -do - local t = {} - for i=1,20 do t[i] = 1 end - for i=1,20 do - for a,b in ipairs(t) do - local s = {i} - end - end -end - +local assert = assert + +do --- DCE or sink trivial TNEW or TDUP. + for i=1,100 do local t={} end + for i=1,100 do local t={1} end +end + +do --- Sink TNEW/TDUP + ASTORE/HSTORE. + for i=1,100 do local t={i}; assert(t[1] == i) end + for i=1,100 do local t={foo=i}; assert(t.foo == i) end + for i=1,100 do local t={1,i}; assert(t[2] == i) end + for i=1,100 do local t={bar=1,foo=i}; assert(t.foo == i) end +end + +do --- Sink outermost table of nested TNEW. + local x + for i=1,100 do + local t = {[0]={{1,i}}} + if i == 90 then x = t end + assert(t[0][1][2] == i) + end + assert(x[0][1][2] == 90) + for i=1,100 do + local t = {foo={bar={baz=i}}} + if i == 90 then x = t end + assert(t.foo.bar.baz == i) + end + assert(x.foo.bar.baz == 90) +end + +do --- Sink one TNEW + FSTORE. + for i=1,100 do local t = setmetatable({}, {}) end +end + +do --- Sink TDUP or TDUP + HSTORE. Guard of HREFK eliminated. + local x + for i=1,100 do local t = { foo = 1 }; x = t.foo; end + assert(x == 1) + for i=1,100 do local t = { foo = i }; x = t.foo; end + assert(x == 100) +end + +do --- Sink of simplified complex add, unused in next iteration, drop PHI. + local x={1,2} + for i=1,100 do x = {x[1]+3, x[2]+4} end + assert(x[1] == 301) + assert(x[2] == 402) +end + +do --- Sink of complex add, unused in next iteration, drop PHI. + local x,k={1.5,2.5},{3.5,4.5} + for i=1,100 do x = {x[1]+k[1], x[2]+k[2]} end + assert(x[1] == 351.5) + assert(x[2] == 452.5) +end + +do --- Sink of TDUP with stored values that are both PHI and non-PHI. + local x,k={1,2},{3,4} + for i=1,100 do x = {x[1]+k[1], k[2]} end + assert(x[1] == 301) + assert(x[2] == 4) +end + +do --- Sink of CONV. + local t = {1} + local x,y + for i=1,200 do + local v = {i} + local w = {i+1} + x = v[1] + y = w[1] + if i > 100 then end + end + assert(x == 200 and y == 201) +end + +do --- Sink of stores with numbers. + local x = {1.5, 0} + for i=1,200 do x = {x[1]+1, 99.5}; x[2]=4.5; if i > 100 then end end + assert(x[1] == 201.5) + assert(x[2] == 4.5) +end + +do --- Sink of stores with constants. + for i=1,100 do local t = {false}; t[1] = true; if i > 100 then g=t end end +end + +do --- Sink with two references to the same table. + for i=1,200 do + local t = {i} + local q = t + if i > 100 then assert(t == q) end + end +end + +do --- point + local point + point = { + new = function(self, x, y) + return setmetatable({x=x, y=y}, self) + end, + __add = function(a, b) + return point:new(a.x + b.x, a.y + b.y) + end, + } + point.__index = point + local a, b = point:new(1, 1), point:new(2, 2) + for i=1,100 do a = (a + b) + b end + assert(a.x == 401) + assert(a.y == 401) + assert(getmetatable(a) == point) + for i=1,200 do a = (a + b) + b; if i > 100 then end end + assert(a.x == 1201) + assert(a.y == 1201) + assert(getmetatable(a) == point) +end + +do --- untitled + local t = {} + for i=1,20 do t[i] = 1 end + for i=1,20 do + for a,b in ipairs(t) do + local s = {i} + end + end +end diff --git a/test/opt/sink/index b/test/opt/sink/index new file mode 100644 index 0000000000..b3a78ebe09 --- /dev/null +++ b/test/opt/sink/index @@ -0,0 +1,2 @@ +alloc.lua +nosink.lua diff --git a/test/misc/sink_nosink.lua b/test/opt/sink/nosink.lua similarity index 64% rename from test/misc/sink_nosink.lua rename to test/opt/sink/nosink.lua index 5badfd2690..3a1bdf0752 100644 --- a/test/misc/sink_nosink.lua +++ b/test/opt/sink/nosink.lua @@ -1,124 +1,109 @@ - -local assert = assert - --- Cannot sink TNEW, aliased load. -do - local k = 1 - for i=1,100 do local t={i}; assert(t[k]==i) end - for i=1,100 do local t={}; t[k]=i; assert(t[1]==i) end -end - --- Cannot sink TNEW, escaping to upvalue. -do - (function() - local uv - return function() - for i=1,100 do uv = {i} end - assert(uv[1] == 100) - end - end)()() -end - --- Cannot sink TNEW, escaping through a store. -do - local t = {} - for i=1,100 do t[1] = {i} end - for i=1,100 do t.foo = {i} end - for i=1,100 do setmetatable(t, {i}) end - assert(t[1][1] == 100) - assert(t.foo[1] == 100) - assert(getmetatable(t)[1] == 100) -end - --- Cannot sink TNEW, iteratively escaping through a store. -do - local t = {} - for i=1,100 do t[1] = {i}; t[1][1] = {i} end - assert(t[1][1][1] == 100) -end - --- Cannot sink TNEW, escaping to next iteration (unused in 1st variant). -do - local t; - for i=1,200 do t = {i} end - assert(t[1] == 200) - for i=1,200 do if i > 100 then assert(t[1] == i-1) end t = {i} end - assert(t[1] == 200) -end - --- Cannot sink TNEW, escaping to next iteration (snapshot ref). -do - local t,x - for i=1,100 do x=t; t={i} end - assert(t[1] == 100) - assert(x[1] == 99) -end - --- Cannot sink TNEW, escaping to next iteration (IR/snapshot ref). -do - local t - for i=1,100 do t={t} end - assert(type(t[1][1][1]) == "table") -end - --- Could sink outer TNEW, but the logic for stores to PHI allocs is too simple. --- Cannot sink inner TNEW, escaping to next iteration (IR ref). -do - local t = {42, 43} - for i=1,100 do t={t[2], {i}} end - assert(t[2][1] == 100) - assert(t[1][1] == 99) -end - --- Cannot sink TNEW, cross-PHI ref (and snapshot ref). -do - local x,y - for i=1,100 do x,y={i},x end - assert(x[1] == 100) - assert(y[1] == 99) -end - --- Cannot sink TNEW, cross-PHI ref (and snapshot ref). -do - local x,y - for i=1,100 do x,y=y,{i} end - assert(x[1] == 99) - assert(y[1] == 100) -end - --- Cannot sink TNEW, escaping to exit. -do - local function f(n, t) - if n == 0 then return t end - return (f(n-1, {t})) - end - local t = f(100, 42) - assert(type(t[1][1][1]) == "table") - t = f(3, 42) - assert(t[1][1][1] == 42) -end - --- Cannot sink TNEW, escaping to exit. -do - local function f(n) - if n == 0 then return 42 end - local t = f(n-1) - return {t} - end - for i=1,20 do - local t = f(100) - assert(type(t[1][1][1]) == "table") - end - t = f(3) - assert(t[1][1][1] == 42) -end - --- Cannot sink, since nested inner table is non-PHI. -do - local a, b = {{1}}, {{1}} - for i=1,10000 do -- Need to force GC exit sometimes - a = {{a[1][1]+b[1][1]}} - end - assert(a[1][1] == 10001) -end - +local assert = assert + +do --- Cannot sink TNEW, aliased load. + local k = 1 + for i=1,100 do local t={i}; assert(t[k]==i) end + for i=1,100 do local t={}; t[k]=i; assert(t[1]==i) end +end + +do --- Cannot sink TNEW, escaping to upvalue. + (function() + local uv + return function() + for i=1,100 do uv = {i} end + assert(uv[1] == 100) + end + end)()() +end + +do --- Cannot sink TNEW, escaping through a store. + local t = {} + for i=1,100 do t[1] = {i} end + for i=1,100 do t.foo = {i} end + for i=1,100 do setmetatable(t, {i}) end + assert(t[1][1] == 100) + assert(t.foo[1] == 100) + assert(getmetatable(t)[1] == 100) +end + +do --- Cannot sink TNEW, iteratively escaping through a store. + local t = {} + for i=1,100 do t[1] = {i}; t[1][1] = {i} end + assert(t[1][1][1] == 100) +end + +do --- Cannot sink TNEW, escaping to next iteration (unused in 1st variant). + local t; + for i=1,200 do t = {i} end + assert(t[1] == 200) + for i=1,200 do if i > 100 then assert(t[1] == i-1) end t = {i} end + assert(t[1] == 200) +end + +do --- Cannot sink TNEW, escaping to next iteration (snapshot ref). + local t,x + for i=1,100 do x=t; t={i} end + assert(t[1] == 100) + assert(x[1] == 99) +end + +do --- Cannot sink TNEW, escaping to next iteration (IR/snapshot ref). + local t + for i=1,100 do t={t} end + assert(type(t[1][1][1]) == "table") +end + +do --- Cannot sink inner TNEW, escaping to next iteration (IR ref). + -- (Could sink outer TNEW, but the logic for stores to PHI allocs is too simple). + local t = {42, 43} + for i=1,100 do t={t[2], {i}} end + assert(t[2][1] == 100) + assert(t[1][1] == 99) +end + +do --- Cannot sink TNEW, cross-PHI ref (and snapshot ref). + local x,y + for i=1,100 do x,y={i},x end + assert(x[1] == 100) + assert(y[1] == 99) +end + +do --- Cannot sink TNEW, cross-PHI ref (and snapshot ref). + local x,y + for i=1,100 do x,y=y,{i} end + assert(x[1] == 99) + assert(y[1] == 100) +end + +do --- Cannot sink TNEW, escaping to exit. + local function f(n, t) + if n == 0 then return t end + return (f(n-1, {t})) + end + local t = f(100, 42) + assert(type(t[1][1][1]) == "table") + t = f(3, 42) + assert(t[1][1][1] == 42) +end + +do --- Cannot sink TNEW, escaping to exit. + local function f(n) + if n == 0 then return 42 end + local t = f(n-1) + return {t} + end + for i=1,20 do + local t = f(100) + assert(type(t[1][1][1]) == "table") + end + local t = f(3) + assert(t[1][1][1] == 42) +end + +do --- Cannot sink, since nested inner table is non-PHI. + local a, b = {{1}}, {{1}} + for i=1,10000 do -- Need to force GC exit sometimes + a = {{a[1][1]+b[1][1]}} + end + assert(a[1][1] == 10001) +end diff --git a/test/clib/cpptest.cpp b/test/src/cpptest.cpp similarity index 100% rename from test/clib/cpptest.cpp rename to test/src/cpptest.cpp diff --git a/test/clib/ctest.c b/test/src/ctest.c similarity index 100% rename from test/clib/ctest.c rename to test/src/ctest.c diff --git a/test/test.lua b/test/test.lua new file mode 100644 index 0000000000..bf16c2745a --- /dev/null +++ b/test/test.lua @@ -0,0 +1,409 @@ +local assert, io_open, io_lines, io_write, load, type, xpcall = + assert, io.open, io.lines, io.write, load, type, xpcall +local debug_traceback, math_random, tonumber, loadstring = + debug.traceback, math.random, tonumber, loadstring or load + +local dirsep = package.config:match"^(.-)\n" +local own_file = debug.getinfo(1, "S").source:match"^@(.*)" or arg[0] +local own_dir = own_file:match("^.*[/".. dirsep .."]") + +local function default_tags() + local tags = {} + + -- Lua version and features + tags.lua = tonumber(_VERSION:match"%d+%.%d+") + if table.pack then + tags["compat5.2"] = true + end + if loadstring"return 0xep+9" then + tags.hexfloat = true + end + + -- Libraries + for _, lib in ipairs{"bit", "ffi", "jit.profile", "table.new"} do + if pcall(require, lib) then + tags[lib] = true + end + end + + -- LuaJIT-specific + if jit then + tags.luajit = tonumber(jit.version:match"%d+%.%d+") + tags[jit.arch:lower()] = true + if jit.os ~= "Other" then + tags[jit.os:lower()] = true + end + if jit.status() then + tags.jit = true + end + for _, flag in ipairs{select(2, jit.status())} do + tags[flag:lower()] = true + end + end + + -- Environment + if dirsep == "\\" then + tags.windows = true + end + if tags.ffi then + local abi = require"ffi".abi + for _, param in ipairs{"le", "be", "fpu", "softfp", "hardfp", "eabi"} do + if abi(param) then + tags[param] = true + end + end + if abi"win" then tags.winabi = true end + if abi"32bit" then tags.abi32 = true end + if abi"64bit" then tags.abi64 = true end + else + local bytecode = string.dump(function()end) + if bytecode:find"^\27Lua[\80-\89]" then + tags[bytecode:byte(7, 7) == 0 and "be" or "le"] = true + tags["abi".. (bytecode:byte(9, 9) * 8)] = true + end + end + + return tags +end + +local function want_meta(opts, meta) + if not opts.want_meta_cache then + opts.want_meta_cache = setmetatable({}, {__index = function(t, meta) + local result = true + for polarity, tag, cond in meta:gmatch"([+-])([^ <>=]+)([<>=0-9.]*)" do + local tagval = opts.tags[tag] + local condresult + if cond == "" or not tagval then + condresult = tagval + else + condresult = assert(loadstring("return (...) ".. cond))(tagval) + end + if polarity == "-" then + condresult = not condresult + end + if not condresult then + result = false + break + end + end + t[meta] = result + return result + end}) + end + return opts.want_meta_cache[meta] +end + +local function parse_args(t) + local opts = { + tags = default_tags(), + want_meta = want_meta, + } + local result = opts + + local i, tlen = 1, #t + local joinedval = "" + local function flagval() + local val + if joinedval ~= "" then + val = joinedval:sub(2) + joinedval = "" + else + val = t[i] + if not val then error("Expected value after ".. t[i-1]) end + i = i + 1 + end + return val + end + + while i <= tlen do + local arg = t[i] + i = i + 1 + if arg:sub(1, 2) == "--" then + arg, joinedval = arg:match"^([^=]+)(=?.*)$" + if arg == "--quiet" then + opts.quiet = true + elseif arg == "--shuffle" then + local seed = tonumber(flagval()) + if not seed then error("Expected numeric seed after --shuffle") end + opts.shuffle = seed + elseif arg == "--shard" then + local i, s = flagval():match"^(%d+)/(%d+)$" + if not s then error("Expected integer/integer after --shard") end + opts.shard = {initial = tonumber(i), step = tonumber(s)} + elseif arg == "--version" then + io_write("LuaJIT test-suite runner v0.1\n") + result = nil + elseif arg == "--help" then + io_write("Usage: ", _G and _G.arg and _G.arg[-1] or "luajit", " ") + io_write(own_file, " [flags] [tags] [root] [numbers]\n") + io_write"\n" + io_write"Root specifies either a directory of tests, or the name of\n" + io_write"a particular .lua test file, defaulting to all tests if not given.\n" + io_write"Tags are specified in the form +tag_name or -tag_name, and\n" + io_write"are used to turn on or off groups of tests. For example,\n" + io_write"pass -ffi to skip tests relating to the ffi library, or\n" + io_write"pass +slow to enable running of slow tests.\n" + io_write"Numbers can be passed to only run particular tests.\n" + io_write"The available flags are:\n" + io_write" --quiet\n" + io_write" --shuffle=SEED\n" + io_write" --shard=INDEX/NUM_SHARDS\n" + io_write" --version\n" + io_write" --help\n" + result = nil + else + error("Unsupported flag: ".. arg) + end + if joinedval ~= "" then + error(arg .." does not expect an argument") + end + elseif arg:find"^[-+]" then + opts.tags[arg:sub(2)] = (arg:sub(1, 1) == "+") + elseif arg:find"^%d+$" then + if not opts.numbers_to_run then + opts.numbers_to_run = {} + end + opts.numbers_to_run[tonumber(arg)] = true + elseif not opts.root then + opts.root = arg + else + error("Unexpected argument ".. arg) + end + end + return result +end + +local function scan_tests(path, opts) + if path:sub(-4, -4) == "." then + local f = assert(io_open(path, "rb")) + local contents = f:read"*a" + f:close() + local prefix = "return {" + local code = contents:gsub("()(do +%-%-%- +)([^\r\n]+)", + function(pos, marker, info) + if pos ~= 1 then + pos = pos - 1 + if contents:sub(pos, pos) ~= "\n" then + return marker .. info + end + end + local result = ("%s%q,function()"):format(prefix, info) + prefix = "," + if info:find" !lex" and not opts:want_meta(info:sub((info:find" +[-+@!]"))) then + result = result .."end--[========[" + prefix = "]========]".. prefix + end + return result + end) + if prefix:sub(-1) ~= "," then + error("No tests found in ".. path) + end + prefix = prefix .."}" + return assert(load(function() + local result = code + code = code ~= prefix and prefix or nil + return result + end, "@".. path))() + else + if path ~= "" and path:sub(-1) ~= "/" and path:sub(-1) ~= dirsep then + path = path .. dirsep + end + local result = {} + local i = 1 + for line in io_lines(path .."index") do + if line ~= "" then + local metaidx = line:find" +[-+@]" + local name = line + local want_these = true + if metaidx then + name = line:sub(1, metaidx - 1) + want_these = opts:want_meta(line:sub(metaidx)) + end + if want_these then + result[i] = line + result[i+1] = scan_tests(path .. name, opts) + i = i + 2 + end + end + end + return result + end +end + +local function upvalue_iterator(f, i) + i = i + 1 + local name, val = debug.getupvalue(f, i) + return name and i, name, val +end + +local function upvalues_of(f) + return upvalue_iterator, f, 0 +end + +local function append_tree_to_plan(test_tree, opts, plan, prefix) + local prefi + for i = 1, #test_tree, 2 do + local info = test_tree[i] + local name = info + local want_these = true + local metaidx = info:find" +[-+@!]" + if metaidx then + name = info:sub(1, metaidx - 1) + want_these = opts:want_meta(info:sub(metaidx)) + end + local planlen = #plan + if want_these then + local test = test_tree[i+1] + if type(test) == "table" then + append_tree_to_plan(test, opts, plan, prefix .. name .. dirsep) + else + if not prefi then + prefi = prefix:sub(1, -2) + end + plan[#plan+1] = {prefi, name, test} + end + end + if metaidx and info:find"!" then + for modifier in info:gmatch"!([^ ]+)" do + if modifier == "private_G" then + local G = setmetatable({}, {__index = _G}) + G._G = G + local function Gfn() return G end + for i = planlen, #plan do + local test = plan[i][3] + if setfenv then + setfenv(test, G) + else + for i, name in upvalues_of(test) do + if name == "_ENV" then + debug.upvaluejoin(test, i, Gfn, 1) + break + end + end + end + end + elseif modifier == "lex" then + -- Handled during test scanning + else + error("Unsupported modifier \"".. modifier .."\" in ".. prefix) + end + end + end + end + return plan +end + +local function seal_globals() + local sealed_mt = {__newindex = function() + error("Tests should not mutate global state", 3) + end} + local function seal(t) + if getmetatable(t) then return end + setmetatable(t, sealed_mt) + for k, v in pairs(t) do + if type(v) == "table" then seal(v) end + end + end + seal(_G) + + if getmetatable(package.loaded) == sealed_mt then + setmetatable(package.loaded, nil) + end +end + +local function check_package_path() + local ok, res = pcall(require, "common.test_runner_canary") + if not ok then + if own_dir then + local _, psep, placeholder = package.config:match"^(.-)\n(.-)\n(.-)\n" + package.path = package.path .. psep .. own_dir .. placeholder ..".lua" + ok, res = pcall(require, "common.test_runner_canary") + end + if not ok then + error(res) + end + end + assert(res == "canary is alive") +end + +local function mutate_plan(plan, opts) + if opts.shuffle then + math.randomseed(opts.shuffle) + for i = #plan, 2, -1 do + local n = math_random(1, i) + plan[i], plan[n] = plan[n], plan[i] + end + end + if opts.shard then + local shard_plan = {} + for i = opts.shard.initial, #plan, opts.shard.step do + shard_plan[#shard_plan + 1] = plan[i] + end + plan = shard_plan + end + if opts.numbers_to_run then + for i = 1, #plan do + if not opts.numbers_to_run[i] then + plan[i][3] = false + end + end + for k in pairs(opts.numbers_to_run) do + if not plan[k] then + error("Test number ".. k .." is not part of the plan") + end + end + end + return plan +end + +local function execute_plan(plan, opts) + if #plan == 0 then + error("No tests selected") + end + local progress_format = ("[%%%dd/%d] "):format(#tostring(#plan), #plan) + local num_tests_run = 0 + local fail_numbers = {} + for i = 1, #plan do + local plan_i = plan[i] + local test = plan_i[3] + if test then + if not opts.quiet then + local file, name = plan_i[1], plan_i[2] + io_write(progress_format:format(i), file) + io_write(file == "" and "" or " --- ", name, "\n") + end + local ok, err = xpcall(test, debug_traceback) + if not ok then + fail_numbers[#fail_numbers + 1] = i + io_write(err, "\n") + end + num_tests_run = num_tests_run + 1 + end + end + if #fail_numbers == 0 then + io_write(num_tests_run, " passed\n") + return true + else + io_write(num_tests_run - #fail_numbers, " passed, ") + io_write(#fail_numbers, " failed\n") + if not opts.quiet and num_tests_run ~= #fail_numbers then + io_write("to run just failing tests, pass command line arguments: ") + io_write(table.concat(fail_numbers, " "), "\n") + end + return false + end +end + +local opts = parse_args{...} +if not opts then + return +end +seal_globals() +check_package_path() +local test_tree = scan_tests(opts.root or own_dir or "", opts) +local plan = append_tree_to_plan(test_tree, opts, {}, "") +plan = mutate_plan(plan, opts) +local all_good = execute_plan(plan, opts) +if not all_good then + os.exit(1) +end diff --git a/test/misc/exit_frame.lua b/test/trace/exit_frame.lua similarity index 84% rename from test/misc/exit_frame.lua rename to test/trace/exit_frame.lua index 897984872b..c8297cb0bc 100644 --- a/test/misc/exit_frame.lua +++ b/test/trace/exit_frame.lua @@ -1,80 +1,79 @@ -do - g = 0 - gf = 1 - gz = 2 - - local function f(i) - if i == 90 then - gf = gf + 1 - return true - end - g = g + 1 - end - - local function z(i) - if f(i) then - gz = gz + 1 - end - end - - for j=1,5 do - for i=1,100 do z(i) end - end - - assert(g == 495) - assert(gf == 6) - assert(gz == 7) -end - -do - local f, g - function f(j) - if j >= 0 then return g(j-1) end - end - function g(j) - for i=1,200 do - if i > 100 then return f(j) end - end - end - for k=1,20 do g(20) end -end - -do - local f, g - function f(j, k) - if j >= 0 then return g(j-1, k) end - if k >= 0 then return g(20, k-1) end - end - function g(j, k) - for i=1,200 do - if i > 100 then return f(j, k) end - end - end - g(20, 20) -end - -do - local k = 0 - local f, g - - function g(a) - -- 'a' is an SLOAD #1 from f's frame and still at slot #1 - -- Avoid losing a in exit if the SLOAD is ignored - if k > 10 then k = 0 end - k= k + 1 - return f(a) - end - - function f(a,b,c,d,e) - if not e then e =1 end - a=a+1 - if a > 1000 then return end - for i=1,100 do - e=e+1 - if i > 90 then return g(a) end - end - end - - f(1,2,3,4,5) -end - +do --- global assignments !private_G + g = 0 + gf = 1 + gz = 2 + + local function f(i) + if i == 90 then + gf = gf + 1 + return true + end + g = g + 1 + end + + local function z(i) + if f(i) then + gz = gz + 1 + end + end + + for j=1,5 do + for i=1,100 do z(i) end + end + + assert(g == 495) + assert(gf == 6) + assert(gz == 7) +end + +do --- mutual recursion + local f, g + function f(j) + if j >= 0 then return g(j-1) end + end + function g(j) + for i=1,200 do + if i > 100 then return f(j) end + end + end + for k=1,20 do g(20) end +end + +do --- multi-path mutual recursion + local f, g + function f(j, k) + if j >= 0 then return g(j-1, k) end + if k >= 0 then return g(20, k-1) end + end + function g(j, k) + for i=1,200 do + if i > 100 then return f(j, k) end + end + end + g(20, 20) +end + +do --- late mutual recursion + local k = 0 + local f, g + + function g(a) + -- 'a' is an SLOAD #1 from f's frame and still at slot #1 + -- Avoid losing a in exit if the SLOAD is ignored + if k > 10 then k = 0 end + k= k + 1 + return f(a) + end + + function f(a,b,c,d,e) + if not e then e =1 end + a=a+1 + if a > 1000 then return end + for i=1,100 do + e=e+1 + if i > 90 then return g(a) end + end + end + + f(1,2,3,4,5) +end diff --git a/test/trace/exit_growstack.lua b/test/trace/exit_growstack.lua new file mode 100644 index 0000000000..20accdf8bb --- /dev/null +++ b/test/trace/exit_growstack.lua @@ -0,0 +1,28 @@ +do --- Exit needs to grow stack before slot fill. + local function f(i) + local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; + local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; + local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; + if i==90 then return end + end + for j=1,5 do + collectgarbage() -- Shrink stack. + for i=1,100 do f(i) end + end +end + +do --- Exit needs to grow stack after slot fill. + local function g(i) + if i==90 then return end + do return end + do + local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; + local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; + local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a; + end + end + for j=1,5 do + collectgarbage() -- Shrink stack. + for i=1,100 do g(i) end + end +end diff --git a/test/trace/exit_jfuncf.lua b/test/trace/exit_jfuncf.lua new file mode 100644 index 0000000000..4895fbf0a7 --- /dev/null +++ b/test/trace/exit_jfuncf.lua @@ -0,0 +1,30 @@ +do --- everything + local assert = assert + + local function rec(a, b, c, d, e, f) + assert(f == a+1) + if b == 0 then return 7 end + do local x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, x32, x33, x34, x35, x36, x37, x38, x39, x40, x41, x42, x43, x44, x45, x46, x47, x48, x49, x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x60, x61, x62, x63, x64, x65, x66, x67, x68, x69, x70, x71, x72, x73, x74, x75, x76, x77, x78, x79, x80, x81, x82, x83, x84, x85, x86, x87, x88, x89, x90, x91, x92, x93, x94, x95, x96, x97, x98, x99, x100 end + return rec(a, b-1, c, d, e, f)+1 + end + + -- Compile recursive function. + assert(rec(42, 200, 1, 2, 3, 43) == 207) + + local function trec() + return rec(42, 0, 1, 2, 3, 43) + end + + -- Compile function jumping to JFUNCF. + for i=1,200 do + gcinfo() + assert(trec() == 7) + end + + -- Shrink stack. + for j=1,10 do collectgarbage() end + + -- Cause an exit due to stack growth with PC pointing to JFUNCF. + -- Needs to load RD with nres+1 and not with the bytecode RD. + assert(trec() == 7) +end diff --git a/test/trace/index b/test/trace/index new file mode 100644 index 0000000000..00e4d3badc --- /dev/null +++ b/test/trace/index @@ -0,0 +1,5 @@ +exit_frame.lua +exit_growstack.lua +exit_jfuncf.lua +snap.lua +stitch.lua diff --git a/test/trace/snap.lua b/test/trace/snap.lua new file mode 100644 index 0000000000..ca31595f0e --- /dev/null +++ b/test/trace/snap.lua @@ -0,0 +1,47 @@ +do --- gcexit + local x = 0 + local t + for i=1,1000 do + if i >= 100 then + -- causes an exit for atomic phase + -- must not merge snapshot #0 with comparison since it has the wrong PC + if i < 150 then x=x+1 end + t = {i} + end + end + assert(x == 50) + assert(t[1] == 1000) +end + + +do --- top !private_G + function randomtable(entries, depth) + if depth == 0 then + return tostring(math.random(2)) -- snapshot between return and CALLMT + end + local t = {} + for k=1,entries do + t[k] = randomtable(entries, depth-1) + end + return t + end + + local t = randomtable(10, 2) +end + +do --- top2 + local function f() + gcinfo() + local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ + local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ + local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ + local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ + local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ + local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ + end + + for i=1,100 do + f() + if i % 3 == 0 then collectgarbage() end + end +end diff --git a/test/misc/stitch.lua b/test/trace/stitch.lua similarity index 86% rename from test/misc/stitch.lua rename to test/trace/stitch.lua index 1eba1810bb..55ce5c4151 100644 --- a/test/misc/stitch.lua +++ b/test/trace/stitch.lua @@ -1,21 +1,19 @@ - -do - local tonumber = tonumber - local function octal(s) return tonumber(s, 8) end - for i=1,100 do - octal("1") - octal("1") - octal("1") - end -end - -do - local t = { - [0] = function() end, - coroutine.wrap(function() while true do coroutine.yield() end end), - } - for i=1,100 do - t[i % 2]() - end -end - +do --- octal + local tonumber = tonumber + local function octal(s) return tonumber(s, 8) end + for i=1,100 do + octal("1") + octal("1") + octal("1") + end +end + +do --- coroutines + local t = { + [0] = function() end, + coroutine.wrap(function() while true do coroutine.yield() end end), + } + for i=1,100 do + t[i % 2]() + end +end