github.com/bir3/gocompiler@v0.9.2202/src/cmd/compile/internal/escape/expr.go (about) 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 5 package escape 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 9 "github.com/bir3/gocompiler/src/cmd/compile/internal/ir" 10 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 11 ) 12 13 // expr models evaluating an expression n and flowing the result into 14 // hole k. 15 func (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 23 func (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) || ir.ShouldAsanCheckPtr(e.curfn)) && n.Type().IsUnsafePtr() && n.X.Type().IsPtr() { 104 // When -d=checkptr=2 or -asan is enabled, 105 // treat 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: 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.OMAKEFACE: 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.OITAB, ir.OIDATA, ir.OSPTR: 127 n := n.(*ir.UnaryExpr) 128 e.expr(k, n.X) 129 case ir.OSLICE2ARR: 130 // Converting a slice to array is effectively a deref. 131 n := n.(*ir.ConvExpr) 132 e.expr(k.deref(n, "slice-to-array"), n.X) 133 case ir.OSLICE2ARRPTR: 134 // the slice pointer flows directly to the result 135 n := n.(*ir.ConvExpr) 136 e.expr(k, n.X) 137 case ir.ORECV: 138 n := n.(*ir.UnaryExpr) 139 e.discard(n.X) 140 141 case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OINLCALL, 142 ir.OLEN, ir.OCAP, ir.OMIN, ir.OMAX, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.ORECOVERFP, 143 ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA: 144 e.call([]hole{k}, n) 145 146 case ir.ONEW: 147 n := n.(*ir.UnaryExpr) 148 e.spill(k, n) 149 150 case ir.OMAKESLICE: 151 n := n.(*ir.MakeExpr) 152 e.spill(k, n) 153 e.discard(n.Len) 154 e.discard(n.Cap) 155 case ir.OMAKECHAN: 156 n := n.(*ir.MakeExpr) 157 e.discard(n.Len) 158 case ir.OMAKEMAP: 159 n := n.(*ir.MakeExpr) 160 e.spill(k, n) 161 e.discard(n.Len) 162 163 case ir.OMETHVALUE: 164 // Flow the receiver argument to both the closure and 165 // to the receiver parameter. 166 167 n := n.(*ir.SelectorExpr) 168 closureK := e.spill(k, n) 169 170 m := n.Selection 171 172 // We don't know how the method value will be called 173 // later, so conservatively assume the result 174 // parameters all flow to the heap. 175 // 176 // TODO(mdempsky): Change ks into a callback, so that 177 // we don't have to create this slice? 178 var ks []hole 179 for i := m.Type.NumResults(); i > 0; i-- { 180 ks = append(ks, e.heapHole()) 181 } 182 name, _ := m.Nname.(*ir.Name) 183 paramK := e.tagHole(ks, name, m.Type.Recv()) 184 185 e.expr(e.teeHole(paramK, closureK), n.X) 186 187 case ir.OPTRLIT: 188 n := n.(*ir.AddrExpr) 189 e.expr(e.spill(k, n), n.X) 190 191 case ir.OARRAYLIT: 192 n := n.(*ir.CompLitExpr) 193 for _, elt := range n.List { 194 if elt.Op() == ir.OKEY { 195 elt = elt.(*ir.KeyExpr).Value 196 } 197 e.expr(k.note(n, "array literal element"), elt) 198 } 199 200 case ir.OSLICELIT: 201 n := n.(*ir.CompLitExpr) 202 k = e.spill(k, n) 203 204 for _, elt := range n.List { 205 if elt.Op() == ir.OKEY { 206 elt = elt.(*ir.KeyExpr).Value 207 } 208 e.expr(k.note(n, "slice-literal-element"), elt) 209 } 210 211 case ir.OSTRUCTLIT: 212 n := n.(*ir.CompLitExpr) 213 for _, elt := range n.List { 214 e.expr(k.note(n, "struct literal element"), elt.(*ir.StructKeyExpr).Value) 215 } 216 217 case ir.OMAPLIT: 218 n := n.(*ir.CompLitExpr) 219 e.spill(k, n) 220 221 // Map keys and values are always stored in the heap. 222 for _, elt := range n.List { 223 elt := elt.(*ir.KeyExpr) 224 e.assignHeap(elt.Key, "map literal key", n) 225 e.assignHeap(elt.Value, "map literal value", n) 226 } 227 228 case ir.OCLOSURE: 229 n := n.(*ir.ClosureExpr) 230 k = e.spill(k, n) 231 e.closures = append(e.closures, closure{k, n}) 232 233 if fn := n.Func; fn.IsHiddenClosure() { 234 for _, cv := range fn.ClosureVars { 235 if loc := e.oldLoc(cv); !loc.captured { 236 loc.captured = true 237 238 // Ignore reassignments to the variable in straightline code 239 // preceding the first capture by a closure. 240 if loc.loopDepth == e.loopDepth { 241 loc.reassigned = false 242 } 243 } 244 } 245 246 for _, n := range fn.Dcl { 247 // Add locations for local variables of the 248 // closure, if needed, in case we're not including 249 // the closure func in the batch for escape 250 // analysis (happens for escape analysis called 251 // from reflectdata.methodWrapper) 252 if n.Op() == ir.ONAME && n.Opt == nil { 253 e.with(fn).newLoc(n, true) 254 } 255 } 256 e.walkFunc(fn) 257 } 258 259 case ir.ORUNES2STR, ir.OBYTES2STR, ir.OSTR2RUNES, ir.OSTR2BYTES, ir.ORUNESTR: 260 n := n.(*ir.ConvExpr) 261 e.spill(k, n) 262 e.discard(n.X) 263 264 case ir.OADDSTR: 265 n := n.(*ir.AddStringExpr) 266 e.spill(k, n) 267 268 // Arguments of OADDSTR never escape; 269 // runtime.concatstrings makes sure of that. 270 e.discards(n.List) 271 272 case ir.ODYNAMICTYPE: 273 // Nothing to do - argument is a *runtime._type (+ maybe a *runtime.itab) pointing to static data section 274 } 275 } 276 277 // unsafeValue evaluates a uintptr-typed arithmetic expression looking 278 // for conversions from an unsafe.Pointer. 279 func (e *escape) unsafeValue(k hole, n ir.Node) { 280 if n.Type().Kind() != types.TUINTPTR { 281 base.Fatalf("unexpected type %v for %v", n.Type(), n) 282 } 283 if k.addrtaken { 284 base.Fatalf("unexpected addrtaken") 285 } 286 287 e.stmts(n.Init()) 288 289 switch n.Op() { 290 case ir.OCONV, ir.OCONVNOP: 291 n := n.(*ir.ConvExpr) 292 if n.X.Type().IsUnsafePtr() { 293 e.expr(k, n.X) 294 } else { 295 e.discard(n.X) 296 } 297 case ir.ODOTPTR: 298 n := n.(*ir.SelectorExpr) 299 if ir.IsReflectHeaderDataField(n) { 300 e.expr(k.deref(n, "reflect.Header.Data"), n.X) 301 } else { 302 e.discard(n.X) 303 } 304 case ir.OPLUS, ir.ONEG, ir.OBITNOT: 305 n := n.(*ir.UnaryExpr) 306 e.unsafeValue(k, n.X) 307 case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.ODIV, ir.OMOD, ir.OAND, ir.OANDNOT: 308 n := n.(*ir.BinaryExpr) 309 e.unsafeValue(k, n.X) 310 e.unsafeValue(k, n.Y) 311 case ir.OLSH, ir.ORSH: 312 n := n.(*ir.BinaryExpr) 313 e.unsafeValue(k, n.X) 314 // RHS need not be uintptr-typed (#32959) and can't meaningfully 315 // flow pointers anyway. 316 e.discard(n.Y) 317 default: 318 e.exprSkipInit(e.discardHole(), n) 319 } 320 } 321 322 // discard evaluates an expression n for side-effects, but discards 323 // its value. 324 func (e *escape) discard(n ir.Node) { 325 e.expr(e.discardHole(), n) 326 } 327 328 func (e *escape) discards(l ir.Nodes) { 329 for _, n := range l { 330 e.discard(n) 331 } 332 } 333 334 // spill allocates a new location associated with expression n, flows 335 // its address to k, and returns a hole that flows values to it. It's 336 // intended for use with most expressions that allocate storage. 337 func (e *escape) spill(k hole, n ir.Node) hole { 338 loc := e.newLoc(n, false) 339 e.flow(k.addr(n, "spill"), loc) 340 return loc.asHole() 341 }