1
2
3
4
5 package walk
6
7 import (
8 "go/constant"
9 "internal/abi"
10
11 "cmd/compile/internal/base"
12 "cmd/compile/internal/ir"
13 "cmd/compile/internal/reflectdata"
14 "cmd/compile/internal/typecheck"
15 "cmd/compile/internal/types"
16 "cmd/internal/src"
17 )
18
19
20 func walkAssign(init *ir.Nodes, n ir.Node) ir.Node {
21 init.Append(ir.TakeInit(n)...)
22
23 var left, right ir.Node
24 switch n.Op() {
25 case ir.OAS:
26 n := n.(*ir.AssignStmt)
27 left, right = n.X, n.Y
28 case ir.OASOP:
29 n := n.(*ir.AssignOpStmt)
30 left, right = n.X, n.Y
31 }
32
33
34
35 var mapAppend *ir.CallExpr
36 if left.Op() == ir.OINDEXMAP && right.Op() == ir.OAPPEND {
37 left := left.(*ir.IndexExpr)
38 mapAppend = right.(*ir.CallExpr)
39 if !ir.SameSafeExpr(left, mapAppend.Args[0]) {
40 base.Fatalf("not same expressions: %v != %v", left, mapAppend.Args[0])
41 }
42 }
43
44 left = walkExpr(left, init)
45 left = safeExpr(left, init)
46 if mapAppend != nil {
47 mapAppend.Args[0] = left
48 }
49
50 if n.Op() == ir.OASOP {
51
52 n = ir.NewAssignStmt(base.Pos, left, typecheck.Expr(ir.NewBinaryExpr(base.Pos, n.(*ir.AssignOpStmt).AsOp, left, right)))
53 } else {
54 n.(*ir.AssignStmt).X = left
55 }
56 as := n.(*ir.AssignStmt)
57
58 if oaslit(as, init) {
59 return ir.NewBlockStmt(as.Pos(), nil)
60 }
61
62 if as.Y == nil {
63
64 return as
65 }
66
67 if !base.Flag.Cfg.Instrumenting && ir.IsZero(as.Y) {
68 return as
69 }
70
71 switch as.Y.Op() {
72 default:
73 as.Y = walkExpr(as.Y, init)
74
75 case ir.ORECV:
76
77
78 recv := as.Y.(*ir.UnaryExpr)
79 recv.X = walkExpr(recv.X, init)
80
81 n1 := typecheck.NodAddr(as.X)
82 r := recv.X
83 return mkcall1(chanfn("chanrecv1", 2, r.Type()), nil, init, r, n1)
84
85 case ir.OAPPEND:
86
87 call := as.Y.(*ir.CallExpr)
88 if call.Type().Elem().NotInHeap() {
89 base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", call.Type().Elem())
90 }
91 var r ir.Node
92 switch {
93 case isAppendOfMake(call):
94
95 r = extendSlice(call, init)
96 case call.IsDDD:
97 r = appendSlice(call, init)
98 default:
99 r = walkAppend(call, init, as)
100 }
101 as.Y = r
102 if r.Op() == ir.OAPPEND {
103 r := r.(*ir.CallExpr)
104
105
106
107 r.Fun = reflectdata.AppendElemRType(base.Pos, r)
108 return as
109 }
110
111
112 }
113
114 if as.X != nil && as.Y != nil {
115 return convas(as, init)
116 }
117 return as
118 }
119
120
121 func walkAssignDotType(n *ir.AssignListStmt, init *ir.Nodes) ir.Node {
122 walkExprListSafe(n.Lhs, init)
123
124 if r, ok := n.Rhs[0].(*ir.TypeAssertExpr); ok && r.Op() == ir.ODOTTYPE2 && !r.Type().IsInterface() {
125 if shapeTypeAssertImpossible(r.X, r.Type()) {
126 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, ir.BlankNode, walkExpr(r.X, init))))
127 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, n.Lhs[0], ir.NewZero(base.Pos, r.Type()))))
128 init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, n.Lhs[1], ir.NewBool(base.Pos, false))))
129 return ir.NewBlockStmt(base.Pos, nil)
130 }
131 }
132
133 n.Rhs[0] = walkExpr(n.Rhs[0], init)
134 return n
135 }
136
137
138 func walkAssignFunc(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
139 init.Append(ir.TakeInit(n)...)
140
141 r := n.Rhs[0]
142 walkExprListSafe(n.Lhs, init)
143 r = walkExpr(r, init)
144
145 if ir.IsIntrinsicCall(r.(*ir.CallExpr)) {
146 n.Rhs = []ir.Node{r}
147 return n
148 }
149 init.Append(r)
150
151 ll := ascompatet(n.Lhs, r.Type())
152 return ir.NewBlockStmt(src.NoXPos, ll)
153 }
154
155
156 func walkAssignList(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
157 init.Append(ir.TakeInit(n)...)
158 return ir.NewBlockStmt(src.NoXPos, ascompatee(ir.OAS, n.Lhs, n.Rhs))
159 }
160
161
162 func walkAssignMapRead(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
163 init.Append(ir.TakeInit(n)...)
164
165 r := n.Rhs[0].(*ir.IndexExpr)
166 walkExprListSafe(n.Lhs, init)
167
168 r.X = walkExpr(r.X, init)
169 r.Index = walkExpr(r.Index, init)
170 t := r.X.Type()
171 fast := mapfast(t)
172 key := mapKeyArg(fast, r, r.Index, false)
173
174
175
176
177
178
179 a := n.Lhs[0]
180
181 var call *ir.CallExpr
182 if w := t.Elem().Size(); w <= abi.ZeroValSize {
183 fn := mapfn(mapaccess2[fast], t, false)
184 call = mkcall1(fn, fn.Type().ResultsTuple(), init, reflectdata.IndexMapRType(base.Pos, r), r.X, key)
185 } else {
186 fn := mapfn("mapaccess2_fat", t, true)
187 z := reflectdata.ZeroAddr(w)
188 call = mkcall1(fn, fn.Type().ResultsTuple(), init, reflectdata.IndexMapRType(base.Pos, r), r.X, key, z)
189 }
190
191
192
193
194 if ok := n.Lhs[1]; !ir.IsBlank(ok) && ok.Type().IsBoolean() {
195 call.Type().Field(1).Type = ok.Type()
196 }
197 n.Rhs = []ir.Node{call}
198 n.SetOp(ir.OAS2FUNC)
199
200
201 if ir.IsBlank(a) {
202 return walkExpr(typecheck.Stmt(n), init)
203 }
204
205 var_ := typecheck.TempAt(base.Pos, ir.CurFunc, types.NewPtr(t.Elem()))
206 var_.SetTypecheck(1)
207 var_.MarkNonNil()
208
209 n.Lhs[0] = var_
210 init.Append(walkExpr(n, init))
211
212 as := ir.NewAssignStmt(base.Pos, a, ir.NewStarExpr(base.Pos, var_))
213 return walkExpr(typecheck.Stmt(as), init)
214 }
215
216
217 func walkAssignRecv(init *ir.Nodes, n *ir.AssignListStmt) ir.Node {
218 init.Append(ir.TakeInit(n)...)
219
220 r := n.Rhs[0].(*ir.UnaryExpr)
221 walkExprListSafe(n.Lhs, init)
222 r.X = walkExpr(r.X, init)
223 var n1 ir.Node
224 if ir.IsBlank(n.Lhs[0]) {
225 n1 = typecheck.NodNil()
226 } else {
227 n1 = typecheck.NodAddr(n.Lhs[0])
228 }
229 fn := chanfn("chanrecv2", 2, r.X.Type())
230 ok := n.Lhs[1]
231 call := mkcall1(fn, types.Types[types.TBOOL], init, r.X, n1)
232 return walkAssign(init, typecheck.Stmt(ir.NewAssignStmt(base.Pos, ok, call)))
233 }
234
235
236 func walkReturn(n *ir.ReturnStmt) ir.Node {
237 fn := ir.CurFunc
238
239 fn.NumReturns++
240 if len(n.Results) == 0 {
241 return n
242 }
243
244 results := fn.Type().Results()
245 dsts := make([]ir.Node, len(results))
246 for i, v := range results {
247
248 dsts[i] = typecheck.AssignExpr(v.Nname.(*ir.Name))
249 }
250
251 n.Results = ascompatee(n.Op(), dsts, n.Results)
252 return n
253 }
254
255
256
257
258
259 func ascompatet(nl ir.Nodes, nr *types.Type) []ir.Node {
260 if len(nl) != nr.NumFields() {
261 base.Fatalf("ascompatet: assignment count mismatch: %d = %d", len(nl), nr.NumFields())
262 }
263
264 var nn ir.Nodes
265 for i, l := range nl {
266 if ir.IsBlank(l) {
267 continue
268 }
269 r := nr.Field(i)
270
271
272
273 if tmp, ok := l.(*ir.Name); !ok || !tmp.AutoTemp() || !types.Identical(tmp.Type(), r.Type) {
274 base.FatalfAt(l.Pos(), "assigning %v to %+v", r.Type, l)
275 }
276
277 res := ir.NewResultExpr(base.Pos, nil, types.BADWIDTH)
278 res.Index = int64(i)
279 res.SetType(r.Type)
280 res.SetTypecheck(1)
281
282 nn.Append(ir.NewAssignStmt(base.Pos, l, res))
283 }
284 return nn
285 }
286
287
288
289
290
291 func ascompatee(op ir.Op, nl, nr []ir.Node) []ir.Node {
292
293 if len(nl) != len(nr) {
294 base.Fatalf("assignment operands mismatch: %+v / %+v", ir.Nodes(nl), ir.Nodes(nr))
295 }
296
297 var assigned ir.NameSet
298 var memWrite, deferResultWrite bool
299
300
301
302 affected := func(n ir.Node) bool {
303 if deferResultWrite {
304 return true
305 }
306 return ir.Any(n, func(n ir.Node) bool {
307 if n.Op() == ir.ONAME && assigned.Has(n.(*ir.Name)) {
308 return true
309 }
310 if memWrite && readsMemory(n) {
311 return true
312 }
313 return false
314 })
315 }
316
317
318
319
320 var early ir.Nodes
321 save := func(np *ir.Node) {
322 if n := *np; affected(n) {
323 *np = copyExpr(n, n.Type(), &early)
324 }
325 }
326
327 var late ir.Nodes
328 for i, lorig := range nl {
329 l, r := lorig, nr[i]
330
331
332 if op == ir.ORETURN && ir.SameSafeExpr(l, r) {
333 continue
334 }
335
336
337
338 for {
339
340
341
342 init := ir.TakeInit(l)
343 walkStmtList(init)
344 early.Append(init...)
345
346 switch ll := l.(type) {
347 case *ir.IndexExpr:
348 if ll.X.Type().IsArray() {
349 save(&ll.Index)
350 l = ll.X
351 continue
352 }
353 case *ir.ParenExpr:
354 l = ll.X
355 continue
356 case *ir.SelectorExpr:
357 if ll.Op() == ir.ODOT {
358 l = ll.X
359 continue
360 }
361 }
362 break
363 }
364
365 var name *ir.Name
366 switch l.Op() {
367 default:
368 base.Fatalf("unexpected lvalue %v", l.Op())
369 case ir.ONAME:
370 name = l.(*ir.Name)
371 case ir.OINDEX, ir.OINDEXMAP:
372 l := l.(*ir.IndexExpr)
373 save(&l.X)
374 save(&l.Index)
375 case ir.ODEREF:
376 l := l.(*ir.StarExpr)
377 save(&l.X)
378 case ir.ODOTPTR:
379 l := l.(*ir.SelectorExpr)
380 save(&l.X)
381 }
382
383
384 save(&r)
385
386 appendWalkStmt(&late, convas(ir.NewAssignStmt(base.Pos, lorig, r), &late))
387
388
389
390
391 if name == nil {
392
393
394 memWrite = true
395 continue
396 }
397
398 if name.Class == ir.PPARAMOUT && ir.CurFunc.HasDefer() {
399
400
401
402 deferResultWrite = true
403 continue
404 }
405
406 if ir.IsBlank(name) {
407
408
409 continue
410 }
411
412 if name.Addrtaken() || !name.OnStack() {
413
414
415 memWrite = true
416 continue
417 }
418
419
420
421 assigned.Add(name)
422 }
423
424 early.Append(late.Take()...)
425 return early
426 }
427
428
429
430 func readsMemory(n ir.Node) bool {
431 switch n.Op() {
432 case ir.ONAME:
433 n := n.(*ir.Name)
434 if n.Class == ir.PFUNC {
435 return false
436 }
437 return n.Addrtaken() || !n.OnStack()
438
439 case ir.OADD,
440 ir.OAND,
441 ir.OANDAND,
442 ir.OANDNOT,
443 ir.OBITNOT,
444 ir.OCONV,
445 ir.OCONVIFACE,
446 ir.OCONVNOP,
447 ir.ODIV,
448 ir.ODOT,
449 ir.ODOTTYPE,
450 ir.OLITERAL,
451 ir.OLSH,
452 ir.OMOD,
453 ir.OMUL,
454 ir.ONEG,
455 ir.ONIL,
456 ir.OOR,
457 ir.OOROR,
458 ir.OPAREN,
459 ir.OPLUS,
460 ir.ORSH,
461 ir.OSUB,
462 ir.OXOR:
463 return false
464 }
465
466
467 return true
468 }
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486 func appendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
487 walkAppendArgs(n, init)
488
489 l1 := n.Args[0]
490 l2 := n.Args[1]
491 l2 = cheapExpr(l2, init)
492 n.Args[1] = l2
493
494 var nodes ir.Nodes
495
496
497 s := typecheck.TempAt(base.Pos, ir.CurFunc, l1.Type())
498 nodes.Append(ir.NewAssignStmt(base.Pos, s, l1))
499
500 elemtype := s.Type().Elem()
501
502
503 oldPtr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
504 oldLen := ir.NewUnaryExpr(base.Pos, ir.OLEN, s)
505 oldCap := ir.NewUnaryExpr(base.Pos, ir.OCAP, s)
506
507
508 num := ir.NewUnaryExpr(base.Pos, ir.OLEN, l2)
509
510
511 newLen := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
512 nodes.Append(ir.NewAssignStmt(base.Pos, newLen, ir.NewBinaryExpr(base.Pos, ir.OADD, oldLen, num)))
513
514
515 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
516 nuint := typecheck.Conv(newLen, types.Types[types.TUINT])
517 scapuint := typecheck.Conv(oldCap, types.Types[types.TUINT])
518 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLE, nuint, scapuint)
519 nif.Likely = true
520
521
522 slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, nil, newLen, nil)
523 slice.SetBounded(true)
524 nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, slice)}
525
526
527 call := walkGrowslice(s, nif.PtrInit(), oldPtr, newLen, oldCap, num)
528 nif.Else = []ir.Node{ir.NewAssignStmt(base.Pos, s, call)}
529
530 nodes.Append(nif)
531
532
533
534
535
536
537
538 idx := ir.NewBinaryExpr(base.Pos, ir.OSUB, newLen, ir.NewUnaryExpr(base.Pos, ir.OLEN, l2))
539
540 var ncopy ir.Node
541 if elemtype.HasPointers() {
542
543 slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, idx, nil, nil)
544 slice.SetType(s.Type())
545 slice.SetBounded(true)
546
547 ir.CurFunc.SetWBPos(n.Pos())
548
549
550 fn := typecheck.LookupRuntime("typedslicecopy", l1.Type().Elem(), l2.Type().Elem())
551 ptr1, len1 := backingArrayPtrLen(cheapExpr(slice, &nodes))
552 ptr2, len2 := backingArrayPtrLen(l2)
553 ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, reflectdata.AppendElemRType(base.Pos, n), ptr1, len1, ptr2, len2)
554 } else if base.Flag.Cfg.Instrumenting && !base.Flag.CompilingRuntime {
555
556
557
558 slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, idx, nil, nil)
559 slice.SetType(s.Type())
560 slice.SetBounded(true)
561
562 ptr1, len1 := backingArrayPtrLen(cheapExpr(slice, &nodes))
563 ptr2, len2 := backingArrayPtrLen(l2)
564
565 fn := typecheck.LookupRuntime("slicecopy", ptr1.Type().Elem(), ptr2.Type().Elem())
566 ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, ptr1, len1, ptr2, len2, ir.NewInt(base.Pos, elemtype.Size()))
567 } else {
568
569 ix := ir.NewIndexExpr(base.Pos, s, idx)
570 ix.SetBounded(true)
571 addr := typecheck.NodAddr(ix)
572
573 sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, l2)
574
575 nwid := cheapExpr(typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, l2), types.Types[types.TUINTPTR]), &nodes)
576 nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(base.Pos, elemtype.Size()))
577
578
579 fn := typecheck.LookupRuntime("memmove", elemtype, elemtype)
580 ncopy = mkcall1(fn, nil, &nodes, addr, sptr, nwid)
581 }
582 ln := append(nodes, ncopy)
583
584 typecheck.Stmts(ln)
585 walkStmtList(ln)
586 init.Append(ln...)
587 return s
588 }
589
590
591
592 func isAppendOfMake(n ir.Node) bool {
593 if base.Flag.N != 0 || base.Flag.Cfg.Instrumenting {
594 return false
595 }
596
597 if n.Typecheck() == 0 {
598 base.Fatalf("missing typecheck: %+v", n)
599 }
600
601 if n.Op() != ir.OAPPEND {
602 return false
603 }
604 call := n.(*ir.CallExpr)
605 if !call.IsDDD || len(call.Args) != 2 || call.Args[1].Op() != ir.OMAKESLICE {
606 return false
607 }
608
609 mk := call.Args[1].(*ir.MakeExpr)
610 if mk.Cap != nil {
611 return false
612 }
613
614
615
616
617
618
619
620 y := mk.Len
621 if !ir.IsConst(y, constant.Int) && y.Type().Size() > types.Types[types.TUINT].Size() {
622 return false
623 }
624
625 return true
626 }
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659 func extendSlice(n *ir.CallExpr, init *ir.Nodes) ir.Node {
660
661
662
663 l2 := typecheck.Conv(n.Args[1].(*ir.MakeExpr).Len, types.Types[types.TINT])
664 l2 = typecheck.Expr(l2)
665 n.Args[1] = l2
666
667 walkAppendArgs(n, init)
668
669 l1 := n.Args[0]
670 l2 = n.Args[1]
671
672 var nodes []ir.Node
673
674
675 nifneg := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGE, l2, ir.NewInt(base.Pos, 0)), nil, nil)
676 nifneg.Likely = true
677
678
679 nifneg.Else = []ir.Node{mkcall("panicmakeslicelen", nil, init)}
680 nodes = append(nodes, nifneg)
681
682
683 s := typecheck.TempAt(base.Pos, ir.CurFunc, l1.Type())
684 nodes = append(nodes, ir.NewAssignStmt(base.Pos, s, l1))
685
686
687
688
689 nifnz := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.ONE, l2, ir.NewInt(base.Pos, 0)), nil, nil)
690 nifnz.Likely = true
691 nodes = append(nodes, nifnz)
692
693 elemtype := s.Type().Elem()
694
695
696 nn := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
697 nifnz.Body = append(nifnz.Body, ir.NewAssignStmt(base.Pos, nn, ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), l2)))
698
699
700 nuint := typecheck.Conv(nn, types.Types[types.TUINT])
701 capuint := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OCAP, s), types.Types[types.TUINT])
702 nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLE, nuint, capuint), nil, nil)
703 nif.Likely = true
704
705
706 nt := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, nil, nn, nil)
707 nt.SetBounded(true)
708 nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, nt)}
709
710
711 nif.Else = []ir.Node{
712 ir.NewAssignStmt(base.Pos, s, walkGrowslice(s, nif.PtrInit(),
713 ir.NewUnaryExpr(base.Pos, ir.OSPTR, s),
714 nn,
715 ir.NewUnaryExpr(base.Pos, ir.OCAP, s),
716 l2)),
717 }
718
719 nifnz.Body = append(nifnz.Body, nif)
720
721
722
723 ix := ir.NewIndexExpr(base.Pos, s, ir.NewBinaryExpr(base.Pos, ir.OSUB, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), l2))
724 ix.SetBounded(true)
725 hp := typecheck.ConvNop(typecheck.NodAddr(ix), types.Types[types.TUNSAFEPTR])
726
727
728 hn := typecheck.Conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, l2, ir.NewInt(base.Pos, elemtype.Size())), types.Types[types.TUINTPTR])
729
730 clrname := "memclrNoHeapPointers"
731 hasPointers := elemtype.HasPointers()
732 if hasPointers {
733 clrname = "memclrHasPointers"
734 ir.CurFunc.SetWBPos(n.Pos())
735 }
736
737 var clr ir.Nodes
738 clrfn := mkcall(clrname, nil, &clr, hp, hn)
739 clr.Append(clrfn)
740 if hasPointers {
741
742
743 nif.Body = append(nif.Body, clr...)
744 } else {
745 nifnz.Body = append(nifnz.Body, clr...)
746 }
747
748 typecheck.Stmts(nodes)
749 walkStmtList(nodes)
750 init.Append(nodes...)
751 return s
752 }
753
View as plain text