1
2
3
4
5 package walk
6
7 import (
8 "fmt"
9 "go/constant"
10 "internal/abi"
11 "internal/buildcfg"
12 "strings"
13
14 "cmd/compile/internal/base"
15 "cmd/compile/internal/ir"
16 "cmd/compile/internal/noder"
17 "cmd/compile/internal/objw"
18 "cmd/compile/internal/reflectdata"
19 "cmd/compile/internal/rttype"
20 "cmd/compile/internal/staticdata"
21 "cmd/compile/internal/typecheck"
22 "cmd/compile/internal/types"
23 "cmd/internal/obj"
24 "cmd/internal/objabi"
25 )
26
27
28
29
30 func walkExpr(n ir.Node, init *ir.Nodes) ir.Node {
31 if n == nil {
32 return n
33 }
34
35 if n, ok := n.(ir.InitNode); ok && init == n.PtrInit() {
36
37
38
39 base.Fatalf("walkExpr init == &n->ninit")
40 }
41
42 if len(n.Init()) != 0 {
43 walkStmtList(n.Init())
44 init.Append(ir.TakeInit(n)...)
45 }
46
47 lno := ir.SetPos(n)
48
49 if base.Flag.LowerW > 1 {
50 ir.Dump("before walk expr", n)
51 }
52
53 if n.Typecheck() != 1 {
54 base.Fatalf("missed typecheck: %+v", n)
55 }
56
57 if n.Type().IsUntyped() {
58 base.Fatalf("expression has untyped type: %+v", n)
59 }
60
61 n = walkExpr1(n, init)
62
63
64 if typ := n.Type(); typ != nil && typ.Kind() != types.TBLANK && !typ.IsFuncArgStruct() {
65 types.CheckSize(typ)
66 }
67 if n, ok := n.(*ir.Name); ok && n.Heapaddr != nil {
68 types.CheckSize(n.Heapaddr.Type())
69 }
70 if ir.IsConst(n, constant.String) {
71
72
73 _ = staticdata.StringSym(n.Pos(), constant.StringVal(n.Val()))
74 }
75
76 if base.Flag.LowerW != 0 && n != nil {
77 ir.Dump("after walk expr", n)
78 }
79
80 base.Pos = lno
81 return n
82 }
83
84 func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
85 switch n.Op() {
86 default:
87 ir.Dump("walk", n)
88 base.Fatalf("walkExpr: switch 1 unknown op %+v", n.Op())
89 panic("unreachable")
90
91 case ir.OGETG, ir.OGETCALLERSP:
92 return n
93
94 case ir.OTYPE, ir.ONAME, ir.OLITERAL, ir.ONIL, ir.OLINKSYMOFFSET:
95
96
97
98
99 return n
100
101 case ir.OMETHEXPR:
102
103 n := n.(*ir.SelectorExpr)
104 return n.FuncName()
105
106 case ir.OMIN, ir.OMAX:
107 n := n.(*ir.CallExpr)
108 return walkMinMax(n, init)
109
110 case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.OSPTR, ir.OITAB, ir.OIDATA:
111 n := n.(*ir.UnaryExpr)
112 n.X = walkExpr(n.X, init)
113 return n
114
115 case ir.ODOTMETH, ir.ODOTINTER:
116 n := n.(*ir.SelectorExpr)
117 n.X = walkExpr(n.X, init)
118 return n
119
120 case ir.OADDR:
121 n := n.(*ir.AddrExpr)
122 n.X = walkExpr(n.X, init)
123 return n
124
125 case ir.ODEREF:
126 n := n.(*ir.StarExpr)
127 n.X = walkExpr(n.X, init)
128 return n
129
130 case ir.OMAKEFACE, ir.OAND, ir.OANDNOT, ir.OSUB, ir.OMUL, ir.OADD, ir.OOR, ir.OXOR, ir.OLSH, ir.ORSH,
131 ir.OUNSAFEADD:
132 n := n.(*ir.BinaryExpr)
133 n.X = walkExpr(n.X, init)
134 n.Y = walkExpr(n.Y, init)
135 if n.Op() == ir.OUNSAFEADD && ir.ShouldCheckPtr(ir.CurFunc, 1) {
136
137
138 x := typecheck.ConvNop(n.X, types.Types[types.TUINTPTR])
139 y := typecheck.Conv(n.Y, types.Types[types.TUINTPTR])
140 conv := typecheck.ConvNop(ir.NewBinaryExpr(n.Pos(), ir.OADD, x, y), types.Types[types.TUNSAFEPTR])
141 walkExpr(conv, init)
142 }
143 return n
144
145 case ir.OUNSAFESLICE:
146 n := n.(*ir.BinaryExpr)
147 return walkUnsafeSlice(n, init)
148
149 case ir.OUNSAFESTRING:
150 n := n.(*ir.BinaryExpr)
151 return walkUnsafeString(n, init)
152
153 case ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
154 n := n.(*ir.UnaryExpr)
155 return walkUnsafeData(n, init)
156
157 case ir.ODOT, ir.ODOTPTR:
158 n := n.(*ir.SelectorExpr)
159 return walkDot(n, init)
160
161 case ir.ODOTTYPE, ir.ODOTTYPE2:
162 n := n.(*ir.TypeAssertExpr)
163 return walkDotType(n, init)
164
165 case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2:
166 n := n.(*ir.DynamicTypeAssertExpr)
167 return walkDynamicDotType(n, init)
168
169 case ir.OLEN, ir.OCAP:
170 n := n.(*ir.UnaryExpr)
171 return walkLenCap(n, init)
172
173 case ir.OCOMPLEX:
174 n := n.(*ir.BinaryExpr)
175 n.X = walkExpr(n.X, init)
176 n.Y = walkExpr(n.Y, init)
177 return n
178
179 case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
180 n := n.(*ir.BinaryExpr)
181 return walkCompare(n, init)
182
183 case ir.OANDAND, ir.OOROR:
184 n := n.(*ir.LogicalExpr)
185 return walkLogical(n, init)
186
187 case ir.OPRINT, ir.OPRINTLN:
188 return walkPrint(n.(*ir.CallExpr), init)
189
190 case ir.OPANIC:
191 n := n.(*ir.UnaryExpr)
192 return mkcall("gopanic", nil, init, n.X)
193
194 case ir.ORECOVER:
195 return walkRecover(n.(*ir.CallExpr), init)
196
197 case ir.OCFUNC:
198 return n
199
200 case ir.OCALLINTER, ir.OCALLFUNC:
201 n := n.(*ir.CallExpr)
202 return walkCall(n, init)
203
204 case ir.OAS, ir.OASOP:
205 return walkAssign(init, n)
206
207 case ir.OAS2:
208 n := n.(*ir.AssignListStmt)
209 return walkAssignList(init, n)
210
211
212 case ir.OAS2FUNC:
213 n := n.(*ir.AssignListStmt)
214 return walkAssignFunc(init, n)
215
216
217
218 case ir.OAS2RECV:
219 n := n.(*ir.AssignListStmt)
220 return walkAssignRecv(init, n)
221
222
223 case ir.OAS2MAPR:
224 n := n.(*ir.AssignListStmt)
225 return walkAssignMapRead(init, n)
226
227 case ir.ODELETE:
228 n := n.(*ir.CallExpr)
229 return walkDelete(init, n)
230
231 case ir.OAS2DOTTYPE:
232 n := n.(*ir.AssignListStmt)
233 return walkAssignDotType(n, init)
234
235 case ir.OCONVIFACE:
236 n := n.(*ir.ConvExpr)
237 return walkConvInterface(n, init)
238
239 case ir.OCONV, ir.OCONVNOP:
240 n := n.(*ir.ConvExpr)
241 return walkConv(n, init)
242
243 case ir.OSLICE2ARR:
244 n := n.(*ir.ConvExpr)
245 return walkSliceToArray(n, init)
246
247 case ir.OSLICE2ARRPTR:
248 n := n.(*ir.ConvExpr)
249 n.X = walkExpr(n.X, init)
250 return n
251
252 case ir.ODIV, ir.OMOD:
253 n := n.(*ir.BinaryExpr)
254 return walkDivMod(n, init)
255
256 case ir.OINDEX:
257 n := n.(*ir.IndexExpr)
258 return walkIndex(n, init)
259
260 case ir.OINDEXMAP:
261 n := n.(*ir.IndexExpr)
262 return walkIndexMap(n, init)
263
264 case ir.ORECV:
265 base.Fatalf("walkExpr ORECV")
266 panic("unreachable")
267
268 case ir.OSLICEHEADER:
269 n := n.(*ir.SliceHeaderExpr)
270 return walkSliceHeader(n, init)
271
272 case ir.OSTRINGHEADER:
273 n := n.(*ir.StringHeaderExpr)
274 return walkStringHeader(n, init)
275
276 case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
277 n := n.(*ir.SliceExpr)
278 return walkSlice(n, init)
279
280 case ir.ONEW:
281 n := n.(*ir.UnaryExpr)
282 return walkNew(n, init)
283
284 case ir.OADDSTR:
285 return walkAddString(n.(*ir.AddStringExpr), init, nil)
286
287 case ir.OAPPEND:
288
289 base.Fatalf("append outside assignment")
290 panic("unreachable")
291
292 case ir.OCOPY:
293 return walkCopy(n.(*ir.BinaryExpr), init, base.Flag.Cfg.Instrumenting && !base.Flag.CompilingRuntime)
294
295 case ir.OCLEAR:
296 n := n.(*ir.UnaryExpr)
297 return walkClear(n, init)
298
299 case ir.OCLOSE:
300 n := n.(*ir.UnaryExpr)
301 return walkClose(n, init)
302
303 case ir.OMAKECHAN:
304 n := n.(*ir.MakeExpr)
305 return walkMakeChan(n, init)
306
307 case ir.OMAKEMAP:
308 n := n.(*ir.MakeExpr)
309 return walkMakeMap(n, init)
310
311 case ir.OMAKESLICE:
312 n := n.(*ir.MakeExpr)
313 return walkMakeSlice(n, init)
314
315 case ir.OMAKESLICECOPY:
316 n := n.(*ir.MakeExpr)
317 return walkMakeSliceCopy(n, init)
318
319 case ir.ORUNESTR:
320 n := n.(*ir.ConvExpr)
321 return walkRuneToString(n, init)
322
323 case ir.OBYTES2STR, ir.ORUNES2STR:
324 n := n.(*ir.ConvExpr)
325 return walkBytesRunesToString(n, init)
326
327 case ir.OBYTES2STRTMP:
328 n := n.(*ir.ConvExpr)
329 return walkBytesToStringTemp(n, init)
330
331 case ir.OSTR2BYTES:
332 n := n.(*ir.ConvExpr)
333 return walkStringToBytes(n, init)
334
335 case ir.OSTR2BYTESTMP:
336 n := n.(*ir.ConvExpr)
337 return walkStringToBytesTemp(n, init)
338
339 case ir.OSTR2RUNES:
340 n := n.(*ir.ConvExpr)
341 return walkStringToRunes(n, init)
342
343 case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT, ir.OSTRUCTLIT, ir.OPTRLIT:
344 return walkCompLit(n, init)
345
346 case ir.OSEND:
347 n := n.(*ir.SendStmt)
348 return walkSend(n, init)
349
350 case ir.OCLOSURE:
351 return walkClosure(n.(*ir.ClosureExpr), init)
352
353 case ir.OMETHVALUE:
354 return walkMethodValue(n.(*ir.SelectorExpr), init)
355
356 case ir.OMOVE2HEAP:
357 n := n.(*ir.MoveToHeapExpr)
358 n.Slice = walkExpr(n.Slice, init)
359 return n
360 }
361
362
363
364
365 }
366
367
368
369
370
371
372 func walkExprList(s []ir.Node, init *ir.Nodes) {
373 for i := range s {
374 s[i] = walkExpr(s[i], init)
375 }
376 }
377
378 func walkExprListCheap(s []ir.Node, init *ir.Nodes) {
379 for i, n := range s {
380 s[i] = cheapExpr(n, init)
381 s[i] = walkExpr(s[i], init)
382 }
383 }
384
385 func walkExprListSafe(s []ir.Node, init *ir.Nodes) {
386 for i, n := range s {
387 s[i] = safeExpr(n, init)
388 s[i] = walkExpr(s[i], init)
389 }
390 }
391
392
393
394 func cheapExpr(n ir.Node, init *ir.Nodes) ir.Node {
395 switch n.Op() {
396 case ir.ONAME, ir.OLITERAL, ir.ONIL:
397 return n
398 }
399
400 return copyExpr(n, n.Type(), init)
401 }
402
403
404
405 func safeExpr(n ir.Node, init *ir.Nodes) ir.Node {
406 if n == nil {
407 return nil
408 }
409
410 if len(n.Init()) != 0 {
411 walkStmtList(n.Init())
412 init.Append(ir.TakeInit(n)...)
413 }
414
415 switch n.Op() {
416 case ir.ONAME, ir.OLITERAL, ir.ONIL, ir.OLINKSYMOFFSET:
417 return n
418
419 case ir.OLEN, ir.OCAP:
420 n := n.(*ir.UnaryExpr)
421 l := safeExpr(n.X, init)
422 if l == n.X {
423 return n
424 }
425 a := ir.Copy(n).(*ir.UnaryExpr)
426 a.X = l
427 return walkExpr(typecheck.Expr(a), init)
428
429 case ir.ODOT, ir.ODOTPTR:
430 n := n.(*ir.SelectorExpr)
431 l := safeExpr(n.X, init)
432 if l == n.X {
433 return n
434 }
435 a := ir.Copy(n).(*ir.SelectorExpr)
436 a.X = l
437 return walkExpr(typecheck.Expr(a), init)
438
439 case ir.ODEREF:
440 n := n.(*ir.StarExpr)
441 l := safeExpr(n.X, init)
442 if l == n.X {
443 return n
444 }
445 a := ir.Copy(n).(*ir.StarExpr)
446 a.X = l
447 return walkExpr(typecheck.Expr(a), init)
448
449 case ir.OINDEX, ir.OINDEXMAP:
450 n := n.(*ir.IndexExpr)
451 l := safeExpr(n.X, init)
452 r := safeExpr(n.Index, init)
453 if l == n.X && r == n.Index {
454 return n
455 }
456 a := ir.Copy(n).(*ir.IndexExpr)
457 a.X = l
458 a.Index = r
459 return walkExpr(typecheck.Expr(a), init)
460
461 case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT:
462 n := n.(*ir.CompLitExpr)
463 if isStaticCompositeLiteral(n) {
464 return n
465 }
466 }
467
468
469 if ir.IsAddressable(n) {
470 base.Fatalf("missing lvalue case in safeExpr: %v", n)
471 }
472 return cheapExpr(n, init)
473 }
474
475 func copyExpr(n ir.Node, t *types.Type, init *ir.Nodes) ir.Node {
476 l := typecheck.TempAt(base.Pos, ir.CurFunc, t)
477 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, l, n))
478 return l
479 }
480
481
482
483 func walkAddString(x *ir.AddStringExpr, init *ir.Nodes, conv *ir.ConvExpr) ir.Node {
484 c := len(x.List)
485 if c < 2 {
486 base.Fatalf("walkAddString count %d too small", c)
487 }
488
489 typ := x.Type()
490 if conv != nil {
491 typ = conv.Type()
492 }
493
494
495 var args []ir.Node
496
497 var fn, fnsmall, fnbig string
498
499 buf := typecheck.NodNil()
500 switch {
501 default:
502 base.FatalfAt(x.Pos(), "unexpected type: %v", typ)
503 case typ.IsString():
504 if x.Esc() == ir.EscNone {
505 sz := int64(0)
506 for _, n1 := range x.List {
507 if n1.Op() == ir.OLITERAL {
508 sz += int64(len(ir.StringVal(n1)))
509 }
510 }
511
512
513 if sz < tmpstringbufsize {
514
515 buf = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
516 }
517 }
518
519 args = []ir.Node{buf}
520 fnsmall, fnbig = "concatstring%d", "concatstrings"
521 case typ.IsSlice() && typ.Elem().IsKind(types.TUINT8):
522 if conv != nil && conv.Esc() == ir.EscNone {
523 buf = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8])
524 }
525 args = []ir.Node{buf}
526 fnsmall, fnbig = "concatbyte%d", "concatbytes"
527 }
528
529 if c <= 5 {
530
531
532 fn = fmt.Sprintf(fnsmall, c)
533
534 for _, n2 := range x.List {
535 args = append(args, typecheck.Conv(n2, types.Types[types.TSTRING]))
536 }
537 } else {
538
539 fn = fnbig
540 t := types.NewSlice(types.Types[types.TSTRING])
541
542 slargs := make([]ir.Node, len(x.List))
543 for i, n2 := range x.List {
544 slargs[i] = typecheck.Conv(n2, types.Types[types.TSTRING])
545 }
546 slice := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, t, slargs)
547 slice.Prealloc = x.Prealloc
548 args = append(args, slice)
549 slice.SetEsc(ir.EscNone)
550 }
551
552 cat := typecheck.LookupRuntime(fn)
553 r := ir.NewCallExpr(base.Pos, ir.OCALL, cat, nil)
554 r.Args = args
555 r1 := typecheck.Expr(r)
556 r1 = walkExpr(r1, init)
557 r1.SetType(typ)
558
559 return r1
560 }
561
562 type hookInfo struct {
563 paramType types.Kind
564 argsNum int
565 runtimeFunc string
566 }
567
568 var hooks = map[string]hookInfo{
569 "strings.EqualFold": {paramType: types.TSTRING, argsNum: 2, runtimeFunc: "libfuzzerHookEqualFold"},
570 }
571
572
573 func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node {
574 if n.Op() == ir.OCALLMETH {
575 base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
576 }
577 if n.Op() == ir.OCALLINTER || n.Fun.Op() == ir.OMETHEXPR {
578
579
580 usemethod(n)
581 }
582 if n.Op() == ir.OCALLINTER {
583 reflectdata.MarkUsedIfaceMethod(n)
584 }
585
586 if n.Op() == ir.OCALLFUNC && n.Fun.Op() == ir.OCLOSURE {
587 directClosureCall(n)
588 }
589
590 if ir.IsFuncPCIntrinsic(n) {
591
592
593 name := n.Fun.(*ir.Name).Sym().Name
594 arg := n.Args[0]
595 var wantABI obj.ABI
596 switch name {
597 case "FuncPCABI0":
598 wantABI = obj.ABI0
599 case "FuncPCABIInternal":
600 wantABI = obj.ABIInternal
601 }
602 if n.Type() != types.Types[types.TUINTPTR] {
603 base.FatalfAt(n.Pos(), "FuncPC intrinsic should return uintptr, got %v", n.Type())
604 }
605 n := ir.FuncPC(n.Pos(), arg, wantABI)
606 return walkExpr(n, init)
607 }
608
609 if n.Op() == ir.OCALLFUNC {
610 fn := ir.StaticCalleeName(n.Fun)
611 if fn != nil && fn.Sym().Pkg.Path == "internal/abi" && strings.HasPrefix(fn.Sym().Name, "EscapeNonString[") {
612
613
614
615
616 ps := fn.Type().Params()
617 if len(ps) == 2 && ps[1].Type.IsShape() {
618 return walkExpr(n.Args[1], init)
619 }
620 }
621 }
622
623 if name, ok := n.Fun.(*ir.Name); ok {
624 sym := name.Sym()
625 if sym.Pkg.Path == "go.runtime" && sym.Name == "deferrangefunc" {
626
627
628
629 ir.CurFunc.SetHasDefer(true)
630 ir.CurFunc.SetOpenCodedDeferDisallowed(true)
631 }
632 }
633
634 walkCall1(n, init)
635 return n
636 }
637
638 func walkCall1(n *ir.CallExpr, init *ir.Nodes) {
639 if n.Walked() {
640 return
641 }
642 n.SetWalked(true)
643
644 if n.Op() == ir.OCALLMETH {
645 base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck")
646 }
647
648 args := n.Args
649 params := n.Fun.Type().Params()
650
651 n.Fun = walkExpr(n.Fun, init)
652 walkExprList(args, init)
653
654 for i, arg := range args {
655
656 param := params[i]
657 if !types.Identical(arg.Type(), param.Type) {
658 base.FatalfAt(n.Pos(), "assigning %L to parameter %v (type %v)", arg, param.Sym, param.Type)
659 }
660
661
662
663
664 if mayCall(arg) {
665
666 tmp := typecheck.TempAt(base.Pos, ir.CurFunc, param.Type)
667 init.Append(convas(typecheck.Stmt(ir.NewAssignStmt(base.Pos, tmp, arg)).(*ir.AssignStmt), init))
668
669 args[i] = tmp
670 }
671 }
672
673 funSym := n.Fun.Sym()
674 if base.Debug.Libfuzzer != 0 && funSym != nil {
675 if hook, found := hooks[funSym.Pkg.Path+"."+funSym.Name]; found {
676 if len(args) != hook.argsNum {
677 panic(fmt.Sprintf("%s.%s expects %d arguments, but received %d", funSym.Pkg.Path, funSym.Name, hook.argsNum, len(args)))
678 }
679 var hookArgs []ir.Node
680 for _, arg := range args {
681 hookArgs = append(hookArgs, tracecmpArg(arg, types.Types[hook.paramType], init))
682 }
683 hookArgs = append(hookArgs, fakePC(n))
684 init.Append(mkcall(hook.runtimeFunc, nil, init, hookArgs...))
685 }
686 }
687 }
688
689
690 func walkDivMod(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
691 n.X = walkExpr(n.X, init)
692 n.Y = walkExpr(n.Y, init)
693
694
695 et := n.X.Type().Kind()
696
697 if types.IsComplex[et] && n.Op() == ir.ODIV {
698 t := n.Type()
699 call := mkcall("complex128div", types.Types[types.TCOMPLEX128], init, typecheck.Conv(n.X, types.Types[types.TCOMPLEX128]), typecheck.Conv(n.Y, types.Types[types.TCOMPLEX128]))
700 return typecheck.Conv(call, t)
701 }
702
703
704 if types.IsFloat[et] {
705 return n
706 }
707
708
709
710
711 if types.RegSize < 8 && (et == types.TINT64 || et == types.TUINT64) {
712 if n.Y.Op() == ir.OLITERAL {
713
714
715
716 switch et {
717 case types.TINT64:
718 if ir.Int64Val(n.Y) != 0 {
719 return n
720 }
721 case types.TUINT64:
722 if ir.Uint64Val(n.Y) != 0 {
723 return n
724 }
725 }
726 }
727
728 var fn string
729 if et == types.TINT64 {
730 fn = "int64"
731 } else {
732 fn = "uint64"
733 }
734 if n.Op() == ir.ODIV {
735 fn += "div"
736 } else {
737 fn += "mod"
738 }
739 return mkcall(fn, n.Type(), init, typecheck.Conv(n.X, types.Types[et]), typecheck.Conv(n.Y, types.Types[et]))
740 }
741 return n
742 }
743
744
745 func walkDot(n *ir.SelectorExpr, init *ir.Nodes) ir.Node {
746 usefield(n)
747 n.X = walkExpr(n.X, init)
748 return n
749 }
750
751
752 func walkDotType(n *ir.TypeAssertExpr, init *ir.Nodes) ir.Node {
753 n.X = walkExpr(n.X, init)
754
755 if !n.Type().IsInterface() && !n.X.Type().IsEmptyInterface() {
756 n.ITab = reflectdata.ITabAddrAt(base.Pos, n.Type(), n.X.Type())
757 }
758 if n.X.Type().IsInterface() && n.Type().IsInterface() && !n.Type().IsEmptyInterface() {
759
760
761 n.Descriptor = makeTypeAssertDescriptor(n.Type(), n.Op() == ir.ODOTTYPE2)
762 }
763 return n
764 }
765
766
767
768
769 func shapeTypeAssertImpossible(src ir.Node, dst *types.Type) bool {
770 if dst.IsInterface() {
771 return false
772 }
773 srcShape := convIfaceShapeType(src)
774 if srcShape == nil {
775 return false
776 }
777 return !types.Identical(srcShape, noder.Shapify(dst, false)) &&
778 !types.Identical(srcShape, noder.Shapify(dst, true))
779 }
780
781
782
783 func convIfaceShapeType(src ir.Node) *types.Type {
784 for {
785 switch s := src.(type) {
786 case *ir.ParenExpr:
787 src = s.X
788 continue
789 case *ir.ConvExpr:
790 if s.Op() == ir.OCONVNOP {
791 src = s.X
792 continue
793 }
794 if s.Op() == ir.OCONVIFACE {
795 srcType := s.X.Type()
796 if srcType != nil && !srcType.IsInterface() && srcType.IsShape() {
797 return srcType
798 }
799 return nil
800 }
801 }
802 break
803 }
804
805 if name, ok := src.(*ir.Name); ok && shapeConvSources != nil {
806 return shapeConvSources[name.Canonical()]
807 }
808 return nil
809 }
810
811 func makeTypeAssertDescriptor(target *types.Type, canFail bool) *obj.LSym {
812
813
814 lsym := types.LocalPkg.Lookup(fmt.Sprintf(".typeAssert.%d", typeAssertGen)).LinksymABI(obj.ABI0)
815 typeAssertGen++
816 c := rttype.NewCursor(lsym, 0, rttype.TypeAssert)
817 c.Field("Cache").WritePtr(typecheck.LookupRuntimeVar("emptyTypeAssertCache"))
818 c.Field("Inter").WritePtr(reflectdata.TypeLinksym(target))
819 c.Field("CanFail").WriteBool(canFail)
820 objw.Global(lsym, int32(rttype.TypeAssert.Size()), obj.LOCAL)
821 lsym.Gotype = reflectdata.TypeLinksym(rttype.TypeAssert)
822 return lsym
823 }
824
825 var typeAssertGen int
826
827
828 func walkDynamicDotType(n *ir.DynamicTypeAssertExpr, init *ir.Nodes) ir.Node {
829 n.X = walkExpr(n.X, init)
830 n.RType = walkExpr(n.RType, init)
831 n.ITab = walkExpr(n.ITab, init)
832
833 if n.RType != nil && n.RType.Op() == ir.OADDR {
834 addr := n.RType.(*ir.AddrExpr)
835 if addr.X.Op() == ir.OLINKSYMOFFSET {
836 r := ir.NewTypeAssertExpr(n.Pos(), n.X, n.Type())
837 if n.Op() == ir.ODYNAMICDOTTYPE2 {
838 r.SetOp(ir.ODOTTYPE2)
839 }
840 r.SetType(n.Type())
841 r.SetTypecheck(1)
842 return walkExpr(r, init)
843 }
844 }
845 return n
846 }
847
848
849 func walkIndex(n *ir.IndexExpr, init *ir.Nodes) ir.Node {
850 n.X = walkExpr(n.X, init)
851
852
853
854 r := n.Index
855
856 n.Index = walkExpr(n.Index, init)
857
858
859
860 if n.Bounded() {
861 return n
862 }
863 t := n.X.Type()
864 if t != nil && t.IsPtr() {
865 t = t.Elem()
866 }
867 if t.IsArray() {
868 n.SetBounded(bounded(r, t.NumElem()))
869 if base.Flag.LowerM != 0 && n.Bounded() && !ir.IsConst(n.Index, constant.Int) {
870 base.Warn("index bounds check elided")
871 }
872 } else if ir.IsConst(n.X, constant.String) {
873 n.SetBounded(bounded(r, int64(len(ir.StringVal(n.X)))))
874 if base.Flag.LowerM != 0 && n.Bounded() && !ir.IsConst(n.Index, constant.Int) {
875 base.Warn("index bounds check elided")
876 }
877 }
878 return n
879 }
880
881
882
883
884 func mapKeyArg(fast int, n, key ir.Node, assigned bool) ir.Node {
885 if fast == mapslow {
886
887
888 return typecheck.NodAddr(key)
889 }
890 if assigned {
891
892 return key
893 }
894
895 switch fast {
896 case mapfast32ptr:
897 return ir.NewConvExpr(n.Pos(), ir.OCONVNOP, types.Types[types.TUINT32], key)
898 case mapfast64ptr:
899 return ir.NewConvExpr(n.Pos(), ir.OCONVNOP, types.Types[types.TUINT64], key)
900 default:
901
902 return key
903 }
904 }
905
906
907
908 func walkIndexMap(n *ir.IndexExpr, init *ir.Nodes) ir.Node {
909 n.X = walkExpr(n.X, init)
910 n.Index = walkExpr(n.Index, init)
911 map_ := n.X
912 t := map_.Type()
913 fast := mapfast(t)
914 key := mapKeyArg(fast, n, n.Index, n.Assigned)
915 args := []ir.Node{reflectdata.IndexMapRType(base.Pos, n), map_, key}
916
917 var mapFn ir.Node
918 switch {
919 case n.Assigned:
920 mapFn = mapfn(mapassign[fast], t, false)
921 case t.Elem().Size() > abi.ZeroValSize:
922 args = append(args, reflectdata.ZeroAddr(t.Elem().Size()))
923 mapFn = mapfn("mapaccess1_fat", t, true)
924 default:
925 mapFn = mapfn(mapaccess1[fast], t, false)
926 }
927 call := mkcall1(mapFn, nil, init, args...)
928 call.SetType(types.NewPtr(t.Elem()))
929 call.MarkNonNil()
930 star := ir.NewStarExpr(base.Pos, call)
931 star.SetType(t.Elem())
932 star.SetTypecheck(1)
933 return star
934 }
935
936
937 func walkLogical(n *ir.LogicalExpr, init *ir.Nodes) ir.Node {
938 n.X = walkExpr(n.X, init)
939
940
941
942
943 var ll ir.Nodes
944
945 n.Y = walkExpr(n.Y, &ll)
946 n.Y = ir.InitExpr(ll, n.Y)
947 return n
948 }
949
950
951 func walkSend(n *ir.SendStmt, init *ir.Nodes) ir.Node {
952 n1 := n.Value
953 n1 = typecheck.AssignConv(n1, n.Chan.Type().Elem(), "chan send")
954 n1 = walkExpr(n1, init)
955 n1 = typecheck.NodAddr(n1)
956 return mkcall1(chanfn("chansend1", 2, n.Chan.Type()), nil, init, n.Chan, n1)
957 }
958
959
960 func walkSlice(n *ir.SliceExpr, init *ir.Nodes) ir.Node {
961 n.X = walkExpr(n.X, init)
962 n.Low = walkExpr(n.Low, init)
963 if n.Low != nil && ir.IsZero(n.Low) {
964
965 n.Low = nil
966 }
967 n.High = walkExpr(n.High, init)
968 n.Max = walkExpr(n.Max, init)
969
970 if (n.Op() == ir.OSLICE || n.Op() == ir.OSLICESTR) && n.Low == nil && n.High == nil {
971
972 if base.Debug.Slice > 0 {
973 base.Warn("slice: omit slice operation")
974 }
975 return n.X
976 }
977 return n
978 }
979
980
981 func walkSliceHeader(n *ir.SliceHeaderExpr, init *ir.Nodes) ir.Node {
982 n.Ptr = walkExpr(n.Ptr, init)
983 n.Len = walkExpr(n.Len, init)
984 n.Cap = walkExpr(n.Cap, init)
985 return n
986 }
987
988
989 func walkStringHeader(n *ir.StringHeaderExpr, init *ir.Nodes) ir.Node {
990 n.Ptr = walkExpr(n.Ptr, init)
991 n.Len = walkExpr(n.Len, init)
992 return n
993 }
994
995
996 func bounded(n ir.Node, max int64) bool {
997 if n.Type() == nil || !n.Type().IsInteger() {
998 return false
999 }
1000
1001 sign := n.Type().IsSigned()
1002 bits := int32(8 * n.Type().Size())
1003
1004 if ir.IsSmallIntConst(n) {
1005 v := ir.Int64Val(n)
1006 return 0 <= v && v < max
1007 }
1008
1009 switch n.Op() {
1010 case ir.OAND, ir.OANDNOT:
1011 n := n.(*ir.BinaryExpr)
1012 v := int64(-1)
1013 switch {
1014 case ir.IsSmallIntConst(n.X):
1015 v = ir.Int64Val(n.X)
1016 case ir.IsSmallIntConst(n.Y):
1017 v = ir.Int64Val(n.Y)
1018 if n.Op() == ir.OANDNOT {
1019 v = ^v
1020 if !sign {
1021 v &= 1<<uint(bits) - 1
1022 }
1023 }
1024 }
1025 if 0 <= v && v < max {
1026 return true
1027 }
1028
1029 case ir.OMOD:
1030 n := n.(*ir.BinaryExpr)
1031 if !sign && ir.IsSmallIntConst(n.Y) {
1032 v := ir.Int64Val(n.Y)
1033 if 0 <= v && v <= max {
1034 return true
1035 }
1036 }
1037
1038 case ir.ODIV:
1039 n := n.(*ir.BinaryExpr)
1040 if !sign && ir.IsSmallIntConst(n.Y) {
1041 v := ir.Int64Val(n.Y)
1042 for bits > 0 && v >= 2 {
1043 bits--
1044 v >>= 1
1045 }
1046 }
1047
1048 case ir.ORSH:
1049 n := n.(*ir.BinaryExpr)
1050 if !sign && ir.IsSmallIntConst(n.Y) {
1051 v := ir.Int64Val(n.Y)
1052 if v > int64(bits) {
1053 return max > 0
1054 }
1055 bits -= int32(v)
1056 }
1057 }
1058
1059 if !sign && bits <= 62 && 1<<uint(bits) <= max {
1060 return true
1061 }
1062
1063 return false
1064 }
1065
1066
1067
1068 func usemethod(n *ir.CallExpr) {
1069
1070
1071
1072 if base.Ctxt.Pkgpath == "reflect" {
1073
1074 switch fn := ir.CurFunc.Nname.Sym().Name; {
1075 case fn == "(*rtype).Method", fn == "(*rtype).MethodByName":
1076 return
1077 case fn == "(*interfaceType).Method", fn == "(*interfaceType).MethodByName":
1078 return
1079 case fn == "Value.Method", fn == "Value.MethodByName":
1080 return
1081 }
1082 }
1083
1084 dot, ok := n.Fun.(*ir.SelectorExpr)
1085 if !ok {
1086 return
1087 }
1088
1089
1090
1091
1092
1093
1094
1095 methodName := dot.Sel.Name
1096 t := dot.Selection.Type
1097
1098
1099 if t.NumParams() != 1 || (t.NumResults() != 1 && t.NumResults() != 2) {
1100 return
1101 }
1102
1103
1104 switch pKind := t.Param(0).Type.Kind(); {
1105 case methodName == "Method" && pKind == types.TINT,
1106 methodName == "MethodByName" && pKind == types.TSTRING:
1107
1108 default:
1109
1110 return
1111 }
1112
1113
1114
1115
1116
1117 switch s := t.Result(0).Type.Sym(); {
1118 case s != nil && types.ReflectSymName(s) == "Method",
1119 s != nil && types.ReflectSymName(s) == "Value":
1120
1121 default:
1122
1123 return
1124 }
1125
1126 var targetName ir.Node
1127 switch dot.Op() {
1128 case ir.ODOTINTER:
1129 if methodName == "MethodByName" {
1130 targetName = n.Args[0]
1131 }
1132 case ir.OMETHEXPR:
1133 if methodName == "MethodByName" {
1134 targetName = n.Args[1]
1135 }
1136 default:
1137 base.FatalfAt(dot.Pos(), "usemethod: unexpected dot.Op() %s", dot.Op())
1138 }
1139
1140 if ir.IsConst(targetName, constant.String) {
1141 name := constant.StringVal(targetName.Val())
1142 ir.CurFunc.LSym.AddRel(base.Ctxt, obj.Reloc{
1143 Type: objabi.R_USENAMEDMETHOD,
1144 Sym: staticdata.StringSymNoCommon(name),
1145 })
1146 } else {
1147 ir.CurFunc.LSym.Set(obj.AttrReflectMethod, true)
1148 }
1149 }
1150
1151 func usefield(n *ir.SelectorExpr) {
1152 if !buildcfg.Experiment.FieldTrack {
1153 return
1154 }
1155
1156 switch n.Op() {
1157 default:
1158 base.Fatalf("usefield %v", n.Op())
1159
1160 case ir.ODOT, ir.ODOTPTR:
1161 break
1162 }
1163
1164 field := n.Selection
1165 if field == nil {
1166 base.Fatalf("usefield %v %v without paramfld", n.X.Type(), n.Sel)
1167 }
1168 if field.Sym != n.Sel {
1169 base.Fatalf("field inconsistency: %v != %v", field.Sym, n.Sel)
1170 }
1171 if !strings.Contains(field.Note, "go:\"track\"") {
1172 return
1173 }
1174
1175 outer := n.X.Type()
1176 if outer.IsPtr() {
1177 outer = outer.Elem()
1178 }
1179 if outer.Sym() == nil {
1180 base.Errorf("tracked field must be in named struct type")
1181 }
1182
1183 sym := reflectdata.TrackSym(outer, field)
1184 if ir.CurFunc.FieldTrack == nil {
1185 ir.CurFunc.FieldTrack = make(map[*obj.LSym]struct{})
1186 }
1187 ir.CurFunc.FieldTrack[sym] = struct{}{}
1188 }
1189
View as plain text