|
| 1 | +local tap = require('tap') |
| 2 | + |
| 3 | +-- The test file to demonstrate JIT slots overflow when compiling |
| 4 | +-- the return from the trace with up-recursion. |
| 5 | +-- See also: https://github.com/LuaJIT/LuaJIT/issues/1358. |
| 6 | + |
| 7 | +local test = tap.test('lj-1358-jslot-overflow-uprecursion'):skipcond({ |
| 8 | + ['Test requires JIT enabled'] = not jit.status(), |
| 9 | +}) |
| 10 | + |
| 11 | +test:plan(1) |
| 12 | + |
| 13 | +-- The test generates the functions with the following workload: |
| 14 | +-- |
| 15 | +-- | local uprec_func() |
| 16 | +-- | if cond then return end |
| 17 | +-- | return 'x', --[[...]] 'x', uprec_func() |
| 18 | +-- | end |
| 19 | +-- | |
| 20 | +-- | local function empty() end |
| 21 | +-- | empty('x', --[[...]] 'x', uprec_func()) |
| 22 | +-- |
| 23 | +-- The recording of the return from `uprec_func()` before the call |
| 24 | +-- to `empty()` causes the assertion failure in the |
| 25 | +-- `rec_check_slots()`. |
| 26 | + |
| 27 | +-- Generate a function with many return values plus up-recursion. |
| 28 | +local function generate_uprec_payload(n_returns) |
| 29 | + local str_func = [[ |
| 30 | + local counter = 0 |
| 31 | + local function payload_f() |
| 32 | + counter = counter + 1 |
| 33 | + if counter > 5 then return end |
| 34 | + return |
| 35 | + ]] |
| 36 | + for _ = 1, n_returns do |
| 37 | + str_func = str_func .. '"x", ' |
| 38 | + end |
| 39 | + str_func = str_func .. [[ |
| 40 | + payload_f() |
| 41 | + end |
| 42 | + return payload_f |
| 43 | + ]] |
| 44 | + local f = assert(loadstring(str_func)) |
| 45 | + return f() |
| 46 | +end |
| 47 | + |
| 48 | +-- Generate the necessary number of locals for a huge enough |
| 49 | +-- `cbase`. |
| 50 | +local function generate_nloc_payload(n_locals) |
| 51 | + local str_func = [[ |
| 52 | + -- Function to be called after return with all stack slots used. |
| 53 | + local function empty() end |
| 54 | + empty( |
| 55 | + ]] |
| 56 | + for _ = 1, n_locals do |
| 57 | + str_func = str_func .. '"x", ' |
| 58 | + end |
| 59 | + str_func = str_func .. [[ |
| 60 | + _G.uprec_func() |
| 61 | + ) |
| 62 | + ]] |
| 63 | + local f = assert(loadstring(str_func)) |
| 64 | + return f |
| 65 | +end |
| 66 | + |
| 67 | +-- Avoid an unrelated JIT output. |
| 68 | +jit.off() |
| 69 | +-- 30 * 5 = 150 returned values for the first call. |
| 70 | +_G.uprec_func = generate_uprec_payload(30) |
| 71 | +-- Plus 100 slots for locals, plus a slot for the function to be |
| 72 | +-- called causes JIT stack slots overflow. |
| 73 | +local test_func = generate_nloc_payload(100) |
| 74 | + |
| 75 | +jit.on() |
| 76 | +jit.opt.start('hotloop=1', 'hotexit=1', 'recunroll=1') |
| 77 | + |
| 78 | +test_func() |
| 79 | + |
| 80 | +test:ok(true, 'no assertion on JIT slots overflow') |
| 81 | + |
| 82 | +test:done(true) |
0 commit comments