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.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.
   273  func (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.
   318  func (e *escape) discard(n ir.Node) {
   319  	e.expr(e.discardHole(), n)
   320  }
   321  
   322  func (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.
   331  func (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  

View as plain text