From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id ECEE7CC313; Wed, 20 Jan 2021 18:10:21 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org ECEE7CC313 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1611155422; bh=gsK8+To2gYQqaUbZXaL0YGc9KeFogW9iXulWj0j11uU=; h=To:Cc:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=HsGJSIWGAxNia2KMVT/GXV7LJLXRsu228kJaqMfioxh+a/BFTP8VXN2Qv9DOvCCm8 M4lk7X+9bcyq+s4hNNmJKQJVcdDKL2A+bVVgWeuE6+MTuAt03FAkyDIwvIZ+eIssQA XOgN3optklzuBFBMqv8nrJF0YKlr02mrjKHXflDc= Received: from smtpng3.m.smailru.net (smtpng3.m.smailru.net [94.100.177.149]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 795DFCC307 for ; Wed, 20 Jan 2021 18:09:56 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 795DFCC307 Received: by smtpng3.m.smailru.net with esmtpa (envelope-from ) id 1l2F7K-0000jX-G4; Wed, 20 Jan 2021 18:09:55 +0300 To: imun@tarantool.org Cc: tarantool-patches@dev.tarantool.org Date: Wed, 20 Jan 2021 18:09:54 +0300 Message-Id: <81a6433632e929cc04712c41d1787bb4287969dd.1611155231.git.imeevma@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD9D0E79FBC973162CDDA1A336500443B3AD46BC604C28ED16A00894C459B0CD1B9E5EBB21F893877AEADF699F3AE7AC6BD59DB5610BE91FE5A43EB7D3813763A1D X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7F65C230EDDCD559EEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F79006370D3D68FCEFFDD9EA8638F802B75D45FF5571747095F342E8C7A0BC55FA0FE5FC9CAD4C552894ECA0700F2D2B9323239CCB448273B5BF6AA5389733CBF5DBD5E913377AFFFEAFD269A417C69337E82CC2CC7F00164DA146DAFE8445B8C89999729449624AB7ADAF37F6B57BC7E64490611E7FA7ABCAF51C92A417C69337E82CC2CC7F00164DA146DA6F5DAA56C3B73B23C77107234E2CFBA567F23339F89546C55F5C1EE8F4F765FCD5DDBEEAE3B12F1775ECD9A6C639B01BBD4B6F7A4D31EC0BC0CAF46E325F83A522CA9DD8327EE4931B544F03EFBC4D571CE60B8040019C36C4224003CC836476C0CAF46E325F83A50BF2EBBBDD9D6B0F5D41B9178041F3E72623479134186CDE6BA297DBC24807EABDAD6C7F3747799A X-C1DE0DAB: C20DE7B7AB408E4181F030C43753B8186998911F362727C414F749A5E30D975C2549B6A8B600A67A32CF0C47C8CD538E9A0C611BC55AC3DF9C2B6934AE262D3EE7EAB7254005DCED7532B743992DF240BDC6A1CF3F042BAD6DF99611D93F60EF6EA1BA7CA28B4A74699F904B3F4130E343918A1A30D5E7FCCB5012B2E24CD356 X-C8649E89: 4E36BF7865823D7055A7F0CF078B5EC49A30900B95165D34EE6683D9E546CC6243C82255A02C6A063D02FFCCCC3AF47F9CF82830F9C672B05F65764F5B411DC71D7E09C32AA3244C8C6C04875AA0F0F447B6FD2227DE41A07101BF96129E4011729B2BEF169E0186 X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu530nj6fImhcD4MUrOEAnl0W826KZ9Q+tr5ycPtXkTV4k65bRjmOUUP8cvGozZ33TWg5HZplvhhXbhDGzqmQDTd6OAevLeAnq3Ra9uf7zvY2zzsIhlcp/Y7m53TZgf2aB4JOg4gkr2bioj7AvRt3Uvx5T8vqER9wcr9A== X-Mailru-Sender: 689FA8AB762F73936BC43F508A0638228D5FF983C0520E02CBD61184CF2BB43583D72C36FC87018B9F80AB2734326CD2FB559BB5D741EB96352A0ABBE4FDA4210A04DAD6CC59E33667EA787935ED9F1B X-Mras: Ok Subject: [Tarantool-patches] [PATCH v1 1/7] tests: add LuaJIT-test-cleanup test suite X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Mergen Imeev via Tarantool-patches Reply-To: imeevma@tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" This patch adds LuaJIT-test-cleanup test suite: https://github.com/LuaJIT/LuaJIT-test-cleanup Part of tarantool/tarantool#4064 --- test/CMakeLists.txt | 2 + test/LuaJIT-test-cleanup/CMakeLists.txt | 14 + test/LuaJIT-test-cleanup/README.md | 110 +++ test/LuaJIT-test-cleanup/bc/constov.lua | 16 + test/LuaJIT-test-cleanup/bc/index | 1 + .../common/expect_error.lua | 16 + test/LuaJIT-test-cleanup/common/ffi_util.inc | 41 + .../common/test_runner_canary.lua | 1 + test/LuaJIT-test-cleanup/computations.lua | 113 +++ test/LuaJIT-test-cleanup/index | 6 + test/LuaJIT-test-cleanup/lang/andor.lua | 61 ++ test/LuaJIT-test-cleanup/lang/assignment.lua | 46 + test/LuaJIT-test-cleanup/lang/compare.lua | 323 +++++++ test/LuaJIT-test-cleanup/lang/compare_nan.lua | 99 +++ test/LuaJIT-test-cleanup/lang/concat.lua | 112 +++ test/LuaJIT-test-cleanup/lang/constant/index | 2 + .../lang/constant/number.lua | 12 + .../lang/constant/table.lua | 15 + test/LuaJIT-test-cleanup/lang/coroutine.lua | 8 + test/LuaJIT-test-cleanup/lang/for.lua | 45 + test/LuaJIT-test-cleanup/lang/gc.lua | 42 + test/LuaJIT-test-cleanup/lang/goto.lua | 149 ++++ test/LuaJIT-test-cleanup/lang/index | 18 + test/LuaJIT-test-cleanup/lang/length.lua | 23 + test/LuaJIT-test-cleanup/lang/meta/arith.lua | 118 +++ .../lang/meta/arith_jit.lua | 68 ++ test/LuaJIT-test-cleanup/lang/meta/call.lua | 81 ++ test/LuaJIT-test-cleanup/lang/meta/cat.lua | 61 ++ test/LuaJIT-test-cleanup/lang/meta/comp.lua | 120 +++ .../lang/meta/comp_jit.lua | 104 +++ .../lang/meta/debuginfo.lua | 81 ++ test/LuaJIT-test-cleanup/lang/meta/eq.lua | 30 + test/LuaJIT-test-cleanup/lang/meta/eq_jit.lua | 35 + .../lang/meta/framegap.lua | 24 + test/LuaJIT-test-cleanup/lang/meta/index | 14 + test/LuaJIT-test-cleanup/lang/meta/index.lua | 60 ++ test/LuaJIT-test-cleanup/lang/meta/len.lua | 42 + .../lang/meta/newindex.lua | 69 ++ test/LuaJIT-test-cleanup/lang/meta/nomm.lua | 21 + test/LuaJIT-test-cleanup/lang/modulo.lua | 46 + test/LuaJIT-test-cleanup/lang/self.lua | 19 + test/LuaJIT-test-cleanup/lang/table.lua | 32 + .../lang/tail_recursion.lua | 20 + .../lang/upvalue/closure.lua | 84 ++ test/LuaJIT-test-cleanup/lang/upvalue/index | 1 + test/LuaJIT-test-cleanup/lang/vararg_jit.lua | 95 +++ test/LuaJIT-test-cleanup/lib/base/assert.lua | 33 + test/LuaJIT-test-cleanup/lib/base/error.lua | 43 + test/LuaJIT-test-cleanup/lib/base/getfenv.lua | 13 + .../lib/base/getsetmetatable.lua | 33 + test/LuaJIT-test-cleanup/lib/base/index | 11 + test/LuaJIT-test-cleanup/lib/base/ipairs.lua | 41 + test/LuaJIT-test-cleanup/lib/base/next.lua | 17 + test/LuaJIT-test-cleanup/lib/base/pairs.lua | 73 ++ .../lib/base/pcall_jit.lua | 74 ++ test/LuaJIT-test-cleanup/lib/base/select.lua | 105 +++ .../lib/base/tonumber_tostring.lua | 81 ++ .../lib/base/xpcall_jit.lua | 83 ++ test/LuaJIT-test-cleanup/lib/bit.lua | 98 +++ test/LuaJIT-test-cleanup/lib/contents.lua | 155 ++++ test/LuaJIT-test-cleanup/lib/coroutine/index | 1 + .../lib/coroutine/yield.lua | 109 +++ test/LuaJIT-test-cleanup/lib/ffi/bit64.lua | 130 +++ .../LuaJIT-test-cleanup/lib/ffi/cdata_var.lua | 47 ++ .../LuaJIT-test-cleanup/lib/ffi/copy_fill.lua | 64 ++ test/LuaJIT-test-cleanup/lib/ffi/err.lua | 35 + .../lib/ffi/ffi_arith_ptr.lua | 106 +++ .../lib/ffi/ffi_bitfield.lua | 108 +++ test/LuaJIT-test-cleanup/lib/ffi/ffi_call.lua | 266 ++++++ .../lib/ffi/ffi_callback.lua | 158 ++++ .../LuaJIT-test-cleanup/lib/ffi/ffi_const.lua | 113 +++ .../lib/ffi/ffi_convert.lua | 787 ++++++++++++++++++ test/LuaJIT-test-cleanup/lib/ffi/ffi_enum.lua | 57 ++ .../lib/ffi/ffi_gcstep_recursive.lua | 66 ++ .../lib/ffi/ffi_jit_arith.lua | 155 ++++ .../lib/ffi/ffi_jit_call.lua | 154 ++++ .../lib/ffi/ffi_jit_conv.lua | 277 ++++++ .../lib/ffi/ffi_lex_number.lua | 51 ++ .../lib/ffi/ffi_metatype.lua | 245 ++++++ test/LuaJIT-test-cleanup/lib/ffi/ffi_new.lua | 106 +++ .../lib/ffi/ffi_parse_array.lua | 78 ++ .../lib/ffi/ffi_parse_basic.lua | 131 +++ .../lib/ffi/ffi_parse_cdef.lua | 77 ++ .../lib/ffi/ffi_parse_struct.lua | 259 ++++++ .../LuaJIT-test-cleanup/lib/ffi/ffi_tabov.lua | 12 + test/LuaJIT-test-cleanup/lib/ffi/index | 12 + test/LuaJIT-test-cleanup/lib/ffi/istype.lua | 88 ++ .../LuaJIT-test-cleanup/lib/ffi/jit_array.lua | 104 +++ .../lib/ffi/jit_complex.lua | 109 +++ test/LuaJIT-test-cleanup/lib/ffi/jit_misc.lua | 109 +++ .../lib/ffi/jit_struct.lua | 201 +++++ .../lib/ffi/meta_tostring.lua | 55 ++ test/LuaJIT-test-cleanup/lib/ffi/redir.lua | 19 + .../lib/ffi/type_punning.lua | 138 +++ test/LuaJIT-test-cleanup/lib/index | 8 + test/LuaJIT-test-cleanup/lib/math/abs.lua | 16 + .../lib/math/constants.lua | 8 + test/LuaJIT-test-cleanup/lib/math/index | 3 + test/LuaJIT-test-cleanup/lib/math/random.lua | 47 ++ test/LuaJIT-test-cleanup/lib/string/byte.lua | 92 ++ test/LuaJIT-test-cleanup/lib/string/char.lua | 29 + test/LuaJIT-test-cleanup/lib/string/dump.lua | 31 + .../lib/string/format/index | 1 + .../lib/string/format/num.lua | 184 ++++ test/LuaJIT-test-cleanup/lib/string/index | 11 + test/LuaJIT-test-cleanup/lib/string/len.lua | 14 + .../lib/string/lower_upper.lua | 51 ++ .../lib/string/metatable.lua | 3 + .../lib/string/multiple_functions.lua | 16 + test/LuaJIT-test-cleanup/lib/string/rep.lua | 68 ++ .../lib/string/reverse.lua | 13 + test/LuaJIT-test-cleanup/lib/string/sub.lua | 189 +++++ test/LuaJIT-test-cleanup/lib/table/concat.lua | 55 ++ test/LuaJIT-test-cleanup/lib/table/index | 6 + test/LuaJIT-test-cleanup/lib/table/insert.lua | 17 + test/LuaJIT-test-cleanup/lib/table/misc.lua | 58 ++ test/LuaJIT-test-cleanup/lib/table/new.lua | 11 + test/LuaJIT-test-cleanup/lib/table/pack.lua | 7 + test/LuaJIT-test-cleanup/lib/table/remove.lua | 42 + test/LuaJIT-test-cleanup/lib/table/sort.lua | 27 + test/LuaJIT-test-cleanup/misc/alias_alloc.lua | 54 ++ test/LuaJIT-test-cleanup/misc/api_call.lua | 98 +++ test/LuaJIT-test-cleanup/misc/catch_wrap.lua | 45 + .../misc/coro_traceback.lua | 8 + test/LuaJIT-test-cleanup/misc/coro_yield.lua | 111 +++ test/LuaJIT-test-cleanup/misc/debug_gc.lua | 47 ++ test/LuaJIT-test-cleanup/misc/dualnum.lua | 47 ++ test/LuaJIT-test-cleanup/misc/for_dir.lua | 13 + test/LuaJIT-test-cleanup/misc/fori_coerce.lua | 33 + test/LuaJIT-test-cleanup/misc/gc_rechain.lua | 32 + test/LuaJIT-test-cleanup/misc/gc_trace.lua | 37 + test/LuaJIT-test-cleanup/misc/gcstep.lua | 33 + test/LuaJIT-test-cleanup/misc/hook_active.lua | 95 +++ test/LuaJIT-test-cleanup/misc/hook_line.lua | 41 + .../misc/hook_norecord.lua | 12 + test/LuaJIT-test-cleanup/misc/hook_record.lua | 8 + test/LuaJIT-test-cleanup/misc/hook_top.lua | 55 ++ test/LuaJIT-test-cleanup/misc/jit_flush.lua | 50 ++ test/LuaJIT-test-cleanup/misc/lightud.lua | 88 ++ test/LuaJIT-test-cleanup/misc/loop_unroll.lua | 35 + test/LuaJIT-test-cleanup/misc/parse_comp.lua | 13 + test/LuaJIT-test-cleanup/misc/parse_esc.lua | 7 + test/LuaJIT-test-cleanup/misc/parse_misc.lua | 31 + test/LuaJIT-test-cleanup/misc/phi_conv.lua | 53 ++ .../LuaJIT-test-cleanup/misc/recurse_deep.lua | 29 + .../LuaJIT-test-cleanup/misc/recurse_tail.lua | 22 + test/LuaJIT-test-cleanup/misc/stack_gc.lua | 15 + test/LuaJIT-test-cleanup/misc/stack_purge.lua | 25 + test/LuaJIT-test-cleanup/misc/stackov.lua | 40 + test/LuaJIT-test-cleanup/misc/stackovc.lua | 4 + test/LuaJIT-test-cleanup/misc/tcall_base.lua | 20 + test/LuaJIT-test-cleanup/misc/tcall_loop.lua | 8 + .../misc/tonumber_scan.lua | 180 ++++ test/LuaJIT-test-cleanup/misc/uclo.lua | 91 ++ .../misc/unordered_jit.lua | 96 +++ test/LuaJIT-test-cleanup/misc/wbarrier.lua | 7 + .../LuaJIT-test-cleanup/misc/wbarrier_jit.lua | 18 + .../misc/wbarrier_obar.lua | 22 + test/LuaJIT-test-cleanup/opt/dse/array.lua | 197 +++++ test/LuaJIT-test-cleanup/opt/dse/field.lua | 70 ++ test/LuaJIT-test-cleanup/opt/dse/index | 2 + test/LuaJIT-test-cleanup/opt/fold/index | 1 + test/LuaJIT-test-cleanup/opt/fold/kfold.lua | 81 ++ test/LuaJIT-test-cleanup/opt/fuse.lua | 5 + .../opt/fwd/hrefk_rollback.lua | 32 + test/LuaJIT-test-cleanup/opt/fwd/index | 3 + .../LuaJIT-test-cleanup/opt/fwd/tnew_tdup.lua | 69 ++ test/LuaJIT-test-cleanup/opt/fwd/upval.lua | 50 ++ test/LuaJIT-test-cleanup/opt/index | 6 + test/LuaJIT-test-cleanup/opt/loop/index | 1 + test/LuaJIT-test-cleanup/opt/loop/unroll.lua | 32 + test/LuaJIT-test-cleanup/opt/sink/alloc.lua | 126 +++ test/LuaJIT-test-cleanup/opt/sink/ffi.lua | 121 +++ .../opt/sink/ffi_nosink.lua | 45 + test/LuaJIT-test-cleanup/opt/sink/index | 4 + test/LuaJIT-test-cleanup/opt/sink/nosink.lua | 109 +++ test/LuaJIT-test-cleanup/src/cpptest.cpp | 129 +++ test/LuaJIT-test-cleanup/src/ctest.c | 339 ++++++++ test/LuaJIT-test-cleanup/sysdep/catch_cpp.lua | 71 ++ .../sysdep/ffi_include_gtk.lua | 9 + .../sysdep/ffi_include_std.lua | 36 + test/LuaJIT-test-cleanup/sysdep/ffi_lib_c.lua | 87 ++ test/LuaJIT-test-cleanup/sysdep/ffi_lib_z.lua | 107 +++ test/LuaJIT-test-cleanup/test.lua | 416 +++++++++ test/LuaJIT-test-cleanup/trace/exit_frame.lua | 79 ++ .../trace/exit_growstack.lua | 28 + .../LuaJIT-test-cleanup/trace/exit_jfuncf.lua | 30 + .../trace/gc64_slot_revival.lua | 18 + test/LuaJIT-test-cleanup/trace/index | 7 + .../trace/phi/copyspill.lua | 53 ++ test/LuaJIT-test-cleanup/trace/phi/index | 3 + test/LuaJIT-test-cleanup/trace/phi/ref.lua | 131 +++ test/LuaJIT-test-cleanup/trace/phi/rotate.lua | 149 ++++ test/LuaJIT-test-cleanup/trace/snap.lua | 47 ++ test/LuaJIT-test-cleanup/trace/stitch.lua | 19 + .../unportable/ffi_arith_int64.lua | 68 ++ .../unportable/math_special.lua | 55 ++ 197 files changed, 13252 insertions(+) create mode 100644 test/LuaJIT-test-cleanup/CMakeLists.txt create mode 100644 test/LuaJIT-test-cleanup/README.md create mode 100644 test/LuaJIT-test-cleanup/bc/constov.lua create mode 100644 test/LuaJIT-test-cleanup/bc/index create mode 100644 test/LuaJIT-test-cleanup/common/expect_error.lua create mode 100644 test/LuaJIT-test-cleanup/common/ffi_util.inc create mode 100644 test/LuaJIT-test-cleanup/common/test_runner_canary.lua create mode 100644 test/LuaJIT-test-cleanup/computations.lua create mode 100644 test/LuaJIT-test-cleanup/index create mode 100644 test/LuaJIT-test-cleanup/lang/andor.lua create mode 100644 test/LuaJIT-test-cleanup/lang/assignment.lua create mode 100644 test/LuaJIT-test-cleanup/lang/compare.lua create mode 100644 test/LuaJIT-test-cleanup/lang/compare_nan.lua create mode 100644 test/LuaJIT-test-cleanup/lang/concat.lua create mode 100644 test/LuaJIT-test-cleanup/lang/constant/index create mode 100644 test/LuaJIT-test-cleanup/lang/constant/number.lua create mode 100644 test/LuaJIT-test-cleanup/lang/constant/table.lua create mode 100644 test/LuaJIT-test-cleanup/lang/coroutine.lua create mode 100644 test/LuaJIT-test-cleanup/lang/for.lua create mode 100644 test/LuaJIT-test-cleanup/lang/gc.lua create mode 100644 test/LuaJIT-test-cleanup/lang/goto.lua create mode 100644 test/LuaJIT-test-cleanup/lang/index create mode 100644 test/LuaJIT-test-cleanup/lang/length.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/arith.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/arith_jit.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/call.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/cat.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/comp.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/comp_jit.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/debuginfo.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/eq.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/eq_jit.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/framegap.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/index create mode 100644 test/LuaJIT-test-cleanup/lang/meta/index.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/len.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/newindex.lua create mode 100644 test/LuaJIT-test-cleanup/lang/meta/nomm.lua create mode 100644 test/LuaJIT-test-cleanup/lang/modulo.lua create mode 100644 test/LuaJIT-test-cleanup/lang/self.lua create mode 100644 test/LuaJIT-test-cleanup/lang/table.lua create mode 100644 test/LuaJIT-test-cleanup/lang/tail_recursion.lua create mode 100644 test/LuaJIT-test-cleanup/lang/upvalue/closure.lua create mode 100644 test/LuaJIT-test-cleanup/lang/upvalue/index create mode 100644 test/LuaJIT-test-cleanup/lang/vararg_jit.lua create mode 100644 test/LuaJIT-test-cleanup/lib/base/assert.lua create mode 100644 test/LuaJIT-test-cleanup/lib/base/error.lua create mode 100644 test/LuaJIT-test-cleanup/lib/base/getfenv.lua create mode 100644 test/LuaJIT-test-cleanup/lib/base/getsetmetatable.lua create mode 100644 test/LuaJIT-test-cleanup/lib/base/index create mode 100644 test/LuaJIT-test-cleanup/lib/base/ipairs.lua create mode 100644 test/LuaJIT-test-cleanup/lib/base/next.lua create mode 100644 test/LuaJIT-test-cleanup/lib/base/pairs.lua create mode 100644 test/LuaJIT-test-cleanup/lib/base/pcall_jit.lua create mode 100644 test/LuaJIT-test-cleanup/lib/base/select.lua create mode 100644 test/LuaJIT-test-cleanup/lib/base/tonumber_tostring.lua create mode 100644 test/LuaJIT-test-cleanup/lib/base/xpcall_jit.lua create mode 100644 test/LuaJIT-test-cleanup/lib/bit.lua create mode 100644 test/LuaJIT-test-cleanup/lib/contents.lua create mode 100644 test/LuaJIT-test-cleanup/lib/coroutine/index create mode 100644 test/LuaJIT-test-cleanup/lib/coroutine/yield.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/bit64.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/cdata_var.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/copy_fill.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/err.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_arith_ptr.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_bitfield.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_call.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_callback.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_const.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_convert.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_enum.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_gcstep_recursive.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_arith.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_call.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_conv.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_lex_number.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_metatype.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_new.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_array.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_basic.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_cdef.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_struct.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/ffi_tabov.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/index create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/istype.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/jit_array.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/jit_complex.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/jit_misc.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/jit_struct.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/meta_tostring.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/redir.lua create mode 100644 test/LuaJIT-test-cleanup/lib/ffi/type_punning.lua create mode 100644 test/LuaJIT-test-cleanup/lib/index create mode 100644 test/LuaJIT-test-cleanup/lib/math/abs.lua create mode 100644 test/LuaJIT-test-cleanup/lib/math/constants.lua create mode 100644 test/LuaJIT-test-cleanup/lib/math/index create mode 100644 test/LuaJIT-test-cleanup/lib/math/random.lua create mode 100644 test/LuaJIT-test-cleanup/lib/string/byte.lua create mode 100644 test/LuaJIT-test-cleanup/lib/string/char.lua create mode 100644 test/LuaJIT-test-cleanup/lib/string/dump.lua create mode 100644 test/LuaJIT-test-cleanup/lib/string/format/index create mode 100644 test/LuaJIT-test-cleanup/lib/string/format/num.lua create mode 100644 test/LuaJIT-test-cleanup/lib/string/index create mode 100644 test/LuaJIT-test-cleanup/lib/string/len.lua create mode 100644 test/LuaJIT-test-cleanup/lib/string/lower_upper.lua create mode 100644 test/LuaJIT-test-cleanup/lib/string/metatable.lua create mode 100644 test/LuaJIT-test-cleanup/lib/string/multiple_functions.lua create mode 100644 test/LuaJIT-test-cleanup/lib/string/rep.lua create mode 100644 test/LuaJIT-test-cleanup/lib/string/reverse.lua create mode 100644 test/LuaJIT-test-cleanup/lib/string/sub.lua create mode 100644 test/LuaJIT-test-cleanup/lib/table/concat.lua create mode 100644 test/LuaJIT-test-cleanup/lib/table/index create mode 100644 test/LuaJIT-test-cleanup/lib/table/insert.lua create mode 100644 test/LuaJIT-test-cleanup/lib/table/misc.lua create mode 100644 test/LuaJIT-test-cleanup/lib/table/new.lua create mode 100644 test/LuaJIT-test-cleanup/lib/table/pack.lua create mode 100644 test/LuaJIT-test-cleanup/lib/table/remove.lua create mode 100644 test/LuaJIT-test-cleanup/lib/table/sort.lua create mode 100644 test/LuaJIT-test-cleanup/misc/alias_alloc.lua create mode 100644 test/LuaJIT-test-cleanup/misc/api_call.lua create mode 100644 test/LuaJIT-test-cleanup/misc/catch_wrap.lua create mode 100644 test/LuaJIT-test-cleanup/misc/coro_traceback.lua create mode 100644 test/LuaJIT-test-cleanup/misc/coro_yield.lua create mode 100644 test/LuaJIT-test-cleanup/misc/debug_gc.lua create mode 100644 test/LuaJIT-test-cleanup/misc/dualnum.lua create mode 100644 test/LuaJIT-test-cleanup/misc/for_dir.lua create mode 100644 test/LuaJIT-test-cleanup/misc/fori_coerce.lua create mode 100644 test/LuaJIT-test-cleanup/misc/gc_rechain.lua create mode 100644 test/LuaJIT-test-cleanup/misc/gc_trace.lua create mode 100644 test/LuaJIT-test-cleanup/misc/gcstep.lua create mode 100644 test/LuaJIT-test-cleanup/misc/hook_active.lua create mode 100644 test/LuaJIT-test-cleanup/misc/hook_line.lua create mode 100644 test/LuaJIT-test-cleanup/misc/hook_norecord.lua create mode 100644 test/LuaJIT-test-cleanup/misc/hook_record.lua create mode 100644 test/LuaJIT-test-cleanup/misc/hook_top.lua create mode 100644 test/LuaJIT-test-cleanup/misc/jit_flush.lua create mode 100644 test/LuaJIT-test-cleanup/misc/lightud.lua create mode 100644 test/LuaJIT-test-cleanup/misc/loop_unroll.lua create mode 100644 test/LuaJIT-test-cleanup/misc/parse_comp.lua create mode 100644 test/LuaJIT-test-cleanup/misc/parse_esc.lua create mode 100644 test/LuaJIT-test-cleanup/misc/parse_misc.lua create mode 100644 test/LuaJIT-test-cleanup/misc/phi_conv.lua create mode 100644 test/LuaJIT-test-cleanup/misc/recurse_deep.lua create mode 100644 test/LuaJIT-test-cleanup/misc/recurse_tail.lua create mode 100644 test/LuaJIT-test-cleanup/misc/stack_gc.lua create mode 100644 test/LuaJIT-test-cleanup/misc/stack_purge.lua create mode 100644 test/LuaJIT-test-cleanup/misc/stackov.lua create mode 100644 test/LuaJIT-test-cleanup/misc/stackovc.lua create mode 100644 test/LuaJIT-test-cleanup/misc/tcall_base.lua create mode 100644 test/LuaJIT-test-cleanup/misc/tcall_loop.lua create mode 100644 test/LuaJIT-test-cleanup/misc/tonumber_scan.lua create mode 100644 test/LuaJIT-test-cleanup/misc/uclo.lua create mode 100644 test/LuaJIT-test-cleanup/misc/unordered_jit.lua create mode 100644 test/LuaJIT-test-cleanup/misc/wbarrier.lua create mode 100644 test/LuaJIT-test-cleanup/misc/wbarrier_jit.lua create mode 100644 test/LuaJIT-test-cleanup/misc/wbarrier_obar.lua create mode 100644 test/LuaJIT-test-cleanup/opt/dse/array.lua create mode 100644 test/LuaJIT-test-cleanup/opt/dse/field.lua create mode 100644 test/LuaJIT-test-cleanup/opt/dse/index create mode 100644 test/LuaJIT-test-cleanup/opt/fold/index create mode 100644 test/LuaJIT-test-cleanup/opt/fold/kfold.lua create mode 100644 test/LuaJIT-test-cleanup/opt/fuse.lua create mode 100644 test/LuaJIT-test-cleanup/opt/fwd/hrefk_rollback.lua create mode 100644 test/LuaJIT-test-cleanup/opt/fwd/index create mode 100644 test/LuaJIT-test-cleanup/opt/fwd/tnew_tdup.lua create mode 100644 test/LuaJIT-test-cleanup/opt/fwd/upval.lua create mode 100644 test/LuaJIT-test-cleanup/opt/index create mode 100644 test/LuaJIT-test-cleanup/opt/loop/index create mode 100644 test/LuaJIT-test-cleanup/opt/loop/unroll.lua create mode 100644 test/LuaJIT-test-cleanup/opt/sink/alloc.lua create mode 100644 test/LuaJIT-test-cleanup/opt/sink/ffi.lua create mode 100644 test/LuaJIT-test-cleanup/opt/sink/ffi_nosink.lua create mode 100644 test/LuaJIT-test-cleanup/opt/sink/index create mode 100644 test/LuaJIT-test-cleanup/opt/sink/nosink.lua create mode 100644 test/LuaJIT-test-cleanup/src/cpptest.cpp create mode 100644 test/LuaJIT-test-cleanup/src/ctest.c create mode 100644 test/LuaJIT-test-cleanup/sysdep/catch_cpp.lua create mode 100644 test/LuaJIT-test-cleanup/sysdep/ffi_include_gtk.lua create mode 100644 test/LuaJIT-test-cleanup/sysdep/ffi_include_std.lua create mode 100644 test/LuaJIT-test-cleanup/sysdep/ffi_lib_c.lua create mode 100644 test/LuaJIT-test-cleanup/sysdep/ffi_lib_z.lua create mode 100644 test/LuaJIT-test-cleanup/test.lua create mode 100644 test/LuaJIT-test-cleanup/trace/exit_frame.lua create mode 100644 test/LuaJIT-test-cleanup/trace/exit_growstack.lua create mode 100644 test/LuaJIT-test-cleanup/trace/exit_jfuncf.lua create mode 100644 test/LuaJIT-test-cleanup/trace/gc64_slot_revival.lua create mode 100644 test/LuaJIT-test-cleanup/trace/index create mode 100644 test/LuaJIT-test-cleanup/trace/phi/copyspill.lua create mode 100644 test/LuaJIT-test-cleanup/trace/phi/index create mode 100644 test/LuaJIT-test-cleanup/trace/phi/ref.lua create mode 100644 test/LuaJIT-test-cleanup/trace/phi/rotate.lua create mode 100644 test/LuaJIT-test-cleanup/trace/snap.lua create mode 100644 test/LuaJIT-test-cleanup/trace/stitch.lua create mode 100644 test/LuaJIT-test-cleanup/unportable/ffi_arith_int64.lua create mode 100644 test/LuaJIT-test-cleanup/unportable/math_special.lua diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 299766c..5086fa1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -34,9 +34,11 @@ endif() add_custom_target(${PROJECT_NAME}-luacheck DEPENDS luacheck.ok) add_subdirectory(tarantool-tests) +add_subdirectory(LuaJIT-test-cleanup) add_custom_target(${PROJECT_NAME}-test DEPENDS tarantool-tests + LuaJIT-test-cleanup ) if(LUAJIT_USE_TEST) diff --git a/test/LuaJIT-test-cleanup/CMakeLists.txt b/test/LuaJIT-test-cleanup/CMakeLists.txt new file mode 100644 index 0000000..a40d028 --- /dev/null +++ b/test/LuaJIT-test-cleanup/CMakeLists.txt @@ -0,0 +1,14 @@ +# See the rationale in the root CMakeLists.txt +cmake_minimum_required(VERSION 3.1 FATAL_ERROR) + +add_custom_command( + COMMENT "Running LuaJIT-test-cleanup" + OUTPUT tests.ok + DEPENDS ${LUAJIT_TEST_BINARY} + COMMAND + ${LUAJIT_TEST_BINARY} ${CMAKE_CURRENT_SOURCE_DIR}/test.lua + && touch tests.ok + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +add_custom_target(LuaJIT-test-cleanup DEPENDS tests.ok) diff --git a/test/LuaJIT-test-cleanup/README.md b/test/LuaJIT-test-cleanup/README.md new file mode 100644 index 0000000..ff16ac8 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/bc/constov.lua b/test/LuaJIT-test-cleanup/bc/constov.lua new file mode 100644 index 0000000..5827840 --- /dev/null +++ b/test/LuaJIT-test-cleanup/bc/constov.lua @@ -0,0 +1,16 @@ + +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/LuaJIT-test-cleanup/bc/index b/test/LuaJIT-test-cleanup/bc/index new file mode 100644 index 0000000..dead10f --- /dev/null +++ b/test/LuaJIT-test-cleanup/bc/index @@ -0,0 +1 @@ +constov.lua +slow diff --git a/test/LuaJIT-test-cleanup/common/expect_error.lua b/test/LuaJIT-test-cleanup/common/expect_error.lua new file mode 100644 index 0000000..e155090 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/common/ffi_util.inc b/test/LuaJIT-test-cleanup/common/ffi_util.inc new file mode 100644 index 0000000..1eee8dd --- /dev/null +++ b/test/LuaJIT-test-cleanup/common/ffi_util.inc @@ -0,0 +1,41 @@ +-- This should be turned into a proper module and not use globals. +-- Or combined into a generiv test utility module. With FFI +-- functionality turned off, if the FFI module is not built-in. + +local ffi = require("ffi") + +function checkfail(t, f) + f = f or ffi.typeof + for i=1,1e9 do + local tp = t[i] + if not tp then break end + assert(pcall(f, tp) == false, tp) + end +end + +function checktypes(t) + for i=1,1e9,3 do + local tp = t[i+2] + if not tp then break end + local id = ffi.typeof(tp) + assert(ffi.sizeof(id) == t[i], tp) + assert(ffi.alignof(id) == t[i+1], tp) + end +end + +function fails(f, ...) + if pcall(f, ...) ~= false then error("failure expected", 2) end +end + +local incroot = os.getenv("INCROOT") or "/usr/include" +local cdefs = os.getenv("CDEFS") or "" + +function include(name) + local flags = ffi.abi("32bit") and "-m32" or "-m64" + if string.sub(name, 1, 1) ~= "/" then name = incroot.."/"..name end + local fp = assert(io.popen("cc -E -P "..flags.." "..cdefs.." "..name)) + local s = fp:read("*a") + fp:close() + ffi.cdef(s) +end + diff --git a/test/LuaJIT-test-cleanup/common/test_runner_canary.lua b/test/LuaJIT-test-cleanup/common/test_runner_canary.lua new file mode 100644 index 0000000..fc9cadc --- /dev/null +++ b/test/LuaJIT-test-cleanup/common/test_runner_canary.lua @@ -0,0 +1 @@ +return "canary is alive" diff --git a/test/LuaJIT-test-cleanup/computations.lua b/test/LuaJIT-test-cleanup/computations.lua new file mode 100644 index 0000000..4fce7fc --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/index b/test/LuaJIT-test-cleanup/index new file mode 100644 index 0000000..bd4081e --- /dev/null +++ b/test/LuaJIT-test-cleanup/index @@ -0,0 +1,6 @@ +lang +lib +bc +luajit>=2 +computations.lua +trace +jit +opt +jit diff --git a/test/LuaJIT-test-cleanup/lang/andor.lua b/test/LuaJIT-test-cleanup/lang/andor.lua new file mode 100644 index 0000000..55b2c75 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lang/assignment.lua b/test/LuaJIT-test-cleanup/lang/assignment.lua new file mode 100644 index 0000000..e9745ef --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lang/compare.lua b/test/LuaJIT-test-cleanup/lang/compare.lua new file mode 100644 index 0000000..09c5488 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/compare.lua @@ -0,0 +1,323 @@ +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 + +do --- String comparisons: + local function str_cmp(a, b, lt, gt, le, ge) + assert(ab == gt) + assert(a<=b == le) + assert(a>=b == ge) + assert((not (ab)) == (not gt)) + assert((not (a<=b)) == (not le)) + assert((not (a>=b)) == (not ge)) + end + + local function str_lo(a, b) + str_cmp(a, b, true, false, true, false) + end + + local function str_eq(a, b) + str_cmp(a, b, false, false, true, true) + end + + local function str_hi(a, b) + str_cmp(a, b, false, true, false, true) + end + + str_lo("a", "b") + str_eq("a", "a") + str_hi("b", "a") + + str_lo("a", "aa") + str_hi("aa", "a") + + str_lo("a", "a\0") + str_hi("a\0", "a") +end + +do --- obj_eq/ne + local function obj_eq(a, b) + assert(a==b == true) + assert(a~=b == false) + end + + local function obj_ne(a, b) + assert(a==b == false) + assert(a~=b == true) + end + + obj_eq(nil, nil) + obj_ne(nil, false) + obj_ne(nil, true) + + obj_ne(false, nil) + obj_eq(false, false) + obj_ne(false, true) + + obj_ne(true, nil) + obj_ne(true, false) + obj_eq(true, true) + + obj_eq(1, 1) + obj_ne(1, 2) + obj_ne(2, 1) + + obj_eq("a", "a") + obj_ne("a", "b") + obj_ne("a", 1) + obj_ne(1, "a") + + local t, t2 = {}, {} + obj_eq(t, t) + obj_ne(t, t2) + obj_ne(t, 1) + obj_ne(t, "") +end diff --git a/test/LuaJIT-test-cleanup/lang/compare_nan.lua b/test/LuaJIT-test-cleanup/lang/compare_nan.lua new file mode 100644 index 0000000..878f39a --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/compare_nan.lua @@ -0,0 +1,99 @@ + +local function check(a, b) + if a ~= b then + error("check failed with "..tostring(a).." ~= "..tostring(b), 2) + end +end + +local nan, one = 0/0, 1 + +do --- nan nan + check(nannan, false) + check(nan>=nan, false) + check(nan==nan, false) + check(nan~=nan, true) +end + +do --- nan one + check(nanone, false) + check(nan>=one, false) + check(nan==one, false) + check(nan~=one, true) +end + +do --- one nan + check(onenan, false) + check(one>=nan, false) + check(one==nan, false) + check(one~=nan, true) +end + +do --- nan 1 + check(nan<1, false) + check(nan<=1, false) + check(nan>1, false) + check(nan>=1, false) + check(nan==1, false) + check(nan~=1, true) +end + +do --- 1 nan + check(1nan, false) + check(1>=nan, false) + check(1==nan, false) + check(1~=nan, true) +end + +do --- not nan nan + check(not (nannan), true) + check(not (nan>=nan), true) + check(not (nan==nan), true) + check(not (nan~=nan), false) +end + +do --- not nan one + check(not (nanone), true) + check(not (nan>=one), true) + check(not (nan==one), true) + check(not (nan~=one), false) +end + +do --- not one nan + check(not (onenan), true) + check(not (one>=nan), true) + check(not (one==nan), true) + check(not (one~=nan), false) +end + +do --- not nan 1 + check(not (nan<1), true) + check(not (nan<=1), true) + check(not (nan>1), true) + check(not (nan>=1), true) + check(not (nan==1), true) + check(not (nan~=1), false) +end + +do --- not 1 nan + check(not (1nan), true) + check(not (1>=nan), true) + check(not (1==nan), true) + check(not (1~=nan), false) +end + diff --git a/test/LuaJIT-test-cleanup/lang/concat.lua b/test/LuaJIT-test-cleanup/lang/concat.lua new file mode 100644 index 0000000..04d665b --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/concat.lua @@ -0,0 +1,112 @@ +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 + +do --- Very long strings + for i, s in ipairs{"a", "bc", "def"} do + for n = 1, 20 do + s = s .. s + end + assert(#s == 2^20*i) + assert(s:sub(1, 6) == s:sub(7, 12)) + assert(s:sub(1, 6) == s:sub(-6, -1)) + end +end diff --git a/test/LuaJIT-test-cleanup/lang/constant/index b/test/LuaJIT-test-cleanup/lang/constant/index new file mode 100644 index 0000000..e738357 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/constant/index @@ -0,0 +1,2 @@ +number.lua +table.lua diff --git a/test/LuaJIT-test-cleanup/lang/constant/number.lua b/test/LuaJIT-test-cleanup/lang/constant/number.lua new file mode 100644 index 0000000..fb67356 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lang/constant/table.lua b/test/LuaJIT-test-cleanup/lang/constant/table.lua new file mode 100644 index 0000000..899d0f6 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/constant/table.lua @@ -0,0 +1,15 @@ + +do --- tnew + local a = nil + local b = {} + local t = {[true] = a, [false] = b or 1} + assert(t[true] == nil) + assert(t[false] == b) +end + +do --- tdup + local b = {} + local t = {[true] = nil, [false] = b or 1} + assert(t[true] == nil) + assert(t[false] == b) +end diff --git a/test/LuaJIT-test-cleanup/lang/coroutine.lua b/test/LuaJIT-test-cleanup/lang/coroutine.lua new file mode 100644 index 0000000..405135c --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lang/for.lua b/test/LuaJIT-test-cleanup/lang/for.lua new file mode 100644 index 0000000..4982b32 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lang/gc.lua b/test/LuaJIT-test-cleanup/lang/gc.lua new file mode 100644 index 0000000..35e6a1f --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/gc.lua @@ -0,0 +1,42 @@ +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 + +do --- TSETM gc + local function f() + collectgarbage() + return "a", "b" + end + for i = 1, 10 do + local t = {f()} + assert(t[1] == "a") + assert(t[2] == "b") + end +end diff --git a/test/LuaJIT-test-cleanup/lang/goto.lua b/test/LuaJIT-test-cleanup/lang/goto.lua new file mode 100644 index 0000000..1563a23 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/goto.lua @@ -0,0 +1,149 @@ +local loadstring = loadstring or load + +local function expect(src, msg) + local ok, err = loadstring(src) + if msg then + assert(not ok and string.find(err, msg), err) + else + assert(ok, err) + end +end + +do --- Basic goto and label semantics. + -- Error: duplicate label. + expect("::a:: ::a::", "'a'") + expect("::a:: ::b:: do ::b:: end ::a::", "'a'") + + -- Error: undefined label. + expect("goto a", "'a'") + expect("goto a; ::b::", "'a'") + expect("do ::a:: end; goto a", "'a'") + expect("goto a; do ::a:: end", "'a'") + expect("break", "break") + expect("if x then break end", "break") + + -- Error: goto into variable scope. + expect("goto a; local x; ::a:: local y", "'x'") + expect("do local v,w; goto a; end; local x; ::a:: local y", "'x'") + expect("repeat goto a; local x; ::a:: until x", "'x'") + + ::a:: do goto a; ::a:: end -- Forward jump, not an infinite loop. +end + +do --- Goto is not a keyword. -compat5.2 !lex !private_G + goto = 1 +end + +do --- Goto is a keyword. +compat5.2 + expect("goto = 1", "") +end + +do --- Trailing label is considered to be out of scope. + local x = 11 + do + goto a + goto a + local y = 22 + x = y + ::a:: + ::b:: + end + assert(x == 11) +end + +do --- Trailing labels and empty statements are considered to be out of scope. +compat5.2 !lex + local x = 11 + do + goto a + goto a + local y = 22 + x = y + ::a:: ;; + ::b:: ;; + end + assert(x == 11) +end + +do --- Simple loop with cross-jumping. + local x = 1 + while true do + goto b + ::a:: if x < 100 then goto c end + goto d + ::b:: x = x + 1; goto a + ::c:: + end + ::d:: + assert(x == 100) +end + +do --- Backwards goto must close upval. + local t = {} + local i = 1 + ::a:: + local x + t[i] = function() return x end + x = i + i = i + 1 + if i <= 2 then goto a end + assert(t[1]() == 1) + assert(t[2]() == 2) +end + +do --- Break must close upval, even if closure is parsed after break. + local foo + repeat + local x + ::a:: + if x then break end + function foo() return x end + x = true + goto a + until false + assert(foo() == true) +end + +do --- Label prevents joining to KNIL. -lua==5.2 + local k = 0 + local x + ::foo:: + local y + assert(y == nil) + y = true + k = k + 1 + if k < 2 then goto foo end +end + +do --- Break resolved from the right scope. + local function p(lvl) + lvl = lvl or 1 + while true do + lvl = lvl + 1 + if lvl == nil then break end + local idx = 1 + while true do + if key == nil then break end + idx = idx + 1 + end + end + end +end + +do --- Do not join twice with UCLO. + while true do + do + local x + local function f() return x end + end + break + end + + while true do + do + local x + local function f() return x end + end + goto foo + end + ::foo:: +end diff --git a/test/LuaJIT-test-cleanup/lang/index b/test/LuaJIT-test-cleanup/lang/index new file mode 100644 index 0000000..88e2edf --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/index @@ -0,0 +1,18 @@ +andor.lua +assignment.lua +compare.lua +compare_nan.lua +constant +for.lua +length.lua +modulo.lua +concat.lua +self.lua +table.lua +upvalue +coroutine.lua +tail_recursion.lua +vararg_jit.lua +gc.lua +goto.lua +goto +meta diff --git a/test/LuaJIT-test-cleanup/lang/length.lua b/test/LuaJIT-test-cleanup/lang/length.lua new file mode 100644 index 0000000..67c68ae --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/length.lua @@ -0,0 +1,23 @@ + +do --- length increasing and decreasing in loop + local t = {} + for i=1,100 do t[#t+1] = i end + assert(#t == 100) + for i=1,100 do t[#t] = nil end + assert(#t == 0) +end + +do --- length increasing in loop with existing element + local t = {} + t[90] = 999 + for i=1,100 do t[#t+1] = i end + assert(#t > 100 and t[#t] == 100) +end + +do --- length decreasing in loop with erased element + local t = {} + for i=1,100 do t[i] = i end + t[10] = nil + for i=1,99 do t[#t] = nil end + assert(#t == 0) +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/arith.lua b/test/LuaJIT-test-cleanup/lang/meta/arith.lua new file mode 100644 index 0000000..17de4c8 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/arith.lua @@ -0,0 +1,118 @@ +local function create(arith, v1, v2) + local meta = { + __add=function(a,b) return arith("add", a, b) end, + __sub=function(a,b) return arith("sub", a, b) end, + __mul=function(a,b) return arith("mul", a, b) end, + __div=function(a,b) return arith("div", a, b) end, + __mod=function(a,b) return arith("mod", a, b) end, + __pow=function(a,b) return arith("pow", a, b) end, + __unm=function(a,b) return arith("unm", a, b) end, + } + return setmetatable({v1}, meta), setmetatable({v2}, meta) +end + +do --- op + local a, b = create(function(op,a,b) return op end) + assert(a+b == "add") + assert(a-b == "sub") + assert(a*b == "mul") + assert(a/b == "div") + assert(a%b == "mod") + assert(a^b == "pow") + assert(-a == "unm") +end + +do --- lhs + local a, b = create(function(op,a,b) return a[1] end, "foo", 42) + assert(a+b == "foo") + assert(a-b == "foo") + assert(a*b == "foo") + assert(a/b == "foo") + assert(a%b == "foo") + assert(a^b == "foo") + assert(-a == "foo") +end + +do --- rhs + local a, b = create(function(op,a,b) return b[1] end, 42, "foo") + assert(a+b == "foo") + assert(a-b == "foo") + assert(a*b == "foo") + assert(a/b == "foo") + assert(a%b == "foo") + assert(a^b == "foo") + assert(-a == 42) +end + +do --- meta only lhs + local a, b = create(function(op,a,b) return a[1]+b end, 39), 3 + assert(a+b == 42) + assert(a-b == 42) + assert(a*b == 42) + assert(a/b == 42) + assert(a%b == 42) + assert(a^b == 42) +end + +do --- meta only rhs + local a, b = 39, create(function(op,a,b) return a+b[1] end, 3) + assert(a+b == 42) + assert(a-b == 42) + assert(a*b == 42) + assert(a/b == 42) + assert(a%b == 42) + assert(a^b == 42) +end + +do --- defaults string, int + local a, b = "39", 3 + assert(a+b == 42) + assert(a-b == 36) + assert(a*b == 117) + assert(a/b == 13) + assert(a%b == 0) + assert(a^b == 59319) + assert(-a == -39) +end + +do --- defaults int, string + local a, b = 39, "3" + assert(a+b == 42) + assert(a-b == 36) + assert(a*b == 117) + assert(a/b == 13) + assert(a%b == 0) + assert(a^b == 59319) + assert(-a == -39) +end + +do --- defaults string, string + local a, b = "39", "3" + assert(a+b == 42) + assert(a-b == 36) + assert(a*b == 117) + assert(a/b == 13) + assert(a%b == 0) + assert(a^b == 59319) + assert(-a == -39) +end + +do --- defaults string, kint + local a = "39" + assert(a+3 == 42) + assert(a-3 == 36) + assert(a*3 == 117) + assert(a/3 == 13) + assert(a%3 == 0) + assert(a^3 == 59319) +end + +do --- defaults kint, string + local b = "3" + assert(39+b == 42) + assert(39-b == 36) + assert(39*b == 117) + assert(39/b == 13) + assert(39%b == 0) + assert(39^b == 59319) +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/arith_jit.lua b/test/LuaJIT-test-cleanup/lang/meta/arith_jit.lua new file mode 100644 index 0000000..2cb35db --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/arith_jit.lua @@ -0,0 +1,68 @@ + +do --- assert rhs + local t = {} + local mt = { + __add = function(a, b) assert(b == t); return a+11 end, + __sub = function(a, b) assert(b == t); return a+12 end, + __mul = function(a, b) assert(b == t); return a+13 end, + __div = function(a, b) assert(b == t); return a+14 end, + __mod = function(a, b) assert(b == t); return a+15 end, + __pow = function(a, b) assert(b == t); return a+16 end, + __unm = function(a, b) assert(a == t and b == t); return 17 end, + } + t = setmetatable(t, mt) + do local x = 0; for i=1,100 do x = x + t end; assert(x == 1100); end + do local x = 0; for i=1,100 do x = x - t end; assert(x == 1200); end + do local x = 0; for i=1,100 do x = x * t end; assert(x == 1300); end + do local x = 0; for i=1,100 do x = x / t end; assert(x == 1400); end + do local x = 0; for i=1,100 do x = x % t end; assert(x == 1500); end + do local x = 0; for i=1,100 do x = x ^ t end; assert(x == 1600); end + do local x = 0; for i=1,100 do x = x + (-t) end; assert(x == 1700); end +end + +do --- assert lhs + local t = {} + local mt = { + __add = function(a, b) assert(a == t); return b+11 end, + __sub = function(a, b) assert(a == t); return b+12 end, + __mul = function(a, b) assert(a == t); return b+13 end, + __div = function(a, b) assert(a == t); return b+14 end, + __mod = function(a, b) assert(a == t); return b+15 end, + __pow = function(a, b) assert(a == t); return b+16 end, + } + t = setmetatable(t, mt) + do local x = 0; for i=1,100 do x = t + x end; assert(x == 1100); end + do local x = 0; for i=1,100 do x = t - x end; assert(x == 1200); end + do local x = 0; for i=1,100 do x = t * x end; assert(x == 1300); end + do local x = 0; for i=1,100 do x = t / x end; assert(x == 1400); end + do local x = 0; for i=1,100 do x = t % x end; assert(x == 1500); end + do local x = 0; for i=1,100 do x = t ^ x end; assert(x == 1600); end +end + +do --- assert both sides + local t = {} + local mt = { + __add = function(a, b) assert(a == t and b == t); return 11 end, + __sub = function(a, b) assert(a == t and b == t); return 12 end, + __mul = function(a, b) assert(a == t and b == t); return 13 end, + __div = function(a, b) assert(a == t and b == t); return 14 end, + __mod = function(a, b) assert(a == t and b == t); return 15 end, + __pow = function(a, b) assert(a == t and b == t); return 16 end, + } + t = setmetatable(t, mt) + do local x = 0; for i=1,100 do x = t + t end; assert(x == 11); end + do local x = 0; for i=1,100 do x = t - t end; assert(x == 12); end + do local x = 0; for i=1,100 do x = t * t end; assert(x == 13); end + do local x = 0; for i=1,100 do x = t / t end; assert(x == 14); end + do local x = 0; for i=1,100 do x = t % t end; assert(x == 15); end + do local x = 0; for i=1,100 do x = t ^ t end; assert(x == 16); end +end + +do --- adjust no result to one result + local t = {} + local mt = { __add = function(a, b) end } + t = setmetatable(t, mt) + local x + for i=1,100 do x = t+t end + assert(x == nil) +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/call.lua b/test/LuaJIT-test-cleanup/lang/meta/call.lua new file mode 100644 index 0000000..c77c0dd --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/call.lua @@ -0,0 +1,81 @@ + +local function callmeta(o, a, b) + return o, a, b +end + +local meta = { __call = callmeta } + +do --- table + local t = setmetatable({}, meta) + local o,a,b = t() + assert(o == t and a == nil and b == nil) + local o,a,b = t("foo") + assert(o == t and a == "foo" and b == nil) + local o,a,b = t("foo", "bar") + assert(o == t and a == "foo" and b == "bar") +end + +do --- userdata +lua<5.2 + local u = newproxy(true) + getmetatable(u).__call = callmeta + + local o,a,b = u() + assert(o == u and a == nil and b == nil) + local o,a,b = u("foo") + assert(o == u and a == "foo" and b == nil) + local o,a,b = u("foo", "bar") + assert(o == u and a == "foo" and b == "bar") +end + +do --- number + debug.setmetatable(0, meta) + local o,a,b = (42)() + assert(o == 42 and a == nil and b == nil) + local o,a,b = (42)("foo") + assert(o == 42 and a == "foo" and b == nil) + local o,a,b = (42)("foo", "bar") + assert(o == 42 and a == "foo" and b == "bar") + debug.setmetatable(0, nil) +end + +do --- table with changing metamethod + local tc = setmetatable({}, { __call = function(o,a,b) return o end}) + local ta = setmetatable({}, { __add = tc}) + local o,a = ta + ta + assert(o == tc and a == nil) + + getmetatable(tc).__call = function(o,a,b) return a end + local o,a = ta + ta + assert(o == ta and a == nil) +end + +do --- jit table + local t = setmetatable({}, { __call = function(t, a) return 100-a end }) + for i=1,100 do assert(t(i) == 100-i) end +end + +do --- jit table rawget as metamethod + local t = setmetatable({}, { __call = rawget }) + for i=1,100 do t[i] = 100-i end + for i=1,100 do assert(t(i) == 100-i) end +end + +do --- jit number + debug.setmetatable(0, { __call = function(n) return 100-n end }) + for i=1,100 do assert((i)() == 100-i) end + debug.setmetatable(0, nil) +end + +do --- jit newindex pcall + local t = setmetatable({}, { __newindex = pcall, __call = rawset }) + for i=1,100 do t[i] = 100-i end + for i=1,100 do assert(t[i] == 100-i) end +end + +do --- jit index pcall + local t = setmetatable({}, { + __index = pcall, __newindex = rawset, + __call = function(t, i) t[i] = 100-i end, + }) + for i=1,100 do assert(t[i] == true and rawget(t, i) == 100-i) end +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/cat.lua b/test/LuaJIT-test-cleanup/lang/meta/cat.lua new file mode 100644 index 0000000..48a89e4 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/cat.lua @@ -0,0 +1,61 @@ +local function create(cat, v1, v2) + local meta = { __concat = cat } + return setmetatable({v1}, meta), setmetatable({v2}, meta) +end + +do --- default + local a, b, c = "foo", "bar", "baz" + assert(a..b == "foobar") + assert(a..b..c == "foobarbaz") +end + +do --- lhs + local a, b = create(function(a, b) return a end) + assert(a..b == a) + assert(b..a == b) + assert(a..b..b == a) + assert(a..a..b == a) + assert(a..b..a == a) + assert(a..b..b..b..b..b..b..b == a) +end + +do --- rhs + local a, b = create(function(a, b) return b end) + assert(a..b == b) + assert(b..a == a) + assert(a..b..b == b) + assert(a..a..b == b) + assert(b..b..a == a) + assert(a..a..a..a..a..a..a..b == b) +end + +do --- mixed types + local a, b = create(function(a, b) + return (type(a) == "string" and a or a[1]).. + (type(b) == "string" and b or b[1]) + end, "a", "b") + assert(a..b == "ab") + assert(a..b == "ab") + assert(a..b..b == "abb") + assert(a..b..a == "aba") + assert(a..a..a..a..a..a..a..b == "aaaaaaab") + assert(a..a..a.."x".."x"..a..a..b == "aaaxxaab") + assert("x"..a..a..a..a..a..a..b == "xaaaaaab") + assert(a..b..a..b..a.."x".."x".."x" == "ababaxxx") +end + +do --- jit mixed types + local a, b = create(function(a, b) + if a ~= b then local x = gg end + return (type(a) == "string" and a or a[1]).. + (type(b) == "string" and b or b[1]) + end, "a", "b") + local y + for i=1,100 do y = a..b end + assert(y == "ab") + for i=1,100 do y = a..b.."x" end + assert(y == "abx") + for i=1,100 do y = a..b.. 1 .. "z" end + assert(y == "ab1z") +end + diff --git a/test/LuaJIT-test-cleanup/lang/meta/comp.lua b/test/LuaJIT-test-cleanup/lang/meta/comp.lua new file mode 100644 index 0000000..23f18b0 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/comp.lua @@ -0,0 +1,120 @@ + +local function create(comp, v1, v2) + local meta = { + __lt=function(a,b) return comp("lt", a, b) end, + __le=function(a,b) return comp("le", a, b) end, + } + return setmetatable({v1}, meta), setmetatable({v2}, meta) +end + +do --- __lt and __le xop + local xop + local a, b = create(function(op,a,b) xop = op; return "" end) + assert(ab == true and xop == "lt"); xop = nil + assert(a<=b == true and xop == "le"); xop = nil + assert(a>=b == true and xop == "le"); xop = nil + + assert(not (ab) == false and xop == "lt"); xop = nil + assert(not (a<=b) == false and xop == "le"); xop = nil + assert(not (a>=b) == false and xop == "le"); xop = nil + + -- __le metamethod is optional and substituted with arg+res inverted __lt. + local f = getmetatable(a).__le + getmetatable(a).__le = nil + assert(ab == true and xop == "lt"); xop = nil + assert(a<=b == false and xop == "lt"); xop = nil + assert(a>=b == false and xop == "lt"); xop = nil + + assert(not (ab) == false and xop == "lt"); xop = nil + assert(not (a<=b) == true and xop == "lt"); xop = nil + assert(not (a>=b) == true and xop == "lt"); xop = nil + getmetatable(a).__le = f + + -- Different metatable, but same metamethod works, too. + setmetatable(b, { __lt = getmetatable(b).__lt, __le = getmetatable(b).__le }) + assert(ab == true and xop == "lt"); xop = nil + assert(a<=b == true and xop == "le"); xop = nil + assert(a>=b == true and xop == "le"); xop = nil + + assert(not (ab) == false and xop == "lt"); xop = nil + assert(not (a<=b) == false and xop == "le"); xop = nil + assert(not (a>=b) == false and xop == "le"); xop = nil +end + +do --- __lt and __le values + local a, b = create(function(op,a,b) + if op == "lt" then return a[1]b == false) + assert(a<=b == true) + assert(a>=b == false) + + assert(not (ab) == true) + assert(not (a<=b) == false) + assert(not (a>=b) == true) + + b[1] = 1 + assert(ab == false) + assert(a<=b == true) + assert(a>=b == true) + + assert(not (ab) == true) + assert(not (a<=b) == false) + assert(not (a>=b) == false) + + a[1] = 2 + assert(ab == true) + assert(a<=b == false) + assert(a>=b == true) + + assert(not (ab) == false) + assert(not (a<=b) == true) + assert(not (a>=b) == false) + + -- __le metamethod is optional and substituted with arg+res inverted __lt. + getmetatable(a).__le = nil + a[1] = 1 + b[1] = 2 + assert(ab == false) + assert(a<=b == true) + assert(a>=b == false) + + assert(not (ab) == true) + assert(not (a<=b) == false) + assert(not (a>=b) == true) + + b[1] = 1 + assert(ab == false) + assert(a<=b == true) + assert(a>=b == true) + + assert(not (ab) == true) + assert(not (a<=b) == false) + assert(not (a>=b) == false) + + a[1] = 2 + assert(ab == true) + assert(a<=b == false) + assert(a>=b == true) + + assert(not (ab) == false) + assert(not (a<=b) == true) + assert(not (a>=b) == false) +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/comp_jit.lua b/test/LuaJIT-test-cleanup/lang/meta/comp_jit.lua new file mode 100644 index 0000000..d0a19d8 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/comp_jit.lua @@ -0,0 +1,104 @@ +do --- coverage + local lt, le = false, false + local t, u = {}, {} + local x, ax, bx + local function ck(xx, a, b) + if x ~= xx then error("bad x", 2) end + if ax ~= a then error("bad ax", 2) end + if bx ~= b then error("bad bx", 2) end + end + local mt = { + __lt = function(a, b) ax=a; bx=b; return lt end, + __le = function(a, b) ax=a; bx=b; return le end, + } + t = setmetatable(t, mt) + u = setmetatable(u, mt) + lt, le = false, false + x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(1, u, t) + x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(1, u, t) + x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(2, u, t) + x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(2, u, t) + lt, le = false, true + x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(1, u, t) + x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(2, u, t) + x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(2, u, t) + x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(1, u, t) + lt, le = true, false + x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(2, u, t) + x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(1, u, t) + x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(1, u, t) + x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(2, u, t) + lt, le = true, true + x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(2, u, t) + x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(2, u, t) + x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(1, u, t) + x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(1, u, t) + mt.__le = nil + lt = false + x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(2, u, t) + x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(1, u, t) + x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(1, u, t) + x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(2, u, t) + x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(1, t, u) + lt = true + x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(1, u, t) + x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(2, u, t) + x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(2, u, t) + x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(1, u, t) + x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(2, t, u) +end + +do --- Mixed metamethods for ordered comparisons. + local mt1 = { __lt = function(a, b) return a[1] < b[1] end } + local mt2 = { __lt = function(a, b) return a[1] < b[1] end } + local t1 = setmetatable({1}, mt1) + local t2 = setmetatable({2}, mt2) + do + local x + for i=1,100 do x = t1 <= t1 end + assert(x == true) + end + local ok, ret = pcall(function() + local x + for i=1,100 do x = t1 < t2 end + return x + end) + if table.pack then + assert(ok and ret == true) + else + assert(not ok) + end + local ok, ret = pcall(function() + local x + for i=1,100 do x = t1 <= t2 end + return x + end) + if table.pack then + assert(ok and ret == true) + else + assert(not ok) + end +end + diff --git a/test/LuaJIT-test-cleanup/lang/meta/debuginfo.lua b/test/LuaJIT-test-cleanup/lang/meta/debuginfo.lua new file mode 100644 index 0000000..a99941f --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/debuginfo.lua @@ -0,0 +1,81 @@ + +local what + +local function mm(a, b) + local dbg = debug.getinfo(1) + what = dbg.namewhat == "metamethod" and dbg.name or + dbg.namewhat.." "..(dbg.name or "?") +end + +local function ck(s) + assert(what == s, "bad debug info for metamethod "..s) +end + +local mt = { + __index = mm, + __newindex = mm, + __eq = mm, + __add = mm, + __sub = mm, + __mul = mm, + __div = mm, + __mod = mm, + __pow = mm, + __unm = mm, + __len = mm, + __lt = mm, + __le = mm, + __concat = mm, + __call = mm, +} + +do --- table metamethods +goto + local t = setmetatable({}, mt) + local t2 = setmetatable({}, mt) + + local x = t.x; ck("__index") + t.x = 1; ck("__newindex") + local x = t + t; ck("__add") + local x = t - t; ck("__sub") + local x = t * t; ck("__mul") + local x = t / t; ck("__div") + local x = t % t; ck("__mod") + local x = t ^ t; ck("__pow") + local x = -t; ck("__unm") + local x = t..t; ck("__concat") + local x = t(); ck("local t") + + local x = t == t2; ck("__eq") + local x = t ~= t2; ck("__eq") + local x = t < t2; ck("__lt") + local x = t > t2; ck("__lt") + local x = t <= t2; ck("__le") + local x = t >= t2; ck("__le") +end + +do --- userdata metamethods +luajit + local u = newproxy() + local u2 = newproxy() + debug.setmetatable(u, mt) + debug.setmetatable(u2, mt) + + local x = u.x; ck("__index") + u.x = 1; ck("__newindex") + local x = u + u; ck("__add") + local x = u - u; ck("__sub") + local x = u * u; ck("__mul") + local x = u / u; ck("__div") + local x = u % u; ck("__mod") + local x = u ^ u; ck("__pow") + local x = -u; ck("__unm") + local x = #u; ck("__len") + local x = u..u; ck("__concat") + local x = u(); ck("local u") + + local x = u == u2; ck("__eq") + local x = u ~= u2; ck("__eq") + local x = u < u2; ck("__lt") + local x = u > u2; ck("__lt") + local x = u <= u2; ck("__le") + local x = u >= u2; ck("__le") +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/eq.lua b/test/LuaJIT-test-cleanup/lang/meta/eq.lua new file mode 100644 index 0000000..ebf6043 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/eq.lua @@ -0,0 +1,30 @@ +local function create(equal, v1, v2) + local meta = { __eq = equal } + return setmetatable({v1}, meta), setmetatable({v2}, meta) +end + +do --- __eq xop + local xop + local a, b = create(function(a,b) xop = "eq" return "" end) + assert(a==b == true and xop == "eq"); xop = nil + assert(a~=b == false and xop == "eq"); xop = nil + + -- Different metatable, but same metamethod works, too. + setmetatable(b, { __eq = getmetatable(b).__eq }) + assert(a==b == true and xop == "eq"); xop = nil + assert(a~=b == false and xop == "eq"); xop = nil +end + +do --- __eq values + local a, b = create(function(a,b) return a[1] == b[1] end, 1, 2) + assert(a==b == false) + assert(a~=b == true) + + b[1] = 1 + assert(a==b == true) + assert(a~=b == false) + + a[1] = 2 + assert(a==b == false) + assert(a~=b == true) +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/eq_jit.lua b/test/LuaJIT-test-cleanup/lang/meta/eq_jit.lua new file mode 100644 index 0000000..47e1420 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/eq_jit.lua @@ -0,0 +1,35 @@ + +do --- coverage + local eq = false + local t, u = {}, {} + local x, ax, bx + local function ck(xx, a, b) + if x ~= xx then error("bad x", 2) end + if ax ~= a then error("bad ax", 2) end + if bx ~= b then error("bad bx", 2) end + end + local mt = { + __eq = function(a, b) ax=a; bx=b; return eq end, + } + t = setmetatable(t, mt) + u = setmetatable(u, mt) + eq = false + x = 0; for i=1,100 do x = t == u and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = t ~= u and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = not (t == u) and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = not (t ~= u) and 2 or 1 end ck(1, t, u) + eq = true + x = 0; for i=1,100 do x = t == u and 2 or 1 end ck(2, t, u) + x = 0; for i=1,100 do x = t ~= u and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = not (t == u) and 2 or 1 end ck(1, t, u) + x = 0; for i=1,100 do x = not (t ~= u) and 2 or 1 end ck(2, t, u) +end + +do --- non-constant objects +bit + local bit = require("bit") + local mt = { __eq = function(a, b) return true end } + local tt = { [0] = setmetatable({}, mt), setmetatable({}, mt) } + for i=0,100 do + assert(tt[0] == tt[bit.band(i, 1)]) + end +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/framegap.lua b/test/LuaJIT-test-cleanup/lang/meta/framegap.lua new file mode 100644 index 0000000..0080633 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/framegap.lua @@ -0,0 +1,24 @@ +do --- untitled + local t = setmetatable({}, { __add = function(a, b) + if b > 200 then + for j=1,10 do end + return b+3 + elseif b > 100 then + return b+2 + else + return b+1 + end + end }) + + local function f(t, i) + do return t+i end + -- Force large frame with unassigned slots below mm. + do local a,b,c,d,e,f,g,h,i,j,k end + end + + local x = 0 + for i=1,300 do + x = f(t, i) + end + assert(x == 303) +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/index b/test/LuaJIT-test-cleanup/lang/meta/index new file mode 100644 index 0000000..f114e78 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/index @@ -0,0 +1,14 @@ +arith.lua +arith_jit.lua +call.lua +cat.lua +comp.lua +comp_jit.lua +eq.lua +eq_jit.lua +framegap.lua +index.lua +len.lua +newindex.lua +nomm.lua +debuginfo.lua diff --git a/test/LuaJIT-test-cleanup/lang/meta/index.lua b/test/LuaJIT-test-cleanup/lang/meta/index.lua new file mode 100644 index 0000000..4d6d0ff --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/index.lua @@ -0,0 +1,60 @@ +do --- table 1 + local t=setmetatable({}, {__index=function(t,k) + return 100-k + end}) + + for i=1,100 do assert(t[i] == 100-i) end + + for i=1,100 do t[i] = i end + for i=1,100 do assert(t[i] == i) end + + for i=1,100 do t[i] = nil end + for i=1,100 do assert(t[i] == 100-i) end +end + +do --- table 2 + local x + local t2=setmetatable({}, {__index=function(t,k) + x = k + end}) + + assert(t2[1] == nil) + assert(x == 1) + + assert(t2.foo == nil) + assert(x == "foo") +end + +do --- userdata +lua<5.2 + local u = newproxy(true) + getmetatable(u).__index = { foo = u, bar = 42 } + + local x = 0 + for i=1,100 do + x = x + u.bar + u = u.foo + end + assert(x == 4200) + + x = 0 + for i=1,100 do + u = u.foo + x = x + u.bar + end + assert(x == 4200) +end + +do --- string + local s = "foo" + local mt = debug.getmetatable(s) + debug.setmetatable(s, {__index = {s = s, len = string.len}}) + local x = 0 + local t = {} + for i=1,100 do + x = x + s:len() + s = s.s + t[s] = t -- Hash store with same type prevents hoisting + end + debug.setmetatable(s, mt) + assert(x == 300) +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/len.lua b/test/LuaJIT-test-cleanup/lang/meta/len.lua new file mode 100644 index 0000000..2410daa --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/len.lua @@ -0,0 +1,42 @@ +local compat52 = table.pack +local mt = { __len = function(o, o2) + if compat52 then + assert(o2 == o) + else + assert(o2 == nil) + end + return 42 +end } + +do --- table + local t = {1,2,3} + assert(#t == 3) + assert(#"abcdef" == 6) + + setmetatable(t, { __foo = function() end }) + assert(#t == 3) + assert(#t == 3) + + setmetatable(t, mt) + if compat52 then + assert(#t == 42) -- __len DOES work on tables. + assert(rawlen(t) == 3) + else + assert(#t == 3) -- __len does NOT work on tables. + end +end + +do --- userdata +lua<5.2 + local u = newproxy(true) + getmetatable(u).__len = function(o) return 42 end + assert(#u == 42) + local x = 0 + for i=1,100 do x = x + #u end + assert(x == 4200) +end + +do --- number + debug.setmetatable(0, mt) + assert(#1 == 42) + debug.setmetatable(0, nil) +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/newindex.lua b/test/LuaJIT-test-cleanup/lang/meta/newindex.lua new file mode 100644 index 0000000..6c46b8c --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/newindex.lua @@ -0,0 +1,69 @@ +do --- table 1 + local t=setmetatable({}, {__newindex=function(t,k,v) + rawset(t, k, 100-v) + end}) + + for i=1,100 do t[i] = i end + for i=1,100 do assert(t[i] == 100-i) end + + for i=1,100 do t[i] = i end + for i=1,100 do assert(t[i] == i) end + + for i=1,100 do t[i] = nil end + for i=1,100 do t[i] = i end + for i=1,100 do assert(t[i] == 100-i) end +end + +do --- jit gaining href + local count = 0 + local t = setmetatable({ foo = nil }, + { __newindex=function() count = count + 1 end }) + for j=1,2 do + for i=1,100 do t.foo = 1 end + rawset(t, "foo", 1) + end + assert(count == 100) +end + +do --- jit gaining aref + local count = 0 + local t = setmetatable({ nil }, + { __newindex=function() count = count + 1 end }) + for j=1,2 do + for i=1,100 do t[1] = 1 end + rawset(t, 1, 1) + end + assert(count == 100) +end + +do --- resize + local grandparent = {} + grandparent.__newindex = function(s,_,_) tostring(s) end + + local parent = {} + parent.__newindex = parent + parent.bar = 1 + setmetatable(parent, grandparent) + + local child = setmetatable({}, parent) + child.foo = _ +end + +do --- str + local t=setmetatable({}, {__newindex=function(t,k,v) + assert(v == "foo"..k) + rawset(t, k, "bar"..k) + end}) + + for i=1,100 do t[i]="foo"..i end + for i=1,100 do assert(t[i] == "bar"..i) end + + for i=1,100 do t[i]="baz"..i end + for i=1,100 do assert(t[i] == "baz"..i) end + + local t=setmetatable({foo=1,bar=1,baz=1},{}) + t.baz=nil + t.baz=2 + t.baz=nil + t.baz=2 +end diff --git a/test/LuaJIT-test-cleanup/lang/meta/nomm.lua b/test/LuaJIT-test-cleanup/lang/meta/nomm.lua new file mode 100644 index 0000000..2b3db86 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/meta/nomm.lua @@ -0,0 +1,21 @@ + +do --- untitled + local keys = {} + for i=1,100 do keys[i] = "foo" end + keys[95] = "__index" + local function fidx(t, k) return 12345 end + local mt = { foo = 1, __index = "" } + local t = setmetatable({ 1 }, mt) + t[1] = nil + mt.__index = nil + local x = nil + for i=1,100 do + mt[keys[i]] = fidx + if t[1] then + if not x then x = i end + assert(t[1] == 12345) + end + end + assert(x == 95) +end + diff --git a/test/LuaJIT-test-cleanup/lang/modulo.lua b/test/LuaJIT-test-cleanup/lang/modulo.lua new file mode 100644 index 0000000..eddaea7 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lang/self.lua b/test/LuaJIT-test-cleanup/lang/self.lua new file mode 100644 index 0000000..d374666 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lang/table.lua b/test/LuaJIT-test-cleanup/lang/table.lua new file mode 100644 index 0000000..3ff38cf --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/table.lua @@ -0,0 +1,32 @@ +do --- tables as keys in tables + local fwd, bck = {}, {} + for i = 1,100 do + local v = {} + fwd[i] = v + bck[v] = i + end + for i = 1,100 do + local v = fwd[i] + assert(type(v) == "table") + assert(bck[v] == i) + end +end + +do --- some tables as keys in tables + local fwd, bck = {}, {} + for i = 1,100 do + local v = {} + fwd[i] = v + if i > 90 then + bck[v] = i + end + end + local n = 0 + for i = 1, 100 do + local v = fwd[i] + if bck[v] then + n = n + 1 + end + end + assert(n == 10) +end diff --git a/test/LuaJIT-test-cleanup/lang/tail_recursion.lua b/test/LuaJIT-test-cleanup/lang/tail_recursion.lua new file mode 100644 index 0000000..78f071f --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lang/upvalue/closure.lua b/test/LuaJIT-test-cleanup/lang/upvalue/closure.lua new file mode 100644 index 0000000..faa4de1 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lang/upvalue/index b/test/LuaJIT-test-cleanup/lang/upvalue/index new file mode 100644 index 0000000..3c170db --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/upvalue/index @@ -0,0 +1 @@ +closure.lua diff --git a/test/LuaJIT-test-cleanup/lang/vararg_jit.lua b/test/LuaJIT-test-cleanup/lang/vararg_jit.lua new file mode 100644 index 0000000..4e78f96 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lang/vararg_jit.lua @@ -0,0 +1,95 @@ + +do --- 1 + local function f(a, b, c, ...) + assert(c == nil) + assert(a == 100-b) + return 100-a, 100-b + end + for i=1,100 do + local x, y = f(i, 100-i) + assert(x == 100-i) + assert(y == i) + end +end + +do --- 2 + local function f(a, b, ...) + if a > b then return b end + return a + end + local x = 0 + for i=1,200 do + x = x + f(i, 100, 99, 88, 77) + end + assert(x == 15050) +end + +do --- 3 + local function f(a, b, ...) + local c, d = ... + if c > d then return d end + return c + end + local x = 0 + for i=1,200 do + x = x + f(77, 88, i, 100) + end + assert(x == 15050) +end + +do --- 4 + local function f(a, b, ...) + if a > b then end + return ... + end + local x = 0 + for i=1,200 do + x = x + f(i, 100, i, 100) + assert(f(i, 100) == nil) + assert(f(i, 100, 2) == 2) + end + assert(x == 20100) +end + +do --- 5 + local function f(a, ...) + local x, y = 0, 0 + for i=1,100 do + local b, c = ... + x = x + b + y = y + c + end + assert(x == 200 and y == 300) + end + f(1, 2, 3) +end + +do --- 6 + local function f(a, ...) + local t = {[0]=9, 9} + local v, w, x, y = 0, 0, 0, 0 + for i=1,100 do + v, w = ... + t[0] = 9; t[1] = 9; + x, y = ... + end + assert(v == 2 and w == 3 and x == 2 and y == 3) + end + f(1, 2, 3) +end + +do --- 7 + local function f(a, b, ...) + for i=1,100 do + local c, d = ... + assert(a == c); + assert(b == d); + end + end + f(2, 3, 2, 3) + f(2, nil, 2) + f(nil, nil) + f(nil) + f() +end + diff --git a/test/LuaJIT-test-cleanup/lib/base/assert.lua b/test/LuaJIT-test-cleanup/lib/base/assert.lua new file mode 100644 index 0000000..9c30ba0 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/base/error.lua b/test/LuaJIT-test-cleanup/lib/base/error.lua new file mode 100644 index 0000000..9193085 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/base/getfenv.lua b/test/LuaJIT-test-cleanup/lib/base/getfenv.lua new file mode 100644 index 0000000..9c00ed7 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/base/getsetmetatable.lua b/test/LuaJIT-test-cleanup/lib/base/getsetmetatable.lua new file mode 100644 index 0000000..7d57343 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/base/getsetmetatable.lua @@ -0,0 +1,33 @@ + +do --- get __metatable + local t = setmetatable({}, { __metatable = "foo" }) + for i=1,100 do assert(getmetatable(t) == "foo") end +end + +do --- jit smoke + local mt = {} + local t = setmetatable({}, mt) + for i=1,100 do assert(getmetatable(t) == mt) end + for i=1,100 do assert(setmetatable(t, mt) == t) end +end + +do --- jit assorted + local mt = {} + local t = {} + for i=1,200 do t[i] = setmetatable({}, mt) end + t[150] = setmetatable({}, { __metatable = "foo" }) + for i=1,200 do + if not pcall(setmetatable, t[i], mt) then assert(i == 150) end + end + for i=1,200 do assert(getmetatable(t[i]) == mt or i == 150) end + for i=1,200 do + if not pcall(setmetatable, t[i], nil) then assert(i == 150) end + end + for i=1,200 do assert(getmetatable(t[i]) == nil or i == 150) end +end + +do --- jit get primitive metatable + local x = true + for i=1,100 do x = getmetatable(i) end + assert(x == nil) +end diff --git a/test/LuaJIT-test-cleanup/lib/base/index b/test/LuaJIT-test-cleanup/lib/base/index new file mode 100644 index 0000000..942c53c --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/base/index @@ -0,0 +1,11 @@ +assert.lua +error.lua +getfenv.lua +lua<5.2 +getsetmetatable.lua +ipairs.lua +next.lua +pairs.lua +pcall_jit.lua +select.lua +tonumber_tostring.lua +xpcall_jit.lua +compat5.2 diff --git a/test/LuaJIT-test-cleanup/lib/base/ipairs.lua b/test/LuaJIT-test-cleanup/lib/base/ipairs.lua new file mode 100644 index 0000000..a9de087 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/base/ipairs.lua @@ -0,0 +1,41 @@ +do --- small integer values + local t = { 4,5,6,7,8,9,10 } + local n = 0 + for i,v in ipairs(t) do + assert(v == i+3) + n = n + 1 + end + assert(n == 7) +end + +do --- jit key=value + local t = {} + for i=1,100 do t[i]=i end + local n = 0 + for i,v in ipairs(t) do + assert(i == v) + n = n + 1 + end + assert(n == 100) +end + +do --- untitled + local t = {} + local o = {{}, {}} + for i=1,100 do + local c = i.."" + t[i] = c + o[1][c] = i + o[2][c] = i + end + o[1]["90"] = nil + + local n = 0 + for _, c in ipairs(t) do + for i = 1, 2 do + o[i][c] = o[i][c] or 1 + n = n + 1 + end + end + assert(n == 200) +end diff --git a/test/LuaJIT-test-cleanup/lib/base/next.lua b/test/LuaJIT-test-cleanup/lib/base/next.lua new file mode 100644 index 0000000..0e40615 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/base/next.lua @@ -0,0 +1,17 @@ +do --- _G 1 + local ok, err = pcall(next, _G, 1) + assert(not ok) + local ok, err = pcall(function() next(_G, 1) end) + assert(not ok) +end + +do --- as iterator + local t = { foo = 9, bar = 10, 4, 5, 6 } + local r = {} + local function dummy() end + local function f(next) + for k,v in next,t,nil do r[#r+1] = k; if v == 5 then f(dummy) end end + end + f(next) + assert(#r == 5) +end diff --git a/test/LuaJIT-test-cleanup/lib/base/pairs.lua b/test/LuaJIT-test-cleanup/lib/base/pairs.lua new file mode 100644 index 0000000..4d89d42 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/base/pairs.lua @@ -0,0 +1,73 @@ + +do --- nometatable + local t = {} + for i=1,10 do t[i] = i+100 end + local a, b = 0, 0 + for j=1,100 do for k,v in ipairs(t) do a = a + k; b = b + v end end + assert(a == 5500) + assert(b == 105500) + a, b = 0, 0 + for j=1,100 do for k,v in pairs(t) do a = a + k; b = b + v end end + assert(a == 5500) + assert(b == 105500) +end + +do --- empty metatable + local t = setmetatable({}, {}) + for i=1,10 do t[i] = i+100 end + local a, b = 0, 0 + for j=1,100 do for k,v in ipairs(t) do a = a + k; b = b + v end end + assert(a == 5500) + assert(b == 105500) + a, b = 0, 0 + for j=1,100 do for k,v in pairs(t) do a = a + k; b = b + v end end + assert(a == 5500) + assert(b == 105500) +end + +do --- metamethods +compat5.2 + local function iter(t, i) + i = i + 1 + if t[i] then return i, t[i]+2 end + end + local function itergen(t) + return iter, t, 0 + end + local t = setmetatable({}, { __pairs = itergen, __ipairs = itergen }) + for i=1,10 do t[i] = i+100 end + local a, b = 0, 0 + for j=1,100 do for k,v in ipairs(t) do a = a + k; b = b + v end end + assert(a == 5500) + assert(b == 107500) + a, b = 0, 0 + for j=1,100 do for k,v in pairs(t) do a = a + k; b = b + v end end + assert(a == 5500) + assert(b == 107500) +end + +do --- _G + local n = 0 + for k,v in pairs(_G) do + assert(_G[k] == v) + n = n + 1 + end + assert(n >= 35) +end + +do --- count + local function count(t) + local n = 0 + for i,v in pairs(t) do + n = n + 1 + end + return n; + end + assert(count({ 4,5,6,nil,8,nil,10}) == 5) + assert(count({ [0] = 3, 4,5,6,nil,8,nil,10}) == 6) + assert(count({ foo=1, bar=2, baz=3 }) == 3) + assert(count({ foo=1, bar=2, baz=3, boo=4 }) == 4) + assert(count({ 4,5,6,nil,8,nil,10, foo=1, bar=2, baz=3 }) == 8) + local t = { foo=1, bar=2, baz=3, boo=4 } + t.bar = nil; t.boo = nil + assert(count(t) == 2) +end diff --git a/test/LuaJIT-test-cleanup/lib/base/pcall_jit.lua b/test/LuaJIT-test-cleanup/lib/base/pcall_jit.lua new file mode 100644 index 0000000..dc9cd5f --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/base/pcall_jit.lua @@ -0,0 +1,74 @@ + +do --- square sum + local function f(x) return x*x end + local x = 0 + for i=1,100 do + local ok1, ok2, ok3, y = pcall(pcall, pcall, f, 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 = pcall(pcall, pcall, math.sqrt, 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 = pcall(pcall, pcall, f, i) + if not ok1 or not ok2 or not ok3 then + assert(ok1 and ok2 and not ok3) + assert(y == "test") + break + end + x = x + y + end + assert(x == 11175) +end + +do --- sum or square + 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 = pcall(pcall, pcall, f, 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 = pcall(pcall, pcall, f, i) + if not ok1 or not ok2 or not ok3 then + assert(ok1 and ok2 and not ok3) + assert(y == "test") + -- note: no break, so we get an exit to interpreter + else + x = x + y + end + end + assert(x == 668575) +end diff --git a/test/LuaJIT-test-cleanup/lib/base/select.lua b/test/LuaJIT-test-cleanup/lib/base/select.lua new file mode 100644 index 0000000..8278e5e --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/base/select.lua @@ -0,0 +1,105 @@ + +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/LuaJIT-test-cleanup/lib/base/tonumber_tostring.lua b/test/LuaJIT-test-cleanup/lib/base/tonumber_tostring.lua new file mode 100644 index 0000000..e7f576c --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/base/tonumber_tostring.lua @@ -0,0 +1,81 @@ + +do --- tonumber int + local x = 0 + for i=1,100 do x = x + tonumber(i) end + assert(x == 5050) +end + +do --- tonumber float + local x = 0 + for i=1.5,100.5 do x = x + tonumber(i) end + assert(x == 5100) +end + +do --- tostring int / tonumber + local t = {} + for i=1,100 do t[i] = tostring(i) end + local x = 0 + for i=1,100 do assert(type(t[i]) == "string"); x = x + tonumber(t[i]) end + assert(x == 5050) +end + +do --- tostring float / tonumber + local t = {} + for i=1,100 do t[i] = tostring(i+0.5) end + local x = 0 + for i=1,100 do assert(type(t[i]) == "string"); x = x + tonumber(t[i]) end + assert(x == 5100) +end + +do --- tonumber table + for i=1,100 do assert(tonumber({}) == nil) end +end + +do --- tostring int / tostring + local t = {} + for i=1,100 do t[i] = tostring(i) end + for i=1,100 do t[i] = tostring(t[i]) end + local x = 0 + for i=1,100 do assert(type(t[i]) == "string"); x = x + t[i] end + assert(x == 5050) +end + +do --- tostring table __tostring + local mt = { __tostring = function(t) return tostring(t[1]) end } + local t = {} + for i=1,100 do t[i] = setmetatable({i}, mt) end + for i=1,100 do t[i] = tostring(t[i]) end + local x = 0 + for i=1,100 do assert(type(t[i]) == "string"); x = x + t[i] end + assert(x == 5050) +end + +do --- tostring table __tostring __call + local r = setmetatable({}, + { __call = function(x, t) return tostring(t[1]) end }) + local mt = { __tostring = r } + local t = {} + for i=1,100 do t[i] = setmetatable({i}, mt) end + for i=1,100 do t[i] = tostring(t[i]) end + local x = 0 + for i=1,100 do assert(type(t[i]) == "string"); x = x + t[i] end + assert(x == 5050) +end + +do --- print calls overridden tostring +lua<5.2 + local x = false + local co = coroutine.create(function() print(1) end) + debug.setfenv(co, setmetatable({}, { __index = { + tostring = function() x = true end }})) + coroutine.resume(co) + assert(x == true) +end + +do --- tonumber base 2 + assert(tonumber(111, 2) == 7) +end + +do --- __tostring must be callable + local t = setmetatable({}, { __tostring = "" }) + assert(pcall(function() tostring(t) end) == false) +end diff --git a/test/LuaJIT-test-cleanup/lib/base/xpcall_jit.lua b/test/LuaJIT-test-cleanup/lib/base/xpcall_jit.lua new file mode 100644 index 0000000..f4993cc --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/base/xpcall_jit.lua @@ -0,0 +1,83 @@ +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/LuaJIT-test-cleanup/lib/bit.lua b/test/LuaJIT-test-cleanup/lib/bit.lua new file mode 100644 index 0000000..1adf550 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/contents.lua b/test/LuaJIT-test-cleanup/lib/contents.lua new file mode 100644 index 0000000..a1d8b9b --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/contents.lua @@ -0,0 +1,155 @@ +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 -compat5.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 -compat5.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:typeof", "typeinfo") +end + +do --- ffi 2.1 +fii +luajit>=2.1 + assert(require"ffi".typeinfo) +end diff --git a/test/LuaJIT-test-cleanup/lib/coroutine/index b/test/LuaJIT-test-cleanup/lib/coroutine/index new file mode 100644 index 0000000..9c5c17e --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/coroutine/index @@ -0,0 +1 @@ +yield.lua diff --git a/test/LuaJIT-test-cleanup/lib/coroutine/yield.lua b/test/LuaJIT-test-cleanup/lib/coroutine/yield.lua new file mode 100644 index 0000000..d995bf8 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/ffi/bit64.lua b/test/LuaJIT-test-cleanup/lib/ffi/bit64.lua new file mode 100644 index 0000000..d1b47be --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/bit64.lua @@ -0,0 +1,130 @@ +local ffi = require("ffi") +local bit = require("bit") + +local tobit, bnot, bswap = bit.tobit, bit.bnot, bit.bswap +local band, bor, bxor = bit.band, bit.bor, bit.bxor +local shl, shr, sar = bit.lshift, bit.rshift, bit.arshift +local rol, ror = bit.rol, bit.ror + +ffi.cdef[[ +typedef enum { ZZI = -1 } ienum_t; +typedef enum { ZZU } uenum_t; +]] + +do --- smoke tobit + assert(tobit(0xfedcba9876543210ll) == 0x76543210) + assert(tobit(0xfedcba9876543210ull) == 0x76543210) +end + +do --- smoke band + assert(tostring(band(1ll, 1, 1ll, -1)) == "1LL") + assert(tostring(band(1ll, 1, 1ull, -1)) == "1ULL") +end + +do --- smoke shl + assert(shl(10ll, 2) == 40) + assert(shl(10, 2ll) == 40) + assert(shl(10ll, 2ll) == 40) +end + +do --- smoke tohex + assert(bit.tohex(0x123456789abcdef0LL) == "123456789abcdef0") +end + +do --- tobit/band assorted C types + for _,tp in ipairs{"int", "ienum_t", "uenum_t", "int64_t", "uint64_t"} do + local x = ffi.new(tp, 10) + local y = tobit(x) + local z = band(x) + assert(type(y) == "number" and y == 10) + assert(type(z) == "cdata" and z == 10) + end +end + +do --- tobit/band negative unsigned enum + local x = ffi.new("uenum_t", -10) + local y = tobit(x) + local z = band(x) + assert(type(y) == "number") + assert(y == -10) + assert(type(z) == "cdata") + assert(z == 2^32-10) +end + +do --- jit band/bor/bxor + local a = 0x123456789abcdef0LL + local y1, y2, y3, y4, y5, y6 + for i=1,100 do + y1 = band(a, 0x000000005a5a5a5aLL) + y2 = band(a, 0x5a5a5a5a00000000LL) + y3 = band(a, 0xffffffff5a5a5a5aLL) + y4 = band(a, 0x5a5a5a5affffffffLL) + y5 = band(a, 0xffffffff00000000LL) + y6 = band(a, 0x00000000ffffffffLL) + end + assert(y1 == 0x000000001a185a50LL) + assert(y2 == 0x1210525800000000LL) + assert(y3 == 0x123456781a185a50LL) + assert(y4 == 0x121052589abcdef0LL) + assert(y5 == 0x1234567800000000LL) + assert(y6 == 0x000000009abcdef0LL) + for i=1,100 do + y1 = bor(a, 0x000000005a5a5a5aLL) + y2 = bor(a, 0x5a5a5a5a00000000LL) + y3 = bor(a, 0xffffffff5a5a5a5aLL) + y4 = bor(a, 0x5a5a5a5affffffffLL) + y5 = bor(a, 0xffffffff00000000LL) + y6 = bor(a, 0x00000000ffffffffLL) + end + assert(y1 == 0x12345678dafedefaLL) + assert(y2 == 0x5a7e5e7a9abcdef0LL) + assert(y3 == 0xffffffffdafedefaLL) + assert(y4 == 0x5a7e5e7affffffffLL) + assert(y5 == 0xffffffff9abcdef0LL) + assert(y6 == 0x12345678ffffffffLL) + for i=1,100 do + y1 = bxor(a, 0x000000005a5a5a5aLL) + y2 = bxor(a, 0x5a5a5a5a00000000LL) + y3 = bxor(a, 0xffffffff5a5a5a5aLL) + y4 = bxor(a, 0x5a5a5a5affffffffLL) + y5 = bxor(a, 0xffffffff00000000LL) + y6 = bxor(a, 0x00000000ffffffffLL) + end + assert(y1 == 0x12345678c0e684aaLL) + assert(y2 == 0x486e0c229abcdef0LL) + assert(y3 == 0xedcba987c0e684aaLL) + assert(y4 == 0x486e0c226543210fLL) + assert(y5 == 0xedcba9879abcdef0LL) + assert(y6 == 0x123456786543210fLL) +end + +do --- jit shift/xor + local a, b = 0x123456789abcdef0LL, 0x31415926535898LL + for i=1,200 do + a = bxor(a, b); b = sar(b, 14) + shl(b, 50) + a = a - b; b = shl(b, 5) + sar(b, 59) + b = bxor(a, b); b = b - shl(b, 13) - shr(b, 51) + end + assert(b == -7993764627526027113LL) +end + +do --- jit rotate/xor + local a, b = 0x123456789abcdef0LL, 0x31415926535898LL + for i=1,200 do + a = bxor(a, b); b = rol(b, 14) + a = a - b; b = rol(b, 5) + b = bxor(a, b); b = b - rol(b, 13) + end + assert(b == -6199148037344061526LL) +end + +do --- jit all ops + local a, b = 0x123456789abcdef0LL, 0x31415926535898LL + for i=1,200 do + a = bxor(a, b); b = rol(b, a) + a = a - b; b = shr(b, a) + shl(b, bnot(a)) + b = bxor(a, b); b = b - bswap(b) + end + assert(b == -8881785180777266821LL) +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/cdata_var.lua b/test/LuaJIT-test-cleanup/lib/ffi/cdata_var.lua new file mode 100644 index 0000000..42d6028 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/cdata_var.lua @@ -0,0 +1,47 @@ +local ffi = require("ffi") + +do --- byte array allocations + local typ = ffi.typeof"uint8_t[?]" + for i = 4, 24 do + for d = -5, 5 do + local sz = 2^i + d + assert(ffi.sizeof(typ, sz) == sz) + local mem = ffi.new(typ, sz) + assert(ffi.sizeof(mem) == sz) + mem[0] = 0x21 + mem[1] = 0x32 + mem[2] = 0x43 + mem[sz-3] = 0x54 + mem[sz-2] = 0x65 + mem[sz-1] = 0x76 + assert(mem[0] == 0x21) + assert(mem[1] == 0x32) + assert(mem[2] == 0x43) + assert(mem[3] == 0) + assert(mem[sz-4] == 0) + assert(mem[sz-3] == 0x54) + assert(mem[sz-2] == 0x65) + assert(mem[sz-1] == 0x76) + end + end +end + +do --- int array allocations + local typ = ffi.typeof"int32_t[?]" + for i = 2, 17 do + for d = -2, 2 do + local sz = 2^i + d + assert(ffi.sizeof(typ, sz) == sz*4) + local mem = ffi.new(typ, sz) + assert(ffi.sizeof(mem) == sz*4) + mem[0] = -3 + mem[sz-1] = -4 + assert(mem[0] == -3) + if sz ~= 2 then + assert(mem[1] == 0) + assert(mem[sz-2] == 0) + end + assert(mem[sz-1] == -4) + end + end +end diff --git a/test/LuaJIT-test-cleanup/lib/ffi/copy_fill.lua b/test/LuaJIT-test-cleanup/lib/ffi/copy_fill.lua new file mode 100644 index 0000000..2956381 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/copy_fill.lua @@ -0,0 +1,64 @@ +local ffi = require("ffi") + +do --- misc + local arr = ffi.typeof("char[11]") + local a = arr() + local b = arr() + local c = arr() + + for i=0,9 do a[i] = 97+i; b[i] = 106-i end + a[10] = 0; b[10] = 0; + + ffi.copy(c, a, 11) + for i=0,9 do assert(c[i] == 97+i) end + assert(ffi.string(c) == "abcdefghij") + + ffi.copy(c, b, 5) + for i=0,4 do assert(c[i] == 106-i) end + for i=5,9 do assert(c[i] == 97+i) end + assert(ffi.string(c) == "jihgffghij") + + c[7] = 0 + assert(ffi.string(c) == "jihgffg") + + c[10] = 1 + ffi.copy(c, "ABCDEFGHIJ") + for i=0,9 do assert(c[i] == 65+i) end + assert(c[10] == 0) + assert(ffi.string(c) == "ABCDEFGHIJ") + + ffi.copy(c, "abcdefghij", 5) + assert(ffi.string(c) == "abcdeFGHIJ") + + ffi.fill(c, 10, 65) + assert(ffi.string(c) == "AAAAAAAAAA") + for i=10,0,-1 do ffi.fill(c, i, 96+i) end + assert(ffi.string(c) == "abcdefghij") + ffi.fill(c, 10) + assert(c[0] == 0) + assert(c[9] == 0) + + -- test length parameter to ffi.string + ffi.fill(c, 10, 65) + assert(ffi.string(c, 5) == "AAAAA") +end + +do --- jit char[10] + local a = ffi.new("char[10]", 64) + local x + for i=1,100 do a[0] = i; x = ffi.string(a, 10) end + assert(x == "d@@@@@@@@@") +end + +do --- jit char[1] + local a = ffi.new("char[1]") + local x, y + for i=1,100 do + a[0] = i + x = ffi.string(a, 1) + a[0] = 126 + y = ffi.string(a, 1) + end + assert(x == "d" and y == "~") +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/err.lua b/test/LuaJIT-test-cleanup/lib/ffi/err.lua new file mode 100644 index 0000000..4472365 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/err.lua @@ -0,0 +1,35 @@ +local ffi = require("ffi") + +do --- error in FFI metamethod: don't print metamethod frame. + local ok, err = xpcall(function() + local x = (1ll).foo + end, debug.traceback) + assert(ok == false) + assert(not string.find(err, "__index")) +end + +do --- tailcall in regular metamethod: keep metamethod frame. + local ok, err = xpcall(function() + local t = setmetatable({}, {__index = function() return rawget("x") end }) + local y = t[1] + end, debug.traceback) + assert(ok == false) + assert(string.find(err, "__index")) +end + +do --- error in FFI metamethod: set correct PC. + ffi.cdef[[ +typedef struct { int x; int y; } ffi_err_point; +ffi_err_point ffi_err_strchr(ffi_err_point* op1, ffi_err_point* op2) asm("strchr"); +]] + local point = ffi.metatype("ffi_err_point", { __add = ffi.C.ffi_err_strchr }) + local function foo() + local p = point{ 3, 4 } + local r = p + p + local r = p + 5 + end + local ok, err = xpcall(foo, debug.traceback) + local line = debug.getinfo(foo).linedefined+3 + assert(string.match(err, "traceback:[^:]*:"..line..":")) +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_arith_ptr.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_arith_ptr.lua new file mode 100644 index 0000000..8cf890c --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_arith_ptr.lua @@ -0,0 +1,106 @@ +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +ffi.cdef[[ +typedef struct { int a,b,c; } foo1_t; +void free(void *); +void *malloc(size_t); +struct incomplete; +]] + +do + local a = ffi.new("int[10]") + local p1 = a+0 + p1[0] = 1; + p1[1] = 2; + assert(a[0] == 1) + assert(a[1] == 2) + assert(a == p1) + assert(not (a ~= p1)) + assert(p1 <= a) + assert(a <= p1) + assert(not (p1 < a)) + assert(not (a < p1)) + assert(a ~= nil) + assert(not (a == nil)) + assert(p1 ~= nil) + assert(not (p1 == nil)) + + local p2 = a+2 + p2[0] = 3; + p2[1] = 4; + assert(a[2] == 3) + assert(a[3] == 4) + assert(p2 - p1 == 2) + assert(p1 - p2 == -2) + assert(p1 ~= p2) + assert(not (p1 == p2)) + assert(p1 < p2) + assert(p2 > p1) + assert(not (p1 > p2)) + assert(not (p2 < p1)) + assert(p1 <= p2) + assert(p2 >= p1) + assert(not (p1 >= p2)) + assert(not (p2 <= p1)) + + local p3 = a-2 + assert(p3[2] == 1) + assert(p3[3] == 2) + local p4 = a+(-3) + assert(p4[5] == 3) + assert(p4[6] == 4) + -- bad: adding two pointers or subtracting a pointer + fails(function(p1, p2) return p1 + p2 end, p1, p2) + fails(function(p1) return 1 - p1 end, p1) + -- bad: subtracting different pointer types + fails(function(p1) return p1 - ffi.new("char[1]") end, p1) + -- but different qualifiers are ok + local b = ffi.cast("const int *", a+5) + assert(b - a == 5) +end + +do + local p1 = ffi.cast("void *", 0) + local p2 = ffi.cast("int *", 1) + assert(p1 == p1) + assert(p2 == p2) + assert(p1 ~= p2) + assert(p1 == nil) + assert(p2 ~= nil) +end + +do + local f1 = ffi.C.free + local f2 = ffi.C.malloc + local p1 = ffi.cast("void *", f1) + assert(f1 == f1) + assert(f1 ~= nil) + assert(f1 ~= f2) + assert(p1 == f1) + assert(p1 ~= f2) + assert(f1 < f2 or f1 > f2) + fails(function(f1) return f1 + 1 end, f1) +end + +do + local s = ffi.new("foo1_t[10]") + local p1 = s+3 + p1.a = 1; p1.b = 2; p1.c = 3 + p1[1].a = 4; p1[1].b = 5; p1[1].c = 6 + assert(s[3].a == 1 and s[3].b == 2 and s[3].c == 3) + assert(s[4].a == 4 and s[4].b == 5 and s[4].c == 6) + local p2 = s+6 + assert(p2 - p1 == 3) + assert(p1 - p2 == -3) +end + +do + local mem = ffi.new("int[1]") + local p = ffi.cast("struct incomplete *", mem) + fails(function(p) return p+1 end, p) + local ok, err = pcall(function(p) return p[1] end, p) + assert(not ok and err:match("size.*unknown")) +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_bitfield.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_bitfield.lua new file mode 100644 index 0000000..cd0b181 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_bitfield.lua @@ -0,0 +1,108 @@ +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +do + local x = ffi.new([[ + union { + uint32_t u; + struct { int a:10,b:10,c:11,d:1; }; + struct { unsigned int e:10,f:10,g:11,h:1; }; + struct { int8_t i:4,j:5,k:5,l:3; }; + struct { _Bool b0:1,b1:1,b2:1,b3:1; }; + } + ]]) + + -- bitfield access + x.u = 0xffffffff + assert(x.a == -1 and x.b == -1 and x.c == -1 and x.d == -1) + assert(x.e == 1023 and x.f == 1023 and x.g == 2047 and x.h == 1) + assert(x.i == -1 and x.j == -1 and x.k == -1 and x.l == -1) + assert(x.b0 == true and x.b1 == true and x.b2 == true and x.b3 == true) + x.u = 0x12345678 + if ffi.abi("le") then + assert(x.a == -392 and x.b == 277 and x.c == 291 and x.d == 0) + assert(x.e == 632 and x.f == 277 and x.g == 291 and x.h == 0) + assert(x.i == -8 and x.j == -10 and x.k == -12 and x.l == 1) + assert(x.b0 == false and x.b1 == false and x.b2 == false and x.b3 == true) + else + assert(x.a == 72 and x.b == -187 and x.c == 828 and x.d == 0) + assert(x.e == 72 and x.f == 837 and x.g == 828 and x.h == 0) + assert(x.i == 1 and x.j == 6 and x.k == 10 and x.l == -2) + assert(x.b0 == false and x.b1 == false and x.b2 == false and x.b3 == true) + end + x.u = 0xe8d30edc + if ffi.abi("le") then + assert(x.a == -292 and x.b == 195 and x.c == -371 and x.d == -1) + assert(x.e == 732 and x.f == 195 and x.g == 1677 and x.h == 1) + assert(x.i == -4 and x.j == 14 and x.k == -13 and x.l == -2) + assert(x.b0 == false and x.b1 == false and x.b2 == true and x.b3 == true) + else + assert(x.a == -93 and x.b == 304 and x.c == -146 and x.d == 0) + assert(x.e == 931 and x.f == 304 and x.g == 1902 and x.h == 0) + assert(x.i == -2 and x.j == -6 and x.k == 1 and x.l == -2) + assert(x.b0 == true and x.b1 == true and x.b2 == true and x.b3 == false) + end + + -- bitfield insert + x.u = 0xffffffff + x.a = 0 + if ffi.abi("le") then + assert(x.u == 0xfffffc00) + else + assert(x.u == 0x003fffff) + end + x.u = 0 + x.a = -1 + if ffi.abi("le") then + assert(x.u == 0x3ff) + else + assert(x.u == 0xffc00000) + end + x.u = 0xffffffff + x.b = 0 + if ffi.abi("le") then + assert(x.u == 0xfff003ff) + else + assert(x.u == 0xffc00fff) + end + x.u = 0 + x.b = -1 + if ffi.abi("le") then + assert(x.u == 0x000ffc00) + else + assert(x.u == 0x003ff000) + end + + -- cumulative bitfield insert + x.u = 0xffffffff + if ffi.abi("le") then + x.a = -392; x.b = 277; x.c = 291; x.d = 0 + else + x.a = 72; x.b = -187; x.c = 828; x.d = 0 + end + assert(x.u == 0x12345678) + x.u = 0 + if ffi.abi("le") then + x.a = -392; x.b = 277; x.c = 291; x.d = 0 + else + x.a = 72; x.b = -187; x.c = 828; x.d = 0 + end + assert(x.u == 0x12345678) + x.u = 0xffffffff + x.b0 = true; x.b1 = false; x.b2 = true; x.b3 = false + if ffi.abi("le") then + assert(x.u == 0xfffffff5) + else + assert(x.u == 0xafffffff) + end + x.u = 0 + x.b0 = true; x.b1 = false; x.b2 = true; x.b3 = false + if ffi.abi("le") then + assert(x.u == 0x00000005) + else + assert(x.u == 0xa0000000) + end + +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_call.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_call.lua new file mode 100644 index 0000000..1eb5e90 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_call.lua @@ -0,0 +1,266 @@ + +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +local tonumber = tonumber + +ffi.cdef[[ +typedef struct s_ii { int x, y; } s_ii; +typedef struct s_jj { int64_t x, y; } s_jj; +typedef struct s_ff { float x, y; } s_ff; +typedef struct s_dd { double x, y; } s_dd; +typedef struct s_8i { int a,b,c,d,e,f,g,h; } s_8i; + +int call_i(int a); +int call_ii(int a, int b); +int call_10i(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); + +typedef enum { XYZ } e_u; + +e_u call_ie(e_u a) asm("call_i"); + +int64_t call_ji(int64_t a, int b); +int64_t call_ij(int a, int64_t b); +int64_t call_jj(int64_t a, int64_t b); + +double call_dd(double a, double b); +double call_10d(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); + +float call_ff(float a, float b); +float call_10f(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j); + +double call_idifjd(int a, double b, int c, float d, int64_t e, double f); + +int call_p_i(int *a); +int *call_p_p(int *a); +int call_pp_i(int *a, int *b); + +double call_ividi(int a, ...); + +complex call_dd_cd(double a, double b); +complex call_cd(complex a); +complex call_cdcd(complex a, complex b); + +complex float call_ff_cf(float a, float b); +complex float call_cf(complex float a); +complex float call_cfcf(complex float a, complex float b); + +s_ii call_sii(s_ii a); +s_jj call_sjj(s_jj a); +s_ff call_sff(s_ff a); +s_dd call_sdd(s_dd a); +s_8i call_s8i(s_8i a); +s_ii call_siisii(s_ii a, s_ii b); +s_ff call_sffsff(s_ff a, s_ff b); +s_dd call_sddsdd(s_dd a, s_dd b); +s_8i call_s8is8i(s_8i a, s_8i b); +s_8i call_is8ii(int a, s_8i b, int c); + +int __fastcall fastcall_void(void); +int __fastcall fastcall_i(int a); +int __fastcall fastcall_ii(int a, int b); +int __fastcall fastcall_iii(int a, int b, int c); +int64_t __fastcall fastcall_ji(int64_t a, int b); +double __fastcall fastcall_dd(double a, double b); +int __fastcall fastcall_pp_i(int *a, int *b); +s_ii __fastcall fastcall_siisii(s_ii a, s_ii b); +s_dd __fastcall fastcall_sddsdd(s_dd a, s_dd b); + +int __stdcall stdcall_i(int a); +int __stdcall stdcall_ii(int a, int b); +double __stdcall stdcall_dd(double a, double b); +float __stdcall stdcall_ff(float a, float b); +]] + +local C = ffi.load("../clib/ctest") + +assert(C.call_i(-42) == -41) +assert(C.call_ii(-42, 17) == -42+17) +assert(C.call_10i(-42, 17, 12345, 9987, -100, 11, 51, 0x12345678, 338, -78901234) == -42+17+12345+9987-100+11+51+0x12345678+338-78901234) + +assert(C.call_ie(123) == 124) + +assert(tonumber(C.call_ji(0x123456789LL, -17)) == tonumber(0x123456789LL-17)) +assert(tonumber(C.call_ij(-17, 0x123456789LL)) == tonumber(0x123456789LL-17)) +assert(tonumber(C.call_jj(-42, 17)) == -42+17) +assert(tonumber(C.call_jj(0x123456789abcdef0LL, -0x789abcde99887766LL)) == tonumber(0x123456789abcdef0LL-0x789abcde99887766LL)) + +assert(C.call_dd(12.5, -3.25) == 12.5-3.25) +assert(C.call_10d(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x12345678, 338, -78901234.75) == -42.5+17.125+12345.5+9987-100.625+11+51+0x12345678+338-78901234.75) + +assert(C.call_ff(12.5, -3.25) == 12.5-3.25) +assert(C.call_10f(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x123456, 338, -789012.75) == -42.5+17.125+12345.5+9987-100.625+11+51+0x123456+338-789012.75) + +assert(C.call_idifjd(-42, 17.125, 0x12345, -100.625, 12345678901234, -789012.75) == -42+17.125+0x12345-100.625+12345678901234-789012.75) + +do + local a = ffi.new("int[10]", -42) + assert(C.call_p_i(a) == -42+1) + assert(tonumber(ffi.cast("intptr_t", C.call_p_p(a+3))) == tonumber(ffi.cast("intptr_t", a+4))) + assert(C.call_pp_i(a+8, a+5) == 3) +end + +-- vararg +assert(C.call_ividi(-42, ffi.new("int", 17), 12.5, ffi.new("int", 131)) == -42+17+12.5+131) + +-- complex +if pcall(function() return C.call_dd_cd end) then + do + local c = C.call_dd_cd(12.5, -3.25) + assert(c.re == 12.5 and c.im == -3.25*2) + end + do + local c1 = ffi.new("complex", 12.5, -3.25) + local cz = C.call_cd(c1) + assert(cz.re == 12.5+1 and cz.im == -3.25-2) + end + do + local c1 = ffi.new("complex", 12.5, -3.25) + local c2 = ffi.new("complex", -17.125, 100.625) + local cz = C.call_cdcd(c1, c2) + assert(cz.re == 12.5-17.125 and cz.im == -3.25+100.625) + end + + do + local c = C.call_ff_cf(12.5, -3.25) + assert(c.re == 12.5 and c.im == -3.25*2) + end + do + local c1 = ffi.new("complex float", 12.5, -3.25) + local cz = C.call_cf(c1) + assert(cz.re == 12.5+1 and cz.im == -3.25-2) + end + do + local c1 = ffi.new("complex float", 12.5, -3.25) + local c2 = ffi.new("complex float", -17.125, 100.625) + local cz = C.call_cfcf(c1, c2) + assert(cz.re == 12.5-17.125 and cz.im == -3.25+100.625) + end +end + +-- structs +do + local s1 = ffi.new("s_ii", -42, 17) + local sz = C.call_sii(s1) + assert(s1.x == -42 and s1.y == 17) + assert(sz.x == -42 and sz.y == 17) +end + +do + local s1 = ffi.new("s_jj", 0x123456789abcdef0LL, -0x789abcde99887766LL) + local sz = C.call_sjj(s1) + assert(s1.x == 0x123456789abcdef0LL) + assert(s1.y == -0x789abcde99887766LL) + assert(sz.x == 0x123456789abcdef0LL) + assert(sz.y == -0x789abcde99887766LL) +end + +do + local s1 = ffi.new("s_ff", 12.5, -3.25) + local sz = C.call_sff(s1) + assert(s1.x == 12.5 and s1.y == -3.25) + assert(sz.x == 12.5 and sz.y == -3.25) +end + +do + local s1 = ffi.new("s_dd", 12.5, -3.25) + local sz = C.call_sdd(s1) + assert(s1.x == 12.5 and s1.y == -3.25) + assert(sz.x == 12.5 and sz.y == -3.25) +end + +do + local s1 = ffi.new("s_8i", -42, 17, 12345, 9987, -100, 11, 51, 0x12345678) + local sz = C.call_s8i(s1) + assert(s1.a+s1.b+s1.c+s1.d+s1.e+s1.f+s1.g+s1.h == -42+17+12345+9987-100+11+51+0x12345678) + assert(sz.a+sz.b+sz.c+sz.d+sz.e+sz.f+sz.g+sz.h == -42+17+12345+9987-100+11+51+0x12345678) +end + +do + local s1 = ffi.new("s_ii", -42, 17) + local s2 = ffi.new("s_ii", 0x12345, -98765) + local sz = C.call_siisii(s1, s2) + assert(s1.x == -42 and s1.y == 17) + assert(s2.x == 0x12345 and s2.y == -98765) + assert(sz.x == -42+0x12345 and sz.y == 17-98765) +end + +do + local s1 = ffi.new("s_ff", 12.5, -3.25) + local s2 = ffi.new("s_ff", -17.125, 100.625) + local sz = C.call_sffsff(s1, s2) + assert(s1.x == 12.5 and s1.y == -3.25) + assert(s2.x == -17.125 and s2.y == 100.625) + assert(sz.x == 12.5-17.125 and sz.y == -3.25+100.625) +end + +do + local s1 = ffi.new("s_dd", 12.5, -3.25) + local s2 = ffi.new("s_dd", -17.125, 100.625) + local sz = C.call_sddsdd(s1, s2) + assert(s1.x == 12.5 and s1.y == -3.25) + assert(s2.x == -17.125 and s2.y == 100.625) + assert(sz.x == 12.5-17.125 and sz.y == -3.25+100.625) +end + +do + local s1 = ffi.new("s_8i", -42, 17, 12345, 9987, -100, 11, 51, 0x12345678) + local s2 = ffi.new("s_8i", 99, 311, 98765, -51, 312, 97, 17, 0x44332211) + local sz = C.call_s8is8i(s1, s2) + assert(s1.a+s1.b+s1.c+s1.d+s1.e+s1.f+s1.g+s1.h == -42+17+12345+9987-100+11+51+0x12345678) + assert(s2.a+s2.b+s2.c+s2.d+s2.e+s2.f+s2.g+s2.h == 99+311+98765-51+312+97+17+0x44332211) + assert(sz.a+sz.b+sz.c+sz.d+sz.e+sz.f+sz.g+sz.h == -42+17+12345+9987-100+11+51+0x12345678 + 99+311+98765-51+312+97+17+0x44332211) + assert(sz.a == -42+99) + assert(sz.h == 0x12345678+0x44332211) +end + +do + local s1 = ffi.new("s_8i", -42, 17, 12345, 9987, -100, 11, 51, 0x12345678) + local sz = C.call_is8ii(19, s1, -51) + assert(s1.a+s1.b+s1.c+s1.d+s1.e+s1.f+s1.g+s1.h == -42+17+12345+9987-100+11+51+0x12345678) + assert(sz.a+sz.b+sz.c+sz.d+sz.e+sz.f+sz.g+sz.h == -42+17+12345+9987-100+11+51+0x12345678 + 19-51) + assert(sz.a == -42+19) + assert(sz.c == 12345-51) +end + +-- target-specific +if jit.arch == "x86" then + assert(C.fastcall_void() == 1) + assert(C.fastcall_i(-42) == -41) + assert(C.fastcall_ii(-42, 17) == -42+17) + assert(C.fastcall_iii(-42, 17, 139) == -42+17+139) + assert(tonumber(C.fastcall_ji(0x123456789LL, -17)) == tonumber(0x123456789LL-17)) + assert(C.fastcall_dd(12.5, -3.25) == 12.5-3.25) + + do + local a = ffi.new("int[10]", -42) + assert(C.fastcall_pp_i(a+8, a+5) == 3) + end + + do + local s1 = ffi.new("s_ii", -42, 17) + local s2 = ffi.new("s_ii", 0x12345, -98765) + local sz = C.fastcall_siisii(s1, s2) + assert(s1.x == -42 and s1.y == 17) + assert(s2.x == 0x12345 and s2.y == -98765) + assert(sz.x == -42+0x12345 and sz.y == 17-98765) + end + + do + local s1 = ffi.new("s_dd", 12.5, -3.25) + local s2 = ffi.new("s_dd", -17.125, 100.625) + local sz = C.fastcall_sddsdd(s1, s2) + assert(s1.x == 12.5 and s1.y == -3.25) + assert(s2.x == -17.125 and s2.y == 100.625) + assert(sz.x == 12.5-17.125 and sz.y == -3.25+100.625) + end + + if jit.os == "Windows" then + assert(C.stdcall_i(-42) == -41) + assert(C.stdcall_ii(-42, 17) == -42+17) + assert(C.stdcall_dd(12.5, -3.25) == 12.5-3.25) + assert(C.stdcall_ff(12.5, -3.25) == 12.5-3.25) + end +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_callback.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_callback.lua new file mode 100644 index 0000000..1fd14bd --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_callback.lua @@ -0,0 +1,158 @@ + +local ffi = require("ffi") + +ffi.cdef[[ +void qsort(void *base, size_t nmemb, size_t size, + int (*compar)(const uint8_t *, const uint8_t *)); +]] + +do + local cb = ffi.cast("int (*)(int, int, int)", function(a, b, c) + return a+b+c + end) + + assert(cb(10, 99, 13) == 122) + + -- Don't compile call to blacklisted function. + for i=1,200 do + if i > 60 then assert(cb(10, 99, 13) == 122) end + end +end + +do + assert(ffi.cast("int64_t (*)(int64_t, int64_t, int64_t)", function(a, b, c) + return a+b+c + end)(12345678901234567LL, 70000000000000001LL, 10000000909090904LL) == + 12345678901234567LL+70000000000000001LL+10000000909090904LL) + + assert(ffi.cast("double (*)(double, float, double)", function(a, b, c) + return a+b+c + end)(7.125, -123.25, 9999.33) == 7.125-123.25+9999.33) + + assert(ffi.cast("double (*)(int, double)", function(a, b) + return a+b + end)(12345, 7.125) == 12345 + 7.125) + + assert(ffi.cast("float (*)(double, float, double)", function(a, b, c) + return a+b+c + end)(7.125, -123.25, 9999.33) == 9883.205078125) + + assert(ffi.cast("int (*)(int, int, int, int, int, int, int, int, int, int)", + function(a, b, c, d, e, f, g, h, i, j) + return a+b+c+d+e+f+g+h+i+j + end)(-42, 17, 12345, 9987, -100, 11, 51, 0x12345678, 338, -78901234) == + -42+17+12345+9987-100+11+51+0x12345678+338-78901234) + + assert(ffi.cast("double (*)(double, double, double, double, double, double, double, double, double, double)", + function(a, b, c, d, e, f, g, h, i, j) + return a+b+c+d+e+f+g+h+i+j + end)(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x12345678, 338, -78901234.75) == + -42.5+17.125+12345.5+9987-100.625+11+51+0x12345678+338-78901234.75) +end + +-- Target-specific tests. +if jit.arch == "x86" then + assert(ffi.cast("__fastcall int (*)(int, int, int)", function(a, b, c) + return a+b+c + end)(10, 99, 13) == 122) + + assert(ffi.cast("__stdcall int (*)(int, int, int)", function(a, b, c) + return a+b+c + end)(10, 99, 13) == 122) + + -- Test reordering. + assert(ffi.cast("int64_t __fastcall (*)(int64_t, int, int)", function(a, b, c) + return a+b+c + end)(12345678901234567LL, 12345, 989797123) == + 12345678901234567LL+12345+989797123) +end + +-- Error handling. +do + local function f() + return + end -- Error for result conversion triggered here. + local ok, err = pcall(ffi.cast("int (*)(void)", f)) + assert(ok == false) + assert(string.match(err, ":"..debug.getinfo(f, "S").lastlinedefined..":")) + + assert(pcall(ffi.cast("int (*)(void)", function() end)) == false) + assert(pcall(ffi.cast("int (*)(void)", function() error("test") end)) == false) + assert(pcall(ffi.cast("int (*)(void)", function(a) return a+1 end)) == false) + + assert(pcall(ffi.cast("int (*)(int,int,int,int, int,int,int,int, int)", function() error("test") end), 1,1,1,1, 1,1,1,1, 1) == false) + assert(pcall(ffi.cast("int (*)(int,int,int,int, int,int,int,int, int)", function() error("test") end), 1,1,1,1, 1,1,1,1, 1) == false) +end + +do + local function cmp(pa, pb) + local a, b = pa[0], pb[0] + if a < b then + return -1 + elseif a > b then + return 1 + else + return 0 + end + end + + local arr = ffi.new("uint8_t[?]", 256) + for i=0,255 do arr[i] = math.random(0, 255) end + ffi.C.qsort(arr, 256, 1, cmp) + for i=0,254 do assert(arr[i] <= arr[i+1]) end +end + +if ffi.abi"win" then + ffi.cdef[[ + typedef int (__stdcall *WNDENUMPROC)(void *hwnd, intptr_t l); + int EnumWindows(WNDENUMPROC func, intptr_t l); + int SendMessageA(void *hwnd, uint32_t msg, int w, intptr_t l); + enum { WM_GETTEXT = 13 }; + ]] + + local C = ffi.C + local buf = ffi.new("char[?]", 256) + local lbuf = ffi.cast("intptr_t", buf) + local count = 0 + C.EnumWindows(function(hwnd, l) + if C.SendMessageA(hwnd, C.WM_GETTEXT, 255, lbuf) ~= 0 then + count = count + 1 + end + return true + end, 0) + assert(count > 10) +end + +do + local cb = ffi.cast("int(*)(void)", function() return 1 end) + assert(cb() == 1) + cb:free() + assert(pcall(cb) == false) + assert(pcall(cb.free, cb) == false) + assert(pcall(cb.set, cb, function() end) == false) + cb = ffi.cast("int(*)(void)", function() return 2 end) + assert(cb() == 2) + cb:set(function() return 3 end) + assert(cb() == 3) +end + +do + local ft = ffi.typeof("void(*)(void)") + local function f() end + local t = {} + for i=1,4 do + for i=1,400 do t[i] = ft(f) end + for i=1,400 do t[i]:free() end + end +end + +do + assert(ffi.cast("int (*)()", function() return string.byte"A" end)() == 65) +end + +do + local f = ffi.cast("void (*)(void)", function() debug.traceback() end) + debug.sethook(function() debug.sethook(nil, "", 0); f() end, "", 1) + local x +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_const.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_const.lua new file mode 100644 index 0000000..d42133a --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_const.lua @@ -0,0 +1,113 @@ +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +ffi.cdef[[ +typedef struct s_t { + int v, w; +} s_t; + +typedef const s_t cs_t; + +typedef enum en_t { EE } en_t; + +typedef struct pcs_t { + int v; + const int w; +} pcs_t; + +typedef struct foo_t { + static const int cc = 17; + enum { CC = -37 }; + int i; + const int ci; + int bi:8; + const int cbi:8; + en_t e; + const en_t ce; + int a[10]; + const int ca[10]; + const char cac[10]; + s_t s; + cs_t cs; + pcs_t pcs1, pcs2; + const struct { + int ni; + }; + complex cx; + const complex ccx; + complex *cp; + const complex *ccp; +} foo_t; +]] + +do + local foo_t = ffi.typeof("foo_t") + local x = foo_t() + + -- constval + assert(x.cc == 17) + fails(function(x) x.cc = 1 end, x) + assert(x.CC == -37) + fails(function(x) x.CC = 1 end, x) + + -- fields + x.i = 1 + fails(function(x) x.ci = 1 end, x) + x.e = 1 + fails(function(x) x.ce = 1 end, x) + + -- bitfields + x.bi = 1 + fails(function(x) x.cbi = 1 end, x) + + -- arrays + do + local a = ffi.new("int[10]") + a[0] = 1 + local ca = ffi.new("const int[10]") + fails(function(ca) ca[0] = 1 end, ca) + end + x.a[0] = 1 + fails(function(x) x.ca[0] = 1 end, x) + fails(function(x) x.a = x.ca end, x) -- incompatible type + fails(function(x) x.ca = x.a end, x) + fails(function(x) x.ca = {} end, x) + fails(function(x) x.cac = "abc" end, x) + + -- structs + do + local s = ffi.new("s_t") + s.v = 1 + local cs = ffi.new("cs_t") + fails(function(cs) cs.v = 1 end, cs) + end + x.s.v = 1 + fails(function(x) x.cs.v = 1 end, x) + x.s = x.cs + fails(function(x) x.cs = x.s end, x) + fails(function(x) x.cs = {} end, x) + + -- pseudo-const structs + x.pcs1.v = 1 + fails(function(x) x.pcs1.w = 1 end, x) + fails(function(x) x.pcs1 = x.pcs2 end, x) + fails(function(x) x.pcs1 = {} end, x) + + -- transparent structs + local y = x.ni + fails(function(x) x.ni = 1 end, x) + + -- complex subtype is implicitly const and doesn't inherit const attribute + x.cx = 1 + fails(function(x) x.ccx = 1 end, x) + do + local cxa = ffi.new("complex[1]") + local ccxa = ffi.new("const complex[1]") + x.cp = cxa + x.ccp = cxa + fails(function(x) x.cp = ccxa end, x) + x.ccp = ccxa + end +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_convert.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_convert.lua new file mode 100644 index 0000000..bd3fb1f --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_convert.lua @@ -0,0 +1,787 @@ +local ffi = require("ffi") + +local ctest = require("ctest") + +dofile("../common/ffi_util.inc") + +local tonumber = tonumber + +ffi.cdef[[ +typedef struct bar_t { + int v, w; +} bar_t; +// Same structure, but treated as different struct. +typedef struct barx_t { + int v, w; +} barx_t; + +typedef struct nest_t { + int a,b; + struct { int c,d; }; + struct { int e1,e2; } e; + int f[2]; +} nest_t; + +typedef union uni_t { + int8_t a; + int16_t b; + int32_t c; +} uni_t; + +typedef struct arrinc_t { + int a[]; +} arrinc_t; + +typedef enum uenum_t { + UE0, UE71 = 71, UE72 +} uenum_t; + +typedef enum ienum_t { + IE0, IEM12 = -12, IEM11 +} ienum_t; + +typedef struct foo_t { + bool b; + int8_t i8; + uint8_t u8; + int16_t i16; + uint16_t u16; + int32_t i32; + uint32_t u32; + int64_t i64; + uint64_t u64; + float f; + double d; + complex cf; + complex cd; + uint8_t __attribute__((mode(__V16QI__))) v16qi; + int __attribute__((mode(__V4SI__))) v4si; + double __attribute__((mode(__V2DF__))) v2df; + int *pi; + int *__ptr32 p32i; + const int *pci; + volatile int *pvi; + int **ppi; + const int **ppci; + void **ppv; + char *(*ppf)(char *, const char *); + int ai[10]; + int ai_guard; + int ai2[10]; + char ac[10]; + char ac_guard; + bar_t s; + bar_t s2; + bar_t *ps; + const bar_t *pcs; + barx_t sx; + struct { int a,b,c; } si; + int si_guard; + nest_t sn; + uni_t ui; + uenum_t ue; + ienum_t ie; +} foo_t; + +char *strcpy(char *dest, const char *src); +typedef struct FILE FILE; +int fileno(FILE *stream); +int _fileno(FILE *stream); +]] + +do + local foo_t = ffi.typeof("foo_t") + local sz = ffi.sizeof(foo_t) + local x = foo_t() + local y = foo_t() + ffi.fill(x, sz, 0xff) + ffi.fill(y, sz, 0xee) + + -- unknown member + fails(function(x) local a = x.bad end, x) + fails(function(x) x.bad = 1 end, x) + -- too many initializers + fails(function(x) x.d = ffi.new("double", 1,2) end, x) + + -- conversions to bool + x.b = false + assert(x.b == false) + x.b = true + assert(x.b == true) + x.b = 0 + assert(x.b == false) + x.b = 10 + assert(x.b == true) + y.b = false + x.b = y.b + assert(x.b == false) + x.b = ffi.new("bool", true) + assert(x.b == true) + x.b = ffi.cast("bool", false) + assert(x.b == false) + x.b = ffi.new("int32_t", 17) + assert(x.b == true) + x.b = ffi.new("int32_t", 0) + assert(x.b == false) + + -- conversions from bool + x.i32 = true + assert(x.i32 == 1) + x.i32 = false + assert(x.i32 == 0) + x.i8 = ffi.new("bool", true) + assert(x.i8 == 1) + x.i8 = ffi.new("bool", false) + assert(x.i8 == 0) + x.d = true + assert(x.d == 1) + x.d = ffi.new("bool", false) + assert(x.d == 0) + -- assignment of bool to other types is not allowed + fails(function(x) x.cd = true end, x) + fails(function(x) x.v4si = true end, x) + fails(function(x) x.ai = true end, x) + fails(function(x) x.s = true end, x) + + -- int to int conversions + x.i8 = 99 + assert(x.i8 == 99) + x.i8 = -99 + assert(x.i8 == -99) + x.i8 = 128 + assert(x.i8 == -128) + x.i8 = 0xfffe + assert(x.i8 == -2) + y.i8 = 91 + x.i8 = y.i8 + assert(x.i8 == 91) + x.i8 = ffi.new("uint8_t", 0xb7) + assert(x.i8 == -73) + x.i8 = ffi.new("int16_t", 0x7fa0) + assert(x.i8 == -96) + x.i8 = ffi.new("int32_t", 0xff91) + assert(x.i8 == -111) + x.i8 = ffi.new("int64_t", 0xff81) + assert(x.i8 == -127) + + x.u8 = 99 + assert(x.u8 == 99) + x.u8 = -99 + assert(x.u8 == 256-99) + x.u8 = 128 + assert(x.u8 == 128) + x.u8 = 0xfffe + assert(x.u8 == 0xfe) + x.u8 = ffi.new("int8_t", -73) + assert(x.u8 == 0xb7) + x.u8 = ffi.new("int16_t", 0x7fa0) + assert(x.u8 == 0xa0) + x.u8 = ffi.new("int32_t", 0xff91) + assert(x.u8 == 0x91) + x.u8 = ffi.new("int64_t", 0xff81) + assert(x.u8 == 0x81) + + x.i16 = 99 + assert(x.i16 == 99) + x.i16 = -99 + assert(x.i16 == -99) + x.i16 = 32768 + assert(x.i16 == -32768) + x.i16 = 0xffffffe + assert(x.i16 == -2) + x.i16 = ffi.new("int8_t", -10) + assert(x.i16 == -10) + x.i16 = ffi.new("uint8_t", 254) + assert(x.i16 == 254) + x.i16 = ffi.new("uint16_t", 0xefa0) + assert(x.i16 == 0xefa0-65536) + x.i16 = ffi.new("int32_t", 0xffe291) + assert(x.i16 == 0xe291-65536) + x.i16 = ffi.new("int64_t", 0xffd481) + assert(x.i16 == 0xd481-65536) + + x.u16 = 99 + assert(x.u16 == 99) + x.u16 = -99 + assert(x.u16 == 65536-99) + x.u16 = 32768 + assert(x.u16 == 32768) + x.u16 = 0xffffffe + assert(x.u16 == 65534) + x.u16 = ffi.new("int8_t", -10) + assert(x.u16 == 65536-10) + x.u16 = ffi.new("uint8_t", 254) + assert(x.u16 == 254) + x.u16 = ffi.new("int16_t", 0xefa0-65536) + assert(x.u16 == 0xefa0) + x.u16 = ffi.new("int32_t", 0xffe291) + assert(x.u16 == 0xe291) + x.u16 = ffi.new("int64_t", 0xffd481) + assert(x.u16 == 0xd481) + + x.i32 = 99 + assert(x.i32 == 99) + x.i32 = -99 + assert(x.i32 == -99) + -- double to int conversion for values >= 0x80000000 is undefined + x.i32 = ffi.new("int8_t", -10) + assert(x.i32 == -10) + x.i32 = ffi.new("uint8_t", 254) + assert(x.i32 == 254) + x.i32 = ffi.new("int16_t", -517) + assert(x.i32 == -517) + x.i32 = ffi.new("uint16_t", 35876) + assert(x.i32 == 35876) + x.i32 = ffi.new("uint32_t", 0xffffe291) + assert(x.i32 == 0xffffe291-2^32) + x.i32 = ffi.new("int64_t", 15*2^32-317) + assert(x.i32 == -317) + + x.u32 = 99 + assert(x.u32 == 99) + -- x.u32 = -99 -- this is undefined on some architectures + -- assert(x.u32 == 2^32-99) + x.u32 = 0x87654321 + assert(x.u32 == 0x87654321) + x.u32 = ffi.new("int8_t", -10) + assert(x.u32 == 2^32-10) + x.u32 = ffi.new("uint8_t", 254) + assert(x.u32 == 254) + x.u32 = ffi.new("int16_t", -517) + assert(x.u32 == 2^32-517) + x.u32 = ffi.new("uint16_t", 35876) + assert(x.u32 == 35876) + x.u32 = ffi.new("int32_t", 0xffffe291-2^32) + assert(x.u32 == 0xffffe291) + x.u32 = ffi.new("int64_t", 15*2^32-317) + assert(x.u32 == 2^32-317) + + x.i64 = 99 + assert(tonumber(x.i64) == 99) + x.i64 = -99 + assert(tonumber(x.i64) == -99) + x.i64 = 0x1234*2^32+0x87654321 + assert(tonumber(x.i64) == 0x1234*2^32+0x87654321) + -- double to int64 conversion for values >= 2^63-1 is undefined + x.i64 = ffi.new("int8_t", -10) + assert(tonumber(x.i64) == -10) + x.i64 = ffi.new("uint8_t", 254) + assert(tonumber(x.i64) == 254) + x.i64 = ffi.new("int16_t", -517) + assert(tonumber(x.i64) == -517) + x.i64 = ffi.new("uint16_t", 35876) + assert(tonumber(x.i64) == 35876) + x.i64 = ffi.new("int32_t", -12345678) + assert(tonumber(x.i64) == -12345678) + x.i64 = ffi.new("uint32_t", 0xffeeddcc) + assert(tonumber(x.i64) == 0xffeeddcc) + x.i64 = ffi.new("uint64_t", 0xffeeddcc*2^32) + assert(tonumber(x.i64) == 0xffeeddcc*2^32-2^64) + + x.u64 = 99 + assert(tonumber(x.u64) == 99) + -- x.u64 = -99 -- this is undefined on some architectures + -- assert(tonumber(x.u64) == 2^64-99) + x.u64 = 0x1234*2^32+0x87654321 + assert(tonumber(x.u64) == 0x1234*2^32+0x87654321) + -- double to int64 conversion for values >= 2^63-1 is undefined + x.u64 = ffi.new("int8_t", -10) + assert(tonumber(x.u64) == 2^64-10) + x.u64 = ffi.new("uint8_t", 254) + assert(tonumber(x.u64) == 254) + x.u64 = ffi.new("int16_t", -517) + assert(tonumber(x.u64) == 2^64-517) + x.u64 = ffi.new("uint16_t", 35876) + assert(tonumber(x.u64) == 35876) + x.u64 = ffi.new("int32_t", -12345678) + assert(tonumber(x.u64) == 2^64-12345678) + x.u64 = ffi.new("uint32_t", 0xffeeddcc) + assert(tonumber(x.u64) == 0xffeeddcc) + x.u64 = ffi.new("int64_t", -0x7feeddcc*2^32) + assert(tonumber(x.u64) == 2^64-0x7feeddcc*2^32) + + -- FP to int conversions, test for truncation + x.i32 = 1.9 + assert(x.i32 == 1) + x.i32 = 2.9 + assert(x.i32 == 2) + x.i32 = -1.9 + assert(x.i32 == -1) + x.i32 = -2.9 + assert(x.i32 == -2) + x.i8 = 1.9 + assert(x.i8 == 1) + x.u8 = 1.9 + assert(x.u8 == 1) + x.i16 = 1.9 + assert(x.i16 == 1) + x.u16 = 1.9 + assert(x.u16 == 1) + x.u32 = 1.9 + assert(x.u32 == 1) + x.u64 = 1.9 + assert(tonumber(x.u64) == 1) + + -- int to FP conversions (most tested above) + x.f = ffi.new("int32_t", -17) + assert(x.f == -17) + x.d = ffi.new("int32_t", -17) + assert(x.d == -17) + -- test for rounding due to precision loss + x.f = -1717986919 + assert(x.f == -1717986944) + x.f = ffi.new("int32_t", 0x77777777) + assert(x.f == 0x77777780) + x.d = ffi.new("union { uint32_t u32[2]; uint64_t u64; }", + {{ 0x77777777, 0x77777777}}).u64 + assert(x.d == 0x77777777*2^32 + 0x77777800) + + -- complex initialization + x.cd = ffi.new("complex", 9.125, -78.5) + assert(x.cd.re == 9.125 and x.cd.im == -78.5) + x.cd = ffi.new("complex", {9.125, -78.5}) + assert(x.cd.re == 9.125 and x.cd.im == -78.5) + -- too many initializers + fails(function(x) x.cd = ffi.new("complex", 1,2,3) end, x) + + -- conversions between FP and complex + x.cf = -17.25 + assert(x.cf.re == -17.25 and x.cf.im == 0) + x.cf = ffi.new("complex float", -57.5) -- missing initializer + assert(x.cf.re == -57.5 and x.cf.im == 0) + x.cf = ffi.new("complex float", 9.125, -78.5) + assert(x.cf.re == 9.125 and x.cf.im == -78.5) + x.cf = ffi.new("complex double", 9.125, -78.5) + assert(x.cf.re == 9.125 and x.cf.im == -78.5) + + x.cd = -17.25 + assert(x.cd.re == -17.25 and x.cd.im == 0) + x.cd = ffi.new("complex double", -57.5) -- missing initializer + assert(x.cd.re == -57.5 and x.cd.im == 0) + x.cd = ffi.new("complex float", 9.125, -78.5) + assert(x.cd.re == 9.125 and x.cd.im == -78.5) + x.cd = ffi.new("complex double", 9.125, -78.5) + assert(x.cd.re == 9.125 and x.cd.im == -78.5) + + x.f = ffi.new("complex float", 9.125, -78.5) + assert(x.f == 9.125) + x.f = ffi.new("complex double", 9.125, -78.5) + assert(x.f == 9.125) + + x.d = ffi.new("complex float", 9.125, -78.5) + assert(x.d == 9.125) + x.d = ffi.new("complex double", 9.125, -78.5) + assert(x.d == 9.125) + + -- conversions between int and complex + x.cd = ffi.new("int32_t", -138) + assert(x.cd.re == -138 and x.cd.im == 0) + x.i32 = ffi.new("complex", 9.125, -78.5) + assert(x.i32 == 9) + + -- vector initialization + x.v4si = ffi.new("int __attribute__((mode(__V4SI__)))", 1, 2, 3, 4) + assert(x.v4si[0] == 1 and x.v4si[1] == 2 and + x.v4si[2] == 3 and x.v4si[3] == 4) + x.v2df = ffi.new("double __attribute__((mode(__V2DF__)))", {3.5, -6.75}) + assert(x.v2df[0] == 3.5 and x.v2df[1] == -6.75) + -- too many initializers + fails(function(x) + x.v4si = ffi.new("int __attribute__((mode(__V4SI__)))", 1,2,3,4,5) + end, x) + + -- conversions to vectors + x.v4si = -17 + assert(x.v4si[0] == -17 and x.v4si[1] == -17 and + x.v4si[2] == -17 and x.v4si[3] == -17) + x.v4si = ffi.new("int32_t", 712) + assert(x.v4si[0] == 712 and x.v4si[1] == 712 and + x.v4si[2] == 712 and x.v4si[3] == 712) + x.v2df = 12.5 + assert(x.v2df[0] == 12.5 and x.v2df[1] == 12.5) + x.v2df = ffi.new("complex", 9.125, -78.5) + assert(x.v2df[0] == 9.125 and x.v2df[1] == 9.125) + + -- assignment of same-sized but differently-typed vectors + x.v16qi = 99 + x.v4si = 0x33333333 + x.v16qi = x.v4si + assert(x.v16qi[0] == 0x33 and x.v16qi[15] == 0x33) + + -- string converted to enum + -- x.ue = -1 -- this is undefined on some architectures + -- assert(x.ue == 0xffffffff) + x.ue = "UE0" + assert(x.ue == 0) + x.ue = "UE72" + assert(x.ue == 72) + x.ie = -1 + assert(x.ie == -1) + x.ie = "IE0" + assert(x.ie == 0) + x.ie = "IEM11" + assert(x.ie == -11) + + x.pi = x.pi + -- assignment to pointer with higher qualifiers is ok + x.pci = x.pi + x.pvi = x.pi + -- assignment to pointer with lower qualifiers is not ok + fails(function(x) x.pi = x.pci end, x) + fails(function(x) x.pi = x.pvi end, x) + fails(function(x) x.pci = x.pvi end, x) + fails(function(x) x.pvi = x.pci end, x) + -- assignment of pointers with incompatible child types is not ok + fails(function(x) x.ppi = x.ai end, x) + fails(function(x) x.ppi = x.pi end, x) + fails(function(x) x.ppv = x.ppi end, x) + -- qualifiers of child types must match, higher qualifiers not ok + fails(function(x) x.ppci = x.ppi end, x) + fails(function(x) x.ppi = x.ppci end, x) + + -- pointer/int conversions are not allowed by default + fails(function(x) x.pi = 1 end, x) + fails(function(x) x.i32 = x.pi end, x) + assert(tonumber(x.pi) == nil) + assert(tonumber(x.ai) == nil) + assert(tonumber(x.si) == nil) + + -- but pointer/int casts are allowed + x.pi = ffi.cast("int *", ffi.new("int32_t", 0x12345678)) + x.i32 = ffi.cast("int32_t", x.pi) + assert(x.i32 == 0x12345678) + x.pi = ffi.cast("int *", 1234560.3) + x.i32 = ffi.cast("int32_t", x.pi) + assert(x.i32 == 1234560) + -- bad cast from non-TValue double to pointer + fails(function(x) + ffi.cast("int *", ffi.new("double", 1.5)) + end, x) + + -- nil sets a pointer to NULL + x.pi = nil + assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 0) + + -- userdata and lightuserdata are treated as void * + do + local u = newproxy() + local uaddr = _G.tonumber(string.match(tostring(u), "(0x.*)")) + x.pi = u + assert(tonumber(ffi.cast("uintptr_t", x.pi)) == uaddr) + x.pi = ctest.lightud(12345678) + assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 12345678) + end + + -- io.* file converts to file handle (as a void *) + if ffi.abi("win") then + assert(ffi.C._fileno(io.stdout) == 1) + assert(ffi.C._fileno(io.stderr) == 2) + local x + for i=1,100 do x = ffi.C._fileno(io.stderr) end + assert(x == 2) + else + assert(ffi.C.fileno(io.stdout) == 1) + assert(ffi.C.fileno(io.stderr) == 2) + local x + for i=1,100 do x = ffi.C.fileno(io.stderr) end + assert(x == 2) + end + + -- truncation/extension of __ptr32 + if ffi.abi("64bit") then + x.pi = ffi.cast("int *", 15*2^32+0x12345678) + assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 15*2^32+0x12345678) + x.p32i = x.pi + assert(tonumber(ffi.cast("uintptr_t", x.p32i)) == 0x12345678) + x.pi = ffi.cast("int *", 0x1234*2^32+0x56780000) + x.pi = x.p32i + assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 0x12345678) + end + + -- reference initialization + do + x.ai[0] = 712 + local ri = ffi.new("int &", x.ai) + assert(tonumber(ri) == 712) + local ra = ffi.new("int (&)[10]", ffi.cast("int (*)[10]", x.ai)) + assert(ra[0] == 712) + end + + -- ffi.sizeof follows references + assert(ffi.sizeof(x.ai) == 4*10) + -- ffi.offsetof follows references + assert(ffi.offsetof(x.s, "v") == 0) + assert(ffi.offsetof(x.s, "w") == 4) + + -- ffi.fill writes the right amount + ffi.fill(x.ai2, ffi.sizeof(x.ai2), 0x72) + ffi.fill(x.ai, ffi.sizeof(x.ai), 0x13) + assert(x.ai[0] == 0x13131313) + assert(x.ai[9] == 0x13131313) + assert(x.ai2[0] == 0x72727272) + assert(x.ai2[9] == 0x72727272) + + -- array cannot be assigned a pointer + fails(function(x) x.ai = x.pi end, x) + -- but pointer can be assigned the address of an array + x.pi = x.ai2 + assert(x.pi[0] == 0x72727272) + assert(x.pi[9] == 0x72727272) + x.pi = x.ai + assert(x.pi[0] == 0x13131313) + assert(x.pi[9] == 0x13131313) + x.ai = x.ai2 -- array copy + assert(x.ai[0] == 0x72727272) + assert(x.ai[9] == 0x72727272) + -- reflected via pointer, too + assert(x.pi[0] == 0x72727272) + assert(x.pi[9] == 0x72727272) + -- mismatched type or size in array copy + fails(function(x) x.ai = x.ac end, x) + fails(function(x) x.ai = ffi.new("int[20]") end, x) + fails(function(x) x.ai = ffi.new("arrinc_t").a end, x) + fails(function(x) ffi.new("arrinc_t").a = x.ai end, x) + + ffi.fill(x.s2, ffi.sizeof(x.s2), 0x59) + x.s.v = 0x12345678 + x.s.w = 0x789abcde + assert(x.s.v == 0x12345678) + assert(x.s.w == 0x789abcde) + + -- struct cannot be assigned a pointer + fails(function(x) x.s = x.ps end, x) + -- but pointer can be assigned the address of a struct + x.ps = x.s + assert(x.ps.v == 0x12345678) + assert(x.ps.w == 0x789abcde) + x.pcs = x.s + assert(x.pcs.v == 0x12345678) + assert(x.pcs.w == 0x789abcde) + x.s = x.s2 -- struct copy + assert(x.s.v == 0x59595959) + assert(x.s.w == 0x59595959) + -- reflected via pointer, too + assert(x.ps.v == 0x59595959) + assert(x.ps.w == 0x59595959) + + -- structs must be identical, structural equivalence is not enough + fails(function(x) x.ps = x.sx end, x) + fails(function(x) x.s = x.sx end, x) + + -- string copy to arrays + x.ac_guard = 99 + ffi.fill(x.ac, 10, 0x37) + x.ac = "ABCD" + assert(x.ac[0] == 65+0) + assert(x.ac[3] == 65+3) + assert(x.ac[4] == 0) + assert(x.ac[5] == 0x37) + x.ac = "ABCDEFGHI" + assert(x.ac[8] == 65+8) + assert(x.ac[9] == 0) + x.ac = "ABCDEFGHIJ" -- reduced size + assert(x.ac[8] == 65+8) + assert(x.ac[9] == 65+9) + x.ac = "ABCDEFGHIJKLM" + assert(x.ac[8] == 65+8) + assert(x.ac[9] == 65+9) + do -- copy to a[?] + local vx = ffi.new("struct { char ac[?]; }", 20) + ffi.fill(vx.ac, 20, 0x37) + vx.ac = "ABCDEFGHI" + assert(vx.ac[8] == 65+8) + assert(vx.ac[9] == 0) + end + do -- copy to a[0] + local vx = ffi.new("union { char ac[0]; char c[20]; }") + ffi.fill(vx.ac, 20, 0x37) + vx.ac = "ABCDEFGHI" + assert(vx.ac[8] == 65+8) + assert(vx.ac[9] == 0) + end + -- mismatched type or size in string copy + fails(function(x) x.i32 = "ABCD" end, x) + fails(function(x) x.ai = "ABCD" end, x) + assert(x.ac_guard == 99) -- Check guard + + -- array initialization + x.ai = ffi.new("int[10]") -- zero fill + for i=0,9 do assert(x.ai[i] == 0) end + x.ai = ffi.new("int[10]", -67) -- replicate first element + for i=0,9 do assert(x.ai[i] == -67) end + x.ai = ffi.new("int[10]", 42, -27) -- remainder filled with zero + assert(x.ai[0] == 42) + assert(x.ai[1] == -27) + for i=2,9 do assert(x.ai[i] == 0) end + x.ai = ffi.new("int[10]", 1,2,3,4,5,6,7,8,9,10) + for i=0,9 do assert(x.ai[i] == i+1) end + x.ai = ffi.new("int[10]", {1,2,3,4,5,6,7,8,9,10}) + for i=0,9 do assert(x.ai[i] == i+1) end + -- VLA initialization + do + local v = ffi.new("int[?]", 4) + for i=0,3 do assert(v[i] == 0) end + local v = ffi.new("int[?]", 4, 833) + for i=0,3 do assert(v[i] == 833) end + local v = ffi.new("int[?]", 4, 12, -9) + assert(v[0] == 12 and v[1] == -9 and v[2] == 0 and v[3] == 0) + local v = ffi.new("int[?]", 4, 1,2,3,4) + assert(v[0] == 1 and v[1] == 2 and v[2] == 3 and v[3] == 4) + end + -- too many initializers + fails(function(x) x.ai = {1,2,3,4,5,6,7,8,9,10,11} end, x) + for i=0,9 do assert(x.ai[i] == i+1) end -- but it's partially executed + fails(function(x) + local v = ffi.new("int[?]", 4, 1,2,3,4,5) + end, x) + + -- struct initialization + x.sn = ffi.new("nest_t") -- zero fill + assert(x.sn.e.e2 == 0) + x.sn = ffi.new("nest_t", 1,2) -- remainder filled with zero + assert(x.sn.a == 1 and x.sn.b == 2 and x.sn.c == 0 and x.sn.d == 0) + assert(x.sn.e.e1 == 0 and x.sn.e.e2 == 0) + assert(x.sn.f[0] == 0 and x.sn.f[1] == 0) + x.sn = ffi.new("nest_t", 1,2,3,4,{5,6},{7,8}) -- multi-value init + assert(x.sn.a == 1 and x.sn.b == 2 and x.sn.c == 3 and x.sn.d == 4) + assert(x.sn.e.e1 == 5 and x.sn.e.e2 == 6) + assert(x.sn.f[0] == 7 and x.sn.f[1] == 8) + x.sn = ffi.new("nest_t", {1,2,3,4,{5,6},{7,8}}) -- single-value init + assert(x.sn.a == 1 and x.sn.b == 2 and x.sn.c == 3 and x.sn.d == 4) + assert(x.sn.e.e1 == 5 and x.sn.e.e2 == 6) + assert(x.sn.f[0] == 7 and x.sn.f[1] == 8) + -- VLS initialization + do + local v = ffi.new("struct { int x; int a[?]; }", 4) + assert(v.x == 0) + for i=0,3 do assert(v.a[i] == 0) end + local v = ffi.new("struct { int x; int a[?]; }", 4, 9, {833}) + assert(v.x == 9) + -- NYI: fill up VLA in VLS. currently seen as indefinite length + -- for i=0,3 do assert(v.a[i] == 833) end + assert(v.a[0] == 833 and v.a[1] == 0 and v.a[2] == 0 and v.a[3] == 0) + end + -- no multi-value init beyond first level + fails(function(x) + x.sn = ffi.new("nest_t", 1,2,3,4,5,6,7,8) + end, x) + -- too many initializers + fails(function(x) + x.sn = ffi.new("nest_t", 1,2,3,4,{5,6},{7,8}, 9) + end, x) + + -- union initialization + x.ui = ffi.new("uni_t") -- zero fill + assert(x.ui.a == 0 and x.ui.b == 0 and x.ui.c == 0) + x.ui = ffi.new("uni_t", 255) -- initialize first field, remainder is zero + if ffi.abi("le") then + assert(x.ui.a == -1 and x.ui.b == 255 and x.ui.c == 255) + else + assert(x.ui.a == -1 and x.ui.b == -256 and x.ui.c == -16777216) + end + -- too many initializers + fails(function(x) + x.sn = ffi.new("uni_t", 1,2) + end, x) + fails(function() + ffi.new("union { struct { int x; }; int y; }", 1,2) + end) + + -- table converted to array + ffi.fill(x.ai, ffi.sizeof(x.ai), 0x13) + x.ai_guard = 99 + x.ai = {} -- zero fill + for i=0,9 do assert(x.ai[i] == 0) end + x.ai = {42} -- replicate + for i=0,9 do assert(x.ai[i] == 42) end + x.ai = {[0] = -67} -- replicate from index 0 + for i=0,9 do assert(x.ai[i] == -67) end + x.ai = {42, -27} -- remainder filled with zero + assert(x.ai[0] == 42) + assert(x.ai[1] == -27) + for i=2,9 do assert(x.ai[i] == 0) end + assert(x.ai_guard == 99) -- Check guard + + -- table converted to struct + ffi.fill(x.si, ffi.sizeof(x.si), 0x74) + x.si_guard = 97 + -- convert from array part + x.si = {} -- zero fill + assert(x.si.a == 0 and x.si.b == 0 and x.si.c == 0) + x.si = {42, 18} -- fill fields in order + assert(x.si.a == 42 and x.si.b == 18 and x.si.c == 0) + x.si = {[0] = -67, 12} -- fill fields in order from index 0 + assert(x.si.a == -67 and x.si.b == 12 and x.si.c == 0) + x.si = {42, -27, 19, 8} -- too many initializers ignored + assert(x.si.a == 42 and x.si.b == -27 and x.si.c == 19) + -- convert from hash part + x.si = {b = 12} + assert(x.si.a == 0 and x.si.b == 12 and x.si.c == 0) + x.si = {b = 12, c = 85, a = 35} + assert(x.si.a == 35 and x.si.b == 12 and x.si.c == 85) + x.si = {b = 19, foo = 1, bar = 2} -- unknown initializers ignored + assert(x.si.a == 0 and x.si.b == 19 and x.si.c == 0) + x.si = {b = 12, 5, 6, 7} -- hash part ignored if array part exists + assert(x.si.a == 5 and x.si.b == 6 and x.si.c == 7) + assert(x.si_guard == 97) -- Check guard + + -- table converted to struct with transparent/nested structs and arrays + ffi.fill(x.sn, ffi.sizeof(x.sn), 0x74) + x.sn = {} -- zero fill + assert(x.sn.e.e2 == 0) + x.sn = {1,2,3,4,{5,6},{7,8}} + assert(x.sn.a == 1 and x.sn.b == 2 and x.sn.c == 3 and x.sn.d == 4) + assert(x.sn.e.e1 == 5 and x.sn.e.e2 == 6) + assert(x.sn.f[0] == 7 and x.sn.f[1] == 8) + x.sn = {c = 10, e = {11,12}, f = {13,14}} + assert(x.sn.a == 0 and x.sn.b == 0 and x.sn.c == 10 and x.sn.d == 0) + assert(x.sn.e.e1 == 11 and x.sn.e.e2 == 12) + assert(x.sn.f[0] == 13 and x.sn.f[1] == 14) + + -- table converted to union + ffi.fill(x.ui, ffi.sizeof(x.ui), 0x58) + x.ui = {} -- zero fill + assert(x.ui.a == 0 and x.ui.b == 0 and x.ui.c == 0) + x.ui = {255, -1, -1} -- only first initializer used + if ffi.abi("le") then + assert(x.ui.a == -1 and x.ui.b == 255 and x.ui.c == 255) + else + assert(x.ui.a == -1 and x.ui.b == -256 and x.ui.c == -16777216) + end + x.ui = {b = -1} -- initialize a specific element of the union + if ffi.abi("le") then + assert(x.ui.a == -1 and x.ui.b == -1 and x.ui.c == 65535) + else + assert(x.ui.a == -1 and x.ui.b == -1 and x.ui.c == -65536) + end + + -- copy constructor + do + x.s.v = 1; x.s.w = 2 + local s = ffi.new("bar_t", x.s) + assert(s.v == 1 and s.w == 2) + for i=0,9 do x.ai[i] = i end + local a = ffi.new("int[10]", x.ai) + for i=0,9 do assert(a[i] == i) end + end + + -- assignment to function pointer + x.ppf = ffi.C.strcpy +end + +do + collectgarbage() + local oc = collectgarbage("count") + local cd = ffi.new"struct { struct { int a; } x;}" + local function f(cd) + local x + for i=1,1e5 do x = cd.x end + end + for i=1,2 do + f(cd) + local nc = collectgarbage("count") + assert(nc < oc + 200, "GC step missing for cdata __index") + jit.off(f) + end +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_enum.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_enum.lua new file mode 100644 index 0000000..e8e40ad --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_enum.lua @@ -0,0 +1,57 @@ + +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +ffi.cdef[[ +typedef enum enum_i { FOO_I = -1, II = 10 } enum_i; +typedef enum enum_u { FOO_U = 1, UU = 10 } enum_u; + +enum_i call_ei_i(int a) asm("call_i"); +enum_u call_eu_i(int a) asm("call_i"); +int call_i_ei(enum_i a) asm("call_i"); +int call_i_eu(enum_u a) asm("call_i"); +]] + +local C = ffi.load("../clib/ctest") + +do + + local t = ffi.new("enum_i[100]") + for i=0,99 do t[i] = "II" end + for i=0,99 do assert(t[i] == "II") end + for i=0,99 do assert(t[i] >= "II") end + for i=0,99 do t[i] = -10 end + for i=0,99 do assert(t[i] == -10) end + for i=0,99 do assert(t[i] ~= 2147483648) end + for i=1,99 do assert(t[i] == t[i-1]) end + assert(t[0]+1 == -9) + assert(t[0] ~= "BB") + fails(function() return t[0] > "BB" end) + + local u = ffi.new("enum_u[100]") + for i=0,99 do u[i] = "UU" end + for i=0,99 do assert(u[i] == "UU") end + for i=0,99 do assert(u[i] >= "UU") end + for i=0,99 do u[i] = 4294967296-10 end + for i=0,99 do assert(u[i] == 4294967296-10) end + for i=0,99 do assert(u[i] ~= -10) end + for i=1,99 do assert(u[i] == u[i-1]) end + assert(u[0]+1 == 4294967296-9) + + for i=0,99 do assert(t[i] ~= u[i]) end +end + +do + for i=0,99 do assert(C.call_ei_i(9) == "II") end + for i=0,99 do assert(C.call_eu_i(9) == "UU") end + for i=0,99 do assert(C.call_i_ei("II") == 11) end + for i=0,99 do assert(C.call_i_eu("UU") == 11) end +end + +do + local f = ffi.cast("bool (*)(enum_i)", function(e) return e == "II" end) + assert(f("II")) + assert(not f(0)) +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_gcstep_recursive.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_gcstep_recursive.lua new file mode 100644 index 0000000..cb19df1 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_gcstep_recursive.lua @@ -0,0 +1,66 @@ +-- From Robert G. Jakabosky, 2012-03-20 + +local N=tonumber(arg[1] or 10000) + +local ffi=require"ffi" + +ffi.cdef[[ +struct Buffer { void *buf; }; +typedef struct Buffer Buffer; +]] + +local Buffer_mt = { __index = {} } +local Buffer = ffi.typeof("Buffer") + +-- used to track alive objects +local nobj_obj_flags = {} + +local function obj_to_id(ptr) + return tonumber(ffi.cast('uintptr_t', ffi.cast('void *', ptr))) +end + +function obj_type_Buffer_push(val) + local obj = Buffer(val) + local id = obj_to_id(obj) + nobj_obj_flags[id] = true + return obj +end + +local function Buffer_new(len) + local buf = ffi.cast('void *', 0xdeadbeef) + return obj_type_Buffer_push(buf) +end + +function obj_type_Buffer_delete(obj) + local id = obj_to_id(obj) + if not nobj_obj_flags[id] then return nil end + nobj_obj_flags[id] = nil + return obj.buf +end + +local getmeta = debug.getmetatable + +local function Buffer_close(self) + local buf = obj_type_Buffer_delete(self) + getmeta("Buffer_close") -- cause trace to abort + if buf then + self.buf = nil + end +end +Buffer_mt.__gc = Buffer_close +Buffer_mt.__index.close = Buffer_close + +ffi.metatype(Buffer, Buffer_mt) + +local cdata = {} +for x=1,2 do + cdata = {} + for i=1,N do + cdata[i] = Buffer_new(1) + end + for i=1,N do + cdata[i]:close() + end + cdata = nil +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_arith.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_arith.lua new file mode 100644 index 0000000..0554fe6 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_arith.lua @@ -0,0 +1,155 @@ +local ffi = require("ffi") + +do + local a = ffi.new("int64_t[?]", 101) + for i=1,100 do a[i] = -2 end + for i=1,100 do a[i] = i end + local x, y, m = 0ll, 0ll, 0ll + for i=1,100 do x = x + a[i]; y = y - a[i]; m = -a[i] end + assert(x == 5050) + assert(y == -5050) + assert(m == -100) + local z, z0 = 1ll, 3ll + for i=1,100 do z = a[i] * z0 end + assert(z == 300) + for i=1,100 do z = a[i] * 4ll end -- test MUL -> BSHL rule + assert(z == 400) + z, z0 = 1ll, 0x123456789abcdef0ll + for i=1,100 do z = z0 / a[i] end + assert(z == 0x123456789abcdef0ll / 100) + z, z0 = 1ll, 0x123456789abcdef0ll + for i=1,100 do z = z0 % a[i] end + assert(z == 0x123456789abcdef0ll % 100) + -- use multiple 64 bit PHIs + local t, u, v, w = 0ll, 0ll, 0ll, 0ll + for i=1,100 do t = t + a[i]; u = u + a[i]; v = v + a[i]; w = w + a[i] end + assert(t == 5050) + assert(u == 5050) + assert(v == 5050) + assert(w == 5050) +end + +do + local a = ffi.new("uint64_t[?]", 101) + for i=1,100 do a[i] = i end + local x, y, m = 0ull, 0ull, 0ull + for i=1,100 do x = x + a[i]; y = y - a[i]; m = -a[i] end + assert(x == 5050) + assert(y == 0ull-5050) + assert(m == -100ull) + local z, z0 = 1ull, 3ll + for i=1,100 do z = a[i] * z0 end + assert(z == 300) + z, z0 = 1ull, 0x123456789abcdef0ull + for i=1,100 do z = z0 / a[i] end + assert(z == 0x123456789abcdef0ull / 100) + z, z0 = 1ull, 0x123456789abcdef0ull + for i=1,100 do z = z0 % a[i] end + assert(z == 0x123456789abcdef0ull % 100) +end + +do + local x = 0ll + for i=1,100 do x = x + (-2ll) ^ (bit.band(i, 15)+1ll) end + assert(x == 262120) +end + +do + local x, a = 0ll, -2ll + for i=1,100 do x = x + a ^ (bit.band(i, 15)+1ll) end + assert(x == 262120) +end + +do + local x = 0ull + for i=1,100 do x = x + (-2ll) ^ (bit.band(i, 15)+1ull) end + assert(x == 262120) +end + +do + for i=1,200 do local j = bit.band(i, 7); assert((j == 0ll) == (j == 0)) end + for i=1,200 do assert((i < 100ll) == (i < 100)) end + for i=1,200 do assert((i <= 100ll) == (i <= 100)) end + for i=-100,100 do assert((i > 100ull) == (i < 0)) end +end + +do + local a = ffi.new("int64_t[?]", 100) + for i=0,99 do + a[i] = math.random(0, 2^32)*0x100000000LL + math.random(0, 2^32) + end + a[92] = 0x10000000LL + a[93] = 0x10000001LL + a[94] = math.random(0, 2^32) + a[95] = a[94] + 0x100000000LL + a[96] = a[94] + 0x100000001LL + a[97] = a[20] + a[98] = 0 + a[99] = -1 + + local function cksum(b) + local bxor, rol = bit.bxor, bit.rol + local x = 0 + for i=0,#b do x = rol(bxor(x, (b[i] and i or 0)), 7) end + return x + end + + local s = [[ + local a, b = ... + local k = 0 + for i=0,99 do + for j=0,99 do + b[k] = a[i] %s a[j] + k = k + 1 + end + end + ]] + + local ap = ffi.new("int64_t *", a) + local b = {} + for i=1,2 do + for _,cmp in ipairs{ "==", "~=", "<", "<=", ">", ">=" } do + local f = assert(loadstring(string.format(s, cmp), "operator"..cmp)) + f(ap, b) + local r1 = cksum(b) + jit.off(f) + f(ap, b) + local r2 = cksum(b) + assert(r1 == r2) + end + ap = ffi.new("uint64_t *", a) + end +end + +do + local a, b = ffi.new("char *"), ffi.new("char *") + local z + for i=1,100 do z = a-b end +end + +do + local x = true + local abc = ffi.cast("const char *", "abc") + for i=1,100 do x = abc == "abc" end + assert(x == true) + for i=1,100 do x = abc == "xyz" end + assert(x == false) + for i=1,100 do x = 0LL == "" end + assert(x == false) + for i=1,100 do x = 0LL == false end + assert(x == false) + for i=1,100 do x = 0LL == nil end + assert(x == false) +end + +-- ra_destpair +do + local x, y = 0, 0 + for i=1,100 do + x = x + i/3LL + y = y + i/5LL + end + assert(x == 1650) + assert(y == 970) +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_call.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_call.lua new file mode 100644 index 0000000..b79d60b --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_call.lua @@ -0,0 +1,154 @@ + +local ffi = require("ffi") + +ffi.cdef[[ +int call_10i(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j); +double call_10d(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j); +float call_10f(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j); +int64_t call_ij(int a, int64_t b); +bool call_b(int a) asm("call_i"); + +int64_t call_max(double,double,double,double,double,double,double,double,double,double,double,double,double,double,double,double,double) asm("call_10d"); + +int64_t call_10j_p(int a, int b, int c, int d, int e, int f, int g, int h, int i, const char *p) asm("call_10j"); + +int8_t call_i_i8(int a) asm("call_i"); +uint8_t call_i_u8(int a) asm("call_i"); +int16_t call_i_i16(int a) asm("call_i"); +uint16_t call_i_u16(int a) asm("call_i"); +int call_i8_i(int8_t a) asm("call_i"); +int call_u8_i(uint8_t a) asm("call_i"); +int call_i16_i(int16_t a) asm("call_i"); +int call_u16_i(uint16_t a) asm("call_i"); + +int __fastcall fastcall_void(void); +int __fastcall fastcall_i(int a); +int __fastcall fastcall_ii(int a, int b); +int __fastcall fastcall_iii(int a, int b, int c); +int64_t __fastcall fastcall_ji(int64_t a, int b); +double __fastcall fastcall_dd(double a, double b); +int __fastcall fastcall_pp_i(int *a, int *b); + +int __stdcall stdcall_i(int a); +int __stdcall stdcall_ii(int a, int b); +double __stdcall stdcall_dd(double a, double b); +float __stdcall stdcall_ff(float a, float b); +]] + +local lib = ffi.load("../clib/ctest") + +do + local x + for i=1,100 do + x = lib.call_10i(-42, 17, 12345, 9987, -100, 11, 51, 0x12345678, 338, -78901234) + end + assert(x == -42+17+12345+9987-100+11+51+0x12345678+338-78901234) +end + +do + for i=1,100 do + pcall(lib.call_max, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i) + end +end + +if ffi.abi("64bit") then + local y = ffi.cast("void *", 0x123456789abcdefLL) + local x + for i=1,100 do + lib.call_10j_p(0,0,0,0,0,0,0,0,0, y) + x = lib.call_10j_p(0,0,0,0,0,0,0,0,0, nil) + end + assert(x == 0) +end + +do + local x = 0 + for i=1,100 do + x = x + lib.call_ij(100+i, i*0x300000002LL) + end + assert(x == 0x3b2e0000623eLL) +end + +do + local x + for i=1,100 do + x = lib.call_10d(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x12345678, 338, -78901234.75) + end + assert(x == -42.5+17.125+12345.5+9987-100.625+11+51+0x12345678+338-78901234.75) +end + +do + local x + for i=1,100 do + x = lib.call_10f(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x123456, 338, -789012.75) + end + assert(x == -42.5+17.125+12345.5+9987-100.625+11+51+0x123456+338-789012.75) +end + +do + local x + for i=-100,100 do + if not lib.call_b(i) then x = i end + end + assert(x == -1) + local t = {} + for i=1,100 do t[i] = -1 end + t[90] = 0 + for i=1,100 do + if lib.call_b(t[i]) then x = i end + end + assert(x == 90) +end + +do + local function tail(x) + return lib.call_b(x) + end + for i=1,100 do local a,b,c = tail(1), tail(1), tail(1) end +end + +do + local x = 0 + for i=0x01010080,0x010100ff do x = x + lib.call_i_i8(i) end + assert(x == -8128) + x = 0 + for i=0x01010080,0x010100ff do x = x + lib.call_i_u8(i) end + assert(x == 24384) + x = 0 + for i=0x0101ff80,0x0101ffff do x = x + lib.call_i_i16(i) end + assert(x == -8128) + x = 0 + for i=0x0101ff80,0x0101ffff do x = x + lib.call_i_u16(i) end + assert(x == 8314944) + x = 0 + for i=0x01010080,0x010100ff do x = x + lib.call_i8_i(i) end + assert(x == -8128) + x = 0 + for i=0x01010080,0x010100ff do x = x + lib.call_u8_i(i) end + assert(x == 24640) + x = 0 + for i=0x0101ff80,0x0101ffff do x = x + lib.call_i16_i(i) end + assert(x == -8128) + x = 0 + for i=0x0101ff80,0x0101ffff do x = x + lib.call_u16_i(i) end + assert(x == 8380480) +end + +-- target-specific +if jit.arch == "x86" then + for i=1,100 do assert(lib.fastcall_i(-42) == -41) end + for i=1,100 do assert(lib.fastcall_ii(-42, 17) == -42+17) end + for i=1,100 do assert(lib.fastcall_iii(-42, 17, 139) == -42+17+139) end + for i=1,100 do assert(lib.fastcall_ji(0x123456789LL, -17) == 0x123456789LL-17) end + for i=1,100 do assert(lib.fastcall_dd(12.5, -3.25) == 12.5-3.25) end + local x = lib.fastcall_ji + for i=1,100 do assert(x(0x123456789LL, -17) == 0x123456789LL-17) end + + if jit.os == "Windows" then + for i=1,100 do assert(lib.stdcall_i(-42) == -41) end + for i=1,100 do assert(lib.stdcall_ii(-42, 17) == -42+17) end + for i=1,100 do assert(lib.stdcall_dd(12.5, -3.25) == 12.5-3.25) end + for i=1,100 do assert(lib.stdcall_ff(12.5, -3.25) == 12.5-3.25) end + end +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_conv.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_conv.lua new file mode 100644 index 0000000..d4707db --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_jit_conv.lua @@ -0,0 +1,277 @@ +local ffi = require("ffi") + +local ctest = require("ctest") + +do + local s = ffi.new("struct { int32_t x; }") + s.x = -0x12345678 + for i=1,100 do + s.x = s.x + 1 -- narrowed + end + assert(s.x == -0x12345678+100) +end + +do + local s = ffi.new("struct { uint32_t x; }") + s.x = 0x81234567 + for i=1,100 do + s.x = s.x + 1 -- CONV.num.u32, CONV.u32.num (no narrowing yet) + end + assert(s.x == 0x81234567+100) +end + +do + local s = ffi.new("struct { int8_t x; }") + s.x = 42 + for i=1,100 do + s.x = s.x + 1 + assert(s.x >= -128 and s.x <= 127) -- fwd -> CONV.int.i8 + end + assert(s.x == 142-256) +end + +do + local s = ffi.new("struct { uint8_t x; }") + s.x = 200 + for i=1,100 do + s.x = s.x + 1 + assert(s.x >= 0 and s.x <= 255) -- fwd -> CONV.int.u8 + end + assert(s.x == 300-256) +end + +do + local s = ffi.new("struct { int16_t x; }") + s.x = 32700 + for i=1,100 do + s.x = s.x + 1 + assert(s.x >= -32768 and s.x <= 32767) -- fwd -> CONV.int.i16 + end + assert(s.x == 32800-65536) +end + +do + local s = ffi.new("struct { uint16_t x; }") + s.x = 65450 + for i=1,100 do + s.x = s.x + 1 + assert(s.x >= 0 and s.x <= 65535) -- fwd -> CONV.int.u16 + end + assert(s.x == 65550-65536) +end + +do + local s = ffi.new("union { int32_t x; uint32_t y; }") + s.x = 0x7fffffff - 60 + local x,y = 0,0 + for i=1,100 do + if s.x == 0x7fffffff then s.x = -0x80000000 else s.x = s.x + 1 end + x = x + s.x -- fwd -> CONV.num.int + y = y + s.y -- fwd -> CONV.num.u32 + end + assert(s.x == 0x7fffffff - 60 + 100 - 2^32) + assert(s.y == 0x7fffffff - 60 + 100) + assert(y == (0x7fffffff - 60) * 100 + 5050) + assert(x == y - 40*2^32) +end + +do + local s = ffi.new("union { int32_t x; uint32_t y; }") + local x, z = 0, 2^31 + 42 + for i=1,100 do + s.y = z + x = x + s.x -- fwd -> CONV.int.u32 (dummy) + end + assert(x == 100*(-2^31 + 42)) +end + +do + local s = ffi.new("union { int8_t x; uint8_t y; }") + s.x = 42 + local x,y = 0,0 + for i=1,100 do + s.x = s.x + 1 + x = x + s.x -- fwd -> CONV.int.i8, CONV.num.int + y = y + s.y -- fwd -> CONV.int.u8, CONV.num.int + end + assert(s.x == 142 - 256) + assert(s.y == 142) + assert(y == 42 * 100 + 5050) + assert(x == y - (100-(127-42))*256) +end + +do + local a = ffi.new("uint32_t[?]", 101) + for i=1,100 do a[i] = 0x80000000+i end + local x = 0 + for i=1,100 do + x = bit.bxor(x, a[i]) -- FOLD TOBIT + CONV.num.u32 + end + assert(x == 100) +end + +do + local a = ffi.new("uint32_t[?]", 101) + for i=1,100 do a[i] = 0x80000000+i end + local x = 0 + for i=1,100 do + x = bit.bxor(a[i], 0) -- FOLD TOBIT + CONV.num.u32 + end + assert(x == -0x80000000+100) +end + +do + local v = ffi.new("float", 12.5) + local x = 0 + for i=1,100 do + x = x + tonumber(v) -- CONV.num.flt + end + assert(x == 100*12.5) +end + +do + local v = ffi.new("uint32_t", 0x80000000) + local x = 0 + for i=1,100 do + x = x + tonumber(v) -- CONV.num.u32 + end + assert(x == 100*0x80000000) +end + +do + local v = ffi.new("int64_t", 0x1234567800000000ll) + local x = 0 + for i=1,100 do + x = x + tonumber(v) -- CONV.num.i64 + end + assert(x == 100*0x12345678*2^32) +end + +do + local v = ffi.new("uint64_t", 0x89abcdef00000000ull) + local x = 0 + for i=1,100 do + x = x + tonumber(v) -- CONV.num.u64 + end + assert(x == 100*0x89abcdef*2^32) +end + +do + local a = ffi.new("int64_t[?]", 101) + for i=1,100 do a[i] = -i end + local x = 0 + for i=1,100 do + x = x + tonumber(a[i]) -- CONV.num.i64 + end + assert(x == -5050) +end + +do + local a = ffi.new("uint64_t[?]", 101) + for i=1,100 do a[i] = 2^63+2^32*i end + local x = 0 + for i=1,100 do + x = x + tonumber(a[i]) -- CONV.num.u64 + end + assert(x == 2^63*100+2^32*5050) +end + +do + local v = ffi.new("complex", 12.5, -3.25) + local x = 0 + for i=1,100 do + x = x + tonumber(v) + end + assert(x == 100*12.5) +end + +do + local s = ffi.new("struct { int64_t x;}") + for i=1,100 do + s.x = 0x123456789abcdef0LL + end + assert(tonumber(s.x) == tonumber(0x123456789abcdef0LL)) +end + +do + local s = ffi.new("struct { uint64_t x;}") + for i=1,100 do + s.x = 0x823456789abcdef0ULL + end + assert(tonumber(s.x) == tonumber(0x823456789abcdef0ULL)) +end + +do + ffi.cdef[[ + typedef enum { AA, BB, CC = -42 } foo_i; + typedef enum { DD, EE, FF = 0x80000000u } foo_u; + ]] + local s = ffi.new("struct { foo_i x; foo_u y;}") + for i=1,100 do + s.x = "CC" + assert(s.x == -42) + s.x = "BB" + assert(s.x == 1) + s.y = "FF" + assert(s.y == 0x80000000) + end + local st = ffi.typeof(s) + for i=1,100 do s = st() end + assert(s.x == 0 and s.y == 0) + for i=1,100 do s = st("CC", "EE") end + assert(s.x == -42 and s.y == 1) + local ei = ffi.new("foo_i", "CC") + local eu = ffi.new("foo_u", "EE") + for i=1,100 do s = st(ei, eu) end + assert(s.x == -42 and s.y == 1) + local x + for i=1,100 do x = tonumber(ei) end + assert(x == -42) +end + +do + local s = ffi.new("struct { const char *x; const char *y;}") + local a, tmp = "abcd", "ab" + for i=1,100 do + s.x = "abc" + s.y = string.sub(a, 1, 2) + end + assert(ffi.string(s.x) == "abc") + assert(ffi.string(s.y) == "ab") +end + +do + local s = ffi.new("struct { bool b[200]; int i[200]; double d[200];}") + for i=0,199 do s.i[i] = i-100; s.d[i] = i-100 end + for i=0,99 do s.b[i] = 0 end + for i=100,199 do s.b[i] = 1 end + for i=0,99 do assert(s.b[i] == false) end + for i=100,199 do assert(s.b[i] == true) end + for i=0,199 do s.b[i] = s.i[i] end + for i=0,199 do assert(s.b[i] == (i ~= 100)) end + for i=0,199 do s.b[i] = s.d[i] end + for i=0,199 do assert(s.b[i] == (i ~= 100)) end +end + +do + local a = ffi.new("int16_t[100]", 1) + for i=1,99 do a[i] = a[i] + a[i-1] end + assert(a[99] == 100) +end + +do + local ud = ctest.lightud(12345678) + local s = ffi.new("struct { void *p; }") + for i=1,100 do + assert(ffi.cast("uintptr_t", ud) == 12345678) + s.p = ud + end + assert(ffi.cast("uintptr_t", s.p) == 12345678) +end + +do + local x = ffi.new("struct { int & x;}", ffi.new("int[1]", 42)) + local z + for i=1,100 do z = x.x end + assert(z == 42) +end diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_lex_number.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_lex_number.lua new file mode 100644 index 0000000..e26650e --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_lex_number.lua @@ -0,0 +1,51 @@ +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +local function checklex(t) + for i=1,1e9,2 do + local s = t[i+1] + if not s then break end + local s2 = assert(loadstring("return tostring("..s..")"))() + if s2 ~= t[i] then + print(s2) + error("lexer failed for '"..s.."'", 2) + end + end +end + +checklex{ + "0LL", "0ll", + "0LL", "0LL", + "0ULL", "0ull", + "0ULL", "0ULl", + "18446744073709551615ULL", "18446744073709551615llu", + "9223372036854775807LL", "0x7fffffffffffffffll", + "9223372036854775808ULL", "0x8000000000000000ull", + "1311768467463790320LL", "0x123456789abcdef0ll", + "-1LL", "-1ll", + "18446744073709551615ULL", "-1ull", + "-9223372036854775807LL", "-0x7fffffffffffffffll", + "9223372036854775808ULL", "-0x8000000000000000ull", + "0+0i", "0i", + "0+0i", "0I", + "0+12.5i", "12.5i", + "0+4660i", "0x1234i", + "0+infI", "1e400i", + "0-infI", "-1e400i", + "0-12.5i", "-12.5i", + "0-0i", "-0i", +} + +checkfail({ + "0l", + "0lll", + "0u", + "0ul", + "0ulll", + "0wll", + "0xll", + ".0ll", + "0ii", +}, function(s) assert(loadstring("return "..s)) end) + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_metatype.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_metatype.lua new file mode 100644 index 0000000..2db717f --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_metatype.lua @@ -0,0 +1,245 @@ +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +ffi.cdef[[ +typedef struct { int x; } idx1_t; +typedef struct { int x; } idx2_t; +typedef struct { int x; } idx3_t; +typedef struct { int x,y; } arith_t; +typedef struct { void *p; } gc_t; +]] + +local function ptreq(a, b) + return ffi.cast("void *", a) == ffi.cast("void *", b) +end + +do + local nidx = {} + local tp = ffi.metatype("idx1_t", { + __index = { foo = 99, method = function(c, v) return v end }, + __newindex = nidx, + }) + + fails(function() ffi.metatype("idx1_t", {}) end) + + local s = tp(1234) + assert(s.foo == 99) + assert(s.x == 1234) + -- bad field in __index metatable + fails(function(s) local x = s.bar end, s) + assert(s:method(123) == 123) + s.bar = 42 + assert(nidx.bar == 42) + + local cs = ffi.new("const idx1_t", 9876) + assert(cs.foo == 99) + assert(cs.x == 9876) + -- write to const struct + fails(function(cs) cs.bar = 42 end, cs) + + local cp = ffi.new("const idx1_t *", cs) + assert(cp.foo == 99) + assert(cp.x == 9876) + -- write to const struct pointer + fails(function(cp) cp.bar = 42 end, cp) +end + +do + local uc, uk, uv + local tp = ffi.metatype("idx2_t", { + __index = function(c, k, x, y) + assert(x == nil and y == nil) + uc, uk = c, k; return 99 + end, + __newindex = function(c, k, v) uc, uk, uv = c, k, v end, + }) + + local s = tp(1234) + assert(s.foo == 99) + assert(ptreq(uc, s) and uk == "foo" and uv == nil); uc,uk,uv=nil,nil,nil + assert(s.x == 1234) + assert(uc == nil and uk == nil and uv == nil); uc,uk,uv=nil,nil,nil + + s.bar = 42 + assert(ptreq(uc, s) and uk == "bar" and uv == 42); uc,uk,uv=nil,nil,nil + s[10] = 11 + assert(ptreq(uc, s) and uk == 10 and uv == 11); uc,uk,uv=nil,nil,nil + + local p = ffi.new("idx2_t *", s) + assert(p.foo == 99) + assert(ptreq(uc, p) and uk == "foo" and uv == nil); uc,uk,uv=nil,nil,nil + assert(p.x == 1234) + assert(uc == nil and uk == nil and uv == nil); uc,uk,uv=nil,nil,nil + -- pointer dereference has precedence + assert(ptreq(p[0], p)) + assert(uc == nil and uk == nil and uv == nil); uc,uk,uv=nil,nil,nil + -- pointer dereference has precedence + fails(function(p) p[0] = 11 end, p) +end + +do + local uc, uk, uv + local ti, tn = {}, {} + local tp = ffi.metatype("idx3_t", { + __index = setmetatable(ti, + { __index = function(c, k) uc, uk = c, k; return 99 end }), + __newindex = setmetatable(tn, + { __newindex = function(c, k, v) uc, uk, uv = c, k, v end }), + }) + + local s = tp(1234) + assert(s.foo == 99) + assert(uc == ti and uk == "foo" and uv == nil) + uc, uk, uv = nil, nil, nil + assert(s.x == 1234) + assert(uc == nil and uk == nil and uv == nil) + + s.bar = 42 + assert(uc == tn and uk == "bar" and uv == 42) + uc, uk, uv = nil, nil, nil + s[10] = 11 + assert(uc == tn and uk == 10 and uv == 11) + uc, uk, uv = nil, nil, nil +end + +do + local tp + tp = ffi.metatype("arith_t", { + __add = function(a, b) return tp(a.x+b.x, a.y+b.y) end, + __sub = function(a, b) return tp(a.x-b.x, a.y-b.y) end, + __mul = function(a, z) return tp(a.x*z, a.y*z) end, + __div = function(z, a) return tp(a.x*z, a.y*z) end, + __concat = setmetatable({}, { __call = function(x) return 99 end }), + __len = function(x) return 2 end, + __call = function(a) return a.x+a.y end, + __tostring = function(a) return "foo" end, + __newindex = function(a, k, v) a.y = v end, + __index = { + diff = function(a) return a.x-a.y end, + }, + }) + + local a = tp(10, 20) + local b = tp(1, 2) + local c = a + b + assert(c.x == 11 and c.y == 22) + assert(c:diff() == -11) + assert(c() == 33) + local d = a - b + assert(d.x == 9 and d.y == 18) + assert(d:diff() == -9) + assert(d() == 27) + local e = a * 3 + assert(e.x == 30 and e.y == 60) + local f = 3LL / a + assert(f.x == 30 and f.y == 60) + assert(1 .. c == 99) + assert(c .. 1 == 99) + assert(c .. d == 99) + assert(tostring(c) == "foo") + assert(tostring(ffi.cast("arith_t *", c)) == "foo") + c.foo = 42 + assert(c.y == 42) + + local p = ffi.new("arith_t *", a) + local g1 = p + p + assert(g1.x == 20 and g1.y == 40) + local g2 = p[0] + p[0] + assert(g2.x == 20 and g2.y == 40) + assert(p() == 30) + + local q = ffi.new("arith_t &", a) + fails(function(p) local y = q[0] + q[0] end, q) + local h = q + q + assert(h.x == 20 and h.y == 40) + + local diff = 0 + for i=1,100 do diff = a:diff() end + assert(diff == -10) + + for i=1,100 do c.foo = i end + assert(c.y == 100) + + local z = tp(1, 3) + for i=1,100 do z = z + a end + assert(z.x == 1001 and z.y == 2003) + + local x = 0 + for i=1,100 do x = x + #a end + assert(x == 200) + + local x = 0 + for i=1,100 do x = x + p() end + assert(x == 3000) +end + +do + local count = 0 + local tp = ffi.metatype("gc_t", { + __gc = function(x) count = count + 1 end, + }) + + local a = tp() + a = nil + collectgarbage() + assert(count == 1) + local b,c = tp(), tp() + b = nil + collectgarbage() + assert(count == 2) + c = nil + collectgarbage() + assert(count == 3) + + local z + for i=1,100 do z = tp() end + z = nil + collectgarbage() + assert(count == 103) + + local t = {} + for i=1,100 do t[i] = tp() end + for i=1,100 do ffi.gc(t[i], nil) end + t = nil + collectgarbage() + assert(count == 103) +end + +do + local tp = ffi.metatype([[ +struct { + static const int Z42 = 42; + enum { Z39 = 39 }; + int x; +}]], { + __new = function(tp, x) + return ffi.new(tp, x or -1) + end, + __index = { test = function(x) return x+1 end, x = "hello" } + }) + assert(tp.Z42 == 42) + assert(tp.Z39 == 39) + assert(tp.test(99) == 100) + fails(function() tp.Z42 = 1 end) + fails(function() tp.Z39 = 1 end) + assert(tp.x == "hello") -- Not sure this is a good idea to allow that. + fails(function() tp.x = 1 end) + local o = tp() + assert(o.Z42 == 42) + assert(o.Z39 == 39) + assert(o.test(55) == 56) + fails(function() o.Z42 = 1 end) + fails(function() o.Z39 = 1 end) + assert(o.x == -1) + o.x = 5 + assert(o.x == 5) +end + +do + local fb = ffi.new("struct { int x; }", 99) + local xt = ffi.metatype("struct { }", { __index = fb }) + local o = xt() + assert(o.x == 99) +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_new.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_new.lua new file mode 100644 index 0000000..9cdbd53 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_new.lua @@ -0,0 +1,106 @@ +local ffi = require("ffi") +local bit = require("bit") + +dofile("../common/ffi_util.inc") + +ffi.cdef([[ +typedef struct { int a,b,c; } foo1_t; +typedef int foo2_t[?]; +void *malloc(size_t size); +void free(void *ptr); +]]) + +do + assert(ffi.sizeof("foo1_t") == 12) + local cd = ffi.new("foo1_t") + assert(ffi.sizeof(cd) == 12) + local foo1_t = ffi.typeof("foo1_t") + assert(ffi.sizeof(foo1_t) == 12) + cd = foo1_t() + assert(ffi.sizeof(cd) == 12) +end + +do + assert(ffi.sizeof("foo2_t", 3) == 12) + local cd = ffi.new("foo2_t", 3) + assert(ffi.sizeof(cd) == 12) + local foo2_t = ffi.typeof("foo2_t") + fails(ffi.sizeof, foo2_t) + assert(ffi.sizeof(foo2_t, 3) == 12) + cd = foo2_t(3) + assert(ffi.sizeof(cd) == 12) +end + +do + local tpi = ffi.typeof("int") + local tpb = ffi.typeof("uint8_t") + local t = {} + for i=1,200 do t[i] = tpi end + t[100] = tpb + local x = 0 + for i=1,200 do x = x + tonumber(ffi.new(t[i], 257)) end + assert(x == 199*257 + 1) +end + +do + local oc = collectgarbage("count") + for al=0,15 do + local align = 2^al -- 1, 2, 4, ..., 32768 + local ct = ffi.typeof("struct { char __attribute__((aligned("..align.."))) a; }") + for i=1,100 do + local cd = ct() + local addr = tonumber(ffi.cast("intptr_t", ffi.cast("void *", cd))) + assert(bit.band(addr, align-1) == 0) + end + end + local nc = collectgarbage("count") + assert(nc < oc + 3000, "GC step missing for ffi.new") +end + +do + local t = {} + for i=1,100 do t[i] = ffi.new("int[?]", i) end + assert(ffi.sizeof(t[100]) == 400) + for i=0,99 do assert(t[100][i] == 0) end +end + +do + local t = {} + local ct = ffi.typeof("struct { double x; int y[?];}") + for i=1,100 do t[i] = ct(i) end + assert(ffi.sizeof(t[100]) == 408) + for i=0,99 do assert(t[100].y[i] == 0) end +end + +do + local ct = ffi.typeof("struct __attribute__((aligned(16))) { int x; }") + local y + for i=1,200 do + local x = ct() + if i == 150 then y = x end + end + assert(bit.band(ffi.cast("intptr_t", ffi.cast("void *", y)), 15) == 0) +end + +do + local q + local p = ffi.gc(ffi.new("int[1]"), function(x) q = x end) + p = nil + collectgarbage() + assert(type(q) == "cdata") + q = nil + collectgarbage() + assert(q == nil) +end + +do + local p = ffi.gc(ffi.C.malloc(2^20), ffi.C.free) + p = nil + collectgarbage() +end + +do + local p = ffi.gc(ffi.new("int[1]"), function(x) assert(type(x) == "cdata") end) + -- test for lua_close() cleanup. +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_array.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_array.lua new file mode 100644 index 0000000..3a9616d --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_array.lua @@ -0,0 +1,78 @@ +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +checkfail{ + "int [", + "int [-1]", + "int [[1]]", + "int [10][]", + "int [10][?]", + "int [][]", + "int [][?]", + "int [?][]", + "int [?][?]", + "int [0x10000][0x2000]", + "int [256][256][256][256]", + "int [10](void)", + "int (void)[10]", + "int &[10]", + "union { double x; int a[?]; }", +} + +ffi.cdef([[ + typedef int foo1_t[10]; + typedef foo1_t foo2_t[5]; +]]) +assert(ffi.sizeof("foo1_t") == 40) +assert(ffi.sizeof("foo2_t") == 200) + +local P = ffi.sizeof("void *") + +checktypes{ + 10, 1, "char [10]", + 4*10, 4, "int [10]", + 4*10, 4, "int [10]", + 4*10*5, 4, "int [10][5]", + 4*10*5*3*2*7, 4, "int [10][5][3][2][7]", + 4*10*5, 4, "int ([10])[5]", + P*10, P, "int *[10]", + P, P, "int (*)[10]", + P*5, P, "int (*[5])[10]", + 8*10, 4, "struct { int x; char y; } [10]", + P*5*10, P, "volatile int *(* const *[5][10])(void)", + nil, 4, "int []", + 4*10, 8, "int __attribute__((aligned(8))) [10]", + 4*10, 8, "__attribute__((aligned(8))) int [10]", + 4*10, 8, "int [10] __attribute__((aligned(8)))", + 97, 1, "char ['a']", + 83, 1, "char ['\\123']", + 79, 1, "char ['\x4F']", + 5, 1, "char [sizeof(\"aa\" \"bb\")]", + 80, 8, "double [10]", +} + +do + assert(ffi.sizeof("int [?]", 10) == 4*10) + local id = ffi.typeof("const short [?]") + assert(ffi.sizeof(id, 10) == 2*10) + assert(ffi.sizeof(id, 0) == 0*10) + fails(ffi.sizeof, id) + assert(ffi.sizeof(id, -1) == nil) + assert(ffi.sizeof(id, 0x80000000) == nil) + assert(ffi.sizeof(id, 0x40000000) == nil) + assert(ffi.sizeof(id, 0x3fffffff) == 2*0x3fffffff) +end + +do + assert(ffi.sizeof("struct { double x; int a[?]; }", 10) == 8+4*10) + local id = ffi.typeof("struct { int x; short a[?]; }") + assert(ffi.sizeof(id, 10) == 4+2*10) + assert(ffi.sizeof(id, 0) == 4+0*10) + fails(ffi.sizeof, id) + assert(ffi.sizeof(id, -1) == nil) + assert(ffi.sizeof(id, 0x80000000) == nil) + assert(ffi.sizeof(id, 0x40000000) == nil) + assert(ffi.sizeof(id, 0x3ffffffd) == 4+2*0x3ffffffd) +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_basic.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_basic.lua new file mode 100644 index 0000000..c054bcf --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_basic.lua @@ -0,0 +1,131 @@ +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +checkfail{ + "", + " ", + "\n", + "1", + ".", + ";", + ",", + "*", + "[]", + "()", + "(*)", + "//", + "/*", + "xyz", + "const", + "volatile", + "typedef", + "extern", + "static", + "auto", + "register", + "struct", + "union", + "sizeof", + "int int", + "int char", + "int double", + "int;", +} + +checktypes{ + 1, 1, "char", + 1, 1, " \n\r\t\vchar \n\r\t\v", + 1, 1, "ch\\\nar", + 1, 1, "char /* abc */", + 1, 1, "char /* abc */ const", + 1, 1, "char // abc\n const", +} + +checktypes{ + nil, 1, "void", + 1, 1, "bool", + 1, 1, "_Bool", + 4, 4, "_Bool int", + 1, 1, "char", + 1, 1, "signed char", + 1, 1, "unsigned char", + 2, 2, "short", + 2, 2, "signed short", + 2, 2, "unsigned short", + 4, 4, "int", + 4, 4, "signed int", + 4, 4, "unsigned int", + 4, 4, "signed", + 4, 4, "unsigned", + 4, 4, "float", + 8, 8, "long long", + 8, 8, "signed long long", + 8, 8, "unsigned long long", + 8, 8, "double", + -- NYI: long double is architecture- and compiler-specific. + 8, 4, "_Complex float", + 16, 8, "_Complex", + 16, 8, "_Complex double", +} + +-- mode/vector_size attributes +checktypes{ + 1, 1, "int __attribute__((mode(QI)))", + 2, 2, "int __attribute__((mode(HI)))", + 4, 4, "int __attribute__((mode(SI)))", + 8, 8, "int __attribute__((mode(DI)))", + 16, 16, "int __attribute__((mode(TI)))", + 32, 16, "int __attribute__((mode(OI)))", + 4, 4, "float __attribute__((mode(SF)))", + 8, 8, "float __attribute__((mode(DF)))", + 2, 2, "int __attribute__((mode(V2QI)))", + 16, 16, "float __attribute__((mode(V4SF)))", + 32, 16, "double __attribute__((mode(V8SF)))", + 8, 8, "char __attribute__((vector_size(8)))", + 16, 16, "int __attribute__((vector_size(16)))", + 32, 16, "double __attribute__((vector_size(32)))", + 64, 16, "double __attribute__((vector_size(64)))", +} + +-- ABI-specific types: +local L = (ffi.abi("32bit") or ffi.abi("win")) and 4 or 8 +local P = ffi.abi("32bit") and 4 or 8 +local W = ffi.abi("win") and 2 or 4 + +checktypes{ + L, L, "long", + L, L, "signed long", + L, L, "unsigned long", + P, P, "int *", + P, P, "int **", + 4, 4, "int * __ptr32", +} + +checktypes{ + P, P, "ptrdiff_t", + P, P, "size_t", + W, W, "wchar_t", + 1, 1, "int8_t", + 2, 2, "int16_t", + 4, 4, "int32_t", + 8, 8, "int64_t", + 1, 1, "uint8_t", + 2, 2, "uint16_t", + 4, 4, "uint32_t", + 8, 8, "uint64_t", + P, P, "intptr_t", + P, P, "uintptr_t", +} + +checktypes{ + 1, 8, "char __attribute__((aligned(8)))", + 1, 8, "char __attribute((aligned(8)))", + 1, 8, "char __attribute__((__aligned__(8)))", + 1, 8, "__attribute__((aligned(8))) char", + 1, 8, "char __declspec(align(8))", + 1, 8, "__declspec(align(8)) char", + 1, 2, "char __attribute__((aligned(8))) const __attribute__((aligned(2)))", + 1, 16, "char __attribute__((aligned(8))) const __attribute__((aligned(16)))", +} + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_cdef.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_cdef.lua new file mode 100644 index 0000000..4bb5d90 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_cdef.lua @@ -0,0 +1,77 @@ +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +checkfail({ + "int", + "int aa1; int aa2 ", + "static int x;", + "static const long long x = 1;", -- NYI + "static const double x = 1;", -- NYI + "static const bool x = 1;", -- NYI (intentional, need true/false) + "struct { static int x = 1; };", + ";;static int y" +}, ffi.cdef) + +ffi.cdef[[ +static const int K_42a = 42; +static const char K_42b = 42+256; +static const short K_M1a = 65535; +static const unsigned short K_65535a = 65535; +static const int K_1b = 0xffffffff >> 31; +static const int K_1c = 0xffffffffu >> 31; +static const int K_M1b = (int)0xffffffff >> 31; +]] + +checktypes{ + 42, 1, "char[K_42a]", + 42, 1, "char[K_42b]", + 1, 1, "char[-K_M1a]", + 65535, 1, "char[K_65535a]", + 1, 1, "char[K_1b]", + 1, 1, "char[K_1c]", + 1, 1, "char[-K_M1b]", +} + +ffi.cdef[[ +struct str1 { + enum { + K_99 = 99 + }; + static const int K_55 = 55; +} extk; +]] + +checktypes{ + 99, 1, "char[K_99]", + 99, 1, "char[extk.K_99]", + 99, 1, "char[((struct str1)0).K_99]", + 99, 1, "char[((struct str1 *)0)->K_99]", + 55, 1, "char[extk.K_55]", +} + +checkfail{ + "char[K_55]", +} + +ffi.cdef[[ +extern int func1(void); +extern int func2(); +static int func3(); +static inline int func4(int n) +{ + int i, k = 0; + float x = 1.0f; + for (i = 0; i < n; i++) { + k += i; + } + return k; +} +;;; +]] + +ffi.cdef[[ +int ext1; +extern int ext2; +]] + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_struct.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_struct.lua new file mode 100644 index 0000000..16a3d05 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_parse_struct.lua @@ -0,0 +1,259 @@ +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +checkfail{ + "struct", + "struct {", + "struct xx xx {}", + "struct { int x }", + "struct { int x, }", + "struct { int x,y }", + "struct { void x; }", + "struct { int x(void); }", + "struct recursive1 { struct recursive1 { } x; }", + "union", + "union {", + "union xx xx {}", + "union { int x }", + "union { int x, }", + "union { int x,y }", + "union { void x; }", + "union { int x(void); }", + "union recursive1 { union recursive1 { } x; }", +} + +-- NYI: rollback doesn't recover struct state +-- ffi.cdef("struct zzz") +-- fails(ffi.cdef, "struct zzz { int") +-- ffi.cdef("struct zzz { int x; }") + +ffi.cdef("struct foo; typedef struct foo foo_t;") +assert(ffi.sizeof("struct foo") == nil) +assert(ffi.sizeof("foo_t") == nil) +ffi.cdef("struct foo { int x,y; };") +assert(ffi.sizeof("struct foo") == 8) +assert(ffi.sizeof("foo_t") == 8) +assert(ffi.sizeof(ffi.typeof("struct foo")) == 8) +assert(ffi.sizeof(ffi.typeof("foo_t")) == 8) +ffi.cdef("struct foo;") +fails(ffi.cdef, "struct foo {};") +fails(ffi.cdef, "union foo;") +fails(ffi.cdef, "union foo {};") +fails(ffi.cdef, "enum foo;") +fails(ffi.cdef, "enum foo { ZZZ1 };") + +local P = ffi.sizeof("void *") +local A = (ffi.arch == "x86" and not ffi.abi("win")) and 4 or 8 + +checktypes{ + 0, 1, "struct {}", + 1, 1, "struct { char x; }", + 2, 1, "struct { char x,y; }", + 4, 1, "struct { char x,y; char a,b; }", + 4, 2, "struct { char x; short y; }", + 4, 2, "struct { short x; char y; }", + 8, 4, "struct { char x; int y; }", + 8, 4, "struct { int x; char y; }", + 12, 4, "struct { char x; int y; char z; }", + P*4, P, "struct { char x,*y,**z,a,b,c,d; }", + 64, 4, "struct { struct { struct { struct { int x,y; } a,b; } a,b; } a,b; }", + 4, 4, "struct { struct { struct { struct { int x; }; }; }; }", + 8, 4, "struct { struct foo; }", + 8, 4, "struct { foo_t; }", + 8, 8, "struct __attribute__((aligned(sizeof(foo_t)))) { int a; }", + 6, 2, "struct { char a; char x; short y; char z; char c; }", + 10, 2, "struct { char a; struct { char x; short y; char z; } b; char c; }", + 8, A, "struct { double a; }", + A+8, A, "struct { int a; double b; }", + 8, A, "struct { long long a; }", + A+8, A, "struct { int a; long long b; }", + 16, A, "struct { _Complex a; }", + A+16, A, "struct { int a; _Complex b; }", + 8, 8, "struct { float __attribute__((mode(__V2SF__))) a; }", + 16, 8, "struct { int a; float __attribute__((mode(__V2SF__))) b; }", + 16, 8, "struct { float __attribute__((mode(__V2SF__))) a[2]; }", + 24, 8, "struct { int a; float __attribute__((mode(__V2SF__))) b[2]; }", + 16, 16, "struct { float __attribute__((vector_size(16))) a; }", + 32, 16, "struct { int a; float __attribute__((vector_size(16))) b; }", +} + +checktypes{ + 0, 1, "union {}", + 1, 1, "union { char x; }", + 1, 1, "union { char x,y; }", + 2, 2, "union { char x; short y; }", + 2, 2, "union { short x; char y; }", + 4, 4, "union { char x; int y; }", + 4, 4, "union { int x; char y; }", + 4, 4, "union { char x; int y; short z; }", + P, P, "union { char x,*y,**z,a,b,c,d; }", + 4, 4, "union { union { union { union { int x,y; } a,b; } a,b; } a,b; }", + 4, 4, "union { union { union { union { int x; }; }; }; }", + 2, 2, "union { union { short x; }; char y; }", + 2, 2, "union { struct { short x; }; char y; }", + 4, 2, "struct { union { short x; }; char y; }", + 2, 1, "union { struct { char a,b; }; char y; }", + 2, 1, "struct { union { char a,b; }; char y; }", + 8, A, "union { double a; }", + 8, A, "union { int a; double b; }", + 8, A, "union { long long a; }", + 8, A, "union { int a; long long b; }", + 16, A, "union { _Complex a; }", + 16, A, "union { int a; _Complex b; }", + 8, 8, "union { float __attribute__((mode(__V2SF__))) a; }", + 8, 8, "union { int a; float __attribute__((mode(__V2SF__))) b; }", + 16, 16, "union { float __attribute__((vector_size(16))) a; }", + 16, 16, "union { int a; float __attribute__((vector_size(16))) b; }", +} + +do + local ct + ct = ffi.typeof("struct { int a; char b; short c; int d; }") + assert(ffi.offsetof(ct, "a") == 0) + assert(ffi.offsetof(ct, "b") == 4) + assert(ffi.offsetof(ct, "c") == 6) + assert(ffi.offsetof(ct, "d") == 8) + ct = ffi.typeof("struct { char a; struct { char x; short y; char z; }; char c; }") + assert(ffi.offsetof(ct, "a") == 0) + assert(ffi.offsetof(ct, "x") == 2) + assert(ffi.offsetof(ct, "y") == 4) + assert(ffi.offsetof(ct, "z") == 6) + assert(ffi.offsetof(ct, "c") == 8) + ct = ffi.typeof("struct { char a; struct { short b; struct { int c; }; }; }") + assert(ffi.offsetof(ct, "a") == 0) + assert(ffi.offsetof(ct, "b") == 4) + assert(ffi.offsetof(ct, "c") == 8) + ct = ffi.typeof("struct { int a; double b; }") + assert(ffi.offsetof(ct, "a") == 0) + assert(ffi.offsetof(ct, "b") == A) +end + +checkfail{ + "struct { int :; }", + "struct { int a:; }", + "struct { int a:bad; }", + "struct { int a:0; }", + "struct { int a:33; }", + "struct { int a:-1; }", + "struct { _Bool a:2; }", + "struct { double a:2; }", + "struct { complex a:2; }", + "struct { int __attribute__((mode(__TI__))) a:2; }", + "struct { int __attribute__((vector_size(16))) a:2; }", + "struct { int a[2]:2; }", + "struct { void a:2; }", +} + +checktypes{ + 4, 4, "struct { unsigned a:1; }", + 4, 4, "struct { unsigned a:1, b:1, c:1; }", + 1, 1, "struct { _Bool a:1, b:1, c:1; }", + 8, 4, "struct { unsigned a:16, b:16, c:16; }", + 8, 4, "struct { unsigned a:17, b:16, c:16; }", + 12, 4, "struct { unsigned a:17, b:16, c:17; }", + 12, 4, "struct { unsigned a:16, b:17, c:16; }", + 8, 4, "struct { unsigned a:16, :16, c:16; }", + 8, 4, "struct { unsigned a:17, :16, c:16; }", + 12, 4, "struct { unsigned a:17, :16, c:17; }", + 12, 4, "struct { unsigned a:16, :17, c:16; }", + 8, 4, "struct { unsigned a:16, :0, c:16; }", + 4, 4, "struct { unsigned a:16, b:16, :0, :0; }", + 8, 4, "struct { unsigned a:16, :0, :0, :0, c:16; }", + 1, 1, "struct { char a:1; _Bool b:1; }", + 1, 1, "struct { char a:1; signed char b:1; unsigned char c:1; }", +} + +-- NYI: bit fields > 32 bit +-- local L = ffi.alignof("struct { long long a; }") +-- checktypes{ +-- L, L, "struct { long long a:1; }", +-- } + +-- Bit field packing. +checktypes{ + 1, 1, "struct { _Bool a:1, b:1, c:1; }", + 4, 4, "struct { short a:9; int b:9; char c; }", + 4, 4, "struct { char a; int b:7; }", + 4, 4, "struct { short a; char b; int c:7; }", + 4, 4, "struct { char a:7; int b:7; int c:7; int d:10; }", + 4, 1, "struct { char a:7; char b:7; char c:7; char d:7; }", + 4, 4, "struct { char a:7; int b:7, c:7, d:7; int e:4; }", + 4, 4, "struct { char a:7; int b:7, c:7, d:7; char e:4; }", + 5, 1, "struct { char a:7; char b:7, c:7, d:7; char e:4; }", + 4, 1, "struct __attribute__((packed)) { char a:7; char b:7, c:7, d:7; char e:4; }", + 4, 4, "struct { char a:7; int b:7; int c:7; int d:10; }", + 8, 4, "struct { char a:7; int b:7; char c:7; int d:10; }", + 4, 1, "struct __attribute__((packed)) { char a:7; int b:7; char c:7; int d:10; }", + 4, 1, "struct { char a:7; int b:7; char c:7; int d:10; } __attribute__((packed))", + 2, 1, "struct __attribute__((packed)) { char a:4; char b:8; }", + 2, 1, "struct __attribute__((packed)) { char a:4; char :0; char b:4; }", + 1, 1, "struct __attribute__((packed)) { _Bool a:1; _Bool b:1; }", + 2, 1, "struct __attribute__((packed)) { _Bool a:1; _Bool b:1 __attribute((aligned(1))); }", + 4, 2, "struct __attribute__((packed)) { _Bool a:1; _Bool b:1 __attribute((aligned(2))); }", + 8, 4, "struct { _Bool a:1; int b __attribute((aligned(2))); }", + 16, 8, "struct { _Bool a:1; int b __attribute((aligned(8))); }", + 6, 2, "struct { _Bool a:1; int b __attribute((aligned(2))) __attribute((packed)); }", + 6, 2, "struct __attribute__((packed)) { _Bool a:1; int b __attribute((aligned(2))); }", + 6, 2, "struct __attribute__((packed)) { _Bool a:1; int b __attribute((aligned(2))) __attribute((packed)); }", +} + +do + ffi.cdef[[ + struct foo_packorig { char a; int b; short c; }; + #pragma pack(1) + struct foo_pack1 { char a; int b; short c; }; + #pragma pack(2) + struct foo_pack2 { char a; int b; short c; }; + #pragma pack(4) + struct foo_pack4 { char a; int b; short c; }; + #pragma pack(8) + struct foo_pack8 { char a; int b; short c; }; + #pragma pack() + struct foo_packdef { char a; int b; short c; }; + #pragma pack(push) + struct foo_packpush { char a; int b; short c; }; + #pragma pack(1) + struct foo_packpush1 { char a; int b; short c; }; + #pragma pack(pop) + struct foo_packpop { char a; int b; short c; }; + #pragma pack(push,2) + struct foo_packpush2 { char a; int b; short c; }; + #pragma pack(pop) + struct foo_packpop2 { char a; int b; short c; }; + ]] + + assert(ffi.sizeof("struct foo_packorig") == 12) + assert(ffi.sizeof("struct foo_pack1") == 7) + assert(ffi.sizeof("struct foo_pack2") == 8) + assert(ffi.sizeof("struct foo_pack4") == 12) + assert(ffi.sizeof("struct foo_pack8") == 12) + assert(ffi.sizeof("struct foo_packdef") == 12) + assert(ffi.sizeof("struct foo_packpush") == 12) + assert(ffi.sizeof("struct foo_packpush1") == 7) + assert(ffi.sizeof("struct foo_packpop") == 12) + assert(ffi.sizeof("struct foo_packpush2") == 8) + assert(ffi.sizeof("struct foo_packpop2") == 12) +end + +do + ffi.cdef[[ + #pragma pack(2) + struct foo_packalign8 { + char a; int y __attribute((aligned(8))); + }; + typedef int __attribute((aligned(8))) int_align8; + struct foo_packintalign8 { + char a; int_align8 y; + }; + typedef int __attribute((aligned(1))) int_align1; + struct foo_packintalign1 { + char a; int_align1 y; + }; + ]] + + assert(ffi.sizeof("struct foo_packalign8") == 6) + assert(ffi.sizeof("struct foo_packintalign8") == 6) + assert(ffi.sizeof("struct foo_packintalign1") == 5) +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/ffi_tabov.lua b/test/LuaJIT-test-cleanup/lib/ffi/ffi_tabov.lua new file mode 100644 index 0000000..ba62196 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/ffi_tabov.lua @@ -0,0 +1,12 @@ +local ffi = require("ffi") + +local last = 0 + +assert(pcall(function() + for i=1,65536 do + last = i + ffi.typeof"struct {}" + end +end) == false) + +assert(last > 20000) diff --git a/test/LuaJIT-test-cleanup/lib/ffi/index b/test/LuaJIT-test-cleanup/lib/ffi/index new file mode 100644 index 0000000..59e36dd --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/index @@ -0,0 +1,12 @@ +bit64.lua +luajit>=2.1 +cdata_var.lua +copy_fill.lua +err.lua +istype.lua +jit_array.lua +jit_complex.lua +jit_misc.lua +jit_struct.lua +meta_tostring.lua +redir.lua +type_punning.lua diff --git a/test/LuaJIT-test-cleanup/lib/ffi/istype.lua b/test/LuaJIT-test-cleanup/lib/ffi/istype.lua new file mode 100644 index 0000000..5aba775 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/istype.lua @@ -0,0 +1,88 @@ +local ffi = require("ffi") + +do --- 1 + local void_t = ffi.typeof("void") + assert(ffi.istype(void_t, void_t)) + assert(ffi.istype("const void", void_t)) + + assert(ffi.istype("void", "void") == false) -- 2nd arg is a string. + assert(ffi.istype("double", 1.5) == false) -- 2nd arg is a number. +end + +do --- 2 + local i8_t = ffi.typeof("int8_t") + local u8_t = ffi.typeof("uint8_t") + local i32_t = ffi.typeof("int32_t") + assert(ffi.istype(i32_t, i32_t) == true) + assert(ffi.istype("const int32_t", i32_t) == true) + + assert(ffi.istype("bool", u8_t) == false) + assert(ffi.istype(i8_t, u8_t) == false) + assert(ffi.istype(i32_t, u8_t) == false) + assert(ffi.istype(u8_t, i32_t) == false) + assert(ffi.istype("double", i32_t) == false) + + assert(ffi.istype("int64_t", ffi.typeof("long long"))) + assert(ffi.istype("long long", ffi.typeof("int64_t"))) +end + +do --- 3 + local ptr_t = ffi.typeof("int *") + local p = ptr_t() + assert(ffi.istype(ptr_t, ptr_t) == true) + assert(ffi.istype(ptr_t, p) == true) + assert(ffi.istype(p, ptr_t) == true) + assert(ffi.istype("const int *", ptr_t) == true) + assert(ffi.istype("const int * const", ptr_t) == true) + assert(ffi.istype("unsigned int *", ptr_t) == true) + + assert(ffi.istype("char *", ptr_t) == false) + assert(ffi.istype("void *", ptr_t) == false) +end + +do --- 4 + ffi.cdef[[ +typedef int istype_arr_t[10]; +typedef const istype_arr_t istype_carr_t; +typedef struct { int x; } istype_struct_t; +]] + + local arr_t = ffi.typeof("istype_arr_t") + local carr_t = ffi.typeof("istype_carr_t") + assert(ffi.istype(arr_t, arr_t) == true) + assert(ffi.istype("int[10]", arr_t) == true) + + assert(ffi.istype("int[11]", arr_t) == false) + assert(ffi.istype("int[]", arr_t) == false) + assert(ffi.istype("int *", arr_t) == false) + + assert(ffi.istype("const int[10]", arr_t) == true) + assert(ffi.istype("volatile int[10]", arr_t) == true) + assert(ffi.istype(carr_t, arr_t) == true) + + local struct_t = ffi.typeof("istype_struct_t") + local structp_t = ffi.typeof("istype_struct_t *") + assert(ffi.istype(struct_t, struct_t) == true) + assert(ffi.istype("const istype_struct_t", struct_t) == true) + assert(ffi.istype("struct { int x; }", struct_t) == false) + assert(ffi.istype(struct_t, structp_t) == true) -- struct ptr is ok for struct. + assert(ffi.istype(structp_t, struct_t) == false) +end + +do --- 5 + local int_t = ffi.typeof("int") + local t = {} + for i=1,200 do t[i] = int_t() end + t[100] = ffi.new("uint8_t") + local x = 0 + for i=1,200 do if not ffi.istype("int", t[i]) then x = x + i end end + assert(x == 100) + x = 0 + for i=1,200 do if not ffi.istype(int_t, t[i]) then x = x + i end end + assert(x == 100) + for i=1,200 do t[i] = int_t end + t[100] = ffi.typeof("uint8_t") + x = 0 + for i=1,200 do if not ffi.istype(t[i], int_t) then x = x + i end end + assert(x == 100) +end diff --git a/test/LuaJIT-test-cleanup/lib/ffi/jit_array.lua b/test/LuaJIT-test-cleanup/lib/ffi/jit_array.lua new file mode 100644 index 0000000..e8de4af --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/jit_array.lua @@ -0,0 +1,104 @@ +local ffi = require("ffi") + +do --- smoke + local types = { + "int8_t", "uint8_t", + "int16_t", "uint16_t", + "int32_t", "uint32_t", + "int64_t", "uint64_t", + "float", "double", + } + for j,tp in ipairs(types) do + local t = ffi.new(tp.."[?]", 301) + for i=1,300 do t[i] = 1 end + for i=1,300 do assert(t[i] == 1) end + for i=1,300 do t[i] = t[i-1] end -- reassoc across PHIs, a[i-1] forwarding + for i=1,300 do assert(t[i] == 0) end + for i=1,300 do t[i] = i end + local x = 0 + for i=1,300 do x = x + t[i] end + if tp == "int8_t" then assert(x == 862) + elseif tp == "uint8_t" then assert(x == 33630) + else assert(x == 45150) end + end +end + +do --- int array pointer arithmetic + local a = ffi.new("int[?]", 101) + local p = a+1; + for i=1,100 do + p[0] = i + assert(p - a == i) -- pointer difference + p = p + 1 -- pointer increment by 4 bytes + end + for i=1,100 do assert(a[i] == i) end + for i=1,100 do assert((a+i)[0] == i) end -- pointer arithmetic + for i=1,100 do assert((i+a)[0] == i) end -- pointer arithmetic +end + +do --- double array pointer arithmetic + local a = ffi.new("double[?]", 101) + local p = a+1; + for i=1,100 do + p[0] = i + p = p + 1 -- pointer increment by 8 bytes + end + for i=1,100 do assert(a[i] == i) end + for i=1,100 do assert((a+i)[0] == i) end -- pointer arithmetic +end + +do --- double array pointer comparisons +bit + local a = ffi.new("double[?]", 201) + local p = a+3 + for i=1,200 do local j = bit.band(i, 7); assert((a+j == p) == (j == 3)) end + p = a+100; + for i=1,200 do assert((a+i < p) == (i < 100)) end + for i=1,200 do assert((a+i <= p) == (i <= 100)) end +end + +do --- constant offset in double array index + local a = ffi.new("double[?]", 100) + for i=1,100 do a[i-1LL] = i end + for i=1,100 do assert(a[100LL-i] == 101-i) end +end + +do --- fixed index of minus one + local a = ffi.new("int[10]") + local p = a+1 + local k = ffi.new("int", -1) + a[0] = 42 + for i=1,100 do assert(p[-1] == 42); assert(p[k] == 42) end +end + +do --- uint8_t array element comparisons + local a = ffi.new("uint8_t[?]", 256) + for i=0,255 do a[i] = i end + for i=1,255 do assert(a[i] >= 1) end + for i=0,254 do assert(a[i] <= 254) end +end + +do --- int32_t array bit/bswap tricks +bit + local a = ffi.new("int32_t[?]", 256) + local tobit, bswap, shl = bit.tobit, bit.bswap, bit.lshift + for i=0,255 do a[i] = bswap(i+0x12345600) end + for i=0,255 do assert(a[i] == tobit(shl(i, 24)+0x00563412)) end + for i=0,255 do assert(bswap(a[i]) == tobit(i+0x12345600)) end +end + +do --- int32_t shift/rotate/and +bit + local a = ffi.new("int32_t[?]", 256) + local shl, shr, rol, band = bit.lshift, bit.rshift, bit.rol, bit.band + for i=0,255 do a[i] = i + shl(i, 8) + shl(i, 16) end + + for i=0,255 do assert(shl(band(a[i], 0xff), 8) == shl(i, 8)) end + for i=0,255 do assert(band(shl(a[i], 8), 0xff00) == shl(i, 8)) end + + for i=0,255 do assert(shr(band(a[i], 0xff00), 8) == i) end + for i=0,255 do assert(band(shr(a[i], 8), 255) == i) end + + for i=0,255 do assert(rol(band(a[i], 0xff), 8) == shl(i, 8)) end + for i=0,255 do assert(band(rol(a[i], 8), 0xff00) == shl(i, 8)) end + + for i=0,255 do assert(shl(band(a[i], 0x000000ff), 24) == shl(i, 24)) end + for i=0,255 do assert(shr(band(a[i], 0xffff0000), 16) == i) end +end diff --git a/test/LuaJIT-test-cleanup/lib/ffi/jit_complex.lua b/test/LuaJIT-test-cleanup/lib/ffi/jit_complex.lua new file mode 100644 index 0000000..3296f0c --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/jit_complex.lua @@ -0,0 +1,109 @@ +local ffi = require("ffi") + +local cx = ffi.typeof("complex") +local cxf = ffi.typeof("complex float") + +ffi.cdef[[ +typedef struct jit_complex_chain_t { + struct jit_complex_chain_t *next; + complex c; +} jit_complex_chain_t; +]] + +do --- field access + local c = cx(1, 2) + local x + for i=1,100 do + x = c.re + c.im + end + assert(x == 3) +end + +do --- one element circular chain, named indexing + local cp = ffi.new("jit_complex_chain_t") + local p = cp + p.next = p + p.c = cx(1, 2) + local x,y = 0,0 + for i=1,100 do + x = x + p.c.re + y = y + p.c.im + p = p.next + end + assert(x == 100) + assert(y == 200) +end + +do --- one element circular chain, array indexing + local cp = ffi.new("jit_complex_chain_t") + local p = cp + p.next = p + p.c = cx(1, 2) + local x,y = 0,0 + for i=1,100 do + x = x + p.c[0] + y = y + p.c[1] + p = p.next + end + assert(x == 100) + assert(y == 200) +end + +do --- one-arg initialiser + local ca = ffi.new("complex[?]", 101) + for i=1,100 do + ca[i] = cx(i) -- handled as init single + end + local x,y = 0,0 + for i=1,100 do + x = x + ca[i].re + y = y + ca[i].im + end + assert(x == 5050) + assert(y == 0) +end + +do --- two-arg initialiser + local ca = ffi.new("complex[?]", 101) + for i=1,100 do + ca[i] = cx(i, -i) + end + local x,y = 0,0 + for i=1,100 do + x = x + ca[i].re + y = y + ca[i].im + end + assert(x == 5050) + assert(y == -5050) +end + +do --- float<>double conversions + local ca = ffi.new("complex[?]", 101) + local caf = ffi.new("complex float[?]", 101) + for i=1,100 do + ca[i] = cxf(i, -i) + caf[i] = cx(i, -i) + end + local x,y = 0,0 + for i=1,100 do + x = x + caf[i].re + ca[i].re + y = y + caf[i].im + ca[i].im + end + assert(x == 2*5050) + assert(y == -2*5050) +end + +do --- Complex struct field + local s = ffi.new("struct { complex x;}") + for i=1,100 do + s.x = 12.5i + end + assert(s.x.re == 0) + assert(s.x.im == 12.5) +end + +do --- Index overflow for complex is ignored + local c = cx(1, 2) + local x + for i=1e7,1e7+100 do x = c[i] end +end diff --git a/test/LuaJIT-test-cleanup/lib/ffi/jit_misc.lua b/test/LuaJIT-test-cleanup/lib/ffi/jit_misc.lua new file mode 100644 index 0000000..41e4737 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/jit_misc.lua @@ -0,0 +1,109 @@ +local ffi = require("ffi") + +do --- errno + ffi.errno(42) + local x = 0 + for i=1,100 do x = x + ffi.errno() end + assert(x == 4200) + ffi.errno(0) +end + +do --- string + local a = ffi.new("uint8_t[?]", 101) + for i=0,99 do a[i] = i end + local s + for i=1,90 do s = ffi.string(a+i, 10) end + assert(s == "Z[\\]^_`abc") + for i=1,90 do s = ffi.string(a+i) end + assert(s == "Z[\\]^_`abc") +end + +do --- fill + local a = ffi.new("uint8_t[?]", 100) + local x = 0 + for i=0,90 do x = x + a[i]; ffi.fill(a+i, 10, i); x = x + a[i] end + assert(x == 8100) + for i=1,100 do ffi.fill(a, 15, 0x1234) end + assert(a[0] == 0x34 and a[14] == 0x34 and a[15] == 15) + local b = ffi.new("uint32_t[?]", 104) + for i=0,100 do ffi.fill(b+i, 15, 0x1234) end + assert(b[0] == 0x34343434) + assert(b[103] == (ffi.abi("le") and 0x343434 or 0x34343400)) +end + +do --- copy array elements + local a = ffi.new("uint8_t[?]", 100) + local b = ffi.new("uint8_t[?]", 100) + for i=0,99 do b[i] = i end + local x = 0 + for i=0,90 do x = x + a[i]; ffi.copy(a+i, b+i, 1); x = x + a[i] end + assert(x == 4095) + local x = 0 + for i=0,90 do ffi.copy(b+i, a+90-i, 10); x = x + b[i] end + assert(x == 4095) +end + +do --- copy from string + local a = ffi.new("uint8_t[?]", 100, 42) + for i=0,90 do ffi.copy(a+i, "abc") end + local x = 0 + for i=0,99 do x = x + a[i] end + assert(x == 9276) +end + +do --- copy structures + local tp = ffi.typeof("struct { int x, y; }") + local a = tp(1, 2) + local b = tp(3, 4) + local x = 0 + for i=1,100 do a.y = i; ffi.copy(b, a, 8); x = x + b.y end + assert(x == 5050) + local x = 0 + for i=1,100 do a.y = i; local t = tp(a); x = x + t.y end + assert(x == 5050) +end + +do --- init struct from first field, complex + local tp = ffi.typeof("struct { complex x, y; }") + local cx = ffi.typeof("complex") + local a = tp(cx(1, 2), cx(3, 4)) + local x = 0 + for i=1,100 do a.y = i; local t = tp(a); x = x + t.y.re end + assert(x == 5050) +end + +do --- int array as parameterised type + local tp = ffi.typeof("int[10]") + local a = tp(42) + local b = ffi.new(ffi.typeof("struct { $ x; }", tp)) + for i=1,100 do b.x = a end + assert(b.x[0] == 42 and b.x[9] == 42) +end + +do --- double array as parameterised type + local tp = ffi.typeof("double[5]") + local a = tp(42) + local b = ffi.new(ffi.typeof("struct { $ x; }", tp)) + for i=1,100 do b.x = a end + assert(b.x[0] == 42 and b.x[4] == 42) + b.x[0] = 0 + for i=1,100 do ffi.copy(b.x, a, ffi.sizeof(a)) end + assert(b.x[0] == 42 and b.x[4] == 42) +end + +do --- abi + local x, y + for i=1,100 do x = ffi.abi("32bit"); y = ffi.abi("64bit") end + assert(x == ffi.abi("32bit")) + assert(y == ffi.abi("64bit")) + for _,s in ipairs{"64bit", "32bit", "fpu", "softfp", "hardfp", "eabi", "win", "le", "be"} do + for i=1,100 do x = ffi.abi(s) end + assert(x == ffi.abi(s)) + end +end + +do --- typeof constructed typeof + local ct = ffi.typeof("struct { int x; }") + local cd = ct() + for i=1,100 do assert(ffi.typeof(cd) == ct) end +end diff --git a/test/LuaJIT-test-cleanup/lib/ffi/jit_struct.lua b/test/LuaJIT-test-cleanup/lib/ffi/jit_struct.lua new file mode 100644 index 0000000..8aa64c1 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/jit_struct.lua @@ -0,0 +1,201 @@ +local ffi = require("ffi") + +ffi.cdef[[ +typedef struct { int a, b, c; } jit_struct_foo_t; +typedef struct { int a, b, c; } jit_struct_foo2_t; +typedef struct { int a[10]; int b[10]; } jit_struct_sarr_t; +typedef struct jit_struct_chain_t { + struct jit_struct_chain_t *next; + int v; +} jit_struct_chain_t; +]] + +do --- iteration variable as field name + local s = ffi.new("jit_struct_foo_t") + for j,k in ipairs{ "a", "b", "c" } do + for i=1,100 do s[k] = s[k] + j end + end + assert(s.a == 100) + assert(s.b == 200) + assert(s.c == 300) +end + +do --- constant field names + local s = ffi.new("jit_struct_foo_t") + for i=1,100 do + s.a = s.a + 1 + s.b = s.b + 2 + s.c = s.c + 3 + end + assert(s.a == 100) + assert(s.b == 200) + assert(s.c == 300) +end + +do --- constants from structure + local s = ffi.new("jit_struct_foo_t") + local s2 = ffi.new("jit_struct_foo2_t", 1, 2, 3) + for i=1,100 do + s.a = s.a + s2.a + s.b = s.b + s2.b + s.c = s.c + s2.c + end + assert(s.a == 100) + assert(s.b == 200) + assert(s.c == 300) +end + +do --- adding to array elements + local s = ffi.new("jit_struct_sarr_t") + for i=1,100 do + s.a[5] = s.a[5] + 1 + s.b[5] = s.b[5] + 2 + end + assert(s.a[5] == 100) + assert(s.b[5] == 200) +end + +do --- double indexing + local s = ffi.new([[ + struct { + struct { + int x; + int b[10]; + } a[100]; + }]]) + s.a[10].b[4] = 10 + s.a[95].b[4] = 95 + local x = 0 + for i=1,100 do + x = x + s.a[i-1].b[4] -- reassociate offsets for base and index + end + assert(x == 105) +end + +do --- structurally identical + local s1 = ffi.new("struct { int a; }") + local s2 = ffi.new("struct { int a; }") + local x = 0 + for j=1,2 do + for i=1,100 do + s2.a = i + s1.a = 1 + x = x + s2.a -- cannot forward across aliasing store + end + if j == 1 then + assert(x == 5050) + s2 = s1 + x = 0 + else + assert(x == 100) + end + end +end + +do --- structurally different + local s1 = ffi.new("struct { int a; }") + local s2 = ffi.new("struct { char a; }") + local x = 0 + for j=1,2 do + for i=1,100 do + s2.a = i + s1.a = 1 + x = x + s2.a -- can forward across aliasing store + end + if j == 1 then + assert(x == 5050) + s2 = s1 -- this will cause a side trace + x = 0 + else + assert(x == 100) + end + end +end + +do --- union + local s = ffi.new("union { uint8_t a; int8_t b; }") + local x = 0 + for i=1,200 do + s.a = i + x = x + s.b -- same offset, but must not alias (except if sign-extended) + end + assert(x == 1412) +end + +do --- circular chain + local s1 = ffi.new("jit_struct_chain_t") + local s2 = ffi.new("jit_struct_chain_t") + local s3 = ffi.new("jit_struct_chain_t") + s1.next = s2 + s2.next = s3 + s3.next = s1 + local p = s1 + for i=1,99 do + p.v = i + p = p.next + end + assert(s1.v == 97) + assert(s2.v == 98) + assert(s3.v == 99) +end + +do --- int struct initialiser + local ct = ffi.typeof("struct { int a,b,c; }") + local x,y,z = 0,0,0 + for i=1,100 do + local s = ct(i, i+1) + x = x + s.a + y = y + s.b + z = z + s.c + end + assert(x == 5050) + assert(y == 5150) + assert(z == 0) +end + +do --- double struct initialiser + local ct = ffi.typeof("struct { double a,b,c; }") + local x,y,z = 0,0,0 + for i=1,100 do + local s = ct(i, i+1) + x = x + s.a + y = y + s.b + z = z + s.c + end + assert(x == 5050) + assert(y == 5150) + assert(z == 0) +end + +do --- pointer / int struct initialiser + local s1 = ffi.new("jit_struct_chain_t") + local s + for i=1,100 do + s = ffi.new("jit_struct_chain_t", s1, i) + end + assert(tonumber(ffi.cast("int", s.next)) == + tonumber(ffi.cast("int", ffi.cast("jit_struct_chain_t *", s1)))) + assert(s.v == 100) +end + +do --- unstable pointer/int type struct initialiser + local ct = ffi.typeof("struct { int *p; int y; }") + local s + for i=1,200 do + if i == 100 then ct = ffi.typeof("jit_struct_chain_t") end + s = ct(nil, 10) + end + assert(s.v == 10) +end + +do --- upvalued int box + local s = ffi.new("struct { int x; }", 42) + local function f() + for i=1,100 do + s.x = i + assert(s.x == i) + end + end + f() +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/meta_tostring.lua b/test/LuaJIT-test-cleanup/lib/ffi/meta_tostring.lua new file mode 100644 index 0000000..bb065e1 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/meta_tostring.lua @@ -0,0 +1,55 @@ +local ffi = require("ffi") + +ffi.cdef[[ +typedef union meta_tostring_foo_t { + int64_t i64; + uint64_t u64; + complex cd; + double d[2]; + complex float cf; + float f[2]; +} meta_tostring_foo_t; +]] + +do --- tostring/typeof semi-roundtrip + assert(tostring(ffi.typeof("int (*(*[1][2])[3][4])[5][6]")) == + "ctype") + assert(tostring(ffi.typeof("int (*const)(void)")) == + "ctype") + assert(tostring(ffi.typeof("complex float(*(void))[2]")) == + "ctype") + assert(tostring(ffi.typeof("complex*")) == "ctype") +end + +do --- assorted union fields + local foo_t = ffi.typeof("meta_tostring_foo_t") + local x = foo_t() + + assert(tostring(foo_t) == "ctype") + assert(string.find(tostring(x), "^cdata: ")) + + x.i64 = -1; + assert(tostring(x.i64) == "-1LL") + assert(tostring(x.u64) == "18446744073709551615ULL") + + x.d[0] = 12.5 + x.d[1] = -753.125 + assert(tostring(x.cd) == "12.5-753.125i") + x.d[0] = -12.5 + x.d[1] = 753.125 + assert(tostring(x.cd) == "-12.5+753.125i") + x.d[0] = 0/-1 + x.d[1] = 0/-1 + assert(tostring(x.cd) == "-0-0i") + x.d[0] = 1/0 + x.d[1] = -1/0 + assert(tostring(x.cd) == "inf-infI") + x.d[0] = -1/0 + x.d[1] = 0/0 + assert(tostring(x.cd) == "-inf+nanI") + + x.f[0] = 12.5 + x.f[1] = -753.125 + assert(tostring(x.cf) == "12.5-753.125i") +end + diff --git a/test/LuaJIT-test-cleanup/lib/ffi/redir.lua b/test/LuaJIT-test-cleanup/lib/ffi/redir.lua new file mode 100644 index 0000000..c492055 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/redir.lua @@ -0,0 +1,19 @@ +local ffi = require("ffi") + +do --- function + ffi.cdef[[ + int redir_foo(const char *s) asm("strlen"); + ]] + + assert(ffi.C.redir_foo("abcd") == 4) +end + +do --- variable -windows + ffi.cdef[[ + int redir_bar asm("errno"); + ]] + + ffi.C.redir_bar = 14 + assert(ffi.C.redir_bar == 14) + ffi.C.redir_bar = 0 +end diff --git a/test/LuaJIT-test-cleanup/lib/ffi/type_punning.lua b/test/LuaJIT-test-cleanup/lib/ffi/type_punning.lua new file mode 100644 index 0000000..ac70b4b --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/ffi/type_punning.lua @@ -0,0 +1,138 @@ +local ffi = require("ffi") + +local u = ffi.new([[ +union { + int8_t i8[8]; + uint8_t u8[8]; + int16_t i16[4]; + uint16_t u16[4]; + int32_t i32[2]; + uint32_t u32[2]; + int64_t i64[1]; + uint64_t u64[1]; + void *v[2]; + float f[2]; + double d[1]; +} +]]) + +do --- float -> u32 type punning at same offset + local x = 0LL + for i=1,100 do + u.f[0] = i + x = x + u.u32[0] + end + assert(x == 110888222720LL) +end + +do --- double -> u64 type punning at same offset + local x = 0LL + for i=1,100 do + u.d[0] = i + x = x + u.u64[0] + end + assert(x == 1886586031403171840ULL) +end + +do --- i8 -> u8 type punning at same offset (fwd -> CONV.int.u8) + local x = 0 + for i=-100,100 do + u.i8[0] = i + x = x + u.u8[0] + end + assert(x == 25600) +end + +do --- p32/p64 -> u64 type punning at same offset (32 bit: different size) + local x = 0LL + u.u64[0] = 0 + for i=-100,150 do + u.v[0] = ffi.cast("void *", ffi.cast("ptrdiff_t", i)) + x = x + u.u64[0] + end + assert(x == (ffi.abi"64bit" and 6275ULL or + (ffi.abi"le" and 0x6400001883ULL or 0x188300000000ULL))) +end + +do --- u16 -> u8 type punning at overlapping offsets [0] + local x = 0 + for i=255,520 do + u.u16[0] = i + x = x + u.u8[0] + end + assert(x == (ffi.abi"be" and 274 or 32931)) +end + +do --- u16 -> u8 type punning at overlapping offsets [1] + local x = 0 + for i=255,520 do + u.u16[0] = i + x = x + u.u8[1] + end + assert(x == (ffi.abi"le" and 274 or 32931)) +end + +do --- i16 -> i32 type punning at overlapping offsets [0] + local x = 0 + u.i32[0] = 0 + for i=-100,150 do + u.i16[0] = i + x = x + u.i32[0] + end + assert(x == (ffi.abi"be" and 411238400 or 6559875)) +end + +do --- i16 -> i32 type punning at overlapping offsets [1] + local x = 0 + u.i32[0] = 0 + for i=-100,150 do + u.i16[1] = i + x = x + u.i32[0] + end + assert(x == (ffi.abi"le" and 411238400 or 6559875)) +end + +do --- double -> i32 type punning at overlapping offsets [0] + local x = 0 + for i=1.5,120,1.1 do + u.d[0] = i + x = x + u.i32[0] + end + assert(x == (ffi.abi"be" and 116468870297 or -858993573)) +end + +do --- double -> i32 type punning at overlapping offsets [1] + local x = 0 + for i=1.5,120,1.1 do + u.d[0] = i + x = x + u.i32[1] + end + assert(x == (ffi.abi"le" and 116468870297 or -858993573)) +end + +do --- u32 -> u64 type punning, constify u, 32 bit SPLIT: fold KPTR + local u = ffi.new("union { struct { uint32_t lo, hi; }; uint64_t u64; }") + + local function conv(lo, hi) + u.lo = lo + u.hi = hi + return u.u64 + end + + local x = 0ll + for i=1,100 do + x = x + conv(i, i) + end + assert(x == 21689584849850ULL) +end + +do --- u64 -> u32 -> u64 type punning with KPTR + local s = ffi.new("union { int64_t q; int32_t i[2]; }") + local function f() + s.q = 0 + s.i[1] = 1 + return s.q + end + for i=1,50 do f() f() f() end + assert(f() ~= 0) +end diff --git a/test/LuaJIT-test-cleanup/lib/index b/test/LuaJIT-test-cleanup/lib/index new file mode 100644 index 0000000..cc9d7d7 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/index @@ -0,0 +1,8 @@ +base +bit.lua +bit +math +string +table +coroutine +ffi +ffi +contents.lua \ No newline at end of file diff --git a/test/LuaJIT-test-cleanup/lib/math/abs.lua b/test/LuaJIT-test-cleanup/lib/math/abs.lua new file mode 100644 index 0000000..4223a78 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/math/constants.lua b/test/LuaJIT-test-cleanup/lib/math/constants.lua new file mode 100644 index 0000000..ec35b4c --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/math/index b/test/LuaJIT-test-cleanup/lib/math/index new file mode 100644 index 0000000..944e1ae --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/math/index @@ -0,0 +1,3 @@ +abs.lua +constants.lua +random.lua diff --git a/test/LuaJIT-test-cleanup/lib/math/random.lua b/test/LuaJIT-test-cleanup/lib/math/random.lua new file mode 100644 index 0000000..dc2ca00 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/string/byte.lua b/test/LuaJIT-test-cleanup/lib/string/byte.lua new file mode 100644 index 0000000..697a2c2 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/string/byte.lua @@ -0,0 +1,92 @@ +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/LuaJIT-test-cleanup/lib/string/char.lua b/test/LuaJIT-test-cleanup/lib/string/char.lua new file mode 100644 index 0000000..544767d --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/string/dump.lua b/test/LuaJIT-test-cleanup/lib/string/dump.lua new file mode 100644 index 0000000..216c6eb --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/string/dump.lua @@ -0,0 +1,31 @@ +local loadstring = loadstring or load + +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/LuaJIT-test-cleanup/lib/string/format/index b/test/LuaJIT-test-cleanup/lib/string/format/index new file mode 100644 index 0000000..4408853 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/string/format/index @@ -0,0 +1 @@ +num.lua diff --git a/test/LuaJIT-test-cleanup/lib/string/format/num.lua b/test/LuaJIT-test-cleanup/lib/string/format/num.lua new file mode 100644 index 0000000..e8cb33f --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/string/index b/test/LuaJIT-test-cleanup/lib/string/index new file mode 100644 index 0000000..c0638e9 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/string/index @@ -0,0 +1,11 @@ +metatable.lua +byte.lua +char.lua +dump.lua +format +len.lua +lower_upper.lua +multiple_functions.lua +rep.lua +reverse.lua +sub.lua diff --git a/test/LuaJIT-test-cleanup/lib/string/len.lua b/test/LuaJIT-test-cleanup/lib/string/len.lua new file mode 100644 index 0000000..8ed7e8a --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/string/lower_upper.lua b/test/LuaJIT-test-cleanup/lib/string/lower_upper.lua new file mode 100644 index 0000000..7370c44 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/string/lower_upper.lua @@ -0,0 +1,51 @@ +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 + +do --- repeated with growing string + local y, z + local x = "aBcDe" + for i=1,100 do + y = string.upper(x) + z = y.."fgh" + end + assert(y == "ABCDE") + assert(z == "ABCDEfgh") +end + +do --- misc upper + local y + for i=1,100 do y = string.upper("aBc9") end + assert(y == "ABC9") + local x = ":abCd+" + for i=1,100 do y = string.upper(x) end + assert(y == ":ABCD+") + x = 1234 + for i=1,100 do y = string.upper(x) end + assert(y == "1234") +end + +do --- misc lower + local y + for i=1,100 do y = string.lower("aBc9") end + assert(y == "abc9") + local x = ":abcd+" + for i=1,100 do y = string.lower(x) end + assert(y == ":abcd+") + x = 1234 + for i=1,100 do y = string.lower(x) end + assert(y == "1234") +end diff --git a/test/LuaJIT-test-cleanup/lib/string/metatable.lua b/test/LuaJIT-test-cleanup/lib/string/metatable.lua new file mode 100644 index 0000000..d39ed43 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/string/metatable.lua @@ -0,0 +1,3 @@ +do --- __index metamethod is string library + assert(debug.getmetatable("").__index == string) +end diff --git a/test/LuaJIT-test-cleanup/lib/string/multiple_functions.lua b/test/LuaJIT-test-cleanup/lib/string/multiple_functions.lua new file mode 100644 index 0000000..7b9d0f1 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/string/multiple_functions.lua @@ -0,0 +1,16 @@ +do --- string_op + local t, y = {}, {} + for i=1,100 do t[i] = string.char(i, 16+i, 32+i) end + for i=1,100 do t[i] = string.reverse(t[i]) end + assert(t[100] == "\132\116\100") + for i=1,100 do t[i] = string.reverse(t[i]) end + for i=1,100 do assert(t[i] == string.char(i, 16+i, 32+i)) end + for i=1,100 do y[i] = string.upper(t[i]) end + assert(y[65] == "AQA") + assert(y[97] == "AQ\129") + assert(y[100] == "DT\132") + for i=1,100 do y[i] = string.lower(t[i]) end + assert(y[65] == "aqa") + assert(y[97] == "aq\129") + assert(y[100] == "dt\132") +end diff --git a/test/LuaJIT-test-cleanup/lib/string/rep.lua b/test/LuaJIT-test-cleanup/lib/string/rep.lua new file mode 100644 index 0000000..550c15b --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/string/rep.lua @@ -0,0 +1,68 @@ +local rep = string.rep + +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 + +do --- misc + local y + for i=1,100 do y = rep("a", 10) end + assert(y == "aaaaaaaaaa") + for i=1,100 do y = rep("ab", 10) end + assert(y == "abababababababababab") + local x = "a" + for i=1,100 do y = rep(x, 10) end + assert(y == "aaaaaaaaaa") + local n = 10 + for i=1,100 do y = rep(x, n) end + assert(y == "aaaaaaaaaa") + x = "ab" + for i=1,100 do y = rep(x, n) end + assert(y == "abababababababababab") + x = 12 + n = "10" + for i=1,100 do y = rep(x, n) end + assert(y == "12121212121212121212") +end + +do --- separator +goto + local y + for i=1,100 do y = rep("ab", 10, "c") end + assert(y == "abcabcabcabcabcabcabcabcabcab") +end + +do --- iterate to table + local t = {} + for i=1,100 do t[i] = rep("ab", i-85) end + assert(t[100] == "ababababababababababababababab") +end + +do --- iterate to table with sep +goto + local t = {} + for i=1,100 do t[i] = rep("ab", i-85, "c") end + assert(t[85] == "") + assert(t[86] == "ab") + assert(t[87] == "abcab") + assert(t[100] == "abcabcabcabcabcabcabcabcabcabcabcabcabcabcab") +end + +do --- iterate and concat + local y, z + local x = "ab" + for i=1,100 do + y = rep(x, i-90) + z = y.."fgh" + end + assert(y == "abababababababababab") + assert(z == "ababababababababababfgh") +end diff --git a/test/LuaJIT-test-cleanup/lib/string/reverse.lua b/test/LuaJIT-test-cleanup/lib/string/reverse.lua new file mode 100644 index 0000000..deaade7 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/string/reverse.lua @@ -0,0 +1,13 @@ +local reverse = string.reverse + +do --- misc + local y + for i=1,100 do y = reverse("abc") end + assert(y == "cba") + local x = "abcd" + for i=1,100 do y = reverse(x) end + assert(y == "dcba") + x = 1234 + for i=1,100 do y = reverse(x) end + assert(y == "4321") +end diff --git a/test/LuaJIT-test-cleanup/lib/string/sub.lua b/test/LuaJIT-test-cleanup/lib/string/sub.lua new file mode 100644 index 0000000..ecb8021 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/table/concat.lua b/test/LuaJIT-test-cleanup/lib/table/concat.lua new file mode 100644 index 0000000..1f2a2f9 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/table/index b/test/LuaJIT-test-cleanup/lib/table/index new file mode 100644 index 0000000..bd3af0b --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/test/LuaJIT-test-cleanup/lib/table/insert.lua b/test/LuaJIT-test-cleanup/lib/table/insert.lua new file mode 100644 index 0000000..91d4dd8 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/table/insert.lua @@ -0,0 +1,17 @@ +local tinsert = table.insert +local assert = assert + +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 + +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 + assert(#t == 300 and t[101] == 101 and t[200] == 200 and t[300] == 200) +end + diff --git a/test/LuaJIT-test-cleanup/lib/table/misc.lua b/test/LuaJIT-test-cleanup/lib/table/misc.lua new file mode 100644 index 0000000..e0e2fc5 --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/table/misc.lua @@ -0,0 +1,58 @@ +-- TODO: Organise + +-- ABC elim +-- +opt +abc +do + local s, t = {}, {} + for i=1,100 do t[i] = 1 end + for i=1,100 do s[i] = t end + s[90] = {} + local n = 100 + for i=1,n do s[i][i] = i end +end + +--- TSETM +-- Initialize table with multiple return values +do + local function f(a,b,c) + return a,b,c + end + + local t + + t = {(f(1,2,3))} + assert(t[1] == 1 and t[2] == nil and t[3] == nil) + + t = {f(1,2,3)} + assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == nil) + t = {f(1,2,3),} + assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == nil) + + t = {f(1,2,3), f(4,5,6)} + assert(t[1] == 1 and t[2] == 4 and t[3] == 5 and t[4] == 6 and t[5] == nil) + + t = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + f(2,3,4)} + assert(t[255] == 1 and t[256] == 2 and t[257] == 3 and t[258] == 4 and t[259] == nil) +end + +--- TSETM 2 +-- Initialize table with function returning 2 constant return values +do + local function f() return 9, 10 end + local t + for i=1,100 do t = { 1, 2, 3, f() } end + assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 9 and t[5] == 10 and + t[6] == nil) +end + + + diff --git a/test/LuaJIT-test-cleanup/lib/table/new.lua b/test/LuaJIT-test-cleanup/lib/table/new.lua new file mode 100644 index 0000000..483c129 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/lib/table/pack.lua b/test/LuaJIT-test-cleanup/lib/table/pack.lua new file mode 100644 index 0000000..5bd6ecb --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/test/LuaJIT-test-cleanup/lib/table/remove.lua b/test/LuaJIT-test-cleanup/lib/table/remove.lua new file mode 100644 index 0000000..1b24a4f --- /dev/null +++ b/test/LuaJIT-test-cleanup/lib/table/remove.lua @@ -0,0 +1,42 @@ +local tremove = table.remove +local assert = assert + +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 + +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 + +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 + +do --- TSETR hash part +table.new + local tnew = require"table.new" + local t = tnew(0, 16) + for i=10,1,-1 do t[i] = i+3 end + for i=10,1,-1 do assert(tremove(t) == i+3) end + assert(#t == 0) +end + +do --- TSETR write barrier +table.new + local tnew = require"table.new" + for _, t in ipairs{{}, tnew(0, 16)} do + for i = 1, 10 do t[i] = {i} end + for i = 1, 10 do + collectgarbage() + assert(tremove(t, 1)[1] == i) + end + end +end diff --git a/test/LuaJIT-test-cleanup/lib/table/sort.lua b/test/LuaJIT-test-cleanup/lib/table/sort.lua new file mode 100644 index 0000000..6a86fcf --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/misc/alias_alloc.lua b/test/LuaJIT-test-cleanup/misc/alias_alloc.lua new file mode 100644 index 0000000..02fe618 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/alias_alloc.lua @@ -0,0 +1,54 @@ + +do + local t = {1} + local x + for i=1,100 do + local v = {i} + t[1] = v[1] + x = v[1] + end + assert(x == 100 and t[1] == 100) +end + +do + local t = {1} + local x,y + for i=1,100 do + local v = {i} + local w = {i+1} + x = v[1] + y = w[1] + end + assert(x == 100 and y == 101) +end + +do + local mt = {} + local t = setmetatable({}, mt) + local x + for i=1,100 do + local v = {} + setmetatable(v, getmetatable(t)) + assert(getmetatable(v) == mt) + end +end + +-- See also sink_alloc.lua +do + local x,k={1,2},{3,4} + for i=1,100 do x = {x[1]+k[1], x[2]+k[2]} end + assert(x[1] == 301) + assert(x[2] == 402) +end + +-- FLOAD for tab.asize/tab.array crossing NEWREF. +do + local t = {1} + for i=1,100 do + local v = {} + local w = {} + v[1] = t[1] + w[1] = t[1] + end +end + diff --git a/test/LuaJIT-test-cleanup/misc/api_call.lua b/test/LuaJIT-test-cleanup/misc/api_call.lua new file mode 100644 index 0000000..7dbd5e4 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/api_call.lua @@ -0,0 +1,98 @@ +local ctest = require("ctest") + +local function ret0() end +local function ret1() return 1 end +local function ret2() return 1,2 end +local function ret3() return 1,2,3 end +local function retva(...) return ... end +local function ret1va(...) return 1,... end + +local function pack(...) + return { n = select('#', ...), ... } +end + +local function ck(res, ...) + local ok = pack(...) + if res.n ~= ok.n then error("nresults wrong: "..res.n.." ~= "..ok.n, 2) end + for i=1,res.n do + if res[i] ~= ok[i] then + error("result["..i.."] wrong: "..tostring(res[i]).." ~= "..tostring(ok[i]), 2) + end + end +end + +local function test_adjust_results(testfunc) + + local function cc(nres, f, ...) + return pack(testfunc(nres, f, ...)) + end + + ck(cc(0, ret0)) + ck(cc(0, ret1)) + ck(cc(0, ret2)) + ck(cc(0, ret3)) + ck(cc(0, retva)) + + ck(cc(1, ret0), nil) + ck(cc(1, ret1), 1) + ck(cc(1, ret2), 1) + ck(cc(1, ret3), 1) + ck(cc(1, retva), nil) + ck(cc(1, retva, 1), 1) + + ck(cc(2, ret0), nil, nil) + ck(cc(2, ret1), 1, nil) + ck(cc(2, ret2), 1, 2) + ck(cc(2, ret3), 1, 2) + ck(cc(2, retva), nil, nil) + ck(cc(2, retva, 1), 1, nil) + ck(cc(2, retva, 1, 2), 1, 2) + + ck(cc(-1, ret0)) + ck(cc(-1, ret1), 1) + ck(cc(-1, ret2), 1, 2) + ck(cc(-1, ret3), 1, 2, 3) + ck(cc(-1, retva)) + ck(cc(-1, retva, 1), 1) + ck(cc(-1, retva, 1, 2), 1, 2) +end + +test_adjust_results(ctest.call) +test_adjust_results(ctest.pcall_err) + + +local function gcshrink() + for i=1,10 do collectgarbage() end +end + +assert(select('#', ctest.call(2000, gcshrink)) == 2000) +gcshrink() +assert(select('#', ctest.call(7000, gcshrink)) == 7000) +gcshrink() + +local function test_yield(resume, yield) + local function inpcall() + ck(pack(yield(6, 7)), 18, 19) + end + local co = coroutine.create(function(...) + ck(pack(...), 11, 12) + ck(pack(yield(1, 2))) + ck(pack(yield()), 13, 14, 15) + ck(pack(yield(3, 4, 5)), 16, 17) + assert(pcall(inpcall) == true) + return 8, 9 + end) + + ck(pack(resume(co, 11, 12)), true, 1, 2) + ck(pack(resume(co)), true) + ck(pack(resume(co, 13, 14, 15)), true, 3, 4, 5) + ck(pack(resume(co, 16, 17)), true, 6, 7) + ck(pack(resume(co, 18, 19)), true, 8, 9) + assert(resume(co) == false) +end + +test_yield(coroutine.resume, coroutine.yield) +test_yield(ctest.resume, coroutine.yield) +test_yield(coroutine.resume, ctest.yield) +test_yield(ctest.resume, ctest.yield) + diff --git a/test/LuaJIT-test-cleanup/misc/catch_wrap.lua b/test/LuaJIT-test-cleanup/misc/catch_wrap.lua new file mode 100644 index 0000000..7f656bc --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/catch_wrap.lua @@ -0,0 +1,45 @@ + +local cp = require("cpptest") +cp.wrapon() + +do + local a, b = pcall(cp.catch, function() return "x" end) + assert(a == true and b == "x") +end + +do + local a, b = pcall(function() cp.throw("foo") end) + assert(a == false and b == "foo") +end + +local unwind +do + local a, b = pcall(cp.catch, function() cp.throw("foo") end) + unwind = a + assert((a == false and b == "foo") or (a == true and b == "catch ...")) +end + +do + local st = cp.alloc(function() return cp.isalloc() end) + assert(st == true) + assert(cp.isalloc() == false) +end + +do + local a, b = pcall(cp.alloc, function() + assert(cp.isalloc() == true) + return "foo", cp.throw + end) + assert(a == false and b == "foo") + assert(cp.isalloc() == false) +end + +do + local a, b = pcall(cp.alloc, function() + assert(cp.isalloc() == true) + return "foo", error + end) + assert(a == false and b == "foo") + if unwind then assert(cp.isalloc() == false) end +end + diff --git a/test/LuaJIT-test-cleanup/misc/coro_traceback.lua b/test/LuaJIT-test-cleanup/misc/coro_traceback.lua new file mode 100644 index 0000000..2676d2c --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/coro_traceback.lua @@ -0,0 +1,8 @@ + +local co = coroutine.create(function() + local x = nil + local y = x.x +end) +assert(coroutine.resume(co) == false) +debug.traceback(co) + diff --git a/test/LuaJIT-test-cleanup/misc/coro_yield.lua b/test/LuaJIT-test-cleanup/misc/coro_yield.lua new file mode 100644 index 0000000..ae3206e --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/coro_yield.lua @@ -0,0 +1,111 @@ +local create = coroutine.create +local wrap = coroutine.wrap +local resume = coroutine.resume +local yield = coroutine.yield + +-- Test stack overflow handling on return from coroutine. +do + wrap(function() + local co = create(function() + yield(string.byte(string.rep(" ", 100), 1, 100)) + end) + assert(select('#', resume(co)) == 101) + end)() +end + +do + wrap(function() + local f = wrap(function() + yield(string.byte(string.rep(" ", 100), 1, 100)) + end) + assert(select('#', f()) == 100) + end)() +end + +do + 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 + 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 + 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/LuaJIT-test-cleanup/misc/debug_gc.lua b/test/LuaJIT-test-cleanup/misc/debug_gc.lua new file mode 100644 index 0000000..30fb2b9 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/debug_gc.lua @@ -0,0 +1,47 @@ + +-- Do not run this test unless the JIT compiler is turned off. +if jit and jit.status and jit.status() then return end + +local caught, caught_line, caught_mm + +local function gcmeta() + if caught ~= "end" then +-- print(debug.traceback()) + -- This may point to the wrong instruction if in a JIT trace. + -- But there's no guarantee if, when or where any GC steps occur. + local dbg = debug.getinfo(2) + caught_line = dbg.currentline + caught_mm = debug.getinfo(1).name + caught = true + end +end + +local function testgc(mm, f) + collectgarbage() + caught = false + local u = newproxy(true) + getmetatable(u).__gc = gcmeta + u = nil + for i=1,100000 do + f(i) + -- This check may be hoisted. __gc is not supposed to have side-effects. + if caught then break end + end + if not caught then + error(mm.." metamethod not called", 2) + end + if type(caught_line) ~= "number" or caught_line < 0 then + error("bad linenumber in debug info", 2) + end + if caught_mm ~= mm then + error("bad name for metamethod in debug info", 2) + end +end + +local x +testgc("__gc", function(i) x = {} end) +testgc("__gc", function(i) x = {1} end) +testgc("__gc", function(i) x = function() end end) +testgc("__concat", function(i) x = i.."" end) + +caught = "end" diff --git a/test/LuaJIT-test-cleanup/misc/dualnum.lua b/test/LuaJIT-test-cleanup/misc/dualnum.lua new file mode 100644 index 0000000..5f1288c --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/dualnum.lua @@ -0,0 +1,47 @@ + +-- Positive overflow +do + local x = 0 + for i=2147483446,2147483647,2 do x = x + 1 end + assert(x == 101) +end + +-- Negative overflow +do + local x = 0 + for i=-2147483447,-2147483648,-2 do x = x + 1 end + assert(x == 101) +end + +-- SLOAD with number to integer conversion. +do + local k = 1 + local a, b, c = 1/k, 20/k, 1/k + for i=1,20 do + for j=a,b,c do end + end +end + +do + local function fmin(a, b) + for i=1,100 do a = math.min(a, b) end + return a + end + local function fmax(a, b) + for i=1,100 do a = math.max(a, b) end + return a + end + assert(fmin(1, 3) == 1) + assert(fmin(3, 1) == 1) + assert(fmin(-1, 3) == -1) + assert(fmin(3, -1) == -1) + assert(fmin(-1, -3) == -3) + assert(fmin(-3, -1) == -3) + assert(fmax(1, 3) == 3) + assert(fmax(3, 1) == 3) + assert(fmax(-1, 3) == 3) + assert(fmax(3, -1) == 3) + assert(fmax(-1, -3) == -1) + assert(fmax(-3, -1) == -1) +end + diff --git a/test/LuaJIT-test-cleanup/misc/for_dir.lua b/test/LuaJIT-test-cleanup/misc/for_dir.lua new file mode 100644 index 0000000..4dd38de --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/for_dir.lua @@ -0,0 +1,13 @@ + +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 + diff --git a/test/LuaJIT-test-cleanup/misc/fori_coerce.lua b/test/LuaJIT-test-cleanup/misc/fori_coerce.lua new file mode 100644 index 0000000..7330943 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/fori_coerce.lua @@ -0,0 +1,33 @@ + +do + 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 + 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 + 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/LuaJIT-test-cleanup/misc/gc_rechain.lua b/test/LuaJIT-test-cleanup/misc/gc_rechain.lua new file mode 100644 index 0000000..285f408 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/gc_rechain.lua @@ -0,0 +1,32 @@ + +do + 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/LuaJIT-test-cleanup/misc/gc_trace.lua b/test/LuaJIT-test-cleanup/misc/gc_trace.lua new file mode 100644 index 0000000..bc38ce0 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/gc_trace.lua @@ -0,0 +1,37 @@ + +if not jit or not jit.status or not jit.status() then return end + +collectgarbage() +for j=1,100 do + loadstring("for i=1,100 do end")() +end +local jutil = require("jit.util") +assert(jutil.traceinfo(90) == nil) +collectgarbage() +assert(jutil.traceinfo(1) == nil) +assert(jutil.traceinfo(2) == nil) +assert(jutil.traceinfo(3) == nil) + +do + local f + local function reccb(tr) + if f == nil then + collectgarbage() + local info = jutil.traceinfo(tr) + jutil.tracek(tr, -info.nk) + -- Error in lj_ir_kvalue() if KGC not marked. + -- Only caught with assertions or Valgrind. + end + end + jit.attach(reccb, "record") + for i=1,200 do + if i % 5 == 0 then + f = function() end + elseif f then + f() + f = nil + end + end + jit.attach(reccb) +end + diff --git a/test/LuaJIT-test-cleanup/misc/gcstep.lua b/test/LuaJIT-test-cleanup/misc/gcstep.lua new file mode 100644 index 0000000..533356b --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/gcstep.lua @@ -0,0 +1,33 @@ + +local function testgc(what, func) + collectgarbage() + local oc = gcinfo() + func() + local nc = gcinfo() + assert(nc < oc*4, "GC step missing for "..what) +end + +testgc("TNEW", function() + for i=1,10000 do + local t = {} + end +end) + +testgc("TDUP", function() + for i=1,10000 do + local t = {1} + end +end) + +testgc("FNEW", function() + for i=1,10000 do + local function f() end + end +end) + +testgc("CAT", function() + for i=1,10000 do + local s = "x"..i + end +end) + diff --git a/test/LuaJIT-test-cleanup/misc/hook_active.lua b/test/LuaJIT-test-cleanup/misc/hook_active.lua new file mode 100644 index 0000000..37dfc37 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/hook_active.lua @@ -0,0 +1,95 @@ +local ctest = require("ctest") + +local called = 0 +local function clearhook() debug.sethook(nil, "", 0) end + +-- Return from pcall with active hook must prepend true. FF pcall. +called = 0 +debug.sethook(function() called=called+1; assert(pcall(function() end) == true); clearhook() end, "", 1) +do local x = 1 end +assert(called == 1) + +-- Hook with special caught error must not unblock hooks. FF pcall. +called = 0 +debug.sethook(function() called=called+1; pcall(nil); clearhook() end, "", 1) +do local x = 1 end +assert(called == 1) + +-- Hook with caught error must not unblock hooks. FF pcall. +called = 0 +local function p2() error("") end +debug.sethook(function() called=called+1; pcall(p2); clearhook() end, "", 1) +do local x = 1 end +assert(called == 1) + +-- Hook with special caught error must not unblock hooks. C pcall. +called = 0 +debug.sethook(function() called=called+1; ctest.pcall(nil); clearhook() end, "", 1) +do local x = 1 end +assert(called == 1) + +-- Hook with caught error must not unblock hooks. C pcall +called = 0 +local function p2() error("") end +debug.sethook(function() called=called+1; ctest.pcall(p2); clearhook() end, "", 1) +do local x = 1 end +assert(called == 1) + +-- Regular pcall must not block hooks. +debug.sethook(function() called=called+1 end, "", 1) +pcall(function() end) +called = 0 +do local x = 1 end +assert(called > 0) +pcall(function() error("") end) +called = 0 +do local x = 1 end +assert(called > 0) +ctest.pcall(function() end) +called = 0 +do local x = 1 end +assert(called > 0) +ctest.pcall(function() error("") end) +called = 0 +do local x = 1 end +assert(called > 0) +clearhook() + +-- Hook with uncaught error must unblock hooks. FF pcall +called = 0 +pcall(function() + debug.sethook(function() + local old = called + called = 1 + if old == 0 then error("") end + end, "", 1) + do local x = 1 end +end) +assert(called == 1) +called = 2 +do local x = 1 end +assert(called == 1, "hook not unblocked after uncaught error") +clearhook() +called = 2 +do local x = 1 end +assert(called == 2) + +-- Hook with uncaught error must unblock hooks. C pcall +called = 0 +ctest.pcall(function() + debug.sethook(function() + local old = called + called = 1 + if old == 0 then error("") end + end, "", 1) + do local x = 1 end +end) +assert(called == 1) +called = 2 +do local x = 1 end +assert(called == 1, "hook not unblocked after uncaught error") +clearhook() +called = 2 +do local x = 1 end +assert(called == 2) + diff --git a/test/LuaJIT-test-cleanup/misc/hook_line.lua b/test/LuaJIT-test-cleanup/misc/hook_line.lua new file mode 100644 index 0000000..36f7108 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/hook_line.lua @@ -0,0 +1,41 @@ +local lines = {} +local function hook() + lines[#lines+1] = debug.getinfo(2).currentline +end + +local function dummy() +end -- <-- line 7 + +debug.sethook(hook, "l", 0) +-- <-- line 10 +local x +dummy() +local y = 1 +dummy() dummy() +local z = 2; local r = true +while y < 4 do y = y + 1 end +while z < 4 do + z = z + 1 +end +-- <-- line 20 +local v +debug.sethook(nil, "", 0) + +assert(#lines > 0) +while lines[1] < 10 do table.remove(lines, 1) end +while lines[#lines] > 20 do table.remove(lines) end + +local s = table.concat(lines, " ") +assert(s == "11 12 7 13 14 7 7 15 16 16 16 16 17 18 17 18 17" or + s == "11 12 7 13 14 7 14 7 15 16 16 16 16 17 18 17 18 17") + +lines = {} +local function f() + if true then return end + local function x() end +end -- <-- line 36 +debug.sethook(hook, "l", 0) +f() +debug.sethook(nil, "", 0) +for i=1,#lines do assert(lines[i] ~= 36) end + diff --git a/test/LuaJIT-test-cleanup/misc/hook_norecord.lua b/test/LuaJIT-test-cleanup/misc/hook_norecord.lua new file mode 100644 index 0000000..8e7cba0 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/hook_norecord.lua @@ -0,0 +1,12 @@ + +if not jit or not jit.status or not jit.status() then return end + +local called = false +local function f() local x = "wrong"; called = true end +jit.off(f) +debug.sethook(f, "", 5) +for i=1,1000 do local a,b,c,d,e,f=1,2,3,4,5,6 end +assert(called) +-- Check that no trace was generated. +assert(require("jit.util").traceinfo(1) == nil) + diff --git a/test/LuaJIT-test-cleanup/misc/hook_record.lua b/test/LuaJIT-test-cleanup/misc/hook_record.lua new file mode 100644 index 0000000..6f1646d --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/hook_record.lua @@ -0,0 +1,8 @@ + +if not jit or not jit.status or not jit.status() then return end + +debug.sethook(function() for i=1,100 do end end, "", 10) +for i=1,10 do end +debug.sethook() +assert((require("jit.util").traceinfo(1))) + diff --git a/test/LuaJIT-test-cleanup/misc/hook_top.lua b/test/LuaJIT-test-cleanup/misc/hook_top.lua new file mode 100644 index 0000000..f809fce --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/hook_top.lua @@ -0,0 +1,55 @@ + +local t = {} +for i=1,26 do t[i] = string.char(96+i) end + +local function tcheck(t1, t2) + assert(#t1 == #t2) + for i=1,#t1 do assert(t1[i] == t2[i]) end +end + +local function foo1(...) -- VARG RETM + return ... +end + +local function foo2(...) -- VARG UCLO RETM + local function dummy() end + return ... +end + +local function foo3(...) -- VARG UCLO -> RETM + do return ... end + local function dummy() end +end + +local function foo4() -- UCLO UCLO RET + do + local x + local function dummy() return x end + end +end + +called = false +debug.sethook(function() local x = "wrong"; called = true end, "", 1) +tcheck(t, {foo1(unpack(t))}) -- CALLM TSETM +assert(called) +called = false +tcheck(t, {foo2(unpack(t))}) +assert(called) +called = false +tcheck(t, {foo2(unpack(t))}) +assert(called) +called = false +foo4() +assert(called) + +debug.sethook(function() + local name, val = debug.getlocal(2, 1) + assert(name == "a" and val == nil) + debug.setlocal(2, 1, "bar") + debug.sethook(nil) +end, "c") +local function foo5(a) + assert(a == "bar") +end +foo5() + diff --git a/test/LuaJIT-test-cleanup/misc/jit_flush.lua b/test/LuaJIT-test-cleanup/misc/jit_flush.lua new file mode 100644 index 0000000..ead1e4e --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/jit_flush.lua @@ -0,0 +1,50 @@ + +if not jit or not jit.status or not jit.status() then return end + +for i=1,100 do + if i==50 then jit.flush(2) end + for j=1,100 do end + for j=1,100 do end +end + +jit.flush() + +local function f() for i=1,100 do end end +for i=1,100 do local x = gcinfo(); f() end + +jit.flush() + +local function fib(n) + if n < 2 then return 1 end + return fib(n-2) + fib(n-1) +end + +fib(11) + +jit.flush() + +local names = {} +for i=1,100 do names[i] = i end + +function f() + for k,v in ipairs(names) do end +end + +f() + +for i=1,2 do + f() + f() + jit.flush() +end + +jit.flush() + +jit.flush(1) -- ignored +jit.flush(2) -- ignored +for i=1,1e7 do end -- causes trace #1 + +jit.flush(2) -- ignored +jit.flush(1) -- ok +jit.flush(1) -- crashes + diff --git a/test/LuaJIT-test-cleanup/misc/lightud.lua b/test/LuaJIT-test-cleanup/misc/lightud.lua new file mode 100644 index 0000000..4974d50 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/lightud.lua @@ -0,0 +1,88 @@ +local ctest = require("ctest") + +local lightud = ctest.lightud +local assert = assert + +-- x64 lightud tests +if jit and jit.arch == "x64" then + do + local ud1 = lightud(0x12345678) + local ud2 = lightud(0x12345678) + assert(ud1 == ud2) + assert(tostring(ud1) == "userdata: 0x12345678") + end + do + local ud1 = lightud(1) + local ud2 = lightud(2) + assert(ud1 ~= ud2) + end + do + local ud1 = lightud(2^47-1) + local ud2 = lightud(2^47-1) + assert(ud1 == ud2) + assert(tostring(ud1) == "userdata: 0x7fffffffffff") + end + do + local ud1 = lightud(0x12345678+123*2^32) + local ud2 = lightud(0x12345678+456*2^32) + for i=1,100 do assert(ud1 ~= ud2) end + end + assert(tostring(lightud(0x5abc*2^32 + 0xdef01234)) == "userdata: 0x5abcdef01234") + assert(pcall(lightud, 2^47) == false) + assert(pcall(lightud, 2^64-2048) == false) +end + +assert(getmetatable(lightud(1)) == nil) + +-- lightuserdata SLOAD value and HREF key +do + local ud = lightud(12345) + local t = {[ud] = 42} + for i=1,100 do + assert(t[ud] == 42) + end +end + +-- lightuserdata NEWREF key +do + local ud = lightud(12345) + for i=1,100 do + local t = {[ud] = 42} + assert(t[ud] == 42) + end +end + +-- lightuserdata ASTORE/HSTORE value +do + local ud = lightud(12345) + local t = {} + for i=1,100 do + t[i] = ud + end + assert(t[100] == ud) +end + +-- lightuserdata sync to stack +do + local ud = lightud(12345) + local x = nil + for j=1,20 do + for i=1,50 do + x = ud + end + assert(x == ud) + end +end + +-- lightuserdata vs. number type check +do + local t = {} + for i=1,200 do t[i] = i end + t[180] = lightud(12345) + local x = 0 + assert(not pcall(function(t) + for i=1,200 do x = x + t[i] end + end, t)) + assert(x == 16110) +end + diff --git a/test/LuaJIT-test-cleanup/misc/loop_unroll.lua b/test/LuaJIT-test-cleanup/misc/loop_unroll.lua new file mode 100644 index 0000000..1700fac --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/loop_unroll.lua @@ -0,0 +1,35 @@ + +-- type instability on loop unroll -> record unroll +do + local flip = true + for i=1,100 do flip = not flip end + assert(flip == true) +end + +do + 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 + +-- FAILFOLD on loop unroll -> LJ_TRERR_GFAIL -> record unroll +do + 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 + +-- Unroll if inner loop aborts. +local j = 0 +for i = 1,100 do + repeat + j = j+1 + until true +end + diff --git a/test/LuaJIT-test-cleanup/misc/parse_comp.lua b/test/LuaJIT-test-cleanup/misc/parse_comp.lua new file mode 100644 index 0000000..5e1948d --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/parse_comp.lua @@ -0,0 +1,13 @@ + +do + local f = {{n=5}} + local a = f[1].n + assert(1 < a) + assert(1 < (f[1].n)) + assert(1 < f[1].n) +end + +do + tt = { a = 1 } + assert(not(0 >= tt.a)) +end diff --git a/test/LuaJIT-test-cleanup/misc/parse_esc.lua b/test/LuaJIT-test-cleanup/misc/parse_esc.lua new file mode 100644 index 0000000..4bcce0e --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/parse_esc.lua @@ -0,0 +1,7 @@ +assert("\79\126" == "O~") +assert("\x4f\x7e" == "O~") +assert(loadstring[[return "\xxx"]] == nil) +assert(loadstring[[return "\xxx"]] == nil) +assert(assert(loadstring[[return "abc \z + + def"]])() == "abc def") diff --git a/test/LuaJIT-test-cleanup/misc/parse_misc.lua b/test/LuaJIT-test-cleanup/misc/parse_misc.lua new file mode 100644 index 0000000..8031ec1 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/parse_misc.lua @@ -0,0 +1,31 @@ + +-- Ambiguous syntax: function call vs. new statement. +if os.getenv("LUA52") then + assert(assert(loadstring([[ +local function f() return 99 end +return f +() +]]))() == 99) +else + assert(loadstring([[ +local function f() return 99 end +return f +() +]]) == nil) +end + +-- UTF-8 identifiers. +assert(loadstring([[ +local ä = 1 +local aäa = 2 +local äöü·€晶 = 3 + +assert(ä == 1) +assert(aäa == 2) +assert(äöü·€晶 == 3) + +assert(#"ä" == 2) +assert(#"aäa" == 4) +assert(#"äöü·€晶" == 14) +]]))() + diff --git a/test/LuaJIT-test-cleanup/misc/phi_conv.lua b/test/LuaJIT-test-cleanup/misc/phi_conv.lua new file mode 100644 index 0000000..8d7bea5 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/phi_conv.lua @@ -0,0 +1,53 @@ + +local bit = require("bit") + +local Rm = {} +for i=0,16 do Rm[i] = 0 end + +for k=1,10 do + local seed = 1 + for i=16,0,-1 do + seed = bit.band(seed*9069, 0x7fffffff) + Rm[i] = seed + end + assert(seed == 1952688301) +end + +local retindex = 0 +local retdata = { 3, 1, 1, 1, 0, 3, 1, 0, 0, 2, 0, 2, 0, 0, 3, 1, 1, 1, 1 } + +local function get_bits() + retindex = retindex + 1 + return retdata[retindex] +end + +local hufcodes = { [0] = true, [4] = true, [11] = true, [36] = true, [68] = true } + +local maskhuf = { 0x0002, 0x0003, 0x0004, 0x0005, } + +local function decodeCode() + local lookup = get_bits() + local code = hufcodes[lookup] + local z = {1,1,1,1} + if not code then + for i = 1, 4 do + lookup = bit.bor(lookup, bit.lshift(get_bits(), i + 1)) + -- need PHI for CONV num.int of lookup, used in snapshot + code = hufcodes[lookup + maskhuf[i]] + if code then break end + end + end + assert(code) + return code +end + +local function test() + for i = 1, 6 do + decodeCode() + end +end + +if jit and jit.status and jit.status() then jit.opt.start("hotloop=1") end + +test() + diff --git a/test/LuaJIT-test-cleanup/misc/recurse_deep.lua b/test/LuaJIT-test-cleanup/misc/recurse_deep.lua new file mode 100644 index 0000000..9b9af29 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/recurse_deep.lua @@ -0,0 +1,29 @@ + +do + local function sum(n) + if n == 1 then return 1 end + return n + sum(n-1) + end + assert(sum(200) == 20100) +end + +do + local pcall = pcall + local tr1 + local x = 0 + function tr1(n) + if n <= 0 then return end + x = x + 1 + return pcall(tr1, n-1) + end + assert(tr1(200) == true and x == 200) +end + +do + local function fib(n) + if n < 2 then return 1 end + return fib(n-2) + fib(n-1) + end + assert(fib(15) == 987) +end + diff --git a/test/LuaJIT-test-cleanup/misc/recurse_tail.lua b/test/LuaJIT-test-cleanup/misc/recurse_tail.lua new file mode 100644 index 0000000..ef76443 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/recurse_tail.lua @@ -0,0 +1,22 @@ + +do + local tr1 + function tr1(n) + if n <= 0 then return 0 end + return tr1(n-1) + end + assert(tr1(200) == 0) +end + +do + 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/LuaJIT-test-cleanup/misc/stack_gc.lua b/test/LuaJIT-test-cleanup/misc/stack_gc.lua new file mode 100644 index 0000000..656a06a --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/stack_gc.lua @@ -0,0 +1,15 @@ + +do + local t = setmetatable({}, { __index=function(t, k) + k = k - 1 + if k == 0 then + collectgarbage() -- Mark stack, including holes. + return 0 + else + return t[k] -- Leaves holes in each frame. + end + do local a,b,c,d,e,f,g,h,i,j,k,l,m,n end -- Ensure bigger frame size. + end}) + local x = t[50] +end + diff --git a/test/LuaJIT-test-cleanup/misc/stack_purge.lua b/test/LuaJIT-test-cleanup/misc/stack_purge.lua new file mode 100644 index 0000000..bfaee0f --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/stack_purge.lua @@ -0,0 +1,25 @@ + +-- Must preserve the modified function slot in the RET snapshot. +local function a() + local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ + local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ + local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ + return 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +end + +local function b() + return a() +end + +local function c() + for j=1,10 do + for i=1,50 do b() b() b() end + collectgarbage() + local t = {} + for i=1,50 do t = {t} end + end +end + +jit.off(c) +c() + diff --git a/test/LuaJIT-test-cleanup/misc/stackov.lua b/test/LuaJIT-test-cleanup/misc/stackov.lua new file mode 100644 index 0000000..ef105af --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/stackov.lua @@ -0,0 +1,40 @@ + +local function f() + f() +end + +local err, s = xpcall(f, debug.traceback) +assert(err == false) + +local first = string.match(s, "[^\n]+") +local line = debug.getinfo(f, "S").linedefined+1 +assert(string.match(first, ":"..line..": stack overflow$")) + +local n = 1 +for _ in string.gmatch(s, "\n") do n = n + 1 end +assert(n == 1+1+11+1+10) + +local function g(i) + g(i) +end + +local err, s = xpcall(g, debug.traceback, 1) +assert(err == false) + +--[[ +-- too slow +local function vtail(...) + return vtail(1, ...) +end + +local err, s = xpcall(vtail, debug.traceback, 1) +assert(err == false) +--]] + +local function vcall(...) + vcall(1, ...) +end + +local err, s = xpcall(vcall, debug.traceback, 1) +assert(err == false) + diff --git a/test/LuaJIT-test-cleanup/misc/stackovc.lua b/test/LuaJIT-test-cleanup/misc/stackovc.lua new file mode 100644 index 0000000..c00bcbd --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/stackovc.lua @@ -0,0 +1,4 @@ +local j = 1e4 +local co = coroutine.create(function() t = {} for i = 1, j do t[i] = i end return unpack(t) end) +local ok, err = coroutine.resume(co) +assert(not ok and string.find(err, "unpack")) diff --git a/test/LuaJIT-test-cleanup/misc/tcall_base.lua b/test/LuaJIT-test-cleanup/misc/tcall_base.lua new file mode 100644 index 0000000..c6c4ae1 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/tcall_base.lua @@ -0,0 +1,20 @@ + +local r = 0 +local function g() + r = r + 1 + for i=1,100 do end +end + +local function f() + for j=1,20 do + if j > 19 then + return g() -- Tailcall at base. + -- Let this link to the already compiled loop in g(). + end + end +end + +g() -- Compile this loop first. +for i=1,50 do f() end +assert(r == 51) + diff --git a/test/LuaJIT-test-cleanup/misc/tcall_loop.lua b/test/LuaJIT-test-cleanup/misc/tcall_loop.lua new file mode 100644 index 0000000..d3c6f1a --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/tcall_loop.lua @@ -0,0 +1,8 @@ +local function f(i) + if i > 0 then return f(i-1) end + return 1 +end + +local x = 0 +for i=1,100 do x = x + f(1000) end +assert(x == 100) diff --git a/test/LuaJIT-test-cleanup/misc/tonumber_scan.lua b/test/LuaJIT-test-cleanup/misc/tonumber_scan.lua new file mode 100644 index 0000000..78e1ca3 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/tonumber_scan.lua @@ -0,0 +1,180 @@ +local ffi = require("ffi") +local bit = require("bit") + +ffi.cdef[[ +double strtod(const char *, char **); +]] + +local t = { + -- errors + false, "", + false, " ", + false, "+", + false, "z", + false, ".", + false, ".z", + false, "0.z", + false, ".0z", + false, "0xz", + false, "0x.z", + false, "0x0.z", + false, "0x.0z", + false, ".e5", + false, ".p4", + false, "1.p4", + false, "1.p+4", + false, "0x1.e+4", + false, "infi", + false, "+ 1", + false, "- 9", + -- misc + 0x3ff0000000000000ULL, " \t\n\v\f\r 1", + -- inf/nan + 0x7ff0000000000000ULL, "iNF", + 0xfff0000000000000ULL, "-Inf", + 0x7ff0000000000000ULL, "+iNfInItY", + 0xfff0000000000000ULL, "-INFINITY", + 0xfff8000000000000ULL, "naN", + 0xfff8000000000000ULL, "+NaN", + 0xfff8000000000000ULL, "-nAn", + -- smallest/largest numbers + 0x0000000000000000ULL, "0e1000", + 0x0000000000000000ULL, "0e-1000", + 0x0000000000000000ULL, "0x0p2000", + 0x0000000000000000ULL, "0x0p-2000", + 0x7ff0000000000000ULL, "1e1000", + 0x0000000000000000ULL, "1e-1000", + 0xfff0000000000000ULL, "-1e1000", +-- wrong for DUALNUM: 0x8000000000000000ULL, "-1e-1000", + 0x7ff0000000000000ULL, "0x1p2000", + 0x0000000000000000ULL, "0x1p-2000", + 0xfff0000000000000ULL, "-0x1p2000", +-- wrong for DUALNUM: 0x8000000000000000ULL, "-0x1p-2000", + 0x0010000000000000ULL, "2.2250738585072014e-308", + 0x7fefffffffffffffULL, "1.7976931348623158e+308", + 0x8000b8157268fdafULL, "-1e-309", + 0x000ac941b426dd3bULL, "1.5e-308", + 0x000ac941b426dd3bULL, "0x0.ac941b426dd3b7p-1022", + 0x0000000000000001ULL, "4.9406564584124654e-324", + 0x000f9c7573d7fe52ULL, "2.171e-308", + 0x241d21ecf36d4a22ULL, "1.0020284025808569e-134", + 0x0000000000000001ULL, "0x1p-1074", + 0x0000000000000000ULL, "0x1p-1075", + 0x0000000000000000ULL, "0x1p-1076", + 0x0000000000000000ULL, "0x0.ffffffffffffffffffffffffffp-1075", + 0x0000000000000000ULL, "0x1.00000000000000000000000000p-1075", + 0x0000000000000001ULL, "0x1.00000000000000000000000001p-1075", + 0x7fe0000000000000ULL, "0x1p1023", + 0x7ff0000000000000ULL, "0x1p1024", + 0x7ff0000000000000ULL, "0x1p1025", + 0x7ff0000000000000ULL, "0x3p1023", + 0x7ff0000000000000ULL, "0x3.ffffffffffffecp1023", + 0xfff0000000000000ULL, "-0xf7dcba98765432p969", + 0x7fefffffffffffffULL, "0x1.fffffffffffff0000000000000p1023", + 0x7fefffffffffffffULL, "0x1.fffffffffffff0000000000001p1023", + 0x7fefffffffffffffULL, "0x1.fffffffffffff7ffffffffffffp1023", + 0x7ff0000000000000ULL, "0x1.fffffffffffff8000000000000p1023", + 0x7fefffffffffffffULL, "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0", + 0x7fefffffffffffffULL, "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.999", + 0x7ff0000000000000ULL, "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792.0", + 0x3ff0000000000000ULL, "0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000p-1028", + 0x1214e2995454ee0bULL, "0."..string.rep("0", 220).."1"..string.rep("4", 800), + -- http://www.exploringbinary.com/15-digit-quick-and-dirty-conversions-dont-round-trip/ + 0x04409cf3929ffbc3ULL, "3.409452297963e-288", + 0x7fe02b4782a6c378ULL, "9.08344e+307", + 0x6e05e258a3929ee5ULL, "9.88819e+221", + -- http://www.exploringbinary.com/incorrectly-rounded-conversions-in-gcc-and-glibc/ + 0x3fe0000000000002ULL, "0.500000000000000166533453693773481063544750213623046875", + 0x42c0000000000002ULL, "3.518437208883201171875e13", + 0x404f44abd5aa7ca4ULL, "62.5364939768271845828", + 0x3e0bd5cbaef0fd0cULL, "8.10109172351e-10", + 0x3ff8000000000000ULL, "1.50000000000000011102230246251565404236316680908203125", + 0x433fffffffffffffULL, "9007199254740991.4999999999999999999999999999999995", + 0x7ecd2e77eb6e3fadULL, "6.253649397682718e+302", + 0x7ecd2e77eb6e3fadULL, "6.2536493976827180e+302", + -- http://www.exploringbinary.com/incorrectly-rounded-conversions-in-visual-c-plus-plus/ + 0x43405e6cec57761aULL, "9214843084008499", + 0x3fe0000000000002ULL, "0.500000000000000166533453693773481063544750213623046875", + 0x44997a3c7271b021ULL, "30078505129381147446200", + 0x4458180d5bad2e3eULL, "1777820000000000000001", + 0x3fe0000000000002ULL, "0.500000000000000166547006220929549868969843373633921146392822265625", + 0x3fe0000000000002ULL, "0.50000000000000016656055874808561867439493653364479541778564453125", + 0x3fd92bb352c4623aULL, "0.3932922657273", + -- http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ + 0x0010000000000000ULL, "2.2250738585072012e-308", + -- http://www.exploringbinary.com/incorrectly-rounded-subnormal-conversions-in-java/ + 0x0000000008000000ULL, "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125e-316", + 0x0000000000010000ULL, "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875e-319", + 0x0000800000000100ULL, "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125e-310", + 0x0000000000010800ULL, "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875e-319", + -- EGLIBC 2.16 tests + 0x4028b0a3d70a3d71ULL, "12.345", + 0x441ac4da03bc47e4ULL, "12.345e19", + 0xc197d78400000000ULL, "-.1e+9", + 0x3fc0000000000000ULL, ".125", + 0x4415af1d78b58c40ULL, "1e20", + 0x0000000000000000ULL, "0e-19", + 0x3051144f2d9a718bULL, "5.9e-76", + 0x4024000000000000ULL, "0x1.4p+3", + 0x4024000000000000ULL, "0xAp0", + 0x4024000000000000ULL, "0x0Ap0", + 0x4024000000000000ULL, "0x0A", + 0x4064000000000000ULL, "0xA0", + 0x4064000000000000ULL, "0x0.A0p8", + 0x4064000000000000ULL, "0x0.50p9", + 0x4064000000000000ULL, "0x0.28p10", + 0x4064000000000000ULL, "0x0.14p11", + 0x4064000000000000ULL, "0x0.0A0p12", + 0x4064000000000000ULL, "0x0.050p13", + 0x4064000000000000ULL, "0x0.028p14", + 0x4064000000000000ULL, "0x0.014p15", + 0x4064000000000000ULL, "0x00.00A0p16", + 0x4064000000000000ULL, "0x00.0050p17", + 0x4064000000000000ULL, "0x00.0028p18", + 0x4064000000000000ULL, "0x00.0014p19", + 0x0008000000000000ULL, "0x1p-1023", + 0x0008000000000000ULL, "0x0.8p-1022", + 0x3ff0000140000000ULL, "0x80000Ap-23", + 0x0000000000000000ULL, "1e-324", + 0x4370000000000000ULL, "0x100000000000008p0", + 0x4370000000000000ULL, "0x100000000000008.p0", + 0x4370000000000000ULL, "0x100000000000008.00p0", + 0x43f0000000000000ULL, "0x10000000000000800p0", + 0x43f0000000000001ULL, "0x10000000000000801p0", + -- Fuzzing + 0x699783fbf2d24ea5ULL, "449999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", + 0x43f158e460913d00ULL, "2e19", +} + +local function tohex64(x) + return "0x"..bit.tohex(tonumber(x/2LL^32))..bit.tohex(tonumber(x%2LL^32)).."ULL" +end + +local conv = tonumber + +if arg and arg[1] == "strtod" then + local e = ffi.new("char *[1]") + function conv(s) + local d = ffi.C.strtod(s, e) + return (e[0][0] == 0 and #s ~= 0) and d or nil + end +end + +local u = ffi.new("union { double d; uint64_t x; }") + +for i=1,#t,2 do + local y, s = t[i], t[i+1] + local d = conv(s) + local ok + if d == nil then + ok = (y == false) + else + u.d = d + ok = (y == u.x) + end + if not ok then + io.write('FAIL: "', s, '"\n GOT: ', d and tohex64(u.x) or "nil", " OK: ", y and tohex64(y) or "nil", "\n\n") +-- print(" "..tohex64(u.x)..", \""..s.."\",") + end +end + diff --git a/test/LuaJIT-test-cleanup/misc/uclo.lua b/test/LuaJIT-test-cleanup/misc/uclo.lua new file mode 100644 index 0000000..bd9bd24 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/uclo.lua @@ -0,0 +1,91 @@ + +local function test_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 + +local function test_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 + +local function test_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 + +local function test_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 + +test_for() +test_while() +test_repeat() +test_func() + +do + 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) + end +end + +-- Don't mark upvalue as immutable if written to after prototype definition. +do + 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/LuaJIT-test-cleanup/misc/unordered_jit.lua b/test/LuaJIT-test-cleanup/misc/unordered_jit.lua new file mode 100644 index 0000000..5ff1a1b --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/unordered_jit.lua @@ -0,0 +1,96 @@ + +local nan = 0/0 +local t = {} +for i=1,100 do t[i] = i+0.5 end +for i=101,200 do t[i] = nan end + +do + local z = 0 + for i=1,200 do if t[i] > 1000 then z=i end end + assert(z == 0) +end + +do + local z = 0 + for i=1,200 do if not (t[i] < 1000) then z=i end end + assert(z == 200) +end + +do + local z = 0 + for i=1,200 do if t[i] <= 1000 then z=i end end + assert(z == 100) +end + +do + local z = 0 + for i=1,200 do if not (t[i] >= 1000) then z=i end end + assert(z == 200) +end + +do + local z = 0 + for i=1,200 do if t[i] > 0 then z=i end end + assert(z == 100) +end + +do + local z = 0 + for i=1,200 do if not (t[i] < 0) then z=i end end + assert(z == 200) +end + +do + local z = 0 + for i=1,200 do if t[i] <= 0 then z=i end end + assert(z == 0) +end + +do + local z = 0 + for i=1,200 do if not (t[i] >= 0) then z=i end end + assert(z == 200) +end + +do local z; for i=1,100 do z = 0/0 end; assert(z ~= z) end + +do local z; for i=1,100 do z = nan == nan end; assert(z == false) end +do local z; for i=1,100 do z = nan == 1 end; assert(z == false) end +do local z; for i=1,100 do z = 1 == nan end; assert(z == false) end + +do local z; for i=1,100 do z = nan ~= nan end; assert(z == true) end +do local z; for i=1,100 do z = nan ~= 1 end; assert(z == true) end +do local z; for i=1,100 do z = 1 ~= nan end; assert(z == true) end + +do local z; for i=1,100 do z = nan < nan end; assert(z == false) end +do local z; for i=1,100 do z = nan < 1 end; assert(z == false) end +do local z; for i=1,100 do z = 1 < nan end; assert(z == false) end + +do local z; for i=1,100 do z = not (nan < nan) end; assert(z == true) end +do local z; for i=1,100 do z = not (nan < 1) end; assert(z == true) end +do local z; for i=1,100 do z = not (1 < nan) end; assert(z == true) end + +do local z; for i=1,100 do z = nan > nan end; assert(z == false) end +do local z; for i=1,100 do z = nan > 1 end; assert(z == false) end +do local z; for i=1,100 do z = 1 > nan end; assert(z == false) end + +do local z; for i=1,100 do z = not (nan > nan) end; assert(z == true) end +do local z; for i=1,100 do z = not (nan > 1) end; assert(z == true) end +do local z; for i=1,100 do z = not (1 > nan) end; assert(z == true) end + +do local z; for i=1,100 do z = nan <= nan end; assert(z == false) end +do local z; for i=1,100 do z = nan <= 1 end; assert(z == false) end +do local z; for i=1,100 do z = 1 <= nan end; assert(z == false) end + +do local z; for i=1,100 do z = not (nan <= nan) end; assert(z == true) end +do local z; for i=1,100 do z = not (nan <= 1) end; assert(z == true) end +do local z; for i=1,100 do z = not (1 <= nan) end; assert(z == true) end + +do local z; for i=1,100 do z = nan >= nan end; assert(z == false) end +do local z; for i=1,100 do z = nan >= 1 end; assert(z == false) end +do local z; for i=1,100 do z = 1 >= nan end; assert(z == false) end + +do local z; for i=1,100 do z = not (nan >= nan) end; assert(z == true) end +do local z; for i=1,100 do z = not (nan >= 1) end; assert(z == true) end +do local z; for i=1,100 do z = not (1 >= nan) end; assert(z == true) end + diff --git a/test/LuaJIT-test-cleanup/misc/wbarrier.lua b/test/LuaJIT-test-cleanup/misc/wbarrier.lua new file mode 100644 index 0000000..5536625 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/wbarrier.lua @@ -0,0 +1,7 @@ +local t={} +for i=1,20000 do + t[i] = tostring(i) +end +for i=1,#t do + assert(t[i] == tostring(i)) +end diff --git a/test/LuaJIT-test-cleanup/misc/wbarrier_jit.lua b/test/LuaJIT-test-cleanup/misc/wbarrier_jit.lua new file mode 100644 index 0000000..2c8dd7f --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/wbarrier_jit.lua @@ -0,0 +1,18 @@ + +do + local t = {[0]={}} + for i=1,1e5 do t[i] = {t[i-1]} end + for i=1,1e5 do assert(t[i][1] == t[i-1]) end +end + +do + local f + do + local x = 0 + function f() + for i=1,1e5 do x = {i} end + end + end + f() +end + diff --git a/test/LuaJIT-test-cleanup/misc/wbarrier_obar.lua b/test/LuaJIT-test-cleanup/misc/wbarrier_obar.lua new file mode 100644 index 0000000..258db21 --- /dev/null +++ b/test/LuaJIT-test-cleanup/misc/wbarrier_obar.lua @@ -0,0 +1,22 @@ +-- DSE of USTORE must eliminate OBAR, too. + +if jit and jit.opt then pcall(jit.opt.start, "-sink") end + +local f +do + local x + f = function() + local y = 0 + for i=1,10000 do + x = {1} + if y > 0 then end + x = 1 + end + end +end + +collectgarbage() +collectgarbage("setstepmul", 1) +collectgarbage("restart") +f() + diff --git a/test/LuaJIT-test-cleanup/opt/dse/array.lua b/test/LuaJIT-test-cleanup/opt/dse/array.lua new file mode 100644 index 0000000..8c76624 --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/dse/array.lua @@ -0,0 +1,197 @@ +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/LuaJIT-test-cleanup/opt/dse/field.lua b/test/LuaJIT-test-cleanup/opt/dse/field.lua new file mode 100644 index 0000000..d8a5411 --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/dse/field.lua @@ -0,0 +1,70 @@ +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/LuaJIT-test-cleanup/opt/dse/index b/test/LuaJIT-test-cleanup/opt/dse/index new file mode 100644 index 0000000..7b8ad1f --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/dse/index @@ -0,0 +1,2 @@ +array.lua +field.lua diff --git a/test/LuaJIT-test-cleanup/opt/fold/index b/test/LuaJIT-test-cleanup/opt/fold/index new file mode 100644 index 0000000..8b4648c --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/fold/index @@ -0,0 +1 @@ +kfold.lua diff --git a/test/LuaJIT-test-cleanup/opt/fold/kfold.lua b/test/LuaJIT-test-cleanup/opt/fold/kfold.lua new file mode 100644 index 0000000..9cd3919 --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/fold/kfold.lua @@ -0,0 +1,81 @@ +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 -luajit==2.0 + assert((10^-2 - 0.01) == 0) +end diff --git a/test/LuaJIT-test-cleanup/opt/fuse.lua b/test/LuaJIT-test-cleanup/opt/fuse.lua new file mode 100644 index 0000000..a68381e --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/opt/fwd/hrefk_rollback.lua b/test/LuaJIT-test-cleanup/opt/fwd/hrefk_rollback.lua new file mode 100644 index 0000000..5a6ad87 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/opt/fwd/index b/test/LuaJIT-test-cleanup/opt/fwd/index new file mode 100644 index 0000000..5bb1537 --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/fwd/index @@ -0,0 +1,3 @@ +hrefk_rollback.lua +tnew_tdup.lua +upval.lua diff --git a/test/LuaJIT-test-cleanup/opt/fwd/tnew_tdup.lua b/test/LuaJIT-test-cleanup/opt/fwd/tnew_tdup.lua new file mode 100644 index 0000000..9e18fa3 --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/fwd/tnew_tdup.lua @@ -0,0 +1,69 @@ +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/LuaJIT-test-cleanup/opt/fwd/upval.lua b/test/LuaJIT-test-cleanup/opt/fwd/upval.lua new file mode 100644 index 0000000..a3e83df --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/fwd/upval.lua @@ -0,0 +1,50 @@ +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/LuaJIT-test-cleanup/opt/index b/test/LuaJIT-test-cleanup/opt/index new file mode 100644 index 0000000..94d50ae --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/index @@ -0,0 +1,6 @@ +dse +dse +fold +fold +fwd +fwd +fuse.lua +fuse +loop +loop +sink +sink diff --git a/test/LuaJIT-test-cleanup/opt/loop/index b/test/LuaJIT-test-cleanup/opt/loop/index new file mode 100644 index 0000000..e582023 --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/loop/index @@ -0,0 +1 @@ +unroll.lua diff --git a/test/LuaJIT-test-cleanup/opt/loop/unroll.lua b/test/LuaJIT-test-cleanup/opt/loop/unroll.lua new file mode 100644 index 0000000..6fbd565 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/opt/sink/alloc.lua b/test/LuaJIT-test-cleanup/opt/sink/alloc.lua new file mode 100644 index 0000000..bb2a0f7 --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/sink/alloc.lua @@ -0,0 +1,126 @@ +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/LuaJIT-test-cleanup/opt/sink/ffi.lua b/test/LuaJIT-test-cleanup/opt/sink/ffi.lua new file mode 100644 index 0000000..0bba097 --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/sink/ffi.lua @@ -0,0 +1,121 @@ +local ffi = require("ffi") + +do --- incrementing + local x = 10000000000000ll + for i=1,100 do x=x+1 end + assert(x == 10000000000100ll) +end + +do --- hoistable increment !private_G + local x = 10000000000000ll + local z + for i=1,100 do z=x+1 end + assert(z == 10000000000001ll) + for i=1,100 do local y=x; z=x+1; g=y end + assert(z == 10000000000001ll) + assert(g == 10000000000000ll) +end + +do --- escaping hoistable increment + local x = 10000000000000ll + for i=1,100 do local y=x+1; if i == 90 then x=y end end + assert(x == 10000000000001ll) +end + +do --- escaping addition + local x = 10000000000000ll + for i=1,100 do local y=x+i; if i == 90 then x=y end end + assert(x == 10000000000090ll) +end + +do --- conditional addition / incrementing + local x = 10000000000000ll + for i=1,200 do local y=x+i; if i > 100 then x=y end end + assert(x == 10000000015050ll) +end + +do --- incrementing pointer + local a = ffi.new("int[?]", 100) + local p = a + for i=0,99 do p[0]=i; p=p+1 end + assert(p == a+100) + for i=0,99 do assert(a[i] == i) end +end + +do --- mutating complex + local cx = ffi.typeof("complex") + local x = cx(1, 2) + local k = cx(3, 4) + for i=1,100 do x = cx(x.re+k.re, x.im+k.im) end + assert(x.re == 301) + assert(x.im == 402) +end + +do --- mutating struct + local st = ffi.typeof("struct { int a; int64_t b; double c; }") + local x = st(1, 20000000000LL, 3.5) + local k = st(3, 4, 5.0) + for i=1,100 do x = st(x.a+k.a, x.b+k.b, x.c+k.c) end + assert(x.a == 301) + assert(x.b == 20000000400LL) + assert(x.c == 503.5) + local y, z + for i=1,100 do + local x = st(i, i, i) + if i == 90 then y = st(x.a, x.b, x.c) end + x.b = x.b + 20000000000LL + if i == 95 then z = st(x.a, x.b, x.c) end + end + assert(y.a == 90) + assert(y.b == 90) + assert(y.c == 90) + assert(z.a == 95) + assert(z.b == 20000000095LL) + assert(z.c == 95) + for i=1,200 do + local x = st(i, i, i) + if i > 100 then y = st(x.a, x.b, x.c) end + x.b = x.b + 20000000000LL + if i > 150 then z = st(x.a, x.b, x.c) end + end + assert(y.a == 200) + assert(y.b == 200) + assert(y.c == 200) + assert(z.a == 200) + assert(z.b == 20000000200LL) + assert(z.c == 200) +end + +do --- mutating struct 2 + local st = ffi.typeof("struct { int64_t a; double b; float c; }") + local x = st(1, 2.5, 3.25) + local k = st(3, 4, 5) + for i=1,100 do x = st(x.a+k.a, x.b+k.b, x.c+k.c) end + assert(x.a == 301) + assert(x.b == 402.5) + assert(x.c == 503.25) +end + +do --- escaping loop counter to float + local st = ffi.typeof("struct { float a; }") + local x + for i=1,200 do + local y = st(i) + if i > 100 then x = y end + end + assert(x.a == 200) +end + +do --- 64 bit crash bug !private_G + local t = {} + for i=1,200 do t[i] = "abcd" end + local r + for i=1,200 do + local a,b,c,d + local g = t[201-i] -- Non-zero stack slot above. + local v = ffi.cast("const char *", t[i]) -- Uses 32 bit stack slot! + a,b,c,d = {v[0]},{v[1]},{v[2]},{v[3]} -- Force above to spill. + r = {{i}} -- Spill due to call. + if i > 100 then z = v[0]+a[1]+b[1]+c[1]+d[1] end -- Crash for 64 bit ptr v. + end +end diff --git a/test/LuaJIT-test-cleanup/opt/sink/ffi_nosink.lua b/test/LuaJIT-test-cleanup/opt/sink/ffi_nosink.lua new file mode 100644 index 0000000..8f7cced --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/sink/ffi_nosink.lua @@ -0,0 +1,45 @@ +local ffi = require("ffi") + +do --- escaping global !private_G + local x = 0ll + for i=1,100 do x=x+1; g=x end + assert(x == 100ll) + assert(g == 100ll) +end + +do --- preincrement escaping global !private_G + local x = 0ll + for i=1,100 do local y=x; x=x+1; g=y end + assert(x == 100ll) + assert(g == 99ll) +end + +do --- escaping global and local !private_G + local x = 0ll + local z + for i=1,100 do z=x+1; g=z end + assert(z == 1ll) + assert(g == 1ll) +end + +do --- swapping + local x,y = 0ll, 0ll + for i=1,100 do y,x=x,x+1 end + assert(x == 100ll) + assert(y == 99ll) +end + +do --- pointer to self + local st = ffi.typeof("struct { void *p; }") + local x + for i=1,100 do x = st(); x.p = x end + assert(x.p == ffi.cast("void *", x)) +end + +do --- strchr + ffi.cdef[[char *strchr(char *, int);]] + for i=1,100 do + local p = ffi.new("char[2]"); + ffi.C.strchr(p, 32) + end +end diff --git a/test/LuaJIT-test-cleanup/opt/sink/index b/test/LuaJIT-test-cleanup/opt/sink/index new file mode 100644 index 0000000..8bfa370 --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/sink/index @@ -0,0 +1,4 @@ +alloc.lua +nosink.lua +ffi.lua +ffi +ffi_nosink.lua +ffi diff --git a/test/LuaJIT-test-cleanup/opt/sink/nosink.lua b/test/LuaJIT-test-cleanup/opt/sink/nosink.lua new file mode 100644 index 0000000..762aace --- /dev/null +++ b/test/LuaJIT-test-cleanup/opt/sink/nosink.lua @@ -0,0 +1,109 @@ +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/LuaJIT-test-cleanup/src/cpptest.cpp b/test/LuaJIT-test-cleanup/src/cpptest.cpp new file mode 100644 index 0000000..a5893ed --- /dev/null +++ b/test/LuaJIT-test-cleanup/src/cpptest.cpp @@ -0,0 +1,129 @@ + +#include + +extern "C" { +#define LUA_LIB +#include "lua.h" +#include "lauxlib.h" +#include "luajit.h" +} + +static int testobj_alloc; + +class TestObj { +public: + TestObj(int x) { foo = x; testobj_alloc = 1; } + ~TestObj() { testobj_alloc = 0; } +private: + int foo; +}; + +static int ct_alloc(lua_State *L) +{ + TestObj foo(1); + lua_pushlightuserdata(L, (void *)&foo); + lua_call(L, lua_gettop(L)-1, LUA_MULTRET); + if (lua_iscfunction(L, -1)) { + lua_CFunction f = lua_tocfunction(L, -1); + lua_pop(L, 1); + f(L); + } + return lua_gettop(L); +} + +static int ct_isalloc(lua_State *L) +{ + lua_pushboolean(L, testobj_alloc); + return 1; +} + +static int ct_usereg(lua_State *L) +{ + int n = luaL_checkint(L, 1); + int m = luaL_checkint(L, 2); + int i; + int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0; + for (i = 0; i < n; i++) { + a = (a + 1) ^ 0x12345678; + b = (b + 2) ^ 0x12345678; + c = (c + 3) ^ 0x12345678; + d = (d + 4) ^ 0x12345678; + e = (e + 5) ^ 0x12345678; + f = (f + 5) ^ 0x12345678; + if (i == m) { + if (i & 1) + lua_pcall(L, 1, 0, 0); + else + lua_call(L, 1, 0); + } + } + lua_pushinteger(L, a); + lua_pushinteger(L, b); + lua_pushinteger(L, c); + lua_pushinteger(L, d); + lua_pushinteger(L, e); + lua_pushinteger(L, f); + return 6; +} + +static int ct_catch(lua_State *L) +{ + try { + lua_call(L, lua_gettop(L)-1, LUA_MULTRET); + return lua_gettop(L); + } catch (const char *s) { + lua_pushstring(L, s); + } catch (...) { + lua_pushliteral(L, "catch ..."); + } + return 1; +} + +static int ct_throw(lua_State *L) +{ + const char *s = lua_tostring(L, 1); + throw(s); + return 0; +} + +static int ct_wrap(lua_State *L, lua_CFunction f) +{ + try { + return f(L); + } catch (const char *s) { + lua_pushstring(L, s); + } + return lua_error(L); +} + +static int ct_wrapon(lua_State *L) +{ + lua_pushlightuserdata(L, (void *)ct_wrap); + luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_ON); + return 0; +} + +static int ct_wrapoff(lua_State *L) +{ + luaJIT_setmode(L, 0, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_OFF); + return 0; +} + +static luaL_Reg ct_funcs[] = { + {"isalloc", ct_isalloc }, + {"alloc", ct_alloc }, + {"usereg", ct_usereg }, + {"catch", ct_catch }, + {"throw", ct_throw }, + {"wrapon", ct_wrapon }, + {"wrapoff", ct_wrapoff }, + {NULL, NULL} +}; + +extern "C" { +LUA_API int luaopen_cpptest(lua_State *L) +{ + luaL_register(L, "cpptest", ct_funcs); + return 1; +} +} diff --git a/test/LuaJIT-test-cleanup/src/ctest.c b/test/LuaJIT-test-cleanup/src/ctest.c new file mode 100644 index 0000000..d257567 --- /dev/null +++ b/test/LuaJIT-test-cleanup/src/ctest.c @@ -0,0 +1,339 @@ + +#define LUA_LIB +#include "lua.h" +#include "lauxlib.h" + +/* ------------------------------------------------------------------------ */ + +#ifdef _MSC_VER +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#else +#include +#define complex _Complex +#endif + +#if defined(__i386) || defined(__i386__) || defined(_M_IX86) +#ifdef _MSC_VER +#define LJ_FASTCALL __fastcall +#define LJ_STDCALL __stdcall +#else +#define LJ_FASTCALL __attribute__((fastcall)) +#define LJ_STDCALL __attribute__((stdcall)) +#endif +#endif + +typedef struct s_ii { int x, y; } s_ii; +typedef struct s_jj { int64_t x, y; } s_jj; +typedef struct s_ff { float x, y; } s_ff; +typedef struct s_dd { double x, y; } s_dd; +typedef struct s_8i { int a,b,c,d,e,f,g,h; } s_8i; + +LUA_API int call_i(int a) { return a+1; } +LUA_API int call_ii(int a, int b) { return a+b; } +LUA_API int call_10i(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { return a+b+c+d+e+f+g+h+i+j; } + +LUA_API int64_t call_10j(int a, int b, int c, int d, int e, int f, int g, int h, int i, int64_t j) { return a+b+c+d+e+f+g+h+i+j; } + +LUA_API int64_t call_ji(int64_t a, int b) { return a+b; } +LUA_API int64_t call_ij(int a, int64_t b) { return a+b; } +LUA_API int64_t call_jj(int64_t a, int64_t b) { return a+b; } + +LUA_API double call_dd(double a, double b) { return a+b; } +LUA_API double call_10d(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j) { return a+b+c+d+e+f+g+h+i+j; } + +LUA_API float call_ff(float a, float b) { return a+b; } +LUA_API float call_10f(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j) { return a+b+c+d+e+f+g+h+i+j; } + +LUA_API double call_idifjd(int a, double b, int c, float d, int64_t e, double f) { return a+b+c+d+e+f; } + +LUA_API int call_p_i(int *a) { return *a+1; } +LUA_API int *call_p_p(int *a) { return a+1; } +LUA_API int call_pp_i(int *a, int *b) { return (int)(a-b); } + +#include + +LUA_API double call_ividi(int a, ...) +{ + double y; + va_list argp; + va_start(argp, a); + y = a; + y += va_arg(argp, int); + y += va_arg(argp, double); + y += va_arg(argp, int); + va_end(argp); + return y; +} + +#ifdef complex +LUA_API complex call_dd_cd(double a, double b) { return a+b*2i; } +LUA_API complex call_cd(complex a) { return a+1-2i; } +LUA_API complex call_cdcd(complex a, complex b) { return a+b; } + +LUA_API complex float call_ff_cf(float a, float b) { return a+b*2i; } +LUA_API complex float call_cf(complex float a) { return a+1-2i; } +LUA_API complex float call_cfcf(complex float a, complex float b) { return a+b; } +#endif + +LUA_API s_ii call_sii(s_ii a) { return a; } +LUA_API s_jj call_sjj(s_jj a) { return a; } +LUA_API s_ff call_sff(s_ff a) { return a; } +LUA_API s_dd call_sdd(s_dd a) { return a; } +LUA_API s_8i call_s8i(s_8i a) { return a; } +LUA_API s_ii call_siisii(s_ii a, s_ii b) +{ + s_ii c; + c.x = a.x + b.x; + c.y = a.y + b.y; + return c; +} +LUA_API s_ff call_sffsff(s_ff a, s_ff b) +{ + s_ff c; + c.x = a.x + b.x; + c.y = a.y + b.y; + return c; +} +LUA_API s_dd call_sddsdd(s_dd a, s_dd b) +{ + s_dd c; + c.x = a.x + b.x; + c.y = a.y + b.y; + return c; +} +LUA_API s_8i call_s8is8i(s_8i a, s_8i b) +{ + s_8i c; + c.a = a.a + b.a; + c.b = a.b + b.b; + c.c = a.c + b.c; + c.d = a.d + b.d; + c.e = a.e + b.e; + c.f = a.f + b.f; + c.g = a.g + b.g; + c.h = a.h + b.h; + return c; +} +LUA_API s_8i call_is8ii(int a, s_8i b, int c) +{ + b.a += a; + b.c += c; + return b; +} + +#ifdef LJ_FASTCALL +LUA_API int LJ_FASTCALL fastcall_void(void) { return 1; } +LUA_API int LJ_FASTCALL fastcall_i(int a) { return a+1; } +LUA_API int LJ_FASTCALL fastcall_ii(int a, int b) { return a+b; } +LUA_API int LJ_FASTCALL fastcall_iii(int a, int b, int c) { return a+b+c; } +LUA_API int64_t LJ_FASTCALL fastcall_ji(int64_t a, int b) { return a+b; } +LUA_API double LJ_FASTCALL fastcall_dd(double a, double b) { return a+b; } +LUA_API int LJ_FASTCALL fastcall_pp_i(int *a, int *b) { return (int)(a-b); } +LUA_API s_ii LJ_FASTCALL fastcall_siisii(s_ii a, s_ii b) +{ + s_ii c; + c.x = a.x + b.x; + c.y = a.y + b.y; + return c; +} +LUA_API s_dd LJ_FASTCALL fastcall_sddsdd(s_dd a, s_dd b) +{ + s_dd c; + c.x = a.x + b.x; + c.y = a.y + b.y; + return c; +} +#endif + +#if defined(LJ_STDCALL) && defined(_WIN32) +LUA_API int LJ_STDCALL stdcall_i(int a) { return a+1; } +LUA_API int LJ_STDCALL stdcall_ii(int a, int b) { return a+b; } +LUA_API double LJ_STDCALL stdcall_dd(double a, double b) { return a+b; } +LUA_API float LJ_STDCALL stdcall_ff(float a, float b) { return a+b; } +#endif + +/* ------------------------------------------------------------------------ */ + +static int ct_call(lua_State *L) +{ + int nresults = luaL_checkint(L, 1); + luaL_checkstack(L, nresults, "too many results"); + lua_call(L, lua_gettop(L)-2, nresults); + return lua_gettop(L)-1; +} + +static int ct_callon(lua_State *L) +{ + lua_State *co = lua_tothread(L, 1); + int nargs = lua_gettop(L)-1; + int nresults; + lua_xmove(L, co, nargs); + lua_call(co, nargs-1, LUA_MULTRET); + nresults = lua_gettop(co); + lua_xmove(co, L, nresults); + return nresults; +} + +static int ct_pcall_err(lua_State *L) +{ + int nresults = luaL_checkint(L, 1); + luaL_checkstack(L, nresults, "too many results"); + if (lua_pcall(L, lua_gettop(L)-2, nresults, 0)) + lua_error(L); + return lua_gettop(L)-1; +} + +static int ct_pcall(lua_State *L) +{ + int status; + luaL_checkany(L, 1); + status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0); + lua_pushboolean(L, (status == 0)); + lua_insert(L, 1); + return lua_gettop(L); /* return status + all results */ +} + +static int ct_xpcall(lua_State *L) +{ + int status; + luaL_checkany(L, 2); + lua_settop(L, 2); + lua_insert(L, 1); /* put error function under function to be called */ + status = lua_pcall(L, 0, LUA_MULTRET, 1); + lua_pushboolean(L, (status == 0)); + lua_replace(L, 1); + return lua_gettop(L); /* return status + all results */ +} + +#define CO_RUN 0 /* running */ +#define CO_SUS 1 /* suspended */ +#define CO_NOR 2 /* 'normal' (it resumed another coroutine) */ +#define CO_DEAD 3 + +static const char *const statnames[] = + {"running", "suspended", "normal", "dead"}; + +static int costatus(lua_State *L, lua_State *co) { + if (L == co) return CO_RUN; + switch (lua_status(co)) { + case LUA_YIELD: + return CO_SUS; + case 0: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + return CO_NOR; /* it is running */ + else if (lua_gettop(co) == 0) + return CO_DEAD; + else + return CO_SUS; /* initial state */ + } + default: /* some error occured */ + return CO_DEAD; + } +} + +static int auxresume(lua_State *L, lua_State *co, int narg) { + int status = costatus(L, co); + if (!lua_checkstack(co, narg)) + luaL_error(L, "too many arguments to resume"); + if (status != CO_SUS) { + lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]); + return -1; /* error flag */ + } + lua_xmove(L, co, narg); + status = lua_resume(co, narg); + if (status == 0 || status == LUA_YIELD) { + int nres = lua_gettop(co); + if (!lua_checkstack(L, nres + 1)) + luaL_error(L, "too many results to resume"); + lua_xmove(co, L, nres); /* move yielded values */ + return nres; + } + else { + lua_xmove(co, L, 1); /* move error message */ + return -1; /* error flag */ + } +} + +static int ct_resume(lua_State *L) { + lua_State *co = lua_tothread(L, 1); + int r; + luaL_argcheck(L, co, 1, "coroutine expected"); + r = auxresume(L, co, lua_gettop(L) - 1); + if (r < 0) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); + return r + 1; /* return true + `resume' returns */ + } +} + +static int ct_auxwrap(lua_State *L) { + lua_State *co = lua_tothread(L, lua_upvalueindex(1)); + int r = auxresume(L, co, lua_gettop(L)); + if (r < 0) { + if (lua_isstring(L, -1)) { /* error object is a string? */ + luaL_where(L, 1); /* add extra info */ + lua_insert(L, -2); + lua_concat(L, 2); + } + lua_error(L); /* propagate error */ + } + return r; +} + +static int ct_cocreate(lua_State *L) { + lua_State *NL = lua_newthread(L); + luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, + "Lua function expected"); + lua_pushvalue(L, 1); /* move function to top */ + lua_xmove(L, NL, 1); /* move function from L to NL */ + return 1; +} + + +static int ct_wrap(lua_State *L) { + ct_cocreate(L); + lua_pushcclosure(L, ct_auxwrap, 1); + return 1; +} + +static int ct_yield(lua_State *L) { + return lua_yield(L, lua_gettop(L)); +} + +static int ct_lightud(lua_State *L) +{ + lua_pushlightuserdata(L, (void *)(ptrdiff_t)lua_tonumber(L, 1)); + return 1; +} + +static luaL_Reg ct_funcs[] = { + {"call", ct_call }, + {"callon", ct_callon }, + {"pcall", ct_pcall }, + {"xpcall", ct_xpcall }, + {"pcall_err", ct_pcall_err }, + {"resume", ct_resume }, + {"wrap", ct_wrap }, + {"yield", ct_yield }, + {"lightud", ct_lightud }, + {NULL, NULL} +}; + +LUA_API int luaopen_ctest(lua_State *L) +{ + luaL_register(L, "ctest", ct_funcs); + return 1; +} diff --git a/test/LuaJIT-test-cleanup/sysdep/catch_cpp.lua b/test/LuaJIT-test-cleanup/sysdep/catch_cpp.lua new file mode 100644 index 0000000..b225100 --- /dev/null +++ b/test/LuaJIT-test-cleanup/sysdep/catch_cpp.lua @@ -0,0 +1,71 @@ + +local cp = require("cpptest") + +do + local a, b = pcall(cp.catch, function() return "x" end) + assert(a == true and b == "x") +end + +do + local a, b = pcall(function() cp.throw("foo") end) + assert(a == false and b == "C++ exception") +end + +local unwind +do + local a, b = pcall(cp.catch, function() cp.throw("foo") end) + unwind = a + assert((a == false and b == "C++ exception") or (a == true and b == "foo")) +end + +do + local st = cp.alloc(function() return cp.isalloc() end) + assert(st == true) + assert(cp.isalloc() == false) +end + +do + local a, b = pcall(cp.alloc, function() + assert(cp.isalloc() == true) + return "foo", cp.throw + end) + assert(a == false and b == "C++ exception") + assert(cp.isalloc() == false) +end + +if unwind then + local a, b = pcall(cp.alloc, function() + assert(cp.isalloc() == true) + return "foo", error + end) + assert(a == false and b == "foo") + assert(cp.isalloc() == false) +end + +do + local a,b,c,d,e,f = cp.usereg(100, 50, function() end, false) + assert(a==164 and b==312 and c==428 and d==3696 and e==404 and f==404) +end + +do + local function test() + cp.usereg(100, 40, error, "foo") + end + local a,b,c,d,e,f = cp.usereg(100, 51, test, false) + assert(a==164 and b==312 and c==428 and d==3696 and e==404 and f==404) +end + +do + local t = {}; + t.t = t; + local function foo() + for i=1,100 do + local a,b,c,d,e,f = t, t.t, t.t.t, t.t.t.t, t.t.t.t.t, t.t.t.t.t.t + local g,h,j,k,l = f.t, f.t.t, f.t.t.t, f.t.t.t.t, f.t.t.t.t.t + local m = { a,b,c,d,e,f,g,h,j,k,l } + end + end + local a,b,c,d,e,f = cp.usereg(100, 50, foo, false) + assert(a==164 and b==312 and c==428 and d==3696 and e==404 and f==404) +end + diff --git a/test/LuaJIT-test-cleanup/sysdep/ffi_include_gtk.lua b/test/LuaJIT-test-cleanup/sysdep/ffi_include_gtk.lua new file mode 100644 index 0000000..a4bfcea --- /dev/null +++ b/test/LuaJIT-test-cleanup/sysdep/ffi_include_gtk.lua @@ -0,0 +1,9 @@ +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +if cdefs == "" then + cdefs = "-pthread -D_REENTRANT -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/directfb -I/usr/include/libpng12 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include -I/usr/include/gdk-pixbuf-2.0" +end + +include"/usr/include/gtk-2.0/gtk/gtk.h" diff --git a/test/LuaJIT-test-cleanup/sysdep/ffi_include_std.lua b/test/LuaJIT-test-cleanup/sysdep/ffi_include_std.lua new file mode 100644 index 0000000..b88c82b --- /dev/null +++ b/test/LuaJIT-test-cleanup/sysdep/ffi_include_std.lua @@ -0,0 +1,36 @@ +local ffi = require("ffi") + +dofile("../common/ffi_util.inc") + +do + local fp = assert(io.open("/tmp/__tmp.c", "w")) + fp:write[[ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +]] + fp:close() + + local flags = ffi.abi("32bit") and "-m32" or "-m64" + fp = assert(io.popen("cc -E -P -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE /tmp/__tmp.c "..flags)) + local s = fp:read("*a") + fp:close() + os.remove("/tmp/__tmp.c") + ffi.cdef(s) +end + diff --git a/test/LuaJIT-test-cleanup/sysdep/ffi_lib_c.lua b/test/LuaJIT-test-cleanup/sysdep/ffi_lib_c.lua new file mode 100644 index 0000000..a368d75 --- /dev/null +++ b/test/LuaJIT-test-cleanup/sysdep/ffi_lib_c.lua @@ -0,0 +1,87 @@ +local ffi = require("ffi") + +ffi.cdef[[ +// libc/libm +int sprintf(char *buf, const char *fmt, ...); +double pow(double x, double y); +int rmdir(const char *name); +int errno; + +// Windows +unsigned int GetSystemDirectoryA(char *buf, unsigned int sz); +char *CharUpperA(char *str); +int GdiFlush(void); +int _rmdir(const char *name); +static const int _O_TEXT = 0x4000; +static const int _O_BINARY = 0x8000; +int *_errno(void); +int _fmode; + +// Lua/C API +typedef struct lua_State lua_State; +typedef double lua_Number; +lua_State *luaL_newstate(void); +void luaL_openlibs(lua_State *L); +void lua_close(lua_State *L); +int luaL_loadstring(lua_State *L, const char *s); +int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc); +lua_Number lua_tonumber(lua_State *L, int idx); +]] + +local C = ffi.C + +do + local buf = ffi.new("char[?]", 100) + local n = C.sprintf(buf, "test %g %s", 12.5, "foo") + assert(ffi.string(buf, n) == "test 12.5 foo") +end + +assert(ffi.C.pow(2.5, 5) == 97.65625) + +if ffi.abi("win") then + do + local buf = ffi.new("char[?]", 4, "abc") + C.CharUpperA(buf) + assert(ffi.string(buf) == "ABC") + end + + do + local buf = ffi.new("char[?]", 256) + local len = C.GetSystemDirectoryA(buf, 255) + local s = ffi.string(buf, len) + assert(string.find(string.lower(s), "\\system32")) + end + + assert(C.GdiFlush() == 1) + + assert(ffi.C._rmdir("/tmp/does_not_exist") == -1) + assert(ffi.C._errno()[0] == 2) + + ffi.C._fmode = ffi.C._O_BINARY + assert(ffi.C._fmode == ffi.C._O_BINARY) + ffi.C._fmode = ffi.C._O_TEXT +else + assert(ffi.C.rmdir("/tmp/does_not_exist") == -1) + assert(ffi.C.errno == 2) + + ffi.C.errno = 17 + assert(ffi.C.errno == 17) + ffi.C.errno = 0 +end + +do + local L = C.luaL_newstate() + local s = "local x = 0; for i=1,100 do x=x+i end; return x" + C.luaL_openlibs(L) + assert(C.luaL_loadstring(L, s) == 0) + assert(C.lua_pcall(L, 0, 1, 0) == 0) + assert(C.lua_tonumber(L, -1) == 5050) + C.lua_close(L) +end + +do + if not (ffi.os == "Windows" or ffi.os == "Other") then + ffi.load("pthread") + end +end + diff --git a/test/LuaJIT-test-cleanup/sysdep/ffi_lib_z.lua b/test/LuaJIT-test-cleanup/sysdep/ffi_lib_z.lua new file mode 100644 index 0000000..69a19ae --- /dev/null +++ b/test/LuaJIT-test-cleanup/sysdep/ffi_lib_z.lua @@ -0,0 +1,107 @@ +local ffi = require("ffi") + +local compress, uncompress + +if ffi.abi("win") then + + ffi.cdef[[ + int RtlGetCompressionWorkSpaceSize(uint16_t fmt, + unsigned long *wsbufsz, unsigned long *wsfragsz); + int RtlCompressBuffer(uint16_t fmt, + const uint8_t *src, unsigned long srclen, + uint8_t *dst, unsigned long dstsz, + unsigned long chunk, unsigned long *dstlen, void *workspace); + int RtlDecompressBuffer(uint16_t fmt, + uint8_t *dst, unsigned long dstsz, + const uint8_t *src, unsigned long srclen, + unsigned long *dstlen); + ]] + + local ntdll = ffi.load("ntdll") + + local fmt = 0x0102 + local workspace + do + local res = ffi.new("unsigned long[2]") + ntdll.RtlGetCompressionWorkSpaceSize(fmt, res, res+1) + workspace = ffi.new("uint8_t[?]", res[0]) + end + + function compress(txt) + local buf = ffi.new("uint8_t[?]", 4096) + local buflen = ffi.new("unsigned long[1]") + local res = ntdll.RtlCompressBuffer(fmt, txt, #txt, buf, 4096, + 4096, buflen, workspace) + assert(res == 0) + return ffi.string(buf, buflen[0]) + end + + function uncompress(comp, n) + local buf = ffi.new("uint8_t[?]", n) + local buflen = ffi.new("unsigned long[1]") + local res = ntdll.RtlDecompressBuffer(fmt, buf, n, comp, #comp, buflen) + assert(res == 0) + return ffi.string(buf, buflen[0]) + end + +else + + ffi.cdef[[ + unsigned long compressBound(unsigned long sourceLen); + int compress2(uint8_t *dest, unsigned long *destLen, + const uint8_t *source, unsigned long sourceLen, int level); + int uncompress(uint8_t *dest, unsigned long *destLen, + const uint8_t *source, unsigned long sourceLen); + ]] + + local zlib = ffi.load("z") + + function compress(txt) + local n = tonumber(zlib.compressBound(#txt)) + local buf = ffi.new("uint8_t[?]", n) + local buflen = ffi.new("unsigned long[1]", n) + local res = zlib.compress2(buf, buflen, txt, #txt, 9) + assert(res == 0) + return ffi.string(buf, tonumber(buflen[0])) + end + + function uncompress(comp, n) + local buf = ffi.new("uint8_t[?]", n) + local buflen = ffi.new("unsigned long[1]", n) + local res = zlib.uncompress(buf, buflen, comp, #comp) + assert(res == 0) + return ffi.string(buf, tonumber(buflen[0])) + end + +end + + local txt = [[Rebellious subjects, enemies to peace, +Profaners of this neighbour-stained steel,-- +Will they not hear? What, ho! you men, you beasts, +That quench the fire of your pernicious rage +With purple fountains issuing from your veins, +On pain of torture, from those bloody hands +Throw your mistemper'd weapons to the ground, +And hear the sentence of your moved prince. +Three civil brawls, bred of an airy word, +By thee, old Capulet, and Montague, +Have thrice disturb'd the quiet of our streets, +And made Verona's ancient citizens +Cast by their grave beseeming ornaments, +To wield old partisans, in hands as old, +Canker'd with peace, to part your canker'd hate: +If ever you disturb our streets again, +Your lives shall pay the forfeit of the peace. +For this time, all the rest depart away: +You Capulet; shall go along with me: +And, Montague, come you this afternoon, +To know our further pleasure in this case, +To old Free-town, our common judgment-place. +Once more, on pain of death, all men depart.]] +txt = txt..txt..txt..txt + +local c = compress(txt) +assert(2*#c < #txt) +local txt2 = uncompress(c, #txt) +assert(txt2 == txt) + diff --git a/test/LuaJIT-test-cleanup/test.lua b/test/LuaJIT-test-cleanup/test.lua new file mode 100644 index 0000000..b064eff --- /dev/null +++ b/test/LuaJIT-test-cleanup/test.lua @@ -0,0 +1,416 @@ +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 + if loadstring"goto x ::x::" then + tags["goto"] = 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+1, #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 + local file, name = plan_i[1], plan_i[2] + if not opts.quiet then + 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 + if opts.quiet then + io_write(progress_format:format(i), file) + io_write(file == "" and "" or " --- ", name, "\n") + end + 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/LuaJIT-test-cleanup/trace/exit_frame.lua b/test/LuaJIT-test-cleanup/trace/exit_frame.lua new file mode 100644 index 0000000..9537c56 --- /dev/null +++ b/test/LuaJIT-test-cleanup/trace/exit_frame.lua @@ -0,0 +1,79 @@ +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/LuaJIT-test-cleanup/trace/exit_growstack.lua b/test/LuaJIT-test-cleanup/trace/exit_growstack.lua new file mode 100644 index 0000000..658a31a --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/trace/exit_jfuncf.lua b/test/LuaJIT-test-cleanup/trace/exit_jfuncf.lua new file mode 100644 index 0000000..67ad7c3 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/trace/gc64_slot_revival.lua b/test/LuaJIT-test-cleanup/trace/gc64_slot_revival.lua new file mode 100644 index 0000000..40b9d87 --- /dev/null +++ b/test/LuaJIT-test-cleanup/trace/gc64_slot_revival.lua @@ -0,0 +1,18 @@ +do --- BC_KNIL + local function f(x, y) end + for i = 1,100 do + f(i, i) + f(nil, nil) + end +end + +do --- BC_VARG + local function f() end + local function g(...) + f() + f(...) + end + for i = 1,100 do + g() + end +end diff --git a/test/LuaJIT-test-cleanup/trace/index b/test/LuaJIT-test-cleanup/trace/index new file mode 100644 index 0000000..ea7a22e --- /dev/null +++ b/test/LuaJIT-test-cleanup/trace/index @@ -0,0 +1,7 @@ +exit_frame.lua +exit_growstack.lua +exit_jfuncf.lua +gc64_slot_revival.lua +phi +snap.lua +stitch.lua diff --git a/test/LuaJIT-test-cleanup/trace/phi/copyspill.lua b/test/LuaJIT-test-cleanup/trace/phi/copyspill.lua new file mode 100644 index 0000000..17a8698 --- /dev/null +++ b/test/LuaJIT-test-cleanup/trace/phi/copyspill.lua @@ -0,0 +1,53 @@ +do --- mat4mul !private_G +function mat4mul(a11, a21, a31, a41, + a12, a22, a32, a42, + a13, a23, a33, a43, + a14, a24, a34, a44, + b11, b21, b31, b41, + b12, b22, b32, b42, + b13, b23, b33, b43, + b14, b24, b34, b44) + return a11*b11+a21*b12+a31*b13+a41*b14, + a11*b21+a21*b22+a31*b23+a41*b24, + a11*b31+a21*b32+a31*b33+a41*b34, + a11*b41+a21*b42+a31*b43+a41*b44, + a12*b11+a22*b12+a32*b13+a42*b14, + a12*b21+a22*b22+a32*b23+a42*b24, + a12*b31+a22*b32+a32*b33+a42*b34, + a12*b41+a22*b42+a32*b43+a42*b44, + a13*b11+a23*b12+a33*b13+a43*b14, + a13*b21+a23*b22+a33*b23+a43*b24, + a13*b31+a23*b32+a33*b33+a43*b34, + a13*b41+a23*b42+a33*b43+a43*b44, + a14*b11+a24*b12+a34*b13+a44*b14, + a14*b21+a24*b22+a34*b23+a44*b24, + a14*b31+a24*b32+a34*b33+a44*b34, + a14*b41+a24*b42+a34*b43+a44*b44 +end + +local a11, a21, a31, a41 = 1, 0, 0, 0 +local a12, a22, a32, a42 = 0, 1, 0, 0 +local a13, a23, a33, a43 = 0, 0, 1, 0 +local a14, a24, a34, a44 = 0, 0, 0, 1 + +local b11, b21, b31, b41 = 0, 0, -1, 0 +local b12, b22, b32, b42 = 0, 1, 0, 0 +local b13, b23, b33, b43 = 1, 0, 0, 0 +local b14, b24, b34, b44 = 0, 0, 0, 1 + +for i = 1, 1000 do + a11, a21, a31, a41, + a12, a22, a32, a42, + a13, a23, a33, a43, + a14, a24, a34, a44 = mat4mul(a11, a21, a31, a41, + a12, a22, a32, a42, + a13, a23, a33, a43, + a14, a24, a34, a44, + b11, b21, b31, b41, + b12, b22, b32, b42, + b13, b23, b33, b43, + b14, b24, b34, b44) +end +assert(a11 == 1) +assert(a31 == 0) +end diff --git a/test/LuaJIT-test-cleanup/trace/phi/index b/test/LuaJIT-test-cleanup/trace/phi/index new file mode 100644 index 0000000..74a0733 --- /dev/null +++ b/test/LuaJIT-test-cleanup/trace/phi/index @@ -0,0 +1,3 @@ +copyspill.lua +ref.lua +rotate.lua diff --git a/test/LuaJIT-test-cleanup/trace/phi/ref.lua b/test/LuaJIT-test-cleanup/trace/phi/ref.lua new file mode 100644 index 0000000..3662912 --- /dev/null +++ b/test/LuaJIT-test-cleanup/trace/phi/ref.lua @@ -0,0 +1,131 @@ +do --- rref points into invariant part 1 + local x,y=1,2; for i=1,100 do x=x+y; y=i end + assert(y == 100) +end + +do --- rref points into invariant part 2 + local x,y=1,2; for i=1,100.5 do x=x+y; y=i end + assert(y == 100) +end + +do --- rref points into invariant part 3 + local x,y=1,2; for i=1,100 do x,y=y,x end + assert(x == 1) + assert(y == 2) +end + +do --- rref points into invariant part 4 + local x,y,z=1,2,3; for i=1,100 do x,y,z=y,z,x end + assert(x == 2) + assert(y == 3) + assert(z == 1) +end + +do --- rref points into invariant part 5 + local x,y,z=1,2,3; for i=1,100 do x,y,z=z,x,y end + assert(x == 3) + assert(y == 1) + assert(z == 2) +end + +do --- rref points into invariant part 6 + local a,x,y,z=0,1,2,3; for i=1,100 do a=a+x; x=y; y=z; z=i end + assert(a == 4759) + assert(x == 98) + assert(y == 99) + assert(z == 100) +end + +do --- variant slot, but no corresponding SLOAD i-1 + local x,y=1,2; for i=1,100 do x=i; y=i-1 end + assert(x == 100) + assert(y == 99) +end + +do --- variant slot, but no corresponding SLOAD i+1 + local x,y=1,2; for i=1,100 do x=i; y=i+1 end + assert(x == 100) + assert(y == 101) +end + +do --- variant slot, but no corresponding SLOAD side exit + local x=0; for i=1,100 do if i==90 then break end x=i end + assert(x == 89) +end + +do --- dup lref from variant slot (suppressed) + local x,y=1,2; for i=1,100 do x=i; y=i end + assert(x == 100) + assert(y == 100) +end + +do --- const rref + local x,y=1,2 local bxor,tobit=bit.bxor,bit.tobit; + for i=1,100 do x=bxor(i,y); y=tobit(i+1) end + assert(x == 0) + assert(y == 101) +end + +do --- dup rref (ok) + local x,y,z1,z2=1,2,3,4 local bxor,tobit=bit.bxor,bit.tobit; + for i=1,100 do x=bxor(i,y); z2=tobit(i+5); z1=bxor(x,i+5); y=tobit(i+1) end + assert(x == 0) + assert(y == 101) + assert(z1 == 105) + assert(z2 == 105) +end + +do --- variant slot, no corresponding SLOAD + for i=1,5 do + local a, b = 1, 2 + local bits = 0 + while a ~= b do + bits = bits + 1 + a = b + b = bit.lshift(b, 1) + end + assert(bits == 32) + end +end + +do --- don't eliminate PHI if referenced from snapshot + local t = { 0 } + local a = 0 + for i=1,100 do + local b = t[1] + t[1] = i + a + a = b + end + assert(a == 2500) + assert(t[1] == 2550) +end + +do --- don't eliminate PHI if referenced from snapshot + local x = 1 + local function f() + local t = {} + for i=1,200 do t[i] = i end + for i=1,200 do + local x1 = x + x = t[i] + if i > 100 then return x1 end + end + end + assert(f() == 100) +end + +do --- don't eliminate PHI if referenced from another non-redundant PHI + local t = {} + for i=1,256 do + local a, b, k = i, math.floor(i/2), -i + while a > 1 and t[b] > k do + t[a] = t[b] + a = b + b = math.floor(a/2) + end + t[a] = k + end + local x = 0 + for i=1,256 do x = x + bit.bxor(i, t[i]) end + assert(x == -41704) +end diff --git a/test/LuaJIT-test-cleanup/trace/phi/rotate.lua b/test/LuaJIT-test-cleanup/trace/phi/rotate.lua new file mode 100644 index 0000000..cb751e0 --- /dev/null +++ b/test/LuaJIT-test-cleanup/trace/phi/rotate.lua @@ -0,0 +1,149 @@ +do --- rot8 + local function rot8r(n) + local a,b,c,d,e,f,g,h=1,2,3,4,5,6,7,8 + for x=1,n do + a,b,c,d,e,f,g,h=h,a,b,c,d,e,f,g + end + return table.concat{a,b,c,d,e,f,g,h} + end + + local function rot8l(n) + local a,b,c,d,e,f,g,h=1,2,3,4,5,6,7,8 + for x=1,n do + a,b,c,d,e,f,g,h=b,c,d,e,f,g,h,a + end + return table.concat{a,b,c,d,e,f,g,h} + end + + assert(rot8r(0) == "12345678") + assert(rot8r(10) == "78123456") + assert(rot8r(105) == "81234567") + assert(rot8r(0) == "12345678") + assert(rot8r(1) == "81234567") + assert(rot8r(2) == "78123456") + assert(rot8r(0) == "12345678") + assert(rot8r(1) == "81234567") + assert(rot8r(2) == "78123456") + assert(rot8r(105) == "81234567") + + assert(rot8l(0) == "12345678") + assert(rot8l(10) == "34567812") + assert(rot8l(105) == "23456781") + assert(rot8l(0) == "12345678") + assert(rot8l(1) == "23456781") + assert(rot8l(2) == "34567812") + assert(rot8l(0) == "12345678") + assert(rot8l(1) == "23456781") + assert(rot8l(2) == "34567812") + + assert(rot8r(100) == "56781234") + assert(rot8l(100) == "56781234") +end + +do --- rot9 + local function rot9r(n) + local a,b,c,d,e,f,g,h,i=1,2,3,4,5,6,7,8,9 + for x=1,n do + a,b,c,d,e,f,g,h,i=i,a,b,c,d,e,f,g,h + end + return table.concat{a,b,c,d,e,f,g,h,i} + end + + local function rot9l(n) + local a,b,c,d,e,f,g,h,i=1,2,3,4,5,6,7,8,9 + for x=1,n do + a,b,c,d,e,f,g,h,i=b,c,d,e,f,g,h,i,a + end + return table.concat{a,b,c,d,e,f,g,h,i} + end + + assert(rot9r(0) == "123456789") + assert(rot9r(10) == "912345678") + assert(rot9r(105) == "456789123") + assert(rot9r(0) == "123456789") + assert(rot9r(1) == "912345678") + assert(rot9r(2) == "891234567") + assert(rot9r(0) == "123456789") + assert(rot9r(1) == "912345678") + assert(rot9r(2) == "891234567") + assert(rot9r(105) == "456789123") + + assert(rot9l(0) == "123456789") + assert(rot9l(10) == "234567891") + assert(rot9l(105) == "789123456") + assert(rot9l(0) == "123456789") + assert(rot9l(1) == "234567891") + assert(rot9l(2) == "345678912") + assert(rot9l(0) == "123456789") + assert(rot9l(1) == "234567891") + assert(rot9l(2) == "345678912") + + assert(rot9r(100) == "912345678") + assert(rot9l(100) == "234567891") +end + +do --- rot18 + local function rot18r(N) + local a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 + for x=1,N do + a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r=r,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q + end + return table.concat{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r} + end + + local function rot18l(N) + local a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 + for x=1,N do + a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r=b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,a + end + return table.concat{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r} + end + + assert(rot18r(0) == "123456789101112131415161718") + assert(rot18r(10) == "910111213141516171812345678") + assert(rot18r(105) == "456789101112131415161718123") + assert(rot18r(0) == "123456789101112131415161718") + assert(rot18r(1) == "181234567891011121314151617") + assert(rot18r(2) == "171812345678910111213141516") + assert(rot18r(0) == "123456789101112131415161718") + assert(rot18r(1) == "181234567891011121314151617") + assert(rot18r(2) == "171812345678910111213141516") + assert(rot18r(105) == "456789101112131415161718123") + + assert(rot18l(0) == "123456789101112131415161718") + assert(rot18l(10) == "111213141516171812345678910") + assert(rot18l(105) == "161718123456789101112131415") + assert(rot18l(0) == "123456789101112131415161718") + assert(rot18l(1) == "234567891011121314151617181") + assert(rot18l(2) == "345678910111213141516171812") + assert(rot18l(0) == "123456789101112131415161718") + assert(rot18l(1) == "234567891011121314151617181") + assert(rot18l(2) == "345678910111213141516171812") + + assert(rot18r(100) == "910111213141516171812345678") + assert(rot18l(100) == "111213141516171812345678910") +end + +do --- rotx + local function rot9r(n, m) + local a,b,c,d,e,f,g,h,i=1,2,3,4,5,6,7,8,9 + local s = "" + for x=1,n do + a,b,c,d,e,f,g,h,i=i,a,b,c,d,e,f,g,h + if x == m then s = table.concat{a,b,c,d,e,f,g,h,i} end + c,d = d,c + end + return table.concat{a,b,c,d,e,f,g,h,i, s} + end + + assert(rot9r(0,0) == "123456789") + assert(rot9r(10,0) == "893124567") + assert(rot9r(105,0) == "913245678") + assert(rot9r(105,90) == "913245678891324567") + assert(rot9r(0,0) == "123456789") + assert(rot9r(1,0) == "913245678") + assert(rot9r(2,0) == "893124567") + assert(rot9r(1,1) == "913245678912345678") + assert(rot9r(2,1) == "893124567912345678") + assert(rot9r(2,2) == "893124567891324567") +end diff --git a/test/LuaJIT-test-cleanup/trace/snap.lua b/test/LuaJIT-test-cleanup/trace/snap.lua new file mode 100644 index 0000000..ba26326 --- /dev/null +++ b/test/LuaJIT-test-cleanup/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/LuaJIT-test-cleanup/trace/stitch.lua b/test/LuaJIT-test-cleanup/trace/stitch.lua new file mode 100644 index 0000000..3f7f973 --- /dev/null +++ b/test/LuaJIT-test-cleanup/trace/stitch.lua @@ -0,0 +1,19 @@ +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 diff --git a/test/LuaJIT-test-cleanup/unportable/ffi_arith_int64.lua b/test/LuaJIT-test-cleanup/unportable/ffi_arith_int64.lua new file mode 100644 index 0000000..c05e02a --- /dev/null +++ b/test/LuaJIT-test-cleanup/unportable/ffi_arith_int64.lua @@ -0,0 +1,68 @@ +local ffi = require("ffi") + +local int = ffi.typeof("int") + +local inp = { + 0, 0.5, -0.5, 1.5, -1.5, 1, -1, 2, -2, 37, -37, false, + int(0), int(1), int(-1), int(2), int(-2), int(37), int(-37), false, + 0ll, 1ll, -1ll, 2ll, -2ll, 37ll, -37ll, false, + 0ull, 1ull, -1ull, 2ull, -2ull, 37ull, -37ull, +} + +local function cksum(s, r) + local z = 0 + for i=1,#s do z = (z + string.byte(s, i)*i) % 2147483629 end + if z ~= r then + error("test failed (got "..z..", expected "..r..") for:\n"..s, 3) + end +end + +local function tostr(n) + if type(n) == "cdata" then return tostring(n) + elseif n ~= n then return "nan" + else return string.format("%+1.5g", n) end +end + +local function check(f, expected, y) + local inp = inp + local out = {} + for i=1,#inp do + if inp[i] then out[i] = tostr(f(inp[i], y)) else out[i] = "\n" end + end + local got = string.gsub(table.concat(out, " ").."\n", "\n ", "\n") + cksum(got, expected) +end + +jit.off(check) + +local function check2(f, exparray) + local k = 1 + for j=1,#inp do + local y = inp[j] + if y then + check(f, exparray[k], y) + k = k + 1 + end + end +end + +check(function(x) return -x end, 1174528) + +check2(function(x, y) return x+y end, +{1171039,1239261,1239303,1011706,1490711,949996,1415869,756412,1682910,768883,2201023,1265370,1015700,1556902,807607,1862947,814710,2423097,1265370,1015700,1556902,807607,1862947,814710,2423097,4833809,2909723,7784653,1736671,10743770,1126700,13324037,}) + +check2(function(x, y) return x-y end, +{1171039,1239303,1239261,1490711,1011706,1415869,949996,1682910,756412,2201023,768883,1265370,1556902,1015700,1862947,807607,2423097,814710,1265370,1556902,1015700,1862947,807607,2423097,814710,4833809,7784653,2909723,10743770,1736671,13324037,1126700,}) + +check2(function(x, y) return x*y end, +{470257,637182,637132,1308150,1311627,1171039,1174528,1083877,1087553,1561321,1564869,564568,1265370,1269122,1265037,1268973,1643392,1647266,564568,1265370,1269122,1265037,1268973,1643392,1647266,827768,4833809,4847593,4823713,4838210,5230281,5244035,}) + +check2(function(x, y) return x/y end, +{7946210,7360895,7360865,1580465,927251,1171039,622069,1252901,704706,1542087,960011,14749620,1265370,695208,1188639,661058,1049280,587329,14749620,1265370,695208,1188639,661058,1049280,587329,15042810,4833809,828129,4559889,828509,4208862,828929,}) + + +check2(function(x, y) return x%y end, +{7653740,7304160,7304160,527871,851988,527061,850910,556674,717022,610671,613599,14749620,564568,894526,618652,785052,641760,644574,14749620,564568,894526,618652,785052,641760,644574,15042810,827768,2913108,829285,1737261,951059,959905,}) + +check2(function(x, y) return x^y end, +{471871,702627,720692,1385612,1803393,1171039,1772007,763817,1583994,4486762,2380423,566647,1265370,2319256,770581,1990479,4566660,2319835,566647,1265370,2319256,770581,1990479,4566660,2319835,830322,4833809,4644705,1071753,2822313,7709069,4647021,}) diff --git a/test/LuaJIT-test-cleanup/unportable/math_special.lua b/test/LuaJIT-test-cleanup/unportable/math_special.lua new file mode 100644 index 0000000..4916101 --- /dev/null +++ b/test/LuaJIT-test-cleanup/unportable/math_special.lua @@ -0,0 +1,55 @@ + +local inp = { 0, -"0", 0.5, -0.5, 1, -1, 1/0, -1/0, 0/0 } + +local function tostr(n) + if n == 0 and 1/n < 0 then return "-0" + elseif 1/n == 0 then return n < 0 and "-inf" or "+inf" + elseif n ~= n then return "nan" + else return string.format("%+1.5g", n) end +end + +local function check(f, expected) + local inp = inp + local out = {} + for i=1,#inp do out[i] = tostr(f(inp[i])) end + local got = table.concat(out, " ") + if got ~= expected then + error("got: \""..got.."\"\nexpected: \""..expected.."\"", 2) + end +end + +check(function(x) return x end, "+0 -0 +0.5 -0.5 +1 -1 +inf -inf nan") + +local powcheck = { + "+1 +1 +1 +1 +1 +1 +1 +1 +1", + "+1 +1 +1 +1 +1 +1 +1 +1 +1", + "+0 +0 +0.70711 nan +1 nan +inf +inf nan", + "+inf +inf +1.4142 nan +1 nan +0 +0 nan", + "+0 -0 +0.5 -0.5 +1 -1 +inf -inf nan", + "+inf -inf +2 -2 +1 -1 +0 -0 nan", + "+0 +0 +0 +0 +1 +1 +inf +inf nan", + "+inf +inf +inf +inf +1 +1 +0 +0 nan", + "nan nan nan nan +1 nan nan nan nan", +} +for j=1,#inp do + local y = inp[j] + check(function(x) return x^y end, powcheck[j]) +end + +check(math.abs, "+0 +0 +0.5 +0.5 +1 +1 +inf +inf nan") +check(math.floor, "+0 -0 +0 -1 +1 -1 +inf -inf nan") +check(math.ceil, "+0 -0 +1 -0 +1 -1 +inf -inf nan") +check(math.sqrt, "+0 -0 +0.70711 nan +1 nan +inf nan nan") +check(math.sin, "+0 -0 +0.47943 -0.47943 +0.84147 -0.84147 nan nan nan") +check(math.cos, "+1 +1 +0.87758 +0.87758 +0.5403 +0.5403 nan nan nan") +check(math.tan, "+0 -0 +0.5463 -0.5463 +1.5574 -1.5574 nan nan nan") +check(math.asin, "+0 -0 +0.5236 -0.5236 +1.5708 -1.5708 nan nan nan") +check(math.acos, "+1.5708 +1.5708 +1.0472 +2.0944 +0 +3.1416 nan nan nan") +check(math.atan, "+0 -0 +0.46365 -0.46365 +0.7854 -0.7854 +1.5708 -1.5708 nan") +check(math.log, "-inf -inf -0.69315 nan +0 nan +inf nan nan") +check(math.log10, "-inf -inf -0.30103 nan +0 nan +inf nan nan") +check(math.exp, "+1 +1 +1.6487 +0.60653 +2.7183 +0.36788 +inf +0 nan") + +-- Pointless: deg, rad, min, max, pow +-- LATER: %, fmod, frexp, ldexp, modf, sinh, cosh, tanh + -- 2.25.1