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 "cmd/compile/internal/types" 11) 12 13// expr models evaluating an expression n and flowing the result into 14// hole k. 15func (e *escape) expr(k hole, n ir.Node) { 16 if n == nil { 17 return 18 } 19 e.stmts(n.Init()) 20 e.exprSkipInit(k, n) 21} 22 23func (e *escape) exprSkipInit(k hole, n ir.Node) { 24 if n == nil { 25 return 26 } 27 28 lno := ir.SetPos(n) 29 defer func() { 30 base.Pos = lno 31 }() 32 33 if k.derefs >= 0 && !n.Type().IsUntyped() && !n.Type().HasPointers() { 34 k.dst = &e.blankLoc 35 } 36 37 switch n.Op() { 38 default: 39 base.Fatalf("unexpected expr: %s %v", n.Op().String(), n) 40 41 case ir.OLITERAL, ir.ONIL, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OTYPE, ir.OMETHEXPR, ir.OLINKSYMOFFSET: 42 // nop 43 44 case ir.ONAME: 45 n := n.(*ir.Name) 46 if n.Class == ir.PFUNC || n.Class == ir.PEXTERN { 47 return 48 } 49 e.flow(k, e.oldLoc(n)) 50 51 case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT: 52 n := n.(*ir.UnaryExpr) 53 e.discard(n.X) 54 case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.ODIV, ir.OMOD, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE: 55 n := n.(*ir.BinaryExpr) 56 e.discard(n.X) 57 e.discard(n.Y) 58 case ir.OANDAND, ir.OOROR: 59 n := n.(*ir.LogicalExpr) 60 e.discard(n.X) 61 e.discard(n.Y) 62 case ir.OADDR: 63 n := n.(*ir.AddrExpr) 64 e.expr(k.addr(n, "address-of"), n.X) // "address-of" 65 case ir.ODEREF: 66 n := n.(*ir.StarExpr) 67 e.expr(k.deref(n, "indirection"), n.X) // "indirection" 68 case ir.ODOT, ir.ODOTMETH, ir.ODOTINTER: 69 n := n.(*ir.SelectorExpr) 70 e.expr(k.note(n, "dot"), n.X) 71 case ir.ODOTPTR: 72 n := n.(*ir.SelectorExpr) 73 e.expr(k.deref(n, "dot of pointer"), n.X) // "dot of pointer" 74 case ir.ODOTTYPE, ir.ODOTTYPE2: 75 n := n.(*ir.TypeAssertExpr) 76 e.expr(k.dotType(n.Type(), n, "dot"), n.X) 77 case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2: 78 n := n.(*ir.DynamicTypeAssertExpr) 79 e.expr(k.dotType(n.Type(), n, "dot"), n.X) 80 // n.T doesn't need to be tracked; it always points to read-only storage. 81 case ir.OINDEX: 82 n := n.(*ir.IndexExpr) 83 if n.X.Type().IsArray() { 84 e.expr(k.note(n, "fixed-array-index-of"), n.X) 85 } else { 86 // TODO(mdempsky): Fix why reason text. 87 e.expr(k.deref(n, "dot of pointer"), n.X) 88 } 89 e.discard(n.Index) 90 case ir.OINDEXMAP: 91 n := n.(*ir.IndexExpr) 92 e.discard(n.X) 93 e.discard(n.Index) 94 case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR, ir.OSLICESTR: 95 n := n.(*ir.SliceExpr) 96 e.expr(k.note(n, "slice"), n.X) 97 e.discard(n.Low) 98 e.discard(n.High) 99 e.discard(n.Max) 100 101 case ir.OCONV, ir.OCONVNOP: 102 n := n.(*ir.ConvExpr) 103 if ir.ShouldCheckPtr(e.curfn, 2) && n.Type().IsUnsafePtr() && n.X.Type().IsPtr() { 104 // When -d=checkptr=2 is enabled, treat 105 // conversions to unsafe.Pointer as an 106 // escaping operation. This allows better 107 // runtime instrumentation, since we can more 108 // easily detect object boundaries on the heap 109 // than the stack. 110 e.assignHeap(n.X, "conversion to unsafe.Pointer", n) 111 } else if n.Type().IsUnsafePtr() && n.X.Type().IsUintptr() { 112 e.unsafeValue(k, n.X) 113 } else { 114 e.expr(k, n.X) 115 } 116 case ir.OCONVIFACE, ir.OCONVIDATA: 117 n := n.(*ir.ConvExpr) 118 if !n.X.Type().IsInterface() && !types.IsDirectIface(n.X.Type()) { 119 k = e.spill(k, n) 120 } 121 e.expr(k.note(n, "interface-converted"), n.X) 122 case ir.OEFACE: 123 n := n.(*ir.BinaryExpr) 124 // Note: n.X is not needed because it can never point to memory that might escape. 125 e.expr(k, n.Y) 126 case ir.OIDATA, ir.OSPTR: 127 n := n.(*ir.UnaryExpr) 128 e.expr(k, n.X) 129 case ir.OSLICE2ARRPTR: 130 // the slice pointer flows directly to the result 131 n := n.(*ir.ConvExpr) 132 e.expr(k, n.X) 133 case ir.ORECV: 134 n := n.(*ir.UnaryExpr) 135 e.discard(n.X) 136 137 case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OINLCALL, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.ORECOVER, ir.OUNSAFEADD, ir.OUNSAFESLICE: 138 e.call([]hole{k}, n) 139 140 case ir.ONEW: 141 n := n.(*ir.UnaryExpr) 142 e.spill(k, n) 143 144 case ir.OMAKESLICE: 145 n := n.(*ir.MakeExpr) 146 e.spill(k, n) 147 e.discard(n.Len) 148 e.discard(n.Cap) 149 case ir.OMAKECHAN: 150 n := n.(*ir.MakeExpr) 151 e.discard(n.Len) 152 case ir.OMAKEMAP: 153 n := n.(*ir.MakeExpr) 154 e.spill(k, n) 155 e.discard(n.Len) 156 157 case ir.OMETHVALUE: 158 // Flow the receiver argument to both the closure and 159 // to the receiver parameter. 160 161 n := n.(*ir.SelectorExpr) 162 closureK := e.spill(k, n) 163 164 m := n.Selection 165 166 // We don't know how the method value will be called 167 // later, so conservatively assume the result 168 // parameters all flow to the heap. 169 // 170 // TODO(mdempsky): Change ks into a callback, so that 171 // we don't have to create this slice? 172 var ks []hole 173 for i := m.Type.NumResults(); i > 0; i-- { 174 ks = append(ks, e.heapHole()) 175 } 176 name, _ := m.Nname.(*ir.Name) 177 paramK := e.tagHole(ks, name, m.Type.Recv()) 178 179 e.expr(e.teeHole(paramK, closureK), n.X) 180 181 case ir.OPTRLIT: 182 n := n.(*ir.AddrExpr) 183 e.expr(e.spill(k, n), n.X) 184 185 case ir.OARRAYLIT: 186 n := n.(*ir.CompLitExpr) 187 for _, elt := range n.List { 188 if elt.Op() == ir.OKEY { 189 elt = elt.(*ir.KeyExpr).Value 190 } 191 e.expr(k.note(n, "array literal element"), elt) 192 } 193 194 case ir.OSLICELIT: 195 n := n.(*ir.CompLitExpr) 196 k = e.spill(k, n) 197 198 for _, elt := range n.List { 199 if elt.Op() == ir.OKEY { 200 elt = elt.(*ir.KeyExpr).Value 201 } 202 e.expr(k.note(n, "slice-literal-element"), elt) 203 } 204 205 case ir.OSTRUCTLIT: 206 n := n.(*ir.CompLitExpr) 207 for _, elt := range n.List { 208 e.expr(k.note(n, "struct literal element"), elt.(*ir.StructKeyExpr).Value) 209 } 210 211 case ir.OMAPLIT: 212 n := n.(*ir.CompLitExpr) 213 e.spill(k, n) 214 215 // Map keys and values are always stored in the heap. 216 for _, elt := range n.List { 217 elt := elt.(*ir.KeyExpr) 218 e.assignHeap(elt.Key, "map literal key", n) 219 e.assignHeap(elt.Value, "map literal value", n) 220 } 221 222 case ir.OCLOSURE: 223 n := n.(*ir.ClosureExpr) 224 k = e.spill(k, n) 225 e.closures = append(e.closures, closure{k, n}) 226 227 if fn := n.Func; fn.IsHiddenClosure() { 228 for _, cv := range fn.ClosureVars { 229 if loc := e.oldLoc(cv); !loc.captured { 230 loc.captured = true 231 232 // Ignore reassignments to the variable in straightline code 233 // preceding the first capture by a closure. 234 if loc.loopDepth == e.loopDepth { 235 loc.reassigned = false 236 } 237 } 238 } 239 240 for _, n := range fn.Dcl { 241 // Add locations for local variables of the 242 // closure, if needed, in case we're not including 243 // the closure func in the batch for escape 244 // analysis (happens for escape analysis called 245 // from reflectdata.methodWrapper) 246 if n.Op() == ir.ONAME && n.Opt == nil { 247 e.with(fn).newLoc(n, false) 248 } 249 } 250 e.walkFunc(fn) 251 } 252 253 case ir.ORUNES2STR, ir.OBYTES2STR, ir.OSTR2RUNES, ir.OSTR2BYTES, ir.ORUNESTR: 254 n := n.(*ir.ConvExpr) 255 e.spill(k, n) 256 e.discard(n.X) 257 258 case ir.OADDSTR: 259 n := n.(*ir.AddStringExpr) 260 e.spill(k, n) 261 262 // Arguments of OADDSTR never escape; 263 // runtime.concatstrings makes sure of that. 264 e.discards(n.List) 265 266 case ir.ODYNAMICTYPE: 267 // Nothing to do - argument is a *runtime._type (+ maybe a *runtime.itab) pointing to static data section 268 } 269} 270 271// unsafeValue evaluates a uintptr-typed arithmetic expression looking 272// for conversions from an unsafe.Pointer. 273func (e *escape) unsafeValue(k hole, n ir.Node) { 274 if n.Type().Kind() != types.TUINTPTR { 275 base.Fatalf("unexpected type %v for %v", n.Type(), n) 276 } 277 if k.addrtaken { 278 base.Fatalf("unexpected addrtaken") 279 } 280 281 e.stmts(n.Init()) 282 283 switch n.Op() { 284 case ir.OCONV, ir.OCONVNOP: 285 n := n.(*ir.ConvExpr) 286 if n.X.Type().IsUnsafePtr() { 287 e.expr(k, n.X) 288 } else { 289 e.discard(n.X) 290 } 291 case ir.ODOTPTR: 292 n := n.(*ir.SelectorExpr) 293 if ir.IsReflectHeaderDataField(n) { 294 e.expr(k.deref(n, "reflect.Header.Data"), n.X) 295 } else { 296 e.discard(n.X) 297 } 298 case ir.OPLUS, ir.ONEG, ir.OBITNOT: 299 n := n.(*ir.UnaryExpr) 300 e.unsafeValue(k, n.X) 301 case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.ODIV, ir.OMOD, ir.OAND, ir.OANDNOT: 302 n := n.(*ir.BinaryExpr) 303 e.unsafeValue(k, n.X) 304 e.unsafeValue(k, n.Y) 305 case ir.OLSH, ir.ORSH: 306 n := n.(*ir.BinaryExpr) 307 e.unsafeValue(k, n.X) 308 // RHS need not be uintptr-typed (#32959) and can't meaningfully 309 // flow pointers anyway. 310 e.discard(n.Y) 311 default: 312 e.exprSkipInit(e.discardHole(), n) 313 } 314} 315 316// discard evaluates an expression n for side-effects, but discards 317// its value. 318func (e *escape) discard(n ir.Node) { 319 e.expr(e.discardHole(), n) 320} 321 322func (e *escape) discards(l ir.Nodes) { 323 for _, n := range l { 324 e.discard(n) 325 } 326} 327 328// spill allocates a new location associated with expression n, flows 329// its address to k, and returns a hole that flows values to it. It's 330// intended for use with most expressions that allocate storage. 331func (e *escape) spill(k hole, n ir.Node) hole { 332 loc := e.newLoc(n, true) 333 e.flow(k.addr(n, "spill"), loc) 334 return loc.asHole() 335} 336