mirror of
https://github.com/golang/go
synced 2024-11-18 18:04:46 -07:00
cmd/compile: refactor Escape.tagHole
This CL refactors tagHole to handle all three call situations (unknown function; known function in same analysis batch; known function in previous analysis batch). This will make it somewhat easier to reuse in a followup CL. Passes toolstash-check. Change-Id: I764d047a333dfc593d721a881361683e94b485df Reviewed-on: https://go-review.googlesource.com/c/go/+/229059 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
300ff5d8ac
commit
1811533695
@ -718,8 +718,8 @@ func (e *Escape) assignHeap(src *Node, why string, where *Node) {
|
||||
// should contain the holes representing where the function callee's
|
||||
// results flows; where is the OGO/ODEFER context of the call, if any.
|
||||
func (e *Escape) call(ks []EscHole, call, where *Node) {
|
||||
// First, pick out the function callee, its type, and receiver
|
||||
// (if any) and normal arguments list.
|
||||
// First, pick out the function callee (if statically known),
|
||||
// its type, and receiver (if any) and normal arguments list.
|
||||
var fn, recv *Node
|
||||
var fntype *types.Type
|
||||
args := call.List.Slice()
|
||||
@ -730,6 +730,9 @@ func (e *Escape) call(ks []EscHole, call, where *Node) {
|
||||
fn = fn.Func.Closure.Func.Nname
|
||||
}
|
||||
fntype = fn.Type
|
||||
if !(fn.Op == ONAME && fn.Class() == PFUNC) {
|
||||
fn = nil // dynamic call
|
||||
}
|
||||
case OCALLMETH:
|
||||
fn = asNode(call.Left.Type.FuncType().Nname)
|
||||
fntype = fn.Type
|
||||
@ -747,41 +750,22 @@ func (e *Escape) call(ks []EscHole, call, where *Node) {
|
||||
Fatalf("unexpected call op: %v", call.Op)
|
||||
}
|
||||
|
||||
static := fn != nil && fn.Op == ONAME && fn.Class() == PFUNC
|
||||
|
||||
// Setup evaluation holes for each receiver/argument.
|
||||
var recvK EscHole
|
||||
var paramKs []EscHole
|
||||
|
||||
if static && fn.Name.Defn != nil && fn.Name.Defn.Esc < EscFuncTagged {
|
||||
// Static call to function in same mutually recursive
|
||||
// group; incorporate into data flow graph.
|
||||
|
||||
if fn.Name.Defn.Esc == EscFuncUnknown {
|
||||
Fatalf("graph inconsistency")
|
||||
}
|
||||
|
||||
if ks != nil {
|
||||
for i, result := range fntype.Results().FieldSlice() {
|
||||
if call.Op == OCALLFUNC || call.Op == OCALLMETH || call.Op == OCALLINTER {
|
||||
if ks != nil && fn != nil && e.inMutualBatch(fn) {
|
||||
for i, result := range fn.Type.Results().FieldSlice() {
|
||||
e.expr(ks[i], asNode(result.Nname))
|
||||
}
|
||||
}
|
||||
|
||||
if r := fntype.Recv(); r != nil {
|
||||
recvK = e.addr(asNode(r.Nname))
|
||||
recvK = e.tagHole(ks, fn, r)
|
||||
}
|
||||
for _, param := range fntype.Params().FieldSlice() {
|
||||
paramKs = append(paramKs, e.addr(asNode(param.Nname)))
|
||||
}
|
||||
} else if call.Op == OCALLFUNC || call.Op == OCALLMETH || call.Op == OCALLINTER {
|
||||
// Dynamic call, or call to previously tagged
|
||||
// function. Setup flows to heap and/or ks according
|
||||
// to parameter tags.
|
||||
if r := fntype.Recv(); r != nil {
|
||||
recvK = e.tagHole(ks, r, static)
|
||||
}
|
||||
for _, param := range fntype.Params().FieldSlice() {
|
||||
paramKs = append(paramKs, e.tagHole(ks, param, static))
|
||||
paramKs = append(paramKs, e.tagHole(ks, fn, param))
|
||||
}
|
||||
} else {
|
||||
// Handle escape analysis for builtins.
|
||||
@ -862,7 +846,7 @@ func (e *Escape) call(ks []EscHole, call, where *Node) {
|
||||
// For arguments to go:uintptrescapes, peel
|
||||
// away an unsafe.Pointer->uintptr conversion,
|
||||
// if present.
|
||||
if static && arg.Op == OCONVNOP && arg.Type.Etype == TUINTPTR && arg.Left.Type.Etype == TUNSAFEPTR {
|
||||
if fn != nil && arg.Op == OCONVNOP && arg.Type.Etype == TUINTPTR && arg.Left.Type.Etype == TUNSAFEPTR {
|
||||
x := i
|
||||
if fntype.IsVariadic() && x >= fntype.NumParams() {
|
||||
x = fntype.NumParams() - 1
|
||||
@ -901,14 +885,19 @@ func (e *Escape) augmentParamHole(k EscHole, call, where *Node) EscHole {
|
||||
|
||||
// tagHole returns a hole for evaluating an argument passed to param.
|
||||
// ks should contain the holes representing where the function
|
||||
// callee's results flows; static indicates whether this is a static
|
||||
// call.
|
||||
func (e *Escape) tagHole(ks []EscHole, param *types.Field, static bool) EscHole {
|
||||
// callee's results flows. fn is the statically-known callee function,
|
||||
// if any.
|
||||
func (e *Escape) tagHole(ks []EscHole, fn *Node, param *types.Field) EscHole {
|
||||
// If this is a dynamic call, we can't rely on param.Note.
|
||||
if !static {
|
||||
if fn == nil {
|
||||
return e.heapHole()
|
||||
}
|
||||
|
||||
if e.inMutualBatch(fn) {
|
||||
return e.addr(asNode(param.Nname))
|
||||
}
|
||||
|
||||
// Call to previously tagged function.
|
||||
var tagKs []EscHole
|
||||
|
||||
esc := ParseLeaks(param.Note)
|
||||
@ -927,6 +916,21 @@ func (e *Escape) tagHole(ks []EscHole, param *types.Field, static bool) EscHole
|
||||
return e.teeHole(tagKs...)
|
||||
}
|
||||
|
||||
// inMutualBatch reports whether function fn is in the batch of
|
||||
// mutually recursive functions being analyzed. When this is true,
|
||||
// fn has not yet been analyzed, so its parameters and results
|
||||
// should be incorporated directly into the flow graph instead of
|
||||
// relying on its escape analysis tagging.
|
||||
func (e *Escape) inMutualBatch(fn *Node) bool {
|
||||
if fn.Name.Defn != nil && fn.Name.Defn.Esc < EscFuncTagged {
|
||||
if fn.Name.Defn.Esc == EscFuncUnknown {
|
||||
Fatalf("graph inconsistency")
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// An EscHole represents a context for evaluation a Go
|
||||
// expression. E.g., when evaluating p in "x = **p", we'd have a hole
|
||||
// with dst==x and derefs==2.
|
||||
|
Loading…
Reference in New Issue
Block a user