1
0
mirror of https://github.com/golang/go synced 2024-10-05 16:41:21 -06:00

[dev.ssa] cmd/compile/internal/ssa: fix defer in functions with no return

The after-defer test jumps to a deferreturn site.  Some functions
(those with infinite loops) have no deferreturn site.  Add one
so we have one to jump to.

Change-Id: I505e7f3f888f5e7d03ca49a3477b41cf1f78eb8a
Reviewed-on: https://go-review.googlesource.com/14349
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
This commit is contained in:
Keith Randall 2015-09-08 08:59:57 -07:00
parent 8d081679d5
commit ca9e450bed
3 changed files with 54 additions and 15 deletions

View File

@ -2621,6 +2621,12 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
for _, br := range s.branches {
br.p.To.Val = s.bstart[br.b.ID]
}
if s.deferBranches != nil && s.deferTarget == nil {
// This can happen when the function has a defer but
// no return (because it has an infinite loop).
s.deferReturn()
Prog(obj.ARET)
}
for _, p := range s.deferBranches {
p.To.Val = s.deferTarget
}
@ -3463,20 +3469,7 @@ func (s *genState) genBlock(b, next *ssa.Block) {
case ssa.BlockExit:
case ssa.BlockRet:
if Hasdefer != 0 {
// Deferred calls will appear to be returning to
// the CALL deferreturn(SB) that we are about to emit.
// However, the stack trace code will show the line
// of the instruction byte before the return PC.
// To avoid that being an unrelated instruction,
// insert an actual hardware NOP that will have the right line number.
// This is different from obj.ANOP, which is a virtual no-op
// that doesn't make it into the instruction stream.
s.deferTarget = Pc
Thearch.Ginsnop()
p := Prog(obj.ACALL)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = Linksym(Deferreturn.Sym)
s.deferReturn()
}
Prog(obj.ARET)
case ssa.BlockCall:
@ -3537,6 +3530,23 @@ func (s *genState) genBlock(b, next *ssa.Block) {
}
}
func (s *genState) deferReturn() {
// Deferred calls will appear to be returning to
// the CALL deferreturn(SB) that we are about to emit.
// However, the stack trace code will show the line
// of the instruction byte before the return PC.
// To avoid that being an unrelated instruction,
// insert an actual hardware NOP that will have the right line number.
// This is different from obj.ANOP, which is a virtual no-op
// that doesn't make it into the instruction stream.
s.deferTarget = Pc
Thearch.Ginsnop()
p := Prog(obj.ACALL)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = Linksym(Deferreturn.Sym)
}
// addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
func addAux(a *obj.Addr, v *ssa.Value) {
if a.Type != obj.TYPE_MEM {

View File

@ -17,12 +17,18 @@ import (
// TODO: move all these tests elsewhere?
// Perhaps teach test/run.go how to run them with a new action verb.
func runTest(t *testing.T, filename string) {
doTest(t, filename, "run")
}
func buildTest(t *testing.T, filename string) {
doTest(t, filename, "build")
}
func doTest(t *testing.T, filename string, kind string) {
if runtime.GOARCH != "amd64" {
t.Skipf("skipping SSA tests on %s for now", runtime.GOARCH)
}
testenv.MustHaveGoBuild(t)
var stdout, stderr bytes.Buffer
cmd := exec.Command("go", "run", filepath.Join("testdata", filename))
cmd := exec.Command("go", kind, filepath.Join("testdata", filename))
cmd.Stdout = &stdout
cmd.Stderr = &stderr
// TODO: set GOGC=off until we have stackmaps
@ -70,3 +76,5 @@ func TestMap(t *testing.T) { runTest(t, "map_ssa.go") }
func TestRegalloc(t *testing.T) { runTest(t, "regalloc_ssa.go") }
func TestString(t *testing.T) { runTest(t, "string_ssa.go") }
func TestDeferNoReturn(t *testing.T) { buildTest(t, "deferNoReturn_ssa.go") }

View File

@ -0,0 +1,21 @@
// compile
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test that a defer in a function with no return
// statement will compile correctly.
package main
func deferNoReturn_ssa() {
defer func() { println("returned") }()
for {
println("loop")
}
}
func main() {
deferNoReturn_ssa()
}