From: Matthew Dempsky Date: Mon, 20 Apr 2020 18:14:15 +0000 (-0700) Subject: cmd/compile: refactor Escape.tagHole X-Git-Tag: go1.15beta1~456 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=181153369534c6987306c47630f9e4fbf07b467f;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: Cuong Manh Le Reviewed-by: Cherry Zhang --- diff --git a/src/cmd/compile/internal/gc/escape.go b/src/cmd/compile/internal/gc/escape.go index 472d193efd..598750fd8d 100644 --- a/src/cmd/compile/internal/gc/escape.go +++ b/src/cmd/compile/internal/gc/escape.go @@ -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)) - } - 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) + recvK = e.tagHole(ks, fn, r) } 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.