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 var init ir.Nodes
20 e.callCommon(ks, call, &init, nil)
21 if len(init) != 0 {
22 call.(*ir.CallExpr).PtrInit().Append(init...)
23 }
24 }
25
26 func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir.Func) {
27
28
29
30
31 argumentFunc := func(fn *ir.Name, k hole, argp *ir.Node) {
32 e.rewriteArgument(argp, init, call, fn, wrapper)
33
34 e.expr(k.note(call, "call parameter"), *argp)
35 }
36
37 argument := func(k hole, argp *ir.Node) {
38 argumentFunc(nil, k, argp)
39 }
40
41 switch call.Op() {
42 default:
43 ir.Dump("esc", call)
44 base.Fatalf("unexpected call op: %v", call.Op())
45
46 case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
47 call := call.(*ir.CallExpr)
48 typecheck.FixVariadicCall(call)
49 typecheck.FixMethodCall(call)
50
51
52
53
54
55
56
57 var fn *ir.Name
58 switch call.Op() {
59 case ir.OCALLFUNC:
60
61
62
63 if call.X.Op() == ir.OCLOSURE {
64 call.X.(*ir.ClosureExpr).Func.SetClosureCalled(true)
65 }
66
67 switch v := ir.StaticValue(call.X); v.Op() {
68 case ir.ONAME:
69 if v := v.(*ir.Name); v.Class == ir.PFUNC {
70 fn = v
71 }
72 case ir.OCLOSURE:
73 fn = v.(*ir.ClosureExpr).Func.Nname
74 case ir.OMETHEXPR:
75 fn = ir.MethodExprName(v)
76 }
77 case ir.OCALLMETH:
78 base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck")
79 }
80
81 fntype := call.X.Type()
82 if fn != nil {
83 fntype = fn.Type()
84 }
85
86 if ks != nil && fn != nil && e.inMutualBatch(fn) {
87 for i, result := range fn.Type().Results().FieldSlice() {
88 e.expr(ks[i], ir.AsNode(result.Nname))
89 }
90 }
91
92 var recvp *ir.Node
93 if call.Op() == ir.OCALLFUNC {
94
95
96
97
98
99 argument(e.discardHole(), &call.X)
100 } else {
101 recvp = &call.X.(*ir.SelectorExpr).X
102 }
103
104 args := call.Args
105 if recv := fntype.Recv(); recv != nil {
106 if recvp == nil {
107
108
109 recvp = &args[0]
110 args = args[1:]
111 }
112
113 argumentFunc(fn, e.tagHole(ks, fn, recv), recvp)
114 }
115
116 for i, param := range fntype.Params().FieldSlice() {
117 argumentFunc(fn, e.tagHole(ks, fn, param), &args[i])
118 }
119
120 case ir.OINLCALL:
121 call := call.(*ir.InlinedCallExpr)
122 e.stmts(call.Body)
123 for i, result := range call.ReturnVars {
124 k := e.discardHole()
125 if ks != nil {
126 k = ks[i]
127 }
128 e.expr(k, result)
129 }
130
131 case ir.OAPPEND:
132 call := call.(*ir.CallExpr)
133 args := call.Args
134
135
136
137
138
139 appendeeK := ks[0]
140 if args[0].Type().Elem().HasPointers() {
141 appendeeK = e.teeHole(appendeeK, e.heapHole().deref(call, "appendee slice"))
142 }
143 argument(appendeeK, &args[0])
144
145 if call.IsDDD {
146 appendedK := e.discardHole()
147 if args[1].Type().IsSlice() && args[1].Type().Elem().HasPointers() {
148 appendedK = e.heapHole().deref(call, "appended slice...")
149 }
150 argument(appendedK, &args[1])
151 } else {
152 for i := 1; i < len(args); i++ {
153 argument(e.heapHole(), &args[i])
154 }
155 }
156
157 case ir.OCOPY:
158 call := call.(*ir.BinaryExpr)
159 argument(e.discardHole(), &call.X)
160
161 copiedK := e.discardHole()
162 if call.Y.Type().IsSlice() && call.Y.Type().Elem().HasPointers() {
163 copiedK = e.heapHole().deref(call, "copied slice")
164 }
165 argument(copiedK, &call.Y)
166
167 case ir.OPANIC:
168 call := call.(*ir.UnaryExpr)
169 argument(e.heapHole(), &call.X)
170
171 case ir.OCOMPLEX:
172 call := call.(*ir.BinaryExpr)
173 argument(e.discardHole(), &call.X)
174 argument(e.discardHole(), &call.Y)
175
176 case ir.ODELETE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
177 call := call.(*ir.CallExpr)
178 fixRecoverCall(call)
179 for i := range call.Args {
180 argument(e.discardHole(), &call.Args[i])
181 }
182
183 case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
184 call := call.(*ir.UnaryExpr)
185 argument(e.discardHole(), &call.X)
186
187 case ir.OUNSAFEADD, ir.OUNSAFESLICE:
188 call := call.(*ir.BinaryExpr)
189 argument(ks[0], &call.X)
190 argument(e.discardHole(), &call.Y)
191 }
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205
206 func (e *escape) goDeferStmt(n *ir.GoDeferStmt) {
207 k := e.heapHole()
208 if n.Op() == ir.ODEFER && e.loopDepth == 1 {
209
210
211 k = e.later(e.discardHole())
212
213
214
215 n.SetEsc(ir.EscNever)
216 }
217
218 call := n.Call
219
220 init := n.PtrInit()
221 init.Append(ir.TakeInit(call)...)
222 e.stmts(*init)
223
224
225
226 if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC {
227 if sig := call.X.Type(); sig.NumParams()+sig.NumResults() == 0 {
228 if clo, ok := call.X.(*ir.ClosureExpr); ok && n.Op() == ir.OGO {
229 clo.IsGoWrap = true
230 }
231 e.expr(k, call.X)
232 return
233 }
234 }
235
236
237 fn := ir.NewClosureFunc(n.Pos(), true)
238 fn.SetWrapper(true)
239 fn.Nname.SetType(types.NewSignature(types.LocalPkg, nil, nil, nil, nil))
240 fn.Body = []ir.Node{call}
241 if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC {
242
243 x := call.X
244 if x.Op() == ir.ONAME && x.(*ir.Name).Class == ir.PFUNC {
245 fn.WrappedFunc = call.X.(*ir.Name).Func
246 } else if x.Op() == ir.OMETHEXPR && ir.MethodExprFunc(x).Nname != nil {
247 fn.WrappedFunc = ir.MethodExprName(x).Func
248 }
249 }
250
251 clo := fn.OClosure
252 if n.Op() == ir.OGO {
253 clo.IsGoWrap = true
254 }
255
256 e.callCommon(nil, call, init, fn)
257 e.closures = append(e.closures, closure{e.spill(k, clo), clo})
258
259
260 n.Call = ir.NewCallExpr(call.Pos(), ir.OCALL, clo, nil)
261 ir.WithFunc(e.curfn, func() {
262 typecheck.Stmt(n.Call)
263 })
264 }
265
266
267
268
269 func (e *escape) rewriteArgument(argp *ir.Node, init *ir.Nodes, call ir.Node, fn *ir.Name, wrapper *ir.Func) {
270 var pragma ir.PragmaFlag
271 if fn != nil && fn.Func != nil {
272 pragma = fn.Func.Pragma
273 }
274
275
276
277
278 unsafeUintptr := func(arg0 ir.Node) bool {
279 if pragma&(ir.UintptrKeepAlive|ir.UintptrEscapes) == 0 {
280 return false
281 }
282
283
284
285
286
287 if arg0.Op() != ir.OCONVNOP || !arg0.Type().IsUintptr() {
288 return false
289 }
290 arg := arg0.(*ir.ConvExpr)
291
292 if !arg.X.Type().IsUnsafePtr() {
293 return false
294 }
295
296
297 tmp := e.wrapExpr(arg.Pos(), &arg.X, init, call, wrapper)
298
299 if pragma&ir.UintptrEscapes != 0 {
300 e.flow(e.heapHole().note(arg, "//go:uintptrescapes"), e.oldLoc(tmp))
301 }
302
303 if pragma&ir.UintptrKeepAlive != 0 {
304 call := call.(*ir.CallExpr)
305
306
307
308
309
310
311 keep := tmp
312 if keep.Class == ir.PAUTOHEAP {
313 keep = e.copyExpr(arg.Pos(), tmp, call.PtrInit(), wrapper, false)
314 }
315
316 keep.SetAddrtaken(true)
317 call.KeepAlive = append(call.KeepAlive, keep)
318 }
319
320 return true
321 }
322
323 visit := func(pos src.XPos, argp *ir.Node) {
324
325
326
327 switch arg := *argp; arg.Op() {
328 case ir.OLITERAL, ir.ONIL, ir.OMETHEXPR:
329 return
330 case ir.ONAME:
331 if arg.(*ir.Name).Class == ir.PFUNC {
332 return
333 }
334 }
335
336 if unsafeUintptr(*argp) {
337 return
338 }
339
340 if wrapper != nil {
341 e.wrapExpr(pos, argp, init, call, wrapper)
342 }
343 }
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363 if arg := *argp; arg.Op() == ir.OSLICELIT {
364 list := arg.(*ir.CompLitExpr).List
365 for i := range list {
366 el := &list[i]
367 if list[i].Op() == ir.OKEY {
368 el = &list[i].(*ir.KeyExpr).Value
369 }
370 visit(arg.Pos(), el)
371 }
372 } else {
373 visit(call.Pos(), argp)
374 }
375 }
376
377
378
379
380 func (e *escape) wrapExpr(pos src.XPos, exprp *ir.Node, init *ir.Nodes, call ir.Node, wrapper *ir.Func) *ir.Name {
381 tmp := e.copyExpr(pos, *exprp, init, e.curfn, true)
382
383 if wrapper != nil {
384
385
386
387 if call.Op() == ir.OCALLINTER && exprp == &call.(*ir.CallExpr).X.(*ir.SelectorExpr).X {
388 check := ir.NewUnaryExpr(pos, ir.OCHECKNIL, ir.NewUnaryExpr(pos, ir.OITAB, tmp))
389 init.Append(typecheck.Stmt(check))
390 }
391
392 e.oldLoc(tmp).captured = true
393
394 tmp = ir.NewClosureVar(pos, wrapper, tmp)
395 }
396
397 *exprp = tmp
398 return tmp
399 }
400
401
402
403
404 func (e *escape) copyExpr(pos src.XPos, expr ir.Node, init *ir.Nodes, fn *ir.Func, analyze bool) *ir.Name {
405 if ir.HasUniquePos(expr) {
406 pos = expr.Pos()
407 }
408
409 tmp := typecheck.TempAt(pos, fn, expr.Type())
410
411 stmts := []ir.Node{
412 ir.NewDecl(pos, ir.ODCL, tmp),
413 ir.NewAssignStmt(pos, tmp, expr),
414 }
415 typecheck.Stmts(stmts)
416 init.Append(stmts...)
417
418 if analyze {
419 e.newLoc(tmp, false)
420 e.stmts(stmts)
421 }
422
423 return tmp
424 }
425
426
427
428
429
430 func (e *escape) tagHole(ks []hole, fn *ir.Name, param *types.Field) hole {
431
432 if fn == nil {
433 return e.heapHole()
434 }
435
436 if e.inMutualBatch(fn) {
437 return e.addr(ir.AsNode(param.Nname))
438 }
439
440
441
442 var tagKs []hole
443
444 esc := parseLeaks(param.Note)
445 if x := esc.Heap(); x >= 0 {
446 tagKs = append(tagKs, e.heapHole().shift(x))
447 }
448
449 if ks != nil {
450 for i := 0; i < numEscResults; i++ {
451 if x := esc.Result(i); x >= 0 {
452 tagKs = append(tagKs, ks[i].shift(x))
453 }
454 }
455 }
456
457 return e.teeHole(tagKs...)
458 }
459
View as plain text