luau/tests/conformance/native.lua

393 lines
9.7 KiB
Lua
Raw Normal View History

-- This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
print("testing native code generation")
assert((function(x, y)
-- trigger a linear sequence
local t1 = x + 2
local t2 = x - 7
local a = x * 10
local b = a + 1
a = y -- update 'a' version
local t = {} -- call to allocate table forces a spill
local c = x * 10
return c, b, t, t1, t2
end)(5, 10) == 50)
assert((function(x)
local oops -- split to prevent inlining
function oops()
end
-- x is checked to be a number here; we can not execute a reentry from oops() because optimizer assumes this holds until return
local y = math.abs(x)
oops()
return y * x
end)("42") == 1764)
local function fuzzfail1(...)
repeat
_ = nil
until not {}
for _ in ... do
for l0=_,_ do
end
return
end
end
local function fuzzfail2()
local _
do
repeat
_ = typeof(_),{_=_,}
_ = _(_._)
until _
end
end
assert(pcall(fuzzfail2) == false)
local function fuzzfail3()
function _(...)
_({_,_,true,},{...,},_,not _)
end
_()
end
assert(pcall(fuzzfail3) == false)
local function fuzzfail4()
local _ = setmetatable({},setmetatable({_=_,},_))
return _(_:_())
end
assert(pcall(fuzzfail4) == false)
local function fuzzfail5()
local _ = bit32.band
_(_(_,0),_)
_(_,_)
end
assert(pcall(fuzzfail5) == false)
local function fuzzfail6(_)
return bit32.extract(_,671088640,_)
end
assert(pcall(fuzzfail6, 1) == false)
local function fuzzfail7(_)
return bit32.extract(_,_,671088640)
end
assert(pcall(fuzzfail7, 1) == false)
local function fuzzfail8(...)
local _ = _,_
_.n0,_,_,_,_,_,_,_,_._,_,_,_[...],_,_,_ = nil
_,n0,_,_,_,_,_,_,_,_,l0,_,_,_,_ = nil
function _()
end
_._,_,_,_,_,_,_,_,_,_,_[...],_,n0[l0],_ = nil
_[...],_,_,_,_,_,_,_,_()[_],_,_,_,_,_ = _(),...
end
assert(pcall(fuzzfail8) == false)
local function fuzzfail9()
local _ = bit32.bor
local x = _(_(_,_),_(_,_),_(-16834560,_),_(_(- _,-2130706432)),- _),_(_(_,_),_(-16834560,-2130706432))
end
assert(pcall(fuzzfail9) == false)
local function fuzzfail10()
local _
_ = false,if _ then _ else _
_ = not _
l0,_[l0] = not _
end
assert(pcall(fuzzfail10) == false)
Sync to upstream/release/591 (#1012) * Fix a use-after-free bug in the new type cloning algorithm * Tighten up the type of `coroutine.wrap`. It is now `<A..., R...>(f: (A...) -> R...) -> ((A...) -> R...)` * Break `.luaurc` out into a separate library target `Luau.Config`. This makes it easier for applications to reason about config files without also depending on the type inference engine. * Move typechecking limits into `FrontendOptions`. This allows embedders more finely-grained control over autocomplete's internal time limits. * Fix stability issue with debugger onprotectederror callback allowing break in non-yieldable contexts New solver: * Initial work toward [Local Type Inference](https://github.com/Roblox/luau/blob/0e1082108fd6fb3a32dfdf5f1766ea3fc1391328/rfcs/local-type-inference.md) * Introduce a new subtyping test. This will be much nicer than the old test because it is completely separate both from actual type inference and from error reporting. Native code generation: * Added function to compute iterated dominance frontier * Optimize barriers in SET_UPVALUE when tag is known * Cache lua_State::global in a register on A64 * Optimize constant stores in A64 lowering * Track table array size state to optimize array size checks * Add split tag/value store into a VM register * Check that spills can outlive the block only in specific conditions --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-08-19 02:15:41 +08:00
local function fuzzfail11(x, ...)
return bit32.arshift(bit32.bnot(x),(...))
end
assert(fuzzfail11(0xffff0000, 8) == 0xff)
local function fuzzfail12()
_,_,_,_,_,_,_,_ = not _, not _, not _, not _, not _, not _, not _, not _
end
assert(pcall(fuzzfail12) == true)
local function fuzzfail13()
_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_ = not _, not _, not _, not _, not _, not _, not _, not _, not _, not _, not _, not _, not _, not _, not _, not _
end
assert(pcall(fuzzfail13) == true)
Sync to upstream/release/600 (#1076) ### What's Changed - Improve readability of unions and intersections by limiting the number of elements of those types that can be presented on a single line (gated under `FFlag::LuauToStringSimpleCompositeTypesSingleLine`) - Adds a new option to the compiler `--record-stats` to record and output compilation statistics - `if...then...else` expressions are now optimized into `AND/OR` form when possible. ### VM - Add a new `buffer` type to Luau based on the [buffer RFC](https://github.com/Roblox/luau/pull/739) and additional C API functions to work with it; this release does not include the library. - Internal C API to work with string buffers has been updated to align with Lua version more closely ### Native Codegen - Added support for new X64 instruction (rev) and new A64 instruction (bswap) in the assembler - Simplified the way numerical loop condition is translated to IR ### New Type Solver - Operator inference now handled by type families - Created a new system called `Type Paths` to explain why subtyping tests fail in order to improve the quality of error messages. - Systematic changes to implement Data Flow analysis in the new solver (`Breadcrumb` removed and replaced with `RefinementKey`) --- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com>
2023-10-21 09:10:30 +08:00
local function fuzzfail14()
for l0=771751936,_ do
for l0=771751936,0 do
while 538970624 do
end
end
end
end
assert(pcall(fuzzfail14) == false)
local function fuzzfail15()
local a
if a then
repeat until a
else
local b = `{a}`
a = nil
end
end
assert(pcall(fuzzfail15) == true)
Sync to upstream/release/601 (#1084) ## What's changed - `bit32.byteswap` added ([RFC](https://github.com/luau-lang/rfcs/blob/4f543ec23b6a1b53396e0803dd253c83041bae62/docs/function-bit32-byteswap.md)) - Buffer library implementation ([RFC](https://github.com/luau-lang/rfcs/blob/4f543ec23b6a1b53396e0803dd253c83041bae62/docs/type-byte-buffer.md)) - Fixed a missing `stdint.h` include - Fixed parser limiter for recursive type annotations being kind of weird (fixes #645) ### Native Codegen - Fixed a pair of issues when lowering `bit32.extract` - Fixed a narrow edge case that could result in an infinite loop without an interruption - Fixed a negative array out-of-bounds access issue - Temporarily reverted linear block predecessor value propagation ### New type solver - We now type check assignments to annotated variables - Fixed some test cases under local type inference - Moved `isPending` checks for type families to improve performance - Optimized our process for testing if a free type is sufficiently solved - Removed "none ptr" from lea instruction disassembly logging ### Build system & tooling - CMake configuration now validates dependencies to maintain separation between components - Improvements to the fuzzer coverage - Deduplicator for fuzzed callstacks --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
2023-10-28 05:18:41 +08:00
local function fuzzfail16()
_ = {[{[2]=77,_=_,[2]=_,}]=not _,}
_ = {77,[2]=11008,[2]=_,[0]=_,}
end
assert(pcall(fuzzfail16) == true)
local function fuzzfail17()
return bit32.extract(1293942816,1293942816)
end
assert(pcall(fuzzfail17) == false)
local function fuzzfail18()
Sync to upstream/release/611 (#1160) # What's changed? ### Native Code Generation * Fixed an UAF relating to reusing a hash key after a weak table has undergone some GC. * Fixed a bounds check on arm64 to allow access to the last byte of a buffer. ### New Type Solver * Type states now preserves error-suppression, i.e. `local x: any = 5` and `x.foo` does not error. * Made error-suppression logic in subtyping more accurate. * Subtyping now knows how to reduce type families. * Fixed function call overload resolution so that the return type resolves to the correct overload. * Fixed a case where we attempted to reduce irreducible type families a few too many times, leading to duplicate errors. * Type checker needs to type check annotations in function signatures to be able to report errors relating to those annotations. * Fixed an UAF from a pointer to stack-allocated data in Subtyping's `explainReasonings`. ### Nonstrict Type Checker * Fixed a crash when calling a checked function of the form `math.abs` with an incorrect argument type. * Fixed a crash when calling a checked function with a number of arguments that did not exactly match the number of parameters required. --- ### Internal Contributors Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Vighnesh <vvijay@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2024-02-03 05:32:42 +08:00
return bit32.extract(7890276,0)
Sync to upstream/release/601 (#1084) ## What's changed - `bit32.byteswap` added ([RFC](https://github.com/luau-lang/rfcs/blob/4f543ec23b6a1b53396e0803dd253c83041bae62/docs/function-bit32-byteswap.md)) - Buffer library implementation ([RFC](https://github.com/luau-lang/rfcs/blob/4f543ec23b6a1b53396e0803dd253c83041bae62/docs/type-byte-buffer.md)) - Fixed a missing `stdint.h` include - Fixed parser limiter for recursive type annotations being kind of weird (fixes #645) ### Native Codegen - Fixed a pair of issues when lowering `bit32.extract` - Fixed a narrow edge case that could result in an infinite loop without an interruption - Fixed a negative array out-of-bounds access issue - Temporarily reverted linear block predecessor value propagation ### New type solver - We now type check assignments to annotated variables - Fixed some test cases under local type inference - Moved `isPending` checks for type families to improve performance - Optimized our process for testing if a free type is sufficiently solved - Removed "none ptr" from lea instruction disassembly logging ### Build system & tooling - CMake configuration now validates dependencies to maintain separation between components - Improvements to the fuzzer coverage - Deduplicator for fuzzed callstacks --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
2023-10-28 05:18:41 +08:00
end
assert(pcall(fuzzfail18) == true)
assert(fuzzfail18() == 0)
local function arraySizeInv1()
local t = {1, 2, nil, nil, nil, nil, nil, nil, nil, true}
table.insert(t, 3)
return t[10]
end
assert(arraySizeInv1() == true)
local function arraySizeInv2()
local t = {1, 2, nil, nil, nil, nil, nil, nil, nil, true}
local u = {a = t}
table.insert(u.a, 3) -- aliased modifiction of 't' register through other value
return t[10]
end
assert(arraySizeInv2() == true)
local function nilInvalidatesSlot()
local function tabs()
local t = { x=1, y=2, z=3 }
setmetatable(t, { __index = function(t, k) return 42 end })
return t, t
end
local t1, t2 = tabs()
for i=1,2 do
local a = t1.x
t2.x = nil
local b = t1.x
t2.x = 1
assert(a == 1 and b == 42)
end
end
nilInvalidatesSlot()
local function arraySizeOpt1(a)
a[1] += 2
a[1] *= 3
table.insert(a, 3)
table.insert(a, 4)
table.insert(a, 5)
table.insert(a, 6)
a[1] += 4
a[1] *= 5
return a[1] + a[5]
end
assert(arraySizeOpt1({1}) == 71)
local function arraySizeOpt2(a, i)
a[i] += 2
a[i] *= 3
table.insert(a, 3)
table.insert(a, 4)
table.insert(a, 5)
table.insert(a, 6)
a[i] += 4
a[i] *= 5
return a[i] + a[5]
end
assert(arraySizeOpt2({1}, 1) == 71)
function deadLoopBody(n)
local r = 0
if n and false then
for i = 1, n do
r += 1
end
end
return r
end
assert(deadLoopBody(5) == 0)
function arrayIndexingSpecialNumbers1(a, b, c)
local arr = table.create(100000)
arr[a] = 9
arr[b-1] = 80
arr[b] = 700
arr[b+1] = 6000
arr[c-1] = 50000
arr[c] = 400000
arr[c+1] = 3000000
return arr[1] + arr[255] + arr[256] + arr[257] + arr[65535] + arr[65536] + arr[65537]
end
assert(arrayIndexingSpecialNumbers1(1, 256, 65536) == 3456789)
function loopIteratorProtocol(a, t)
local sum = 0
do
local a, b, c, d, e, f, g = {}, {}, {}, {}, {}, {}, {}
end
for k, v in ipairs(t) do
if k == 10 then sum += math.abs('-8') end
sum += k
end
return sum
end
assert(loopIteratorProtocol(0, table.create(100, 5)) == 5058)
Sync to upstream/release/610 (#1154) # What's changed? * Check interrupt handler inside the pattern match engine to eliminate potential for programs to hang during string library function execution. * Allow iteration over table properties to pass the old type solver. ### Native Code Generation * Use in-place memory operands for math library operations on x64. * Replace opaque bools with separate enum classes in IrDump to improve code maintainability. * Translate operations on inferred vectors to IR. * Enable support for debugging native-compiled functions in Roblox Studio. ### New Type Solver * Rework type inference for boolean and string literals to introduce bounded free types (bounded below by the singleton type, and above by the primitive type) and reworked primitive type constraint to decide which is the appropriate type for the literal. * Introduce `FunctionCheckConstraint` to handle bidirectional typechecking for function calls, pushing the expected parameter types from the function onto the arguments. * Introduce `union` and `intersect` type families to compute deferred simplified unions and intersections to be employed by the constraint generation logic in the new solver. * Implement support for expanding the domain of local types in `Unifier2`. * Rework type inference for iteration variables bound by for in loops to use local types. * Change constraint blocking logic to use a set to prevent accidental re-blocking. * Add logic to detect missing return statements in functions. ### Internal Contributors Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Vighnesh <vvijay@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2024-01-27 11:20:56 +08:00
local function vec3compsum(a: vector)
return a.X + a.Y + a.Z
end
assert(vec3compsum(vector(1, 2, 4)) == 7.0)
local function vec3add(a: vector, b: vector) return a + b end
local function vec3sub(a: vector, b: vector) return a - b end
local function vec3mul(a: vector, b: vector) return a * b end
local function vec3div(a: vector, b: vector) return a / b end
local function vec3neg(a: vector) return -a end
assert(vec3add(vector(10, 20, 40), vector(1, 0, 2)) == vector(11, 20, 42))
assert(vec3sub(vector(10, 20, 40), vector(1, 0, 2)) == vector(9, 20, 38))
assert(vec3mul(vector(10, 20, 40), vector(1, 0, 2)) == vector(10, 0, 80))
assert(vec3div(vector(10, 20, 40), vector(1, 0, 2)) == vector(10, math.huge, 20))
assert(vec3neg(vector(10, 20, 40)) == vector(-10, -20, -40))
local function vec3mulnum(a: vector, b: number) return a * b end
local function vec3mulconst(a: vector) return a * 4 end
assert(vec3mulnum(vector(10, 20, 40), 4) == vector(40, 80, 160))
assert(vec3mulconst(vector(10, 20, 40), 4) == vector(40, 80, 160))
Sync to upstream/release/611 (#1160) # What's changed? ### Native Code Generation * Fixed an UAF relating to reusing a hash key after a weak table has undergone some GC. * Fixed a bounds check on arm64 to allow access to the last byte of a buffer. ### New Type Solver * Type states now preserves error-suppression, i.e. `local x: any = 5` and `x.foo` does not error. * Made error-suppression logic in subtyping more accurate. * Subtyping now knows how to reduce type families. * Fixed function call overload resolution so that the return type resolves to the correct overload. * Fixed a case where we attempted to reduce irreducible type families a few too many times, leading to duplicate errors. * Type checker needs to type check annotations in function signatures to be able to report errors relating to those annotations. * Fixed an UAF from a pointer to stack-allocated data in Subtyping's `explainReasonings`. ### Nonstrict Type Checker * Fixed a crash when calling a checked function of the form `math.abs` with an incorrect argument type. * Fixed a crash when calling a checked function with a number of arguments that did not exactly match the number of parameters required. --- ### Internal Contributors Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Vighnesh <vvijay@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2024-02-03 05:32:42 +08:00
local function bufferbounds(zero)
local b1 = buffer.create(1)
local b2 = buffer.create(2)
local b4 = buffer.create(4)
local b8 = buffer.create(8)
local b10 = buffer.create(10)
-- only one valid position and size for a 1 byte buffer
buffer.writei8(b1, zero + 0, buffer.readi8(b1, zero + 0))
buffer.writeu8(b1, zero + 0, buffer.readu8(b1, zero + 0))
-- 2 byte buffer
buffer.writei8(b2, zero + 0, buffer.readi8(b2, zero + 0))
buffer.writeu8(b2, zero + 0, buffer.readu8(b2, zero + 0))
buffer.writei8(b2, zero + 1, buffer.readi8(b2, zero + 1))
buffer.writeu8(b2, zero + 1, buffer.readu8(b2, zero + 1))
buffer.writei16(b2, zero + 0, buffer.readi16(b2, zero + 0))
buffer.writeu16(b2, zero + 0, buffer.readu16(b2, zero + 0))
-- 4 byte buffer
buffer.writei8(b4, zero + 0, buffer.readi8(b4, zero + 0))
buffer.writeu8(b4, zero + 0, buffer.readu8(b4, zero + 0))
buffer.writei8(b4, zero + 3, buffer.readi8(b4, zero + 3))
buffer.writeu8(b4, zero + 3, buffer.readu8(b4, zero + 3))
buffer.writei16(b4, zero + 0, buffer.readi16(b4, zero + 0))
buffer.writeu16(b4, zero + 0, buffer.readu16(b4, zero + 0))
buffer.writei16(b4, zero + 2, buffer.readi16(b4, zero + 2))
buffer.writeu16(b4, zero + 2, buffer.readu16(b4, zero + 2))
buffer.writei32(b4, zero + 0, buffer.readi32(b4, zero + 0))
buffer.writeu32(b4, zero + 0, buffer.readu32(b4, zero + 0))
buffer.writef32(b4, zero + 0, buffer.readf32(b4, zero + 0))
-- 8 byte buffer
buffer.writei8(b8, zero + 0, buffer.readi8(b8, zero + 0))
buffer.writeu8(b8, zero + 0, buffer.readu8(b8, zero + 0))
buffer.writei8(b8, zero + 7, buffer.readi8(b8, zero + 7))
buffer.writeu8(b8, zero + 7, buffer.readu8(b8, zero + 7))
buffer.writei16(b8, zero + 0, buffer.readi16(b8, zero + 0))
buffer.writeu16(b8, zero + 0, buffer.readu16(b8, zero + 0))
buffer.writei16(b8, zero + 6, buffer.readi16(b8, zero + 6))
buffer.writeu16(b8, zero + 6, buffer.readu16(b8, zero + 6))
buffer.writei32(b8, zero + 0, buffer.readi32(b8, zero + 0))
buffer.writeu32(b8, zero + 0, buffer.readu32(b8, zero + 0))
buffer.writef32(b8, zero + 0, buffer.readf32(b8, zero + 0))
buffer.writei32(b8, zero + 4, buffer.readi32(b8, zero + 4))
buffer.writeu32(b8, zero + 4, buffer.readu32(b8, zero + 4))
buffer.writef32(b8, zero + 4, buffer.readf32(b8, zero + 4))
buffer.writef64(b8, zero + 0, buffer.readf64(b8, zero + 0))
-- 'any' size buffer
buffer.writei8(b10, zero + 0, buffer.readi8(b10, zero + 0))
buffer.writeu8(b10, zero + 0, buffer.readu8(b10, zero + 0))
buffer.writei8(b10, zero + 9, buffer.readi8(b10, zero + 9))
buffer.writeu8(b10, zero + 9, buffer.readu8(b10, zero + 9))
buffer.writei16(b10, zero + 0, buffer.readi16(b10, zero + 0))
buffer.writeu16(b10, zero + 0, buffer.readu16(b10, zero + 0))
buffer.writei16(b10, zero + 8, buffer.readi16(b10, zero + 8))
buffer.writeu16(b10, zero + 8, buffer.readu16(b10, zero + 8))
buffer.writei32(b10, zero + 0, buffer.readi32(b10, zero + 0))
buffer.writeu32(b10, zero + 0, buffer.readu32(b10, zero + 0))
buffer.writef32(b10, zero + 0, buffer.readf32(b10, zero + 0))
buffer.writei32(b10, zero + 6, buffer.readi32(b10, zero + 6))
buffer.writeu32(b10, zero + 6, buffer.readu32(b10, zero + 6))
buffer.writef32(b10, zero + 6, buffer.readf32(b10, zero + 6))
buffer.writef64(b10, zero + 0, buffer.readf64(b10, zero + 0))
buffer.writef64(b10, zero + 2, buffer.readf64(b10, zero + 2))
assert(is_native())
end
bufferbounds(0)
return('OK')