}
func mustHeapAlloc(n *Node) bool {
- // TODO(mdempsky): Cleanup this mess.
- return n.Type != nil &&
- (n.Type.Width > maxStackVarSize ||
- (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= maxImplicitStackVarSize ||
- n.Op == OMAKESLICE && !isSmallMakeSlice(n))
+ if n.Type == nil {
+ return false
+ }
+
+ // Parameters are always passed via the stack.
+ if n.Op == ONAME && (n.Class() == PPARAM || n.Class() == PPARAMOUT) {
+ return false
+ }
+
+ if n.Type.Width > maxStackVarSize {
+ return true
+ }
+
+ if (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= maxImplicitStackVarSize {
+ return true
+ }
+
+ if n.Op == OMAKESLICE && !isSmallMakeSlice(n) {
+ return true
+ }
+
+ return false
}
// addrescapes tags node n as having had its address taken
}
n.SetOpt(loc)
- if mustHeapAlloc(n) && !loc.isName(PPARAM) && !loc.isName(PPARAMOUT) {
- loc.escapes = true
+ if mustHeapAlloc(n) {
+ why := "too large for stack"
+ if n.Op == OMAKESLICE && (!Isconst(n.Left, CTINT) || !Isconst(n.Right, CTINT)) {
+ why = "non-constant size"
+ }
+ e.flow(e.heapHole().addr(n, why), loc)
}
}
return loc
return
}
if dst.escapes && k.derefs < 0 { // dst = &src
+ if Debug['m'] >= 2 {
+ pos := linestr(src.n.Pos)
+ fmt.Printf("%s: %v escapes to heap:\n", pos, src.n)
+ e.explainFlow(pos, dst, src, k.derefs, k.notes)
+ }
src.escapes = true
return
}
Fatalf("path inconsistency: %v != %v", edge.src, src)
}
- derefs := "&"
- if edge.derefs >= 0 {
- derefs = strings.Repeat("*", edge.derefs)
- }
-
- fmt.Printf("%s: flow: %s = %s%v:\n", pos, e.explainLoc(dst), derefs, e.explainLoc(src))
- for notes := edge.notes; notes != nil; notes = notes.next {
- fmt.Printf("%s: from %v (%v) at %s\n", pos, notes.where, notes.why, linestr(notes.where.Pos))
- }
+ e.explainFlow(pos, dst, src, edge.derefs, edge.notes)
if dst == root {
break
}
}
+func (e *Escape) explainFlow(pos string, dst, src *EscLocation, derefs int, notes *EscNote) {
+ ops := "&"
+ if derefs >= 0 {
+ ops = strings.Repeat("*", derefs)
+ }
+
+ fmt.Printf("%s: flow: %s = %s%v:\n", pos, e.explainLoc(dst), ops, e.explainLoc(src))
+ for note := notes; note != nil; note = note.next {
+ fmt.Printf("%s: from %v (%v) at %s\n", pos, note.where, note.why, linestr(note.where.Pos))
+ }
+}
+
func (e *Escape) explainLoc(l *EscLocation) string {
if l == &e.heapLoc {
return "{heap}"
n.SetOpt(nil)
// Update n.Esc based on escape analysis results.
- //
- // TODO(mdempsky): Describe path when Debug['m'] >= 2.
if loc.escapes {
if Debug['m'] != 0 && n.Op != ONAME {