1
2
3
4
5 package walk
6
7 import (
8 "fmt"
9 "go/constant"
10 "go/token"
11 "internal/abi"
12 "strings"
13
14 "cmd/compile/internal/base"
15 "cmd/compile/internal/escape"
16 "cmd/compile/internal/ir"
17 "cmd/compile/internal/reflectdata"
18 "cmd/compile/internal/typecheck"
19 "cmd/compile/internal/types"
20 )
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 func walkAppend(n *ir.CallExpr, init *ir.Nodes, dst ir.Node) ir.Node {
45 if !ir.SameSafeExpr(dst, n.Args[0]) {
46 n.Args[0] = safeExpr(n.Args[0], init)
47 n.Args[0] = walkExpr(n.Args[0], init)
48 }
49 walkExprListSafe(n.Args[1:], init)
50
51 nsrc := n.Args[0]
52
53
54
55
56
57
58
59 ls := n.Args[1:]
60 for i, n := range ls {
61 n = cheapExpr(n, init)
62 if !types.Identical(n.Type(), nsrc.Type().Elem()) {
63 n = typecheck.AssignConv(n, nsrc.Type().Elem(), "append")
64 n = walkExpr(n, init)
65 }
66 ls[i] = n
67 }
68
69 argc := len(n.Args) - 1
70 if argc < 1 {
71 return nsrc
72 }
73
74
75
76 if !base.Flag.Cfg.Instrumenting || base.Flag.CompilingRuntime {
77 return n
78 }
79
80 var l []ir.Node
81
82
83 s := typecheck.TempAt(base.Pos, ir.CurFunc, nsrc.Type())
84 l = append(l, ir.NewAssignStmt(base.Pos, s, nsrc))
85
86
87 num := ir.NewInt(base.Pos, int64(argc))
88
89
90 newLen := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
91 l = append(l, ir.NewAssignStmt(base.Pos, newLen, ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), num)))
92
93
94 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
95 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLE, typecheck.Conv(newLen, types.Types[types.TUINT]), typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OCAP, s), types.Types[types.TUINT]))
96 nif.Likely = true
97
98
99 slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, nil, newLen, nil)
100 slice.SetBounded(true)
101 nif.Body = []ir.Node{
102 ir.NewAssignStmt(base.Pos, s, slice),
103 }
104
105
106 nif.Else = []ir.Node{
107 ir.NewAssignStmt(base.Pos, s, walkGrowslice(s, nif.PtrInit(),
108 ir.NewUnaryExpr(base.Pos, ir.OSPTR, s),
109 newLen,
110 ir.NewUnaryExpr(base.Pos, ir.OCAP, s),
111 num)),
112 }
113
114 l = append(l, nif)
115
116 ls = n.Args[1:]
117 for i, n := range ls {
118
119 ix := ir.NewIndexExpr(base.Pos, s, ir.NewBinaryExpr(base.Pos, ir.OSUB, newLen, ir.NewInt(base.Pos, int64(argc-i))))
120 ix.SetBounded(true)
121 l = append(l, ir.NewAssignStmt(base.Pos, ix, n))
122 }
123
124 typecheck.Stmts(l)
125 walkStmtList(l)
126 init.Append(l...)
127 return s
128 }
129
130
131 func walkGrowslice(slice *ir.Name, init *ir.Nodes, oldPtr, newLen, oldCap, num ir.Node) *ir.CallExpr {
132 elemtype := slice.Type().Elem()
133 fn := typecheck.LookupRuntime("growslice", elemtype, elemtype)
134 elemtypeptr := reflectdata.TypePtrAt(base.Pos, elemtype)
135 return mkcall1(fn, slice.Type(), init, oldPtr, newLen, oldCap, num, elemtypeptr)
136 }
137
138
139 func walkClear(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
140 x := walkExpr(n.X, init)
141 typ := n.X.Type()
142 switch {
143 case typ.IsSlice():
144 if n := arrayClear(x.Pos(), x, nil); n != nil {
145 return n
146 }
147
148 return ir.NewBlockStmt(n.Pos(), nil)
149 case typ.IsMap():
150 return mapClear(x, reflectdata.TypePtrAt(x.Pos(), typ))
151 }
152 panic("unreachable")
153 }
154
155
156 func walkClose(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
157 return mkcall1(chanfn("closechan", 1, n.X.Type()), nil, init, n.X)
158 }
159
160
161
162
163
164
165
166
167
168
169
170 func walkCopy(n *ir.BinaryExpr, init *ir.Nodes, runtimecall bool) ir.Node {
171 if n.X.Type().Elem().HasPointers() {
172 ir.CurFunc.SetWBPos(n.Pos())
173 fn := writebarrierfn("typedslicecopy", n.X.Type().Elem(), n.Y.Type().Elem())
174 n.X = cheapExpr(n.X, init)
175 ptrL, lenL := backingArrayPtrLen(n.X)
176 n.Y = cheapExpr(n.Y, init)
177 ptrR, lenR := backingArrayPtrLen(n.Y)
178 return mkcall1(fn, n.Type(), init, reflectdata.CopyElemRType(base.Pos, n), ptrL, lenL, ptrR, lenR)
179 }
180
181 if runtimecall {
182
183
184
185
186 n.X = cheapExpr(n.X, init)
187 ptrL, lenL := backingArrayPtrLen(n.X)
188 n.Y = cheapExpr(n.Y, init)
189 ptrR, lenR := backingArrayPtrLen(n.Y)
190
191 fn := typecheck.LookupRuntime("slicecopy", ptrL.Type().Elem(), ptrR.Type().Elem())
192
193 return mkcall1(fn, n.Type(), init, ptrL, lenL, ptrR, lenR, ir.NewInt(base.Pos, n.X.Type().Elem().Size()))
194 }
195
196 n.X = walkExpr(n.X, init)
197 n.Y = walkExpr(n.Y, init)
198 nl := typecheck.TempAt(base.Pos, ir.CurFunc, n.X.Type())
199 nr := typecheck.TempAt(base.Pos, ir.CurFunc, n.Y.Type())
200 var l []ir.Node
201 l = append(l, ir.NewAssignStmt(base.Pos, nl, n.X))
202 l = append(l, ir.NewAssignStmt(base.Pos, nr, n.Y))
203
204 nfrm := ir.NewUnaryExpr(base.Pos, ir.OSPTR, nr)
205 nto := ir.NewUnaryExpr(base.Pos, ir.OSPTR, nl)
206
207 nlen := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
208
209
210 l = append(l, ir.NewAssignStmt(base.Pos, nlen, ir.NewUnaryExpr(base.Pos, ir.OLEN, nl)))
211
212
213 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
214
215 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OGT, nlen, ir.NewUnaryExpr(base.Pos, ir.OLEN, nr))
216 nif.Body.Append(ir.NewAssignStmt(base.Pos, nlen, ir.NewUnaryExpr(base.Pos, ir.OLEN, nr)))
217 l = append(l, nif)
218
219
220 ne := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.ONE, nto, nfrm), nil, nil)
221 ne.Likely = true
222 l = append(l, ne)
223
224 fn := typecheck.LookupRuntime("memmove", nl.Type().Elem(), nl.Type().Elem())
225 nwid := ir.Node(typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TUINTPTR]))
226 setwid := ir.NewAssignStmt(base.Pos, nwid, typecheck.Conv(nlen, types.Types[types.TUINTPTR]))
227 ne.Body.Append(setwid)
228 nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(base.Pos, nl.Type().Elem().Size()))
229 call := mkcall1(fn, nil, init, nto, nfrm, nwid)
230 ne.Body.Append(call)
231
232 typecheck.Stmts(l)
233 walkStmtList(l)
234 init.Append(l...)
235 return nlen
236 }
237
238
239 func walkDelete(init *ir.Nodes, n *ir.CallExpr) ir.Node {
240 init.Append(ir.TakeInit(n)...)
241 map_ := n.Args[0]
242 key := n.Args[1]
243 map_ = walkExpr(map_, init)
244 key = walkExpr(key, init)
245
246 t := map_.Type()
247 fast := mapfast(t)
248 key = mapKeyArg(fast, n, key, false)
249 return mkcall1(mapfndel(mapdelete[fast], t), nil, init, reflectdata.DeleteMapRType(base.Pos, n), map_, key)
250 }
251
252
253 func walkLenCap(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
254 if isRuneCount(n) {
255
256 return mkcall("countrunes", n.Type(), init, typecheck.Conv(n.X.(*ir.ConvExpr).X, types.Types[types.TSTRING]))
257 }
258 if isByteCount(n) {
259 conv := n.X.(*ir.ConvExpr)
260 walkStmtList(conv.Init())
261 init.Append(ir.TakeInit(conv)...)
262 _, len := backingArrayPtrLen(cheapExpr(conv.X, init))
263 return len
264 }
265 if isChanLenCap(n) {
266 name := "chanlen"
267 if n.Op() == ir.OCAP {
268 name = "chancap"
269 }
270
271
272 fn := typecheck.LookupRuntime(name, n.X.Type())
273 return mkcall1(fn, n.Type(), init, n.X)
274 }
275
276 n.X = walkExpr(n.X, init)
277
278
279
280 t := n.X.Type()
281 if t.IsPtr() {
282 t = t.Elem()
283 }
284 if t.IsArray() {
285
286 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, ir.BlankNode, n.X))
287
288 con := ir.NewConstExpr(constant.MakeInt64(t.NumElem()), n)
289 con.SetTypecheck(1)
290 return con
291 }
292 return n
293 }
294
295
296 func walkMakeChan(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
297
298
299 size := n.Len
300 fnname := "makechan64"
301 argtype := types.Types[types.TINT64]
302
303
304
305
306 if size.Type().IsKind(types.TIDEAL) || size.Type().Size() <= types.Types[types.TUINT].Size() {
307 fnname = "makechan"
308 argtype = types.Types[types.TINT]
309 }
310
311 return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, reflectdata.MakeChanRType(base.Pos, n), typecheck.Conv(size, argtype))
312 }
313
314
315 func walkMakeMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
316 t := n.Type()
317 mapType := reflectdata.MapType()
318 hint := n.Len
319
320
321 var m ir.Node
322 if n.Esc() == ir.EscNone {
323
324
325
326
327 m = stackTempAddr(init, mapType)
328
329
330
331
332
333
334 if !ir.IsConst(hint, constant.Int) ||
335 constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(abi.MapGroupSlots)) {
336
337
338
339
340
341
342
343
344
345
346
347
348 nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLE, hint, ir.NewInt(base.Pos, abi.MapGroupSlots)), nil, nil)
349 nif.Likely = true
350
351 groupType := reflectdata.MapGroupType(t)
352
353
354
355 g := stackTempAddr(&nif.Body, groupType)
356
357
358
359 empty := ir.NewBasicLit(base.Pos, types.UntypedInt, constant.MakeUint64(abi.MapCtrlEmpty))
360
361
362 csym := groupType.Field(0).Sym
363 ca := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, g, csym), empty)
364 nif.Body.Append(ca)
365
366
367 dsym := mapType.Field(2).Sym
368 na := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, m, dsym), typecheck.ConvNop(g, types.Types[types.TUNSAFEPTR]))
369 nif.Body.Append(na)
370 appendWalkStmt(init, nif)
371 }
372 }
373
374 if ir.IsConst(hint, constant.Int) && constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(abi.MapGroupSlots)) {
375
376
377
378
379
380
381
382 if n.Esc() == ir.EscNone {
383
384
385
386 rand := mkcall("rand", types.Types[types.TUINT64], init)
387 seedSym := mapType.Field(1).Sym
388 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, m, seedSym), typecheck.Conv(rand, types.Types[types.TUINTPTR])))
389 return typecheck.ConvNop(m, t)
390 }
391
392
393 fn := typecheck.LookupRuntime("makemap_small", t.Key(), t.Elem())
394 return mkcall1(fn, n.Type(), init)
395 }
396
397 if n.Esc() != ir.EscNone {
398 m = typecheck.NodNil()
399 }
400
401
402
403
404
405
406
407
408 fnname := "makemap64"
409 argtype := types.Types[types.TINT64]
410
411
412
413
414
415 if hint.Type().IsKind(types.TIDEAL) || hint.Type().Size() <= types.Types[types.TUINT].Size() {
416 fnname = "makemap"
417 argtype = types.Types[types.TINT]
418 }
419
420 fn := typecheck.LookupRuntime(fnname, mapType, t.Key(), t.Elem())
421 return mkcall1(fn, n.Type(), init, reflectdata.MakeMapRType(base.Pos, n), typecheck.Conv(hint, argtype), m)
422 }
423
424
425 func walkMakeSlice(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
426 len := n.Len
427 cap := n.Cap
428 len = safeExpr(len, init)
429 if cap != nil {
430 cap = safeExpr(cap, init)
431 } else {
432 cap = len
433 }
434 t := n.Type()
435 if t.Elem().NotInHeap() {
436 base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
437 }
438
439 tryStack := false
440 if n.Esc() == ir.EscNone {
441 if why := escape.HeapAllocReason(n); why != "" {
442 base.Fatalf("%v has EscNone, but %v", n, why)
443 }
444 if ir.IsSmallIntConst(cap) {
445
446 cap := typecheck.IndexConst(cap)
447
448
449
450
451
452
453
454
455 nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(len, types.Types[types.TUINT64]), ir.NewInt(base.Pos, cap)), nil, nil)
456 niflen := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLT, len, ir.NewInt(base.Pos, 0)), nil, nil)
457 niflen.Body = []ir.Node{mkcall("panicmakeslicelen", nil, init)}
458 nif.Body.Append(niflen, mkcall("panicmakeslicecap", nil, init))
459 appendWalkStmt(init, nif)
460
461
462
463 t := types.NewArray(t.Elem(), cap)
464 arr := typecheck.TempAt(base.Pos, ir.CurFunc, t)
465 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, arr, nil))
466 s := ir.NewSliceExpr(base.Pos, ir.OSLICE, arr, nil, len, nil)
467
468 return walkExpr(typecheck.Expr(typecheck.Conv(s, n.Type())), init)
469 }
470
471 tryStack = base.Flag.N == 0 && base.VariableMakeHash.MatchPos(n.Pos(), nil)
472 }
473
474
475 slice := typecheck.TempAt(base.Pos, ir.CurFunc, n.Type())
476
477 if tryStack {
478
479
480
481
482
483
484
485 maxStackSize := int64(base.Debug.VariableMakeThreshold)
486 K := maxStackSize / t.Elem().Size()
487 if K > 0 {
488 nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLE, typecheck.Conv(cap, types.Types[types.TUINT64]), ir.NewInt(base.Pos, K)), nil, nil)
489
490
491
492
493
494 lenCap := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(len, types.Types[types.TUINT64]), typecheck.Conv(cap, types.Types[types.TUINT64])), nil, nil)
495 lenZero := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLT, len, ir.NewInt(base.Pos, 0)), nil, nil)
496 lenZero.Body.Append(mkcall("panicmakeslicelen", nil, &lenZero.Body))
497 lenCap.Body.Append(lenZero)
498 lenCap.Body.Append(mkcall("panicmakeslicecap", nil, &lenCap.Body))
499 nif.Body.Append(lenCap)
500
501 t := types.NewArray(t.Elem(), K)
502
503
504
505
506
507 field := typecheck.Lookup("arr")
508 t = types.NewStruct([]*types.Field{
509 {Sym: types.BlankSym, Type: types.NewArray(types.Types[types.TUINTPTR], 0)},
510 {Sym: field, Type: t},
511 })
512 t.SetNoalg(true)
513 store := typecheck.TempAt(base.Pos, ir.CurFunc, t)
514 nif.Body.Append(ir.NewAssignStmt(base.Pos, store, nil))
515 arr := ir.NewSelectorExpr(base.Pos, ir.ODOT, store, field)
516 s := ir.NewSliceExpr(base.Pos, ir.OSLICE, arr, nil, len, cap)
517 nif.Body.Append(ir.NewAssignStmt(base.Pos, slice, s))
518
519 appendWalkStmt(init, typecheck.Stmt(nif))
520
521
522 init = &nif.Else
523 }
524 }
525
526
527
528
529 fnname := "makeslice64"
530 argtype := types.Types[types.TINT64]
531
532
533
534
535 if (len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size()) &&
536 (cap.Type().IsKind(types.TIDEAL) || cap.Type().Size() <= types.Types[types.TUINT].Size()) {
537 fnname = "makeslice"
538 argtype = types.Types[types.TINT]
539 }
540 fn := typecheck.LookupRuntime(fnname)
541 ptr := mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.MakeSliceElemRType(base.Pos, n), typecheck.Conv(len, argtype), typecheck.Conv(cap, argtype))
542 ptr.MarkNonNil()
543 len = typecheck.Conv(len, types.Types[types.TINT])
544 cap = typecheck.Conv(cap, types.Types[types.TINT])
545 s := ir.NewSliceHeaderExpr(base.Pos, t, ptr, len, cap)
546 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, slice, s))
547
548 return slice
549 }
550
551
552 func walkMakeSliceCopy(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
553 if n.Esc() == ir.EscNone {
554 base.Fatalf("OMAKESLICECOPY with EscNone: %v", n)
555 }
556
557 t := n.Type()
558 if t.Elem().NotInHeap() {
559 base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
560 }
561
562 length := typecheck.Conv(n.Len, types.Types[types.TINT])
563 copylen := ir.NewUnaryExpr(base.Pos, ir.OLEN, n.Cap)
564 copyptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, n.Cap)
565
566 if !t.Elem().HasPointers() && n.Bounded() {
567
568
569
570
571
572
573 size := ir.NewBinaryExpr(base.Pos, ir.OMUL, typecheck.Conv(length, types.Types[types.TUINTPTR]), typecheck.Conv(ir.NewInt(base.Pos, t.Elem().Size()), types.Types[types.TUINTPTR]))
574
575
576 fn := typecheck.LookupRuntime("mallocgc")
577 ptr := mkcall1(fn, types.Types[types.TUNSAFEPTR], init, size, typecheck.NodNil(), ir.NewBool(base.Pos, false))
578 ptr.MarkNonNil()
579 sh := ir.NewSliceHeaderExpr(base.Pos, t, ptr, length, length)
580
581 s := typecheck.TempAt(base.Pos, ir.CurFunc, t)
582 r := typecheck.Stmt(ir.NewAssignStmt(base.Pos, s, sh))
583 r = walkExpr(r, init)
584 init.Append(r)
585
586
587 fn = typecheck.LookupRuntime("memmove", t.Elem(), t.Elem())
588 ncopy := mkcall1(fn, nil, init, ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), copyptr, size)
589 init.Append(walkExpr(typecheck.Stmt(ncopy), init))
590
591 return s
592 }
593
594
595 fn := typecheck.LookupRuntime("makeslicecopy")
596 ptr := mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.MakeSliceElemRType(base.Pos, n), length, copylen, typecheck.Conv(copyptr, types.Types[types.TUNSAFEPTR]))
597 ptr.MarkNonNil()
598 sh := ir.NewSliceHeaderExpr(base.Pos, t, ptr, length, length)
599 return walkExpr(typecheck.Expr(sh), init)
600 }
601
602
603 func walkNew(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
604 t := n.Type().Elem()
605 if t.NotInHeap() {
606 base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", n.Type().Elem())
607 }
608 if n.Esc() == ir.EscNone {
609 if t.Size() > ir.MaxImplicitStackVarSize {
610 base.Fatalf("large ONEW with EscNone: %v", n)
611 }
612 return stackTempAddr(init, t)
613 }
614 types.CalcSize(t)
615 n.MarkNonNil()
616 return n
617 }
618
619 func walkMinMax(n *ir.CallExpr, init *ir.Nodes) ir.Node {
620 init.Append(ir.TakeInit(n)...)
621 walkExprList(n.Args, init)
622 return n
623 }
624
625
626 func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
627
628 walkExprListCheap(nn.Args, init)
629
630
631 if nn.Op() == ir.OPRINTLN {
632 s := nn.Args
633 t := make([]ir.Node, 0, len(s)*2)
634 for i, n := range s {
635 if i != 0 {
636 t = append(t, ir.NewString(base.Pos, " "))
637 }
638 t = append(t, n)
639 }
640 t = append(t, ir.NewString(base.Pos, "\n"))
641 nn.Args = t
642 }
643
644
645 s := nn.Args
646 t := make([]ir.Node, 0, len(s))
647 for i := 0; i < len(s); {
648 var strs []string
649 for i < len(s) && ir.IsConst(s[i], constant.String) {
650 strs = append(strs, ir.StringVal(s[i]))
651 i++
652 }
653 if len(strs) > 0 {
654 t = append(t, ir.NewString(base.Pos, strings.Join(strs, "")))
655 }
656 if i < len(s) {
657 t = append(t, s[i])
658 i++
659 }
660 }
661 nn.Args = t
662
663 calls := []ir.Node{mkcall("printlock", nil, init)}
664 for i, n := range nn.Args {
665 if n.Op() == ir.OLITERAL {
666 if n.Type() == types.UntypedRune {
667 n = typecheck.DefaultLit(n, types.RuneType)
668 }
669
670 switch n.Val().Kind() {
671 case constant.Int:
672 n = typecheck.DefaultLit(n, types.Types[types.TINT64])
673
674 case constant.Float:
675 n = typecheck.DefaultLit(n, types.Types[types.TFLOAT64])
676 }
677 }
678
679 if n.Op() != ir.OLITERAL && n.Type() != nil && n.Type().Kind() == types.TIDEAL {
680 n = typecheck.DefaultLit(n, types.Types[types.TINT64])
681 }
682 n = typecheck.DefaultLit(n, nil)
683 nn.Args[i] = n
684 if n.Type() == nil || n.Type().Kind() == types.TFORW {
685 continue
686 }
687
688 var on *ir.Name
689 switch n.Type().Kind() {
690 case types.TINTER:
691 if n.Type().IsEmptyInterface() {
692 on = typecheck.LookupRuntime("printeface", n.Type())
693 } else {
694 on = typecheck.LookupRuntime("printiface", n.Type())
695 }
696 case types.TPTR:
697 if n.Type().Elem().NotInHeap() {
698 on = typecheck.LookupRuntime("printuintptr")
699 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
700 n.SetType(types.Types[types.TUNSAFEPTR])
701 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
702 n.SetType(types.Types[types.TUINTPTR])
703 break
704 }
705 fallthrough
706 case types.TCHAN, types.TMAP, types.TFUNC, types.TUNSAFEPTR:
707 on = typecheck.LookupRuntime("printpointer", n.Type())
708 case types.TSLICE:
709 on = typecheck.LookupRuntime("printslice", n.Type())
710 case types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
711 if types.RuntimeSymName(n.Type().Sym()) == "hex" {
712 on = typecheck.LookupRuntime("printhex")
713 } else {
714 on = typecheck.LookupRuntime("printuint")
715 }
716 case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64:
717 on = typecheck.LookupRuntime("printint")
718 case types.TFLOAT32:
719 on = typecheck.LookupRuntime("printfloat32")
720 case types.TFLOAT64:
721 on = typecheck.LookupRuntime("printfloat64")
722 case types.TCOMPLEX64:
723 on = typecheck.LookupRuntime("printcomplex64")
724 case types.TCOMPLEX128:
725 on = typecheck.LookupRuntime("printcomplex128")
726 case types.TBOOL:
727 on = typecheck.LookupRuntime("printbool")
728 case types.TSTRING:
729 cs := ""
730 if ir.IsConst(n, constant.String) {
731 cs = ir.StringVal(n)
732 }
733
734 if types.RuntimeSymName(n.Type().Sym()) == "quoted" {
735 on = typecheck.LookupRuntime("printquoted")
736 } else {
737 switch cs {
738 case " ":
739 on = typecheck.LookupRuntime("printsp")
740 case "\n":
741 on = typecheck.LookupRuntime("printnl")
742 default:
743 on = typecheck.LookupRuntime("printstring")
744 }
745 }
746 default:
747 badtype(ir.OPRINT, n.Type(), nil)
748 continue
749 }
750
751 r := ir.NewCallExpr(base.Pos, ir.OCALL, on, nil)
752 if params := on.Type().Params(); len(params) > 0 {
753 t := params[0].Type
754 n = typecheck.Conv(n, t)
755 r.Args.Append(n)
756 }
757 calls = append(calls, r)
758 }
759
760 calls = append(calls, mkcall("printunlock", nil, init))
761
762 typecheck.Stmts(calls)
763 walkExprList(calls, init)
764
765 r := ir.NewBlockStmt(base.Pos, nil)
766 r.List = calls
767 return walkStmt(typecheck.Stmt(r))
768 }
769
770
771 func walkRecover(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
772 return mkcall("gorecover", nn.Type(), init)
773 }
774
775
776 func walkUnsafeData(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
777 slice := walkExpr(n.X, init)
778 res := typecheck.Expr(ir.NewUnaryExpr(n.Pos(), ir.OSPTR, slice))
779 res.SetType(n.Type())
780 return walkExpr(res, init)
781 }
782
783 func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
784 ptr := safeExpr(n.X, init)
785 len := safeExpr(n.Y, init)
786 sliceType := n.Type()
787
788 lenType := types.Types[types.TINT64]
789 unsafePtr := typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR])
790
791
792
793
794
795
796 if ir.ShouldCheckPtr(ir.CurFunc, 1) {
797 fnname := "unsafeslicecheckptr"
798 fn := typecheck.LookupRuntime(fnname)
799 init.Append(mkcall1(fn, nil, init, reflectdata.UnsafeSliceElemRType(base.Pos, n), unsafePtr, typecheck.Conv(len, lenType)))
800 } else {
801
802
803 if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() {
804 lenType = types.Types[types.TINT]
805 } else {
806
807
808
809
810 len64 := typecheck.Conv(len, lenType)
811 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
812 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, typecheck.Conv(typecheck.Conv(len64, types.Types[types.TINT]), lenType), len64)
813 nif.Body.Append(mkcall("panicunsafeslicelen", nil, &nif.Body))
814 appendWalkStmt(init, nif)
815 }
816
817
818 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
819 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, typecheck.Conv(len, lenType), ir.NewInt(base.Pos, 0))
820 nif.Body.Append(mkcall("panicunsafeslicelen", nil, &nif.Body))
821 appendWalkStmt(init, nif)
822
823 if sliceType.Elem().Size() == 0 {
824
825
826
827 nifPtr := ir.NewIfStmt(base.Pos, nil, nil, nil)
828 isNil := ir.NewBinaryExpr(base.Pos, ir.OEQ, unsafePtr, typecheck.NodNil())
829 gtZero := ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(len, lenType), ir.NewInt(base.Pos, 0))
830 nifPtr.Cond =
831 ir.NewLogicalExpr(base.Pos, ir.OANDAND, isNil, gtZero)
832 nifPtr.Body.Append(mkcall("panicunsafeslicenilptr", nil, &nifPtr.Body))
833 appendWalkStmt(init, nifPtr)
834
835 h := ir.NewSliceHeaderExpr(n.Pos(), sliceType,
836 typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]),
837 typecheck.Conv(len, types.Types[types.TINT]),
838 typecheck.Conv(len, types.Types[types.TINT]))
839 return walkExpr(typecheck.Expr(h), init)
840 }
841
842
843 mem := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TUINTPTR])
844 overflow := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TBOOL])
845
846 decl := types.NewSignature(nil,
847 []*types.Field{
848 types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
849 types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
850 },
851 []*types.Field{
852 types.NewField(base.Pos, nil, types.Types[types.TUINTPTR]),
853 types.NewField(base.Pos, nil, types.Types[types.TBOOL]),
854 })
855
856 fn := ir.NewFunc(n.Pos(), n.Pos(), math_MulUintptr, decl)
857
858 call := mkcall1(fn.Nname, fn.Type().ResultsTuple(), init, ir.NewInt(base.Pos, sliceType.Elem().Size()), typecheck.Conv(typecheck.Conv(len, lenType), types.Types[types.TUINTPTR]))
859 appendWalkStmt(init, ir.NewAssignListStmt(base.Pos, ir.OAS2, []ir.Node{mem, overflow}, []ir.Node{call}))
860
861
862
863
864
865
866
867 nif = ir.NewIfStmt(base.Pos, nil, nil, nil)
868 memCond := ir.NewBinaryExpr(base.Pos, ir.OGT, mem, ir.NewUnaryExpr(base.Pos, ir.ONEG, typecheck.Conv(unsafePtr, types.Types[types.TUINTPTR])))
869 nif.Cond = ir.NewLogicalExpr(base.Pos, ir.OOROR, overflow, memCond)
870 nifPtr := ir.NewIfStmt(base.Pos, nil, nil, nil)
871 nifPtr.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, unsafePtr, typecheck.NodNil())
872 nifPtr.Body.Append(mkcall("panicunsafeslicenilptr", nil, &nifPtr.Body))
873 nif.Body.Append(nifPtr, mkcall("panicunsafeslicelen", nil, &nif.Body))
874 appendWalkStmt(init, nif)
875 }
876
877 h := ir.NewSliceHeaderExpr(n.Pos(), sliceType,
878 typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]),
879 typecheck.Conv(len, types.Types[types.TINT]),
880 typecheck.Conv(len, types.Types[types.TINT]))
881 return walkExpr(typecheck.Expr(h), init)
882 }
883
884 var math_MulUintptr = &types.Sym{Pkg: types.NewPkg("internal/runtime/math", "math"), Name: "MulUintptr"}
885
886 func walkUnsafeString(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
887 ptr := safeExpr(n.X, init)
888 len := safeExpr(n.Y, init)
889
890 lenType := types.Types[types.TINT64]
891 unsafePtr := typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR])
892
893
894
895
896 if ir.ShouldCheckPtr(ir.CurFunc, 1) {
897 fnname := "unsafestringcheckptr"
898 fn := typecheck.LookupRuntime(fnname)
899 init.Append(mkcall1(fn, nil, init, unsafePtr, typecheck.Conv(len, lenType)))
900 } else {
901
902
903 if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() {
904 lenType = types.Types[types.TINT]
905 } else {
906
907
908
909
910 len64 := typecheck.Conv(len, lenType)
911 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
912 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, typecheck.Conv(typecheck.Conv(len64, types.Types[types.TINT]), lenType), len64)
913 nif.Body.Append(mkcall("panicunsafestringlen", nil, &nif.Body))
914 appendWalkStmt(init, nif)
915 }
916
917
918 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
919 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, typecheck.Conv(len, lenType), ir.NewInt(base.Pos, 0))
920 nif.Body.Append(mkcall("panicunsafestringlen", nil, &nif.Body))
921 appendWalkStmt(init, nif)
922
923
924
925
926
927
928
929 nifLen := ir.NewIfStmt(base.Pos, nil, nil, nil)
930 nifLen.Cond = ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(len, types.Types[types.TUINTPTR]), ir.NewUnaryExpr(base.Pos, ir.ONEG, typecheck.Conv(unsafePtr, types.Types[types.TUINTPTR])))
931 nifPtr := ir.NewIfStmt(base.Pos, nil, nil, nil)
932 nifPtr.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, unsafePtr, typecheck.NodNil())
933 nifPtr.Body.Append(mkcall("panicunsafestringnilptr", nil, &nifPtr.Body))
934 nifLen.Body.Append(nifPtr, mkcall("panicunsafestringlen", nil, &nifLen.Body))
935 appendWalkStmt(init, nifLen)
936 }
937 h := ir.NewStringHeaderExpr(n.Pos(),
938 typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]),
939 typecheck.Conv(len, types.Types[types.TINT]),
940 )
941 return walkExpr(typecheck.Expr(h), init)
942 }
943
944 func badtype(op ir.Op, tl, tr *types.Type) {
945 var s string
946 if tl != nil {
947 s += fmt.Sprintf("\n\t%v", tl)
948 }
949 if tr != nil {
950 s += fmt.Sprintf("\n\t%v", tr)
951 }
952
953
954 if tl != nil && tr != nil && tl.IsPtr() && tr.IsPtr() {
955 if tl.Elem().IsStruct() && tr.Elem().IsInterface() {
956 s += "\n\t(*struct vs *interface)"
957 } else if tl.Elem().IsInterface() && tr.Elem().IsStruct() {
958 s += "\n\t(*interface vs *struct)"
959 }
960 }
961
962 base.Errorf("illegal types for operand: %v%s", op, s)
963 }
964
965 func writebarrierfn(name string, l *types.Type, r *types.Type) ir.Node {
966 return typecheck.LookupRuntime(name, l, r)
967 }
968
969
970
971 func isRuneCount(n ir.Node) bool {
972 return base.Flag.N == 0 && !base.Flag.Cfg.Instrumenting && n.Op() == ir.OLEN && n.(*ir.UnaryExpr).X.Op() == ir.OSTR2RUNES
973 }
974
975
976 func isByteCount(n ir.Node) bool {
977 return base.Flag.N == 0 && !base.Flag.Cfg.Instrumenting && n.Op() == ir.OLEN &&
978 (n.(*ir.UnaryExpr).X.Op() == ir.OBYTES2STR || n.(*ir.UnaryExpr).X.Op() == ir.OBYTES2STRTMP)
979 }
980
981
982
983
984 func isChanLenCap(n ir.Node) bool {
985 return (n.Op() == ir.OLEN || n.Op() == ir.OCAP) && n.(*ir.UnaryExpr).X.Type().IsChan()
986 }
987
View as plain text