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