Skip to content

Commit

Permalink
Fix bug with UCLO instruction not correctly emitted in while loop
Browse files Browse the repository at this point in the history
Reported on github from tests:

https://github.com/openresty/luajit2-test-suite/blob/master/test/misc/uclo.lua

The uclo-3 test is still failing and needs another fix.
  • Loading branch information
franko committed May 19, 2020
1 parent 9c03ed6 commit be3f8af
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 10 deletions.
9 changes: 9 additions & 0 deletions lang/bytecode.lua
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,8 @@ local function locate_jump(self, name)
return NO_JMP
end
end
-- Emit a jump instruction, JMP or UCLO, to the given "name" location
-- using 'basereg' register.
function Proto.__index:scope_jump(name, basereg, need_uclo)
local jump = locate_jump(self, name)
return self:emit(need_uclo and BC.UCLO or BC.JMP, basereg, jump)
Expand Down Expand Up @@ -997,11 +999,18 @@ function Proto.__index:goto_label(label_name)
return true, label
end
end
-- Add information in the current scope about the loop, its exit location,
-- save register. 'cont' should be the register for continue instruction
-- but is no longer used.
function Proto.__index:loop_register(exit, exit_reg, cont)
self.scope.loop_exit = exit
self.scope.loop_basereg = exit_reg
self.scope.loop_cont = cont
end

-- Looks in current and outer scopes for the closer loop and returns:
-- loop's base register, loop's continue register and if uclo is needed.
-- The loop_cont value is not really used.
function Proto.__index:current_loop(cont)
local scope = self.scope
local need_uclo = false
Expand Down
22 changes: 12 additions & 10 deletions lang/generator.lua
Original file line number Diff line number Diff line change
Expand Up @@ -741,17 +741,19 @@ function StatementRule:AssignmentExpression(node)
self.ctx.freereg = free
end
function StatementRule:WhileStatement(node)
local free = self.ctx.freereg
local loop, exit = genid(), genid()
self:loop_enter(exit, free)
self.ctx:here(loop)
self:test_emit(node.test, exit, free)
self.ctx:loop(exit)
local register_save = self.ctx.freereg
local loop_begin_location, loop_exit_location = genid(), genid()
self:loop_enter(loop_exit_location, register_save)
self.ctx:here(loop_begin_location)
self:test_emit(node.test, loop_exit_location, register_save)
self.ctx:loop(loop_exit_location)
self:block_emit(node.body)
self.ctx:jump(loop, free)
self.ctx:here(exit)
self:loop_leave(node.lastline)
self.ctx.freereg = free
self.ctx:scope_jump(loop_begin_location, register_save, self.ctx.scope.need_uclo)
self.ctx:here(loop_exit_location)
self.ctx:fscope_end()
self.ctx:leave()
if node.lastline then self.ctx:line(node.lastline) end
self.ctx.freereg = register_save
end
function StatementRule:RepeatStatement(node)
local free = self.ctx.freereg
Expand Down
8 changes: 8 additions & 0 deletions tests/uclo-1.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
local z1
local i = 1
while i <= 2 do
local j = i
z1 = z1 or function() return j end
i = i + 1
end
print(z1())
7 changes: 7 additions & 0 deletions tests/uclo-2.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
local z1, z2
for i=1,10 do
local function f() return i end
if z1 then z2 = f else z1 = f end
end
print(z1())
print(z2())
10 changes: 10 additions & 0 deletions tests/uclo-3.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
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
print(z1())
print(z2())
9 changes: 9 additions & 0 deletions tests/uclo-4.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
local x = 1
local function f()
local y = 0
for i=1,100 do y=y+x end
return y
end
print(f())
x = 2
print(f())

0 comments on commit be3f8af

Please sign in to comment.