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  }