forked from LuaJIT/LuaJIT
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LJ_GC64: Always snapshot functions for non-base frames.
Reported by Arseny Vakhrushev. Analysis and fix contributed by Peter Cawley. (cherry picked from commit ff1e72a) The problem is GC64-specific and could be reproduced with enabled compiler options LUA_USE_ASSERT and LUA_USE_APICHECK. Sergey Kaplun: * minimized reproducer made by fuzzing test Sergey Bronnikov: * added the description (see a comment in the test) * added tests for the problem: first one based on the original reproducer and second one based on a reproducer made by fuzzing test. Part of tarantool/tarantool#8825
- Loading branch information
Showing
4 changed files
with
87 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
test/tarantool-tests/lj-611-always-snapshot-functions-for-non-base-frames-1.test.lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
local tap = require('tap') | ||
local test = tap.test('lj-611-always-snapshot-functions-for-non-base-frames-1'):skipcond({ | ||
['Test requires JIT enabled'] = not jit.status(), | ||
}) | ||
|
||
-- GC64: Function missing in snapshot for non-base frame | ||
-- https://github.com/LuaJIT/LuaJIT/issues/611 | ||
|
||
test:plan(1) | ||
|
||
jit.opt.start('hotloop=1', 'hotexit=1') | ||
|
||
local inner_counter = 0 | ||
local SIDE_START = 1 | ||
-- Lower frame to return from `inner()` function side trace. | ||
-- TODO: Give a reason for vararg func. | ||
local function lower_frame(...) | ||
local inner = function() | ||
if inner_counter > SIDE_START then | ||
return | ||
end | ||
inner_counter = inner_counter + 1 | ||
end | ||
inner(..., inner(inner())) | ||
end | ||
|
||
-- Compile `inner()` function. | ||
lower_frame() | ||
lower_frame() | ||
-- Compile hotexit | ||
lower_frame() | ||
-- Take side exit from side trace. | ||
lower_frame(1) | ||
|
||
test:ok(true, 'function is present in snapshot') | ||
test:done(true) |
43 changes: 43 additions & 0 deletions
43
test/tarantool-tests/lj-611-always-snapshot-functions-for-non-base-frames.test.lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
local tap = require('tap') | ||
local test = tap.test('lj-611-always-snapshot-functions-for-non-base-frames') | ||
|
||
test:plan(1) | ||
|
||
jit.opt.start('hotloop=1', 'hotexit=1') | ||
|
||
-- Test reproduces a bug "GC64: Function missing in snapshot for non-base | ||
-- frame" [1], and based on reproducer described in [2]. | ||
-- | ||
-- [1]: https://github.com/LuaJIT/LuaJIT/issues/611 | ||
-- [2]: https://github.com/LuaJIT/LuaJIT/issues/611#issuecomment-679228156 | ||
-- | ||
-- Function `outer` is recorded to a trace and calls a builtin function that is | ||
-- not JIT-compilable and therefore triggers exit to interpreter, and then it | ||
-- resumes tracing just after the call returns - this is a trace stitching. | ||
-- Then, within the call, we need the potential for a side trace. Finally, we need | ||
-- that side exit to be taken enough for the exit to be compiled into a trace. | ||
-- The loop at the bottom has enough iterations to trigger JIT compilation, and | ||
-- enough more on top on trigger compilation of the not case. Compilation of | ||
-- this case hits the assertion failure. | ||
|
||
local inner | ||
for _ = 1, 3 do | ||
inner = function(_, i) | ||
return i < 4 | ||
end | ||
end | ||
|
||
local function outer(i) | ||
-- The function `string.gsub` is not JIT-compilable and triggers a trace | ||
-- exit. For example, `string.gmatch` and `string.match` are suitable as | ||
-- well. | ||
-- See https://github.com/tarantool/tarantool/wiki/LuaJIT-Not-Yet-Implemented. | ||
inner(string.gsub('', '', ''), i) | ||
end | ||
|
||
for i = 1, 4 do | ||
outer(i) | ||
end | ||
|
||
test:ok(true, 'function is present in snapshot') | ||
test:done(true) |