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) || 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.
279func (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.
324func (e *escape) discard(n ir.Node) {
325	e.expr(e.discardHole(), n)
326}
327
328func (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.
337func (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}
342