Source file src/cmd/compile/internal/escape/expr.go

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

View as plain text