1
2
3
4
5 package escape
6
7 import (
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ir"
10 "cmd/compile/internal/typecheck"
11 "cmd/compile/internal/types"
12 "cmd/internal/src"
13 )
14
15
16
17
18 func (e *escape) call(ks []hole, call ir.Node) {
19 argument := func(k hole, arg ir.Node) {
20
21 e.expr(k.note(call, "call parameter"), arg)
22 }
23
24 switch call.Op() {
25 default:
26 ir.Dump("esc", call)
27 base.Fatalf("unexpected call op: %v", call.Op())
28
29 case ir.OCALLFUNC, ir.OCALLINTER:
30 call := call.(*ir.CallExpr)
31 typecheck.AssertFixedCall(call)
32
33
34
35
36
37
38
39 var fn *ir.Name
40 switch call.Op() {
41 case ir.OCALLFUNC:
42 v := ir.StaticValue(call.Fun)
43 fn = ir.StaticCalleeName(v)
44 }
45
46 fntype := call.Fun.Type()
47 if fn != nil {
48 fntype = fn.Type()
49 }
50
51 if ks != nil && fn != nil && e.inMutualBatch(fn) {
52 for i, result := range fn.Type().Results() {
53 e.expr(ks[i], result.Nname.(*ir.Name))
54 }
55 }
56
57 var recvArg ir.Node
58 if call.Op() == ir.OCALLFUNC {
59
60 calleeK := e.discardHole()
61 if fn == nil {
62 for _, k := range ks {
63 if k.dst != &e.blankLoc {
64
65
66
67
68 calleeK = e.calleeHole().note(call, "callee operand")
69 break
70 }
71 }
72 }
73 e.expr(calleeK, call.Fun)
74 } else {
75 recvArg = call.Fun.(*ir.SelectorExpr).X
76 }
77
78
79
80 argumentParam := func(param *types.Field, arg ir.Node) {
81 e.rewriteArgument(arg, call, fn)
82 argument(e.tagHole(ks, fn, param), arg)
83 }
84
85 args := call.Args
86 if recvParam := fntype.Recv(); recvParam != nil {
87 if recvArg == nil {
88
89
90 recvArg, args = args[0], args[1:]
91 }
92
93 argumentParam(recvParam, recvArg)
94 }
95
96 for i, param := range fntype.Params() {
97 argumentParam(param, args[i])
98 }
99
100 case ir.OINLCALL:
101 call := call.(*ir.InlinedCallExpr)
102 e.stmts(call.Body)
103 for i, result := range call.ReturnVars {
104 k := e.discardHole()
105 if ks != nil {
106 k = ks[i]
107 }
108 e.expr(k, result)
109 }
110
111 case ir.OAPPEND:
112 call := call.(*ir.CallExpr)
113 args := call.Args
114
115
116
117
118
119 appendeeK := e.teeHole(ks[0], e.mutatorHole())
120 if args[0].Type().Elem().HasPointers() {
121 appendeeK = e.teeHole(appendeeK, e.heapHole().deref(call, "appendee slice"))
122 }
123 argument(appendeeK, args[0])
124
125 if call.IsDDD {
126 appendedK := e.discardHole()
127 if args[1].Type().IsSlice() && args[1].Type().Elem().HasPointers() {
128 appendedK = e.heapHole().deref(call, "appended slice...")
129 }
130 argument(appendedK, args[1])
131 } else {
132 for i := 1; i < len(args); i++ {
133 argument(e.heapHole(), args[i])
134 }
135 }
136 e.discard(call.RType)
137
138 case ir.OCOPY:
139 call := call.(*ir.BinaryExpr)
140 argument(e.mutatorHole(), call.X)
141
142 copiedK := e.discardHole()
143 if call.Y.Type().IsSlice() && call.Y.Type().Elem().HasPointers() {
144 copiedK = e.heapHole().deref(call, "copied slice")
145 }
146 argument(copiedK, call.Y)
147 e.discard(call.RType)
148
149 case ir.OPANIC:
150 call := call.(*ir.UnaryExpr)
151 argument(e.heapHole(), call.X)
152
153 case ir.OCOMPLEX:
154 call := call.(*ir.BinaryExpr)
155 e.discard(call.X)
156 e.discard(call.Y)
157
158 case ir.ODELETE, ir.OPRINT, ir.OPRINTLN, ir.ORECOVERFP:
159 call := call.(*ir.CallExpr)
160 for _, arg := range call.Args {
161 e.discard(arg)
162 }
163 e.discard(call.RType)
164
165 case ir.OMIN, ir.OMAX:
166 call := call.(*ir.CallExpr)
167 for _, arg := range call.Args {
168 argument(ks[0], arg)
169 }
170 e.discard(call.RType)
171
172 case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
173 call := call.(*ir.UnaryExpr)
174 e.discard(call.X)
175
176 case ir.OCLEAR:
177 call := call.(*ir.UnaryExpr)
178 argument(e.mutatorHole(), call.X)
179
180 case ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
181 call := call.(*ir.UnaryExpr)
182 argument(ks[0], call.X)
183
184 case ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
185 call := call.(*ir.BinaryExpr)
186 argument(ks[0], call.X)
187 e.discard(call.Y)
188 e.discard(call.RType)
189 }
190 }
191
192
193 func (e *escape) goDeferStmt(n *ir.GoDeferStmt) {
194 k := e.heapHole()
195 if n.Op() == ir.ODEFER && e.loopDepth == 1 && n.DeferAt == nil {
196
197
198 k = e.later(e.discardHole())
199
200
201
202 n.SetEsc(ir.EscNever)
203 }
204
205
206
207
208
209
210
211
212 call, ok := n.Call.(*ir.CallExpr)
213 if !ok || call.Op() != ir.OCALLFUNC {
214 base.FatalfAt(n.Pos(), "expected function call: %v", n.Call)
215 }
216 if sig := call.Fun.Type(); sig.NumParams()+sig.NumResults() != 0 {
217 base.FatalfAt(n.Pos(), "expected signature without parameters or results: %v", sig)
218 }
219
220 if clo, ok := call.Fun.(*ir.ClosureExpr); ok && n.Op() == ir.OGO {
221 clo.IsGoWrap = true
222 }
223
224 e.expr(k, call.Fun)
225 }
226
227
228
229 func (e *escape) rewriteArgument(arg ir.Node, call *ir.CallExpr, fn *ir.Name) {
230 if fn == nil || fn.Func == nil {
231 return
232 }
233 pragma := fn.Func.Pragma
234 if pragma&(ir.UintptrKeepAlive|ir.UintptrEscapes) == 0 {
235 return
236 }
237
238
239
240
241 unsafeUintptr := func(arg ir.Node) {
242
243
244
245
246 conv, ok := arg.(*ir.ConvExpr)
247 if !ok || conv.Op() != ir.OCONVNOP {
248 return
249 }
250 if !conv.X.Type().IsUnsafePtr() || !conv.Type().IsUintptr() {
251 return
252 }
253
254
255
256
257
258
259 tmp := e.copyExpr(conv.Pos(), conv.X, call.PtrInit())
260 conv.X = tmp
261
262 k := e.mutatorHole()
263 if pragma&ir.UintptrEscapes != 0 {
264 k = e.heapHole().note(conv, "//go:uintptrescapes")
265 }
266 e.flow(k, e.oldLoc(tmp))
267
268 if pragma&ir.UintptrKeepAlive != 0 {
269 tmp.SetAddrtaken(true)
270 call.KeepAlive = append(call.KeepAlive, tmp)
271 }
272 }
273
274
275
276
277
278
279
280
281
282
283
284 if arg.Op() == ir.OSLICELIT {
285 list := arg.(*ir.CompLitExpr).List
286 for _, el := range list {
287 if el.Op() == ir.OKEY {
288 el = el.(*ir.KeyExpr).Value
289 }
290 unsafeUintptr(el)
291 }
292 } else {
293 unsafeUintptr(arg)
294 }
295 }
296
297
298
299
300 func (e *escape) copyExpr(pos src.XPos, expr ir.Node, init *ir.Nodes) *ir.Name {
301 if ir.HasUniquePos(expr) {
302 pos = expr.Pos()
303 }
304
305 tmp := typecheck.TempAt(pos, e.curfn, expr.Type())
306
307 stmts := []ir.Node{
308 ir.NewDecl(pos, ir.ODCL, tmp),
309 ir.NewAssignStmt(pos, tmp, expr),
310 }
311 typecheck.Stmts(stmts)
312 init.Append(stmts...)
313
314 e.newLoc(tmp, true)
315 e.stmts(stmts)
316
317 return tmp
318 }
319
320
321
322
323
324 func (e *escape) tagHole(ks []hole, fn *ir.Name, param *types.Field) hole {
325
326 if fn == nil {
327 return e.heapHole()
328 }
329
330 if e.inMutualBatch(fn) {
331 if param.Nname == nil {
332 return e.discardHole()
333 }
334 return e.addr(param.Nname.(*ir.Name))
335 }
336
337
338
339 var tagKs []hole
340 esc := parseLeaks(param.Note)
341
342 if x := esc.Heap(); x >= 0 {
343 tagKs = append(tagKs, e.heapHole().shift(x))
344 }
345 if x := esc.Mutator(); x >= 0 {
346 tagKs = append(tagKs, e.mutatorHole().shift(x))
347 }
348 if x := esc.Callee(); x >= 0 {
349 tagKs = append(tagKs, e.calleeHole().shift(x))
350 }
351
352 if ks != nil {
353 for i := 0; i < numEscResults; i++ {
354 if x := esc.Result(i); x >= 0 {
355 tagKs = append(tagKs, ks[i].shift(x))
356 }
357 }
358 }
359
360 return e.teeHole(tagKs...)
361 }
362
View as plain text