1// Copyright 2009 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package walk 6 7import ( 8 "fmt" 9 "go/constant" 10 "internal/buildcfg" 11 "strings" 12 13 "cmd/compile/internal/base" 14 "cmd/compile/internal/ir" 15 "cmd/compile/internal/reflectdata" 16 "cmd/compile/internal/staticdata" 17 "cmd/compile/internal/typecheck" 18 "cmd/compile/internal/types" 19 "cmd/internal/obj" 20) 21 22// The result of walkExpr MUST be assigned back to n, e.g. 23// n.Left = walkExpr(n.Left, init) 24func walkExpr(n ir.Node, init *ir.Nodes) ir.Node { 25 if n == nil { 26 return n 27 } 28 29 if n, ok := n.(ir.InitNode); ok && init == n.PtrInit() { 30 // not okay to use n->ninit when walking n, 31 // because we might replace n with some other node 32 // and would lose the init list. 33 base.Fatalf("walkExpr init == &n->ninit") 34 } 35 36 if len(n.Init()) != 0 { 37 walkStmtList(n.Init()) 38 init.Append(ir.TakeInit(n)...) 39 } 40 41 lno := ir.SetPos(n) 42 43 if base.Flag.LowerW > 1 { 44 ir.Dump("before walk expr", n) 45 } 46 47 if n.Typecheck() != 1 { 48 base.Fatalf("missed typecheck: %+v", n) 49 } 50 51 if n.Type().IsUntyped() { 52 base.Fatalf("expression has untyped type: %+v", n) 53 } 54 55 n = walkExpr1(n, init) 56 57 // Eagerly compute sizes of all expressions for the back end. 58 if typ := n.Type(); typ != nil && typ.Kind() != types.TBLANK && !typ.IsFuncArgStruct() { 59 types.CheckSize(typ) 60 } 61 if n, ok := n.(*ir.Name); ok && n.Heapaddr != nil { 62 types.CheckSize(n.Heapaddr.Type()) 63 } 64 if ir.IsConst(n, constant.String) { 65 // Emit string symbol now to avoid emitting 66 // any concurrently during the backend. 67 _ = staticdata.StringSym(n.Pos(), constant.StringVal(n.Val())) 68 } 69 70 if base.Flag.LowerW != 0 && n != nil { 71 ir.Dump("after walk expr", n) 72 } 73 74 base.Pos = lno 75 return n 76} 77 78func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node { 79 switch n.Op() { 80 default: 81 ir.Dump("walk", n) 82 base.Fatalf("walkExpr: switch 1 unknown op %+v", n.Op()) 83 panic("unreachable") 84 85 case ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP: 86 return n 87 88 case ir.OTYPE, ir.ONAME, ir.OLITERAL, ir.ONIL, ir.OLINKSYMOFFSET: 89 // TODO(mdempsky): Just return n; see discussion on CL 38655. 90 // Perhaps refactor to use Node.mayBeShared for these instead. 91 // If these return early, make sure to still call 92 // StringSym for constant strings. 93 return n 94 95 case ir.OMETHEXPR: 96 // TODO(mdempsky): Do this right after type checking. 97 n := n.(*ir.SelectorExpr) 98 return n.FuncName() 99 100 case ir.ONOT, ir.ONEG, ir.OPLUS, ir.OBITNOT, ir.OREAL, ir.OIMAG, ir.OSPTR, ir.OITAB, ir.OIDATA: 101 n := n.(*ir.UnaryExpr) 102 n.X = walkExpr(n.X, init) 103 return n 104 105 case ir.ODOTMETH, ir.ODOTINTER: 106 n := n.(*ir.SelectorExpr) 107 n.X = walkExpr(n.X, init) 108 return n 109 110 case ir.OADDR: 111 n := n.(*ir.AddrExpr) 112 n.X = walkExpr(n.X, init) 113 return n 114 115 case ir.ODEREF: 116 n := n.(*ir.StarExpr) 117 n.X = walkExpr(n.X, init) 118 return n 119 120 case ir.OEFACE, ir.OAND, ir.OANDNOT, ir.OSUB, ir.OMUL, ir.OADD, ir.OOR, ir.OXOR, ir.OLSH, ir.ORSH, 121 ir.OUNSAFEADD: 122 n := n.(*ir.BinaryExpr) 123 n.X = walkExpr(n.X, init) 124 n.Y = walkExpr(n.Y, init) 125 return n 126 127 case ir.OUNSAFESLICE: 128 n := n.(*ir.BinaryExpr) 129 return walkUnsafeSlice(n, init) 130 131 case ir.ODOT, ir.ODOTPTR: 132 n := n.(*ir.SelectorExpr) 133 return walkDot(n, init) 134 135 case ir.ODOTTYPE, ir.ODOTTYPE2: 136 n := n.(*ir.TypeAssertExpr) 137 return walkDotType(n, init) 138 139 case ir.ODYNAMICDOTTYPE, ir.ODYNAMICDOTTYPE2: 140 n := n.(*ir.DynamicTypeAssertExpr) 141 return walkDynamicDotType(n, init) 142 143 case ir.OLEN, ir.OCAP: 144 n := n.(*ir.UnaryExpr) 145 return walkLenCap(n, init) 146 147 case ir.OCOMPLEX: 148 n := n.(*ir.BinaryExpr) 149 n.X = walkExpr(n.X, init) 150 n.Y = walkExpr(n.Y, init) 151 return n 152 153 case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE: 154 n := n.(*ir.BinaryExpr) 155 return walkCompare(n, init) 156 157 case ir.OANDAND, ir.OOROR: 158 n := n.(*ir.LogicalExpr) 159 return walkLogical(n, init) 160 161 case ir.OPRINT, ir.OPRINTN: 162 return walkPrint(n.(*ir.CallExpr), init) 163 164 case ir.OPANIC: 165 n := n.(*ir.UnaryExpr) 166 return mkcall("gopanic", nil, init, n.X) 167 168 case ir.ORECOVERFP: 169 return walkRecoverFP(n.(*ir.CallExpr), init) 170 171 case ir.OCFUNC: 172 return n 173 174 case ir.OCALLINTER, ir.OCALLFUNC: 175 n := n.(*ir.CallExpr) 176 return walkCall(n, init) 177 178 case ir.OAS, ir.OASOP: 179 return walkAssign(init, n) 180 181 case ir.OAS2: 182 n := n.(*ir.AssignListStmt) 183 return walkAssignList(init, n) 184 185 // a,b,... = fn() 186 case ir.OAS2FUNC: 187 n := n.(*ir.AssignListStmt) 188 return walkAssignFunc(init, n) 189 190 // x, y = <-c 191 // order.stmt made sure x is addressable or blank. 192 case ir.OAS2RECV: 193 n := n.(*ir.AssignListStmt) 194 return walkAssignRecv(init, n) 195 196 // a,b = m[i] 197 case ir.OAS2MAPR: 198 n := n.(*ir.AssignListStmt) 199 return walkAssignMapRead(init, n) 200 201 case ir.ODELETE: 202 n := n.(*ir.CallExpr) 203 return walkDelete(init, n) 204 205 case ir.OAS2DOTTYPE: 206 n := n.(*ir.AssignListStmt) 207 return walkAssignDotType(n, init) 208 209 case ir.OCONVIFACE: 210 n := n.(*ir.ConvExpr) 211 return walkConvInterface(n, init) 212 213 case ir.OCONVIDATA: 214 n := n.(*ir.ConvExpr) 215 return walkConvIData(n, init) 216 217 case ir.OCONV, ir.OCONVNOP: 218 n := n.(*ir.ConvExpr) 219 return walkConv(n, init) 220 221 case ir.OSLICE2ARRPTR: 222 n := n.(*ir.ConvExpr) 223 n.X = walkExpr(n.X, init) 224 return n 225 226 case ir.ODIV, ir.OMOD: 227 n := n.(*ir.BinaryExpr) 228 return walkDivMod(n, init) 229 230 case ir.OINDEX: 231 n := n.(*ir.IndexExpr) 232 return walkIndex(n, init) 233 234 case ir.OINDEXMAP: 235 n := n.(*ir.IndexExpr) 236 return walkIndexMap(n, init) 237 238 case ir.ORECV: 239 base.Fatalf("walkExpr ORECV") // should see inside OAS only 240 panic("unreachable") 241 242 case ir.OSLICEHEADER: 243 n := n.(*ir.SliceHeaderExpr) 244 return walkSliceHeader(n, init) 245 246 case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR: 247 n := n.(*ir.SliceExpr) 248 return walkSlice(n, init) 249 250 case ir.ONEW: 251 n := n.(*ir.UnaryExpr) 252 return walkNew(n, init) 253 254 case ir.OADDSTR: 255 return walkAddString(n.(*ir.AddStringExpr), init) 256 257 case ir.OAPPEND: 258 // order should make sure we only see OAS(node, OAPPEND), which we handle above. 259 base.Fatalf("append outside assignment") 260 panic("unreachable") 261 262 case ir.OCOPY: 263 return walkCopy(n.(*ir.BinaryExpr), init, base.Flag.Cfg.Instrumenting && !base.Flag.CompilingRuntime) 264 265 case ir.OCLOSE: 266 n := n.(*ir.UnaryExpr) 267 return walkClose(n, init) 268 269 case ir.OMAKECHAN: 270 n := n.(*ir.MakeExpr) 271 return walkMakeChan(n, init) 272 273 case ir.OMAKEMAP: 274 n := n.(*ir.MakeExpr) 275 return walkMakeMap(n, init) 276 277 case ir.OMAKESLICE: 278 n := n.(*ir.MakeExpr) 279 return walkMakeSlice(n, init) 280 281 case ir.OMAKESLICECOPY: 282 n := n.(*ir.MakeExpr) 283 return walkMakeSliceCopy(n, init) 284 285 case ir.ORUNESTR: 286 n := n.(*ir.ConvExpr) 287 return walkRuneToString(n, init) 288 289 case ir.OBYTES2STR, ir.ORUNES2STR: 290 n := n.(*ir.ConvExpr) 291 return walkBytesRunesToString(n, init) 292 293 case ir.OBYTES2STRTMP: 294 n := n.(*ir.ConvExpr) 295 return walkBytesToStringTemp(n, init) 296 297 case ir.OSTR2BYTES: 298 n := n.(*ir.ConvExpr) 299 return walkStringToBytes(n, init) 300 301 case ir.OSTR2BYTESTMP: 302 n := n.(*ir.ConvExpr) 303 return walkStringToBytesTemp(n, init) 304 305 case ir.OSTR2RUNES: 306 n := n.(*ir.ConvExpr) 307 return walkStringToRunes(n, init) 308 309 case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT, ir.OSTRUCTLIT, ir.OPTRLIT: 310 return walkCompLit(n, init) 311 312 case ir.OSEND: 313 n := n.(*ir.SendStmt) 314 return walkSend(n, init) 315 316 case ir.OCLOSURE: 317 return walkClosure(n.(*ir.ClosureExpr), init) 318 319 case ir.OMETHVALUE: 320 return walkMethodValue(n.(*ir.SelectorExpr), init) 321 } 322 323 // No return! Each case must return (or panic), 324 // to avoid confusion about what gets returned 325 // in the presence of type assertions. 326} 327 328// walk the whole tree of the body of an 329// expression or simple statement. 330// the types expressions are calculated. 331// compile-time constants are evaluated. 332// complex side effects like statements are appended to init 333func walkExprList(s []ir.Node, init *ir.Nodes) { 334 for i := range s { 335 s[i] = walkExpr(s[i], init) 336 } 337} 338 339func walkExprListCheap(s []ir.Node, init *ir.Nodes) { 340 for i, n := range s { 341 s[i] = cheapExpr(n, init) 342 s[i] = walkExpr(s[i], init) 343 } 344} 345 346func walkExprListSafe(s []ir.Node, init *ir.Nodes) { 347 for i, n := range s { 348 s[i] = safeExpr(n, init) 349 s[i] = walkExpr(s[i], init) 350 } 351} 352 353// return side-effect free and cheap n, appending side effects to init. 354// result may not be assignable. 355func cheapExpr(n ir.Node, init *ir.Nodes) ir.Node { 356 switch n.Op() { 357 case ir.ONAME, ir.OLITERAL, ir.ONIL: 358 return n 359 } 360 361 return copyExpr(n, n.Type(), init) 362} 363 364// return side effect-free n, appending side effects to init. 365// result is assignable if n is. 366func safeExpr(n ir.Node, init *ir.Nodes) ir.Node { 367 if n == nil { 368 return nil 369 } 370 371 if len(n.Init()) != 0 { 372 walkStmtList(n.Init()) 373 init.Append(ir.TakeInit(n)...) 374 } 375 376 switch n.Op() { 377 case ir.ONAME, ir.OLITERAL, ir.ONIL, ir.OLINKSYMOFFSET: 378 return n 379 380 case ir.OLEN, ir.OCAP: 381 n := n.(*ir.UnaryExpr) 382 l := safeExpr(n.X, init) 383 if l == n.X { 384 return n 385 } 386 a := ir.Copy(n).(*ir.UnaryExpr) 387 a.X = l 388 return walkExpr(typecheck.Expr(a), init) 389 390 case ir.ODOT, ir.ODOTPTR: 391 n := n.(*ir.SelectorExpr) 392 l := safeExpr(n.X, init) 393 if l == n.X { 394 return n 395 } 396 a := ir.Copy(n).(*ir.SelectorExpr) 397 a.X = l 398 return walkExpr(typecheck.Expr(a), init) 399 400 case ir.ODEREF: 401 n := n.(*ir.StarExpr) 402 l := safeExpr(n.X, init) 403 if l == n.X { 404 return n 405 } 406 a := ir.Copy(n).(*ir.StarExpr) 407 a.X = l 408 return walkExpr(typecheck.Expr(a), init) 409 410 case ir.OINDEX, ir.OINDEXMAP: 411 n := n.(*ir.IndexExpr) 412 l := safeExpr(n.X, init) 413 r := safeExpr(n.Index, init) 414 if l == n.X && r == n.Index { 415 return n 416 } 417 a := ir.Copy(n).(*ir.IndexExpr) 418 a.X = l 419 a.Index = r 420 return walkExpr(typecheck.Expr(a), init) 421 422 case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT: 423 n := n.(*ir.CompLitExpr) 424 if isStaticCompositeLiteral(n) { 425 return n 426 } 427 } 428 429 // make a copy; must not be used as an lvalue 430 if ir.IsAddressable(n) { 431 base.Fatalf("missing lvalue case in safeExpr: %v", n) 432 } 433 return cheapExpr(n, init) 434} 435 436func copyExpr(n ir.Node, t *types.Type, init *ir.Nodes) ir.Node { 437 l := typecheck.Temp(t) 438 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, l, n)) 439 return l 440} 441 442func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node { 443 c := len(n.List) 444 445 if c < 2 { 446 base.Fatalf("walkAddString count %d too small", c) 447 } 448 449 buf := typecheck.NodNil() 450 if n.Esc() == ir.EscNone { 451 sz := int64(0) 452 for _, n1 := range n.List { 453 if n1.Op() == ir.OLITERAL { 454 sz += int64(len(ir.StringVal(n1))) 455 } 456 } 457 458 // Don't allocate the buffer if the result won't fit. 459 if sz < tmpstringbufsize { 460 // Create temporary buffer for result string on stack. 461 buf = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8]) 462 } 463 } 464 465 // build list of string arguments 466 args := []ir.Node{buf} 467 for _, n2 := range n.List { 468 args = append(args, typecheck.Conv(n2, types.Types[types.TSTRING])) 469 } 470 471 var fn string 472 if c <= 5 { 473 // small numbers of strings use direct runtime helpers. 474 // note: order.expr knows this cutoff too. 475 fn = fmt.Sprintf("concatstring%d", c) 476 } else { 477 // large numbers of strings are passed to the runtime as a slice. 478 fn = "concatstrings" 479 480 t := types.NewSlice(types.Types[types.TSTRING]) 481 // args[1:] to skip buf arg 482 slice := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(t), args[1:]) 483 slice.Prealloc = n.Prealloc 484 args = []ir.Node{buf, slice} 485 slice.SetEsc(ir.EscNone) 486 } 487 488 cat := typecheck.LookupRuntime(fn) 489 r := ir.NewCallExpr(base.Pos, ir.OCALL, cat, nil) 490 r.Args = args 491 r1 := typecheck.Expr(r) 492 r1 = walkExpr(r1, init) 493 r1.SetType(n.Type()) 494 495 return r1 496} 497 498// walkCall walks an OCALLFUNC or OCALLINTER node. 499func walkCall(n *ir.CallExpr, init *ir.Nodes) ir.Node { 500 if n.Op() == ir.OCALLMETH { 501 base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck") 502 } 503 if n.Op() == ir.OCALLINTER || n.X.Op() == ir.OMETHEXPR { 504 // We expect both interface call reflect.Type.Method and concrete 505 // call reflect.(*rtype).Method. 506 usemethod(n) 507 } 508 if n.Op() == ir.OCALLINTER { 509 reflectdata.MarkUsedIfaceMethod(n) 510 } 511 512 if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.OCLOSURE { 513 directClosureCall(n) 514 } 515 516 if isFuncPCIntrinsic(n) { 517 // For internal/abi.FuncPCABIxxx(fn), if fn is a defined function, rewrite 518 // it to the address of the function of the ABI fn is defined. 519 name := n.X.(*ir.Name).Sym().Name 520 arg := n.Args[0] 521 var wantABI obj.ABI 522 switch name { 523 case "FuncPCABI0": 524 wantABI = obj.ABI0 525 case "FuncPCABIInternal": 526 wantABI = obj.ABIInternal 527 } 528 if isIfaceOfFunc(arg) { 529 fn := arg.(*ir.ConvExpr).X.(*ir.Name) 530 abi := fn.Func.ABI 531 if abi != wantABI { 532 base.ErrorfAt(n.Pos(), "internal/abi.%s expects an %v function, %s is defined as %v", name, wantABI, fn.Sym().Name, abi) 533 } 534 var e ir.Node = ir.NewLinksymExpr(n.Pos(), fn.Sym().LinksymABI(abi), types.Types[types.TUINTPTR]) 535 e = ir.NewAddrExpr(n.Pos(), e) 536 e.SetType(types.Types[types.TUINTPTR].PtrTo()) 537 e = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, n.Type(), e) 538 return e 539 } 540 // fn is not a defined function. It must be ABIInternal. 541 // Read the address from func value, i.e. *(*uintptr)(idata(fn)). 542 if wantABI != obj.ABIInternal { 543 base.ErrorfAt(n.Pos(), "internal/abi.%s does not accept func expression, which is ABIInternal", name) 544 } 545 arg = walkExpr(arg, init) 546 var e ir.Node = ir.NewUnaryExpr(n.Pos(), ir.OIDATA, arg) 547 e.SetType(n.Type().PtrTo()) 548 e = ir.NewStarExpr(n.Pos(), e) 549 e.SetType(n.Type()) 550 return e 551 } 552 553 walkCall1(n, init) 554 return n 555} 556 557func walkCall1(n *ir.CallExpr, init *ir.Nodes) { 558 if n.Walked() { 559 return // already walked 560 } 561 n.SetWalked(true) 562 563 if n.Op() == ir.OCALLMETH { 564 base.FatalfAt(n.Pos(), "OCALLMETH missed by typecheck") 565 } 566 567 args := n.Args 568 params := n.X.Type().Params() 569 570 n.X = walkExpr(n.X, init) 571 walkExprList(args, init) 572 573 for i, arg := range args { 574 // Validate argument and parameter types match. 575 param := params.Field(i) 576 if !types.Identical(arg.Type(), param.Type) { 577 base.FatalfAt(n.Pos(), "assigning %L to parameter %v (type %v)", arg, param.Sym, param.Type) 578 } 579 580 // For any argument whose evaluation might require a function call, 581 // store that argument into a temporary variable, 582 // to prevent that calls from clobbering arguments already on the stack. 583 if mayCall(arg) { 584 // assignment of arg to Temp 585 tmp := typecheck.Temp(param.Type) 586 init.Append(convas(typecheck.Stmt(ir.NewAssignStmt(base.Pos, tmp, arg)).(*ir.AssignStmt), init)) 587 // replace arg with temp 588 args[i] = tmp 589 } 590 } 591 592 n.Args = args 593} 594 595// walkDivMod walks an ODIV or OMOD node. 596func walkDivMod(n *ir.BinaryExpr, init *ir.Nodes) ir.Node { 597 n.X = walkExpr(n.X, init) 598 n.Y = walkExpr(n.Y, init) 599 600 // rewrite complex div into function call. 601 et := n.X.Type().Kind() 602 603 if types.IsComplex[et] && n.Op() == ir.ODIV { 604 t := n.Type() 605 call := mkcall("complex128div", types.Types[types.TCOMPLEX128], init, typecheck.Conv(n.X, types.Types[types.TCOMPLEX128]), typecheck.Conv(n.Y, types.Types[types.TCOMPLEX128])) 606 return typecheck.Conv(call, t) 607 } 608 609 // Nothing to do for float divisions. 610 if types.IsFloat[et] { 611 return n 612 } 613 614 // rewrite 64-bit div and mod on 32-bit architectures. 615 // TODO: Remove this code once we can introduce 616 // runtime calls late in SSA processing. 617 if types.RegSize < 8 && (et == types.TINT64 || et == types.TUINT64) { 618 if n.Y.Op() == ir.OLITERAL { 619 // Leave div/mod by constant powers of 2 or small 16-bit constants. 620 // The SSA backend will handle those. 621 switch et { 622 case types.TINT64: 623 c := ir.Int64Val(n.Y) 624 if c < 0 { 625 c = -c 626 } 627 if c != 0 && c&(c-1) == 0 { 628 return n 629 } 630 case types.TUINT64: 631 c := ir.Uint64Val(n.Y) 632 if c < 1<<16 { 633 return n 634 } 635 if c != 0 && c&(c-1) == 0 { 636 return n 637 } 638 } 639 } 640 var fn string 641 if et == types.TINT64 { 642 fn = "int64" 643 } else { 644 fn = "uint64" 645 } 646 if n.Op() == ir.ODIV { 647 fn += "div" 648 } else { 649 fn += "mod" 650 } 651 return mkcall(fn, n.Type(), init, typecheck.Conv(n.X, types.Types[et]), typecheck.Conv(n.Y, types.Types[et])) 652 } 653 return n 654} 655 656// walkDot walks an ODOT or ODOTPTR node. 657func walkDot(n *ir.SelectorExpr, init *ir.Nodes) ir.Node { 658 usefield(n) 659 n.X = walkExpr(n.X, init) 660 return n 661} 662 663// walkDotType walks an ODOTTYPE or ODOTTYPE2 node. 664func walkDotType(n *ir.TypeAssertExpr, init *ir.Nodes) ir.Node { 665 n.X = walkExpr(n.X, init) 666 // Set up interface type addresses for back end. 667 if !n.Type().IsInterface() && !n.X.Type().IsEmptyInterface() { 668 n.Itab = reflectdata.ITabAddr(n.Type(), n.X.Type()) 669 } 670 return n 671} 672 673// walkDynamicdotType walks an ODYNAMICDOTTYPE or ODYNAMICDOTTYPE2 node. 674func walkDynamicDotType(n *ir.DynamicTypeAssertExpr, init *ir.Nodes) ir.Node { 675 n.X = walkExpr(n.X, init) 676 n.T = walkExpr(n.T, init) 677 return n 678} 679 680// walkIndex walks an OINDEX node. 681func walkIndex(n *ir.IndexExpr, init *ir.Nodes) ir.Node { 682 n.X = walkExpr(n.X, init) 683 684 // save the original node for bounds checking elision. 685 // If it was a ODIV/OMOD walk might rewrite it. 686 r := n.Index 687 688 n.Index = walkExpr(n.Index, init) 689 690 // if range of type cannot exceed static array bound, 691 // disable bounds check. 692 if n.Bounded() { 693 return n 694 } 695 t := n.X.Type() 696 if t != nil && t.IsPtr() { 697 t = t.Elem() 698 } 699 if t.IsArray() { 700 n.SetBounded(bounded(r, t.NumElem())) 701 if base.Flag.LowerM != 0 && n.Bounded() && !ir.IsConst(n.Index, constant.Int) { 702 base.Warn("index bounds check elided") 703 } 704 if ir.IsSmallIntConst(n.Index) && !n.Bounded() { 705 base.Errorf("index out of bounds") 706 } 707 } else if ir.IsConst(n.X, constant.String) { 708 n.SetBounded(bounded(r, int64(len(ir.StringVal(n.X))))) 709 if base.Flag.LowerM != 0 && n.Bounded() && !ir.IsConst(n.Index, constant.Int) { 710 base.Warn("index bounds check elided") 711 } 712 if ir.IsSmallIntConst(n.Index) && !n.Bounded() { 713 base.Errorf("index out of bounds") 714 } 715 } 716 717 if ir.IsConst(n.Index, constant.Int) { 718 if v := n.Index.Val(); constant.Sign(v) < 0 || ir.ConstOverflow(v, types.Types[types.TINT]) { 719 base.Errorf("index out of bounds") 720 } 721 } 722 return n 723} 724 725// mapKeyArg returns an expression for key that is suitable to be passed 726// as the key argument for mapaccess and mapdelete functions. 727// n is is the map indexing or delete Node (to provide Pos). 728// Note: this is not used for mapassign, which does distinguish pointer vs. 729// integer key. 730func mapKeyArg(fast int, n, key ir.Node) ir.Node { 731 switch fast { 732 case mapslow: 733 // standard version takes key by reference. 734 // order.expr made sure key is addressable. 735 return typecheck.NodAddr(key) 736 case mapfast32ptr: 737 // mapaccess and mapdelete don't distinguish pointer vs. integer key. 738 return ir.NewConvExpr(n.Pos(), ir.OCONVNOP, types.Types[types.TUINT32], key) 739 case mapfast64ptr: 740 // mapaccess and mapdelete don't distinguish pointer vs. integer key. 741 return ir.NewConvExpr(n.Pos(), ir.OCONVNOP, types.Types[types.TUINT64], key) 742 default: 743 // fast version takes key by value. 744 return key 745 } 746} 747 748// walkIndexMap walks an OINDEXMAP node. 749func walkIndexMap(n *ir.IndexExpr, init *ir.Nodes) ir.Node { 750 // Replace m[k] with *map{access1,assign}(maptype, m, &k) 751 n.X = walkExpr(n.X, init) 752 n.Index = walkExpr(n.Index, init) 753 map_ := n.X 754 key := n.Index 755 t := map_.Type() 756 var call *ir.CallExpr 757 if n.Assigned { 758 // This m[k] expression is on the left-hand side of an assignment. 759 fast := mapfast(t) 760 if fast == mapslow { 761 // standard version takes key by reference. 762 // order.expr made sure key is addressable. 763 key = typecheck.NodAddr(key) 764 } 765 call = mkcall1(mapfn(mapassign[fast], t, false), nil, init, reflectdata.TypePtr(t), map_, key) 766 } else { 767 // m[k] is not the target of an assignment. 768 fast := mapfast(t) 769 key = mapKeyArg(fast, n, key) 770 if w := t.Elem().Size(); w <= zeroValSize { 771 call = mkcall1(mapfn(mapaccess1[fast], t, false), types.NewPtr(t.Elem()), init, reflectdata.TypePtr(t), map_, key) 772 } else { 773 z := reflectdata.ZeroAddr(w) 774 call = mkcall1(mapfn("mapaccess1_fat", t, true), types.NewPtr(t.Elem()), init, reflectdata.TypePtr(t), map_, key, z) 775 } 776 } 777 call.SetType(types.NewPtr(t.Elem())) 778 call.MarkNonNil() // mapaccess1* and mapassign always return non-nil pointers. 779 star := ir.NewStarExpr(base.Pos, call) 780 star.SetType(t.Elem()) 781 star.SetTypecheck(1) 782 return star 783} 784 785// walkLogical walks an OANDAND or OOROR node. 786func walkLogical(n *ir.LogicalExpr, init *ir.Nodes) ir.Node { 787 n.X = walkExpr(n.X, init) 788 789 // cannot put side effects from n.Right on init, 790 // because they cannot run before n.Left is checked. 791 // save elsewhere and store on the eventual n.Right. 792 var ll ir.Nodes 793 794 n.Y = walkExpr(n.Y, &ll) 795 n.Y = ir.InitExpr(ll, n.Y) 796 return n 797} 798 799// walkSend walks an OSEND node. 800func walkSend(n *ir.SendStmt, init *ir.Nodes) ir.Node { 801 n1 := n.Value 802 n1 = typecheck.AssignConv(n1, n.Chan.Type().Elem(), "chan send") 803 n1 = walkExpr(n1, init) 804 n1 = typecheck.NodAddr(n1) 805 return mkcall1(chanfn("chansend1", 2, n.Chan.Type()), nil, init, n.Chan, n1) 806} 807 808// walkSlice walks an OSLICE, OSLICEARR, OSLICESTR, OSLICE3, or OSLICE3ARR node. 809func walkSlice(n *ir.SliceExpr, init *ir.Nodes) ir.Node { 810 n.X = walkExpr(n.X, init) 811 n.Low = walkExpr(n.Low, init) 812 if n.Low != nil && ir.IsZero(n.Low) { 813 // Reduce x[0:j] to x[:j] and x[0:j:k] to x[:j:k]. 814 n.Low = nil 815 } 816 n.High = walkExpr(n.High, init) 817 n.Max = walkExpr(n.Max, init) 818 819 if n.Op().IsSlice3() { 820 if n.Max != nil && n.Max.Op() == ir.OCAP && ir.SameSafeExpr(n.X, n.Max.(*ir.UnaryExpr).X) { 821 // Reduce x[i:j:cap(x)] to x[i:j]. 822 if n.Op() == ir.OSLICE3 { 823 n.SetOp(ir.OSLICE) 824 } else { 825 n.SetOp(ir.OSLICEARR) 826 } 827 return reduceSlice(n) 828 } 829 return n 830 } 831 return reduceSlice(n) 832} 833 834// walkSliceHeader walks an OSLICEHEADER node. 835func walkSliceHeader(n *ir.SliceHeaderExpr, init *ir.Nodes) ir.Node { 836 n.Ptr = walkExpr(n.Ptr, init) 837 n.Len = walkExpr(n.Len, init) 838 n.Cap = walkExpr(n.Cap, init) 839 return n 840} 841 842// TODO(josharian): combine this with its caller and simplify 843func reduceSlice(n *ir.SliceExpr) ir.Node { 844 if n.High != nil && n.High.Op() == ir.OLEN && ir.SameSafeExpr(n.X, n.High.(*ir.UnaryExpr).X) { 845 // Reduce x[i:len(x)] to x[i:]. 846 n.High = nil 847 } 848 if (n.Op() == ir.OSLICE || n.Op() == ir.OSLICESTR) && n.Low == nil && n.High == nil { 849 // Reduce x[:] to x. 850 if base.Debug.Slice > 0 { 851 base.Warn("slice: omit slice operation") 852 } 853 return n.X 854 } 855 return n 856} 857 858// return 1 if integer n must be in range [0, max), 0 otherwise 859func bounded(n ir.Node, max int64) bool { 860 if n.Type() == nil || !n.Type().IsInteger() { 861 return false 862 } 863 864 sign := n.Type().IsSigned() 865 bits := int32(8 * n.Type().Size()) 866 867 if ir.IsSmallIntConst(n) { 868 v := ir.Int64Val(n) 869 return 0 <= v && v < max 870 } 871 872 switch n.Op() { 873 case ir.OAND, ir.OANDNOT: 874 n := n.(*ir.BinaryExpr) 875 v := int64(-1) 876 switch { 877 case ir.IsSmallIntConst(n.X): 878 v = ir.Int64Val(n.X) 879 case ir.IsSmallIntConst(n.Y): 880 v = ir.Int64Val(n.Y) 881 if n.Op() == ir.OANDNOT { 882 v = ^v 883 if !sign { 884 v &= 1<<uint(bits) - 1 885 } 886 } 887 } 888 if 0 <= v && v < max { 889 return true 890 } 891 892 case ir.OMOD: 893 n := n.(*ir.BinaryExpr) 894 if !sign && ir.IsSmallIntConst(n.Y) { 895 v := ir.Int64Val(n.Y) 896 if 0 <= v && v <= max { 897 return true 898 } 899 } 900 901 case ir.ODIV: 902 n := n.(*ir.BinaryExpr) 903 if !sign && ir.IsSmallIntConst(n.Y) { 904 v := ir.Int64Val(n.Y) 905 for bits > 0 && v >= 2 { 906 bits-- 907 v >>= 1 908 } 909 } 910 911 case ir.ORSH: 912 n := n.(*ir.BinaryExpr) 913 if !sign && ir.IsSmallIntConst(n.Y) { 914 v := ir.Int64Val(n.Y) 915 if v > int64(bits) { 916 return true 917 } 918 bits -= int32(v) 919 } 920 } 921 922 if !sign && bits <= 62 && 1<<uint(bits) <= max { 923 return true 924 } 925 926 return false 927} 928 929// usemethod checks calls for uses of reflect.Type.{Method,MethodByName}. 930func usemethod(n *ir.CallExpr) { 931 // Don't mark reflect.(*rtype).Method, etc. themselves in the reflect package. 932 // Those functions may be alive via the itab, which should not cause all methods 933 // alive. We only want to mark their callers. 934 if base.Ctxt.Pkgpath == "reflect" { 935 switch ir.CurFunc.Nname.Sym().Name { // TODO: is there a better way than hardcoding the names? 936 case "(*rtype).Method", "(*rtype).MethodByName", "(*interfaceType).Method", "(*interfaceType).MethodByName": 937 return 938 } 939 } 940 941 dot, ok := n.X.(*ir.SelectorExpr) 942 if !ok { 943 return 944 } 945 946 // Looking for either direct method calls and interface method calls of: 947 // reflect.Type.Method - func(int) reflect.Method 948 // reflect.Type.MethodByName - func(string) (reflect.Method, bool) 949 var pKind types.Kind 950 951 switch dot.Sel.Name { 952 case "Method": 953 pKind = types.TINT 954 case "MethodByName": 955 pKind = types.TSTRING 956 default: 957 return 958 } 959 960 t := dot.Selection.Type 961 if t.NumParams() != 1 || t.Params().Field(0).Type.Kind() != pKind { 962 return 963 } 964 switch t.NumResults() { 965 case 1: 966 // ok 967 case 2: 968 if t.Results().Field(1).Type.Kind() != types.TBOOL { 969 return 970 } 971 default: 972 return 973 } 974 975 // Check that first result type is "reflect.Method". Note that we have to check sym name and sym package 976 // separately, as we can't check for exact string "reflect.Method" reliably (e.g., see #19028 and #38515). 977 if s := t.Results().Field(0).Type.Sym(); s != nil && s.Name == "Method" && types.IsReflectPkg(s.Pkg) { 978 ir.CurFunc.SetReflectMethod(true) 979 // The LSym is initialized at this point. We need to set the attribute on the LSym. 980 ir.CurFunc.LSym.Set(obj.AttrReflectMethod, true) 981 } 982} 983 984func usefield(n *ir.SelectorExpr) { 985 if !buildcfg.Experiment.FieldTrack { 986 return 987 } 988 989 switch n.Op() { 990 default: 991 base.Fatalf("usefield %v", n.Op()) 992 993 case ir.ODOT, ir.ODOTPTR: 994 break 995 } 996 997 field := n.Selection 998 if field == nil { 999 base.Fatalf("usefield %v %v without paramfld", n.X.Type(), n.Sel) 1000 } 1001 if field.Sym != n.Sel { 1002 base.Fatalf("field inconsistency: %v != %v", field.Sym, n.Sel) 1003 } 1004 if !strings.Contains(field.Note, "go:\"track\"") { 1005 return 1006 } 1007 1008 outer := n.X.Type() 1009 if outer.IsPtr() { 1010 outer = outer.Elem() 1011 } 1012 if outer.Sym() == nil { 1013 base.Errorf("tracked field must be in named struct type") 1014 } 1015 if !types.IsExported(field.Sym.Name) { 1016 base.Errorf("tracked field must be exported (upper case)") 1017 } 1018 1019 sym := reflectdata.TrackSym(outer, field) 1020 if ir.CurFunc.FieldTrack == nil { 1021 ir.CurFunc.FieldTrack = make(map[*obj.LSym]struct{}) 1022 } 1023 ir.CurFunc.FieldTrack[sym] = struct{}{} 1024} 1025