Skip to content

Commit

Permalink
cmd/compile: better integrate parameter tagging with escape.go
Browse files Browse the repository at this point in the history
This CL moves parameter tagging to before escape analysis is complete,
so we still have access to EscLocation. This will be useful once
EscLocation starts tracking higher-fidelity escape details.

Notably, this CL stops using n.Esc to record parameter escape analysis
details. Now escape analysis only ever sets n.Esc to EscNone or
EscHeap. (It still defaults to EscUnknown, and is set to EscNever in
some places though.)

Passes toolstash-check.

Updates #33981.

Change-Id: I50a91ea1e38c442092de6cd14e20b211f8f818c9
Reviewed-on: https://go-review.googlesource.com/c/go/+/193178
Run-TryBot: Matthew Dempsky <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Cherry Zhang <[email protected]>
  • Loading branch information
mdempsky committed Sep 10, 2019
1 parent 68a6536 commit b970487
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 46 deletions.
44 changes: 30 additions & 14 deletions src/cmd/compile/internal/gc/esc.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,19 +405,7 @@ const unsafeUintptrTag = "unsafe-uintptr"
// marked go:uintptrescapes.
const uintptrEscapesTag = "uintptr-escapes"

func esctag(fn *Node) {
fn.Esc = EscFuncTagged

narg := 0
for _, fs := range types.RecvsParams {
for _, f := range fs(fn.Type).Fields().Slice() {
narg++
f.Note = escparamtag(fn, narg, f)
}
}
}

func escparamtag(fn *Node, narg int, f *types.Field) string {
func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
name := func() string {
if f.Sym != nil {
return f.Sym.Name
Expand Down Expand Up @@ -446,8 +434,15 @@ func escparamtag(fn *Node, narg int, f *types.Field) string {
// External functions are assumed unsafe, unless
// //go:noescape is given before the declaration.
if fn.Noescape() {
if Debug['m'] != 0 && f.Sym != nil {
Warnl(fn.Pos, "%S %v does not escape", funcSym(fn), name())
}
return mktag(EscNone)
}

if Debug['m'] != 0 && f.Sym != nil {
Warnl(fn.Pos, "leaking param: %v", name())
}
return mktag(EscHeap)
}

Expand Down Expand Up @@ -477,5 +472,26 @@ func escparamtag(fn *Node, narg int, f *types.Field) string {
}

n := asNode(f.Nname)
return mktag(int(n.Esc))
loc := e.oldLoc(n)
esc := finalizeEsc(loc.paramEsc)

if Debug['m'] != 0 && !loc.escapes {
if esc == EscNone {
Warnl(n.Pos, "%S %S does not escape", funcSym(fn), n)
} else if esc == EscHeap {
Warnl(n.Pos, "leaking param: %S", n)
} else {
if esc&EscContentEscapes != 0 {
Warnl(n.Pos, "leaking param content: %S", n)
}
for i := 0; i < numEscReturns; i++ {
if x := getEscReturn(esc, i); x >= 0 {
res := n.Name.Curfn.Type.Results().Field(i).Sym
Warnl(n.Pos, "leaking param: %S to result %v level=%d", n, res, x)
}
}
}
}

return mktag(int(esc))
}
49 changes: 18 additions & 31 deletions src/cmd/compile/internal/gc/escape.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,7 @@ func escapeFuncs(fns []*Node, recursive bool) {
e.curfn = nil

e.walkAll()
e.finish()

// Record parameter tags for package export data.
for _, fn := range fns {
esctag(fn)
}
e.finish(fns)
}

func (e *Escape) initFunc(fn *Node) {
Expand Down Expand Up @@ -1258,7 +1253,20 @@ func (l *EscLocation) leakTo(sink *EscLocation, derefs int) {
}
}

func (e *Escape) finish() {
func (e *Escape) finish(fns []*Node) {
// Record parameter tags for package export data.
for _, fn := range fns {
fn.Esc = EscFuncTagged

narg := 0
for _, fs := range types.RecvsParams {
for _, f := range fs(fn.Type).Fields().Slice() {
narg++
f.Note = e.paramTag(fn, narg, f)
}
}
}

for _, loc := range e.allLocs {
n := loc.n
if n == nil {
Expand All @@ -1279,38 +1287,17 @@ func (e *Escape) finish() {
}
n.Esc = EscHeap
addrescapes(n)
} else if loc.isName(PPARAM) {
n.Esc = finalizeEsc(loc.paramEsc)

if Debug['m'] != 0 && types.Haspointers(n.Type) {
if n.Esc == EscNone {
Warnl(n.Pos, "%S %S does not escape", funcSym(loc.curfn), n)
} else if n.Esc == EscHeap {
Warnl(n.Pos, "leaking param: %S", n)
} else {
if n.Esc&EscContentEscapes != 0 {
Warnl(n.Pos, "leaking param content: %S", n)
}
for i := 0; i < numEscReturns; i++ {
if x := getEscReturn(n.Esc, i); x >= 0 {
res := n.Name.Curfn.Type.Results().Field(i).Sym
Warnl(n.Pos, "leaking param: %S to result %v level=%d", n, res, x)
}
}
}
}
} else {
if Debug['m'] != 0 && n.Op != ONAME && n.Op != OTYPESW && n.Op != ORANGE && n.Op != ODEFER {
Warnl(n.Pos, "%S %S does not escape", funcSym(loc.curfn), n)
}
n.Esc = EscNone
if loc.transient {
switch n.Op {
case OCALLPART, OCLOSURE, ODDDARG, OARRAYLIT, OSLICELIT, OPTRLIT, OSTRUCTLIT:
n.SetNoescape(true)
}
}

if Debug['m'] != 0 && n.Op != ONAME && n.Op != OTYPESW && n.Op != ORANGE && n.Op != ODEFER {
Warnl(n.Pos, "%S %S does not escape", funcSym(loc.curfn), n)
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/uintptrescapes2.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func F1(a uintptr) {} // ERROR "escaping uintptr"

//go:uintptrescapes
//go:noinline
func F2(a ...uintptr) {} // ERROR "escaping ...uintptr" "a does not escape"
func F2(a ...uintptr) {} // ERROR "escaping ...uintptr"

//go:uintptrescapes
//go:noinline
Expand Down

0 comments on commit b970487

Please sign in to comment.