Merge pull request #2345 from nspcc-dev/compiler-defer-duplication
compiler: do not traverse `defer` function literals twice
This commit is contained in:
commit
693eb595d8
3 changed files with 31 additions and 3 deletions
|
@ -803,8 +803,20 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
case *ast.FuncLit:
|
case *ast.FuncLit:
|
||||||
l := c.newLabel()
|
var found bool
|
||||||
c.newLambda(l, n)
|
var l uint16
|
||||||
|
for _, fs := range c.lambda {
|
||||||
|
if fs.decl.Body == n.Body {
|
||||||
|
found = true
|
||||||
|
l = fs.label
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
l = c.newLabel()
|
||||||
|
c.newLambda(l, n)
|
||||||
|
}
|
||||||
|
|
||||||
buf := make([]byte, 4)
|
buf := make([]byte, 4)
|
||||||
binary.LittleEndian.PutUint16(buf, l)
|
binary.LittleEndian.PutUint16(buf, l)
|
||||||
emit.Instruction(c.prog.BinWriter, opcode.PUSHA, buf)
|
emit.Instruction(c.prog.BinWriter, opcode.PUSHA, buf)
|
||||||
|
|
|
@ -126,6 +126,22 @@ func TestDefer(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 0, vm.Estack().Len(), "stack contains unexpected items")
|
require.Equal(t, 0, vm.Estack().Len(), "stack contains unexpected items")
|
||||||
})
|
})
|
||||||
|
t.Run("CodeDuplication", func(t *testing.T) {
|
||||||
|
src := `package main
|
||||||
|
var i int
|
||||||
|
func Main() {
|
||||||
|
defer func() {
|
||||||
|
var j int
|
||||||
|
i += j
|
||||||
|
}()
|
||||||
|
if i == 1 { return }
|
||||||
|
if i == 2 { return }
|
||||||
|
if i == 3 { return }
|
||||||
|
if i == 4 { return }
|
||||||
|
if i == 5 { return }
|
||||||
|
}`
|
||||||
|
checkCallCount(t, src, 0 /* defer body + Main */, 2, -1)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRecover(t *testing.T) {
|
func TestRecover(t *testing.T) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ func checkCallCount(t *testing.T, src string, expectedCall, expectedInitSlot, ex
|
||||||
actualCall++
|
actualCall++
|
||||||
case opcode.INITSLOT:
|
case opcode.INITSLOT:
|
||||||
actualInitSlot++
|
actualInitSlot++
|
||||||
if ctx.IP() == mainStart {
|
if ctx.IP() == mainStart && expectedLocalsMain >= 0 {
|
||||||
require.Equal(t, expectedLocalsMain, int(param[0]))
|
require.Equal(t, expectedLocalsMain, int(param[0]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue