init.Append(stmts...)
if analyze {
- e.newLoc(tmp, false)
+ e.newLoc(tmp, true)
e.stmts(stmts)
}
var b batch
b.heapLoc.escapes = true
- b.blankLoc.transient = true
+ b.heapLoc.persists = true
// Construct data-flow graph from syntax trees.
for _, fn := range fns {
// Allocate locations for local variables.
for _, n := range fn.Dcl {
- e.newLoc(n, false)
+ e.newLoc(n, true)
}
// Also for hidden parameters (e.g., the ".this" parameter to a
// method value wrapper).
if fn.OClosure == nil {
for _, n := range fn.ClosureVars {
- e.newLoc(n.Canonical(), false)
+ e.newLoc(n.Canonical(), true)
}
}
base.WarnfAt(n.Pos(), "%v does not escape", n)
}
n.SetEsc(ir.EscNone)
- if loc.transient {
+ if !loc.persists {
switch n.Op() {
case ir.OCLOSURE:
n := n.(*ir.ClosureExpr)
// analysis (happens for escape analysis called
// from reflectdata.methodWrapper)
if n.Op() == ir.ONAME && n.Opt == nil {
- e.with(fn).newLoc(n, false)
+ e.with(fn).newLoc(n, true)
}
}
e.walkFunc(fn)
// its address to k, and returns a hole that flows values to it. It's
// intended for use with most expressions that allocate storage.
func (e *escape) spill(k hole, n ir.Node) hole {
- loc := e.newLoc(n, true)
+ loc := e.newLoc(n, false)
e.flow(k.addr(n, "spill"), loc)
return loc.asHole()
}
// allocated.
escapes bool
- // transient reports whether the represented expression's
- // address does not outlive the statement; that is, whether
- // its storage can be immediately reused.
- transient bool
+ // persists reports whether the represented expression's address
+ // outlives the statement; that is, whether its storage cannot be
+ // immediately reused.
+ persists bool
// paramEsc records the represented parameter's leak set.
paramEsc leaks
return n.Canonical().Opt.(*location)
}
-func (e *escape) newLoc(n ir.Node, transient bool) *location {
+func (e *escape) newLoc(n ir.Node, persists bool) *location {
if e.curfn == nil {
base.Fatalf("e.curfn isn't set")
}
n: n,
curfn: e.curfn,
loopDepth: e.loopDepth,
- transient: transient,
+ persists: persists,
}
e.allLocs = append(e.allLocs, loc)
if n != nil {
// Given holes "l1 = _", "l2 = **_", "l3 = *_", ..., create a
// new temporary location ltmp, wire it into place, and return
// a hole for "ltmp = _".
- loc := e.newLoc(nil, true)
+ loc := e.newLoc(nil, false)
for _, k := range ks {
// N.B., "p = &q" and "p = &tmp; tmp = q" are not
// semantically equivalent. To combine holes like "l1
// Its main effect is to prevent immediate reuse of temporary
// variables introduced during Order.
func (e *escape) later(k hole) hole {
- loc := e.newLoc(nil, false)
+ loc := e.newLoc(nil, true)
e.flow(k, loc)
return loc.asHole()
}
//
// We walk once from each location (including the heap), and
// then re-enqueue each location on its transition from
- // transient->!transient and !escapes->escapes, which can each
+ // !persists->persists and !escapes->escapes, which can each
// happen at most once. So we take Θ(len(e.allLocs)) walks.
// LIFO queue, has enough room for e.allLocs and e.heapLoc.
// derefs at 0.
derefs = 0
- // If l's address flows to a non-transient
- // location, then l can't be transiently
- // allocated.
- if !root.transient && l.transient {
- l.transient = false
+ // If l's address flows to a persistent location, then l needs
+ // to persist too.
+ if root.persists && !l.persists {
+ l.persists = true
enqueue(l)
}
}
n := n.(*ir.RangeStmt)
base.Assert(!n.DistinctVars) // Should all be rewritten before escape analysis
- // X is evaluated outside the loop.
- tmp := e.newLoc(nil, false)
+ // X is evaluated outside the loop and persists until the loop
+ // terminates.
+ tmp := e.newLoc(nil, true)
e.expr(tmp.asHole(), n.X)
e.loopDepth++