Commit 23bf6af9 authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/compile: refactor escape analysis parameter tagging

No behavior change; just inverting the loop ordering so the
per-parameter behavior is a bit clearer.

Passes toolstash-check.

Updates #33981.

Change-Id: I9bfcd7d0a4aff65a27ced157767ca2ba8038319a
Reviewed-on: https://go-review.googlesource.com/c/go/+/193177
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarCherry Zhang <cherryyz@google.com>
parent cf630586
...@@ -212,6 +212,8 @@ var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string ...@@ -212,6 +212,8 @@ var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string
// mktag returns the string representation for an escape analysis tag. // mktag returns the string representation for an escape analysis tag.
func mktag(mask int) string { func mktag(mask int) string {
switch mask & EscMask { switch mask & EscMask {
case EscHeap:
return ""
case EscNone, EscReturn: case EscNone, EscReturn:
default: default:
Fatalf("escape mktag") Fatalf("escape mktag")
...@@ -406,88 +408,74 @@ const uintptrEscapesTag = "uintptr-escapes" ...@@ -406,88 +408,74 @@ const uintptrEscapesTag = "uintptr-escapes"
func esctag(fn *Node) { func esctag(fn *Node) {
fn.Esc = EscFuncTagged fn.Esc = EscFuncTagged
name := func(s *types.Sym, narg int) string { narg := 0
if s != nil { for _, fs := range types.RecvsParams {
return s.Name for _, f := range fs(fn.Type).Fields().Slice() {
narg++
f.Note = escparamtag(fn, narg, f)
} }
return fmt.Sprintf("arg#%d", narg)
} }
}
// External functions are assumed unsafe, func escparamtag(fn *Node, narg int, f *types.Field) string {
// unless //go:noescape is given before the declaration. name := func() string {
if fn.Nbody.Len() == 0 { if f.Sym != nil {
if fn.Noescape() { return f.Sym.Name
for _, f := range fn.Type.Params().Fields().Slice() {
if types.Haspointers(f.Type) {
f.Note = mktag(EscNone)
}
}
} }
return fmt.Sprintf("arg#%d", narg)
}
if fn.Nbody.Len() == 0 {
// Assume that uintptr arguments must be held live across the call. // Assume that uintptr arguments must be held live across the call.
// This is most important for syscall.Syscall. // This is most important for syscall.Syscall.
// See golang.org/issue/13372. // See golang.org/issue/13372.
// This really doesn't have much to do with escape analysis per se, // This really doesn't have much to do with escape analysis per se,
// but we are reusing the ability to annotate an individual function // but we are reusing the ability to annotate an individual function
// argument and pass those annotations along to importing code. // argument and pass those annotations along to importing code.
narg := 0 if f.Type.Etype == TUINTPTR {
for _, f := range fn.Type.Params().Fields().Slice() { if Debug['m'] != 0 {
narg++ Warnl(fn.Pos, "%v assuming %v is unsafe uintptr", funcSym(fn), name())
if f.Type.Etype == TUINTPTR {
if Debug['m'] != 0 {
Warnl(fn.Pos, "%v assuming %v is unsafe uintptr", funcSym(fn), name(f.Sym, narg))
}
f.Note = unsafeUintptrTag
} }
return unsafeUintptrTag
} }
return if !types.Haspointers(f.Type) { // don't bother tagging for scalars
return ""
}
// External functions are assumed unsafe, unless
// //go:noescape is given before the declaration.
if fn.Noescape() {
return mktag(EscNone)
}
return mktag(EscHeap)
} }
if fn.Func.Pragma&UintptrEscapes != 0 { if fn.Func.Pragma&UintptrEscapes != 0 {
narg := 0 if f.Type.Etype == TUINTPTR {
for _, f := range fn.Type.Params().Fields().Slice() { if Debug['m'] != 0 {
narg++ Warnl(fn.Pos, "%v marking %v as escaping uintptr", funcSym(fn), name())
if f.Type.Etype == TUINTPTR {
if Debug['m'] != 0 {
Warnl(fn.Pos, "%v marking %v as escaping uintptr", funcSym(fn), name(f.Sym, narg))
}
f.Note = uintptrEscapesTag
} }
return uintptrEscapesTag
if f.IsDDD() && f.Type.Elem().Etype == TUINTPTR { }
// final argument is ...uintptr. if f.IsDDD() && f.Type.Elem().Etype == TUINTPTR {
if Debug['m'] != 0 { // final argument is ...uintptr.
Warnl(fn.Pos, "%v marking %v as escaping ...uintptr", funcSym(fn), name(f.Sym, narg)) if Debug['m'] != 0 {
} Warnl(fn.Pos, "%v marking %v as escaping ...uintptr", funcSym(fn), name())
f.Note = uintptrEscapesTag
} }
return uintptrEscapesTag
} }
} }
for _, fs := range types.RecvsParams { if !types.Haspointers(f.Type) { // don't bother tagging for scalars
for _, f := range fs(fn.Type).Fields().Slice() { return ""
if !types.Haspointers(f.Type) { // don't bother tagging for scalars }
continue
}
if f.Note == uintptrEscapesTag {
// Note is already set in the loop above.
continue
}
// Unnamed parameters are unused and therefore do not escape.
if f.Sym == nil || f.Sym.IsBlank() {
f.Note = mktag(EscNone)
continue
}
switch esc := asNode(f.Nname).Esc; esc & EscMask {
case EscNone, // not touched by escflood
EscReturn:
f.Note = mktag(int(esc))
case EscHeap: // touched by escflood, moved to heap // Unnamed parameters are unused and therefore do not escape.
} if f.Sym == nil || f.Sym.IsBlank() {
} return mktag(EscNone)
} }
n := asNode(f.Nname)
return mktag(int(n.Esc))
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment