1// Copyright 2018 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package escape 6 7import ( 8 "cmd/compile/internal/base" 9 "cmd/compile/internal/ir" 10) 11 12// addr evaluates an addressable expression n and returns a hole 13// that represents storing into the represented location. 14func (e *escape) addr(n ir.Node) hole { 15 if n == nil || ir.IsBlank(n) { 16 // Can happen in select case, range, maybe others. 17 return e.discardHole() 18 } 19 20 k := e.heapHole() 21 22 switch n.Op() { 23 default: 24 base.Fatalf("unexpected addr: %v", n) 25 case ir.ONAME: 26 n := n.(*ir.Name) 27 if n.Class == ir.PEXTERN { 28 break 29 } 30 k = e.oldLoc(n).asHole() 31 case ir.OLINKSYMOFFSET: 32 break 33 case ir.ODOT: 34 n := n.(*ir.SelectorExpr) 35 k = e.addr(n.X) 36 case ir.OINDEX: 37 n := n.(*ir.IndexExpr) 38 e.discard(n.Index) 39 if n.X.Type().IsArray() { 40 k = e.addr(n.X) 41 } else { 42 e.discard(n.X) 43 } 44 case ir.ODEREF, ir.ODOTPTR: 45 e.discard(n) 46 case ir.OINDEXMAP: 47 n := n.(*ir.IndexExpr) 48 e.discard(n.X) 49 e.assignHeap(n.Index, "key of map put", n) 50 } 51 52 return k 53} 54 55func (e *escape) addrs(l ir.Nodes) []hole { 56 var ks []hole 57 for _, n := range l { 58 ks = append(ks, e.addr(n)) 59 } 60 return ks 61} 62 63func (e *escape) assignHeap(src ir.Node, why string, where ir.Node) { 64 e.expr(e.heapHole().note(where, why), src) 65} 66 67// assignList evaluates the assignment dsts... = srcs.... 68func (e *escape) assignList(dsts, srcs []ir.Node, why string, where ir.Node) { 69 ks := e.addrs(dsts) 70 for i, k := range ks { 71 var src ir.Node 72 if i < len(srcs) { 73 src = srcs[i] 74 } 75 76 if dst := dsts[i]; dst != nil { 77 // Detect implicit conversion of uintptr to unsafe.Pointer when 78 // storing into reflect.{Slice,String}Header. 79 if dst.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(dst) { 80 e.unsafeValue(e.heapHole().note(where, why), src) 81 continue 82 } 83 84 // Filter out some no-op assignments for escape analysis. 85 if src != nil && isSelfAssign(dst, src) { 86 if base.Flag.LowerM != 0 { 87 base.WarnfAt(where.Pos(), "%v ignoring self-assignment in %v", e.curfn, where) 88 } 89 k = e.discardHole() 90 } 91 } 92 93 e.expr(k.note(where, why), src) 94 } 95 96 e.reassigned(ks, where) 97} 98 99// reassigned marks the locations associated with the given holes as 100// reassigned, unless the location represents a variable declared and 101// assigned exactly once by where. 102func (e *escape) reassigned(ks []hole, where ir.Node) { 103 if as, ok := where.(*ir.AssignStmt); ok && as.Op() == ir.OAS && as.Y == nil { 104 if dst, ok := as.X.(*ir.Name); ok && dst.Op() == ir.ONAME && dst.Defn == nil { 105 // Zero-value assignment for variable declared without an 106 // explicit initial value. Assume this is its initialization 107 // statement. 108 return 109 } 110 } 111 112 for _, k := range ks { 113 loc := k.dst 114 // Variables declared by range statements are assigned on every iteration. 115 if n, ok := loc.n.(*ir.Name); ok && n.Defn == where && where.Op() != ir.ORANGE { 116 continue 117 } 118 loc.reassigned = true 119 } 120} 121