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