Skip to content

Commit 7c8a961

Browse files
committed
cmd/compile: fix stack frame info for calls in receiver slot
Previously, after inlining a call, we made a second pass to rewrite the AST's position information to record the inlined stack frame. The call arguments were part of this AST, but it would be incorrect to rewrite them too, so extra effort was made to temporarily remove them while the position rewriting was done. However, this extra logic was only done for regular arguments: it was not done for receiver arguments. Consequently if m was inlined in "f().m(g(), h())", g and h would have correct call frames, but f would appear to be called by m. The fix taken by this CL is to merge setpos into inlsubst and only rewrite position information for nodes that were actually copied from the original function AST body. As a side benefit, this eliminates an extra AST pass and some AST walking code. Fixes #21879. Change-Id: I22b25c208313fc25c358d3a2eebfc9b012400084 Reviewed-on: https://go-review.googlesource.com/64470 Run-TryBot: Matthew Dempsky <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent f2a5ed8 commit 7c8a961

File tree

3 files changed

+65
-68
lines changed

3 files changed

+65
-68
lines changed

src/cmd/compile/internal/gc/inl.go

Lines changed: 26 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -740,10 +740,18 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
740740

741741
inlgen++
742742

743+
parent := -1
744+
if b := Ctxt.PosTable.Pos(n.Pos).Base(); b != nil {
745+
parent = b.InliningIndex()
746+
}
747+
newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym())
748+
743749
subst := inlsubst{
744-
retlabel: retlabel,
745-
retvars: retvars,
746-
inlvars: inlvars,
750+
retlabel: retlabel,
751+
retvars: retvars,
752+
inlvars: inlvars,
753+
bases: make(map[*src.PosBase]*src.PosBase),
754+
newInlIndex: newIndex,
747755
}
748756

749757
body := subst.list(fn.Func.Inl)
@@ -762,28 +770,6 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
762770
call.Type = n.Type
763771
call.SetTypecheck(1)
764772

765-
// Hide the args from setPos -- the parameters to the inlined
766-
// call already have good line numbers that should be preserved.
767-
args := as.Rlist
768-
as.Rlist.Set(nil)
769-
770-
// Rewrite the line information for the inlined AST.
771-
parent := -1
772-
callBase := Ctxt.PosTable.Pos(n.Pos).Base()
773-
if callBase != nil {
774-
parent = callBase.InliningIndex()
775-
}
776-
newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym())
777-
setpos := &setPos{
778-
bases: make(map[*src.PosBase]*src.PosBase),
779-
newInlIndex: newIndex,
780-
}
781-
setpos.node(call)
782-
783-
as.Rlist.Set(args.Slice())
784-
785-
//dumplist("call body", body);
786-
787773
n = call
788774

789775
// transitive inlining
@@ -861,6 +847,14 @@ type inlsubst struct {
861847
retvars []*Node
862848

863849
inlvars map[*Node]*Node
850+
851+
// bases maps from original PosBase to PosBase with an extra
852+
// inlined call frame.
853+
bases map[*src.PosBase]*src.PosBase
854+
855+
// newInlIndex is the index of the inlined call frame to
856+
// insert for inlined nodes.
857+
newInlIndex int
864858
}
865859

866860
// list inlines a list of nodes.
@@ -908,7 +902,6 @@ func (subst *inlsubst) node(n *Node) *Node {
908902
// dump("Return before substitution", n);
909903
case ORETURN:
910904
m := nod(OGOTO, subst.retlabel, nil)
911-
912905
m.Ninit.Set(subst.list(n.Ninit))
913906

914907
if len(subst.retvars) != 0 && n.List.Len() != 0 {
@@ -934,6 +927,7 @@ func (subst *inlsubst) node(n *Node) *Node {
934927
case OGOTO, OLABEL:
935928
m := nod(OXXX, nil, nil)
936929
*m = *n
930+
m.Pos = subst.updatedPos(m.Pos)
937931
m.Ninit.Set(nil)
938932
p := fmt.Sprintf("%s·%d", n.Left.Sym.Name, inlgen)
939933
m.Left = newname(lookup(p))
@@ -943,6 +937,7 @@ func (subst *inlsubst) node(n *Node) *Node {
943937

944938
m := nod(OXXX, nil, nil)
945939
*m = *n
940+
m.Pos = subst.updatedPos(m.Pos)
946941
m.Ninit.Set(nil)
947942

948943
if n.Op == OCLOSURE {
@@ -959,50 +954,13 @@ func (subst *inlsubst) node(n *Node) *Node {
959954
return m
960955
}
961956

962-
// setPos is a visitor to update position info with a new inlining index.
963-
type setPos struct {
964-
bases map[*src.PosBase]*src.PosBase
965-
newInlIndex int
966-
}
967-
968-
func (s *setPos) nodelist(ll Nodes) {
969-
for _, n := range ll.Slice() {
970-
s.node(n)
971-
}
972-
}
973-
974-
func (s *setPos) node(n *Node) {
975-
if n == nil {
976-
return
977-
}
978-
if n.Op == OLITERAL || n.Op == OTYPE {
979-
if n.Sym != nil {
980-
// This node is not a copy, so don't clobber position.
981-
return
982-
}
983-
}
984-
985-
// don't clobber names, unless they're freshly synthesized
986-
if n.Op != ONAME || !n.Pos.IsKnown() {
987-
n.Pos = s.updatedPos(n)
988-
}
989-
990-
s.node(n.Left)
991-
s.node(n.Right)
992-
s.nodelist(n.List)
993-
s.nodelist(n.Rlist)
994-
s.nodelist(n.Ninit)
995-
s.nodelist(n.Nbody)
996-
}
997-
998-
func (s *setPos) updatedPos(n *Node) src.XPos {
999-
pos := Ctxt.PosTable.Pos(n.Pos)
957+
func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
958+
pos := Ctxt.PosTable.Pos(xpos)
1000959
oldbase := pos.Base() // can be nil
1001-
newbase := s.bases[oldbase]
960+
newbase := subst.bases[oldbase]
1002961
if newbase == nil {
1003-
newbase = src.NewInliningBase(oldbase, s.newInlIndex)
1004-
pos.SetBase(newbase)
1005-
s.bases[oldbase] = newbase
962+
newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
963+
subst.bases[oldbase] = newbase
1006964
}
1007965
pos.SetBase(newbase)
1008966
return Ctxt.PosTable.XPos(pos)

test/fixedbugs/issue21879.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// run
2+
3+
// Copyright 2017 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
import (
10+
"runtime"
11+
)
12+
13+
func main() {
14+
println(caller().frame.Function)
15+
16+
// Used to erroneously print "main.call.name" instead of
17+
// "main.main".
18+
println(caller().name())
19+
}
20+
21+
func caller() call {
22+
var pcs [3]uintptr
23+
n := runtime.Callers(1, pcs[:])
24+
frames := runtime.CallersFrames(pcs[:n])
25+
frame, _ := frames.Next()
26+
frame, _ = frames.Next()
27+
28+
return call{frame: frame}
29+
}
30+
31+
type call struct {
32+
frame runtime.Frame
33+
}
34+
35+
func (c call) name() string {
36+
return c.frame.Function
37+
}

test/fixedbugs/issue21879.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
main.main
2+
main.main

0 commit comments

Comments
 (0)