github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/gc/order.go (about) 1 // Copyright 2012 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 5 package gc 6 7 import ( 8 "fmt" 9 "strings" 10 ) 11 12 // Rewrite tree to use separate statements to enforce 13 // order of evaluation. Makes walk easier, because it 14 // can (after this runs) reorder at will within an expression. 15 // 16 // Rewrite x op= y into x = x op y. 17 // 18 // Introduce temporaries as needed by runtime routines. 19 // For example, the map runtime routines take the map key 20 // by reference, so make sure all map keys are addressable 21 // by copying them to temporaries as needed. 22 // The same is true for channel operations. 23 // 24 // Arrange that map index expressions only appear in direct 25 // assignments x = m[k] or m[k] = x, never in larger expressions. 26 // 27 // Arrange that receive expressions only appear in direct assignments 28 // x = <-c or as standalone statements <-c, never in larger expressions. 29 30 // TODO(rsc): The temporary introduction during multiple assignments 31 // should be moved into this file, so that the temporaries can be cleaned 32 // and so that conversions implicit in the OAS2FUNC and OAS2RECV 33 // nodes can be made explicit and then have their temporaries cleaned. 34 35 // TODO(rsc): Goto and multilevel break/continue can jump over 36 // inserted VARKILL annotations. Work out a way to handle these. 37 // The current implementation is safe, in that it will execute correctly. 38 // But it won't reuse temporaries as aggressively as it might, and 39 // it can result in unnecessary zeroing of those variables in the function 40 // prologue. 41 42 // Order holds state during the ordering process. 43 type Order struct { 44 out []*Node // list of generated statements 45 temp []*Node // stack of temporary variables 46 } 47 48 // Order rewrites fn->nbody to apply the ordering constraints 49 // described in the comment at the top of the file. 50 func order(fn *Node) { 51 if Debug['W'] > 1 { 52 s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym) 53 dumplist(s, fn.Nbody) 54 } 55 56 orderblockNodes(&fn.Nbody) 57 } 58 59 // Ordertemp allocates a new temporary with the given type, 60 // pushes it onto the temp stack, and returns it. 61 // If clear is true, ordertemp emits code to zero the temporary. 62 func ordertemp(t *Type, order *Order, clear bool) *Node { 63 var_ := temp(t) 64 if clear { 65 a := Nod(OAS, var_, nil) 66 a = typecheck(a, Etop) 67 order.out = append(order.out, a) 68 } 69 70 order.temp = append(order.temp, var_) 71 return var_ 72 } 73 74 // Ordercopyexpr behaves like ordertemp but also emits 75 // code to initialize the temporary to the value n. 76 // 77 // The clear argument is provided for use when the evaluation 78 // of tmp = n turns into a function call that is passed a pointer 79 // to the temporary as the output space. If the call blocks before 80 // tmp has been written, the garbage collector will still treat the 81 // temporary as live, so we must zero it before entering that call. 82 // Today, this only happens for channel receive operations. 83 // (The other candidate would be map access, but map access 84 // returns a pointer to the result data instead of taking a pointer 85 // to be filled in.) 86 func ordercopyexpr(n *Node, t *Type, order *Order, clear int) *Node { 87 var_ := ordertemp(t, order, clear != 0) 88 a := Nod(OAS, var_, n) 89 a = typecheck(a, Etop) 90 order.out = append(order.out, a) 91 return var_ 92 } 93 94 // Ordercheapexpr returns a cheap version of n. 95 // The definition of cheap is that n is a variable or constant. 96 // If not, ordercheapexpr allocates a new tmp, emits tmp = n, 97 // and then returns tmp. 98 func ordercheapexpr(n *Node, order *Order) *Node { 99 if n == nil { 100 return nil 101 } 102 switch n.Op { 103 case ONAME, OLITERAL: 104 return n 105 case OLEN, OCAP: 106 l := ordercheapexpr(n.Left, order) 107 if l == n.Left { 108 return n 109 } 110 a := *n 111 a.Orig = &a 112 a.Left = l 113 return typecheck(&a, Erv) 114 } 115 116 return ordercopyexpr(n, n.Type, order, 0) 117 } 118 119 // Ordersafeexpr returns a safe version of n. 120 // The definition of safe is that n can appear multiple times 121 // without violating the semantics of the original program, 122 // and that assigning to the safe version has the same effect 123 // as assigning to the original n. 124 // 125 // The intended use is to apply to x when rewriting x += y into x = x + y. 126 func ordersafeexpr(n *Node, order *Order) *Node { 127 switch n.Op { 128 case ONAME, OLITERAL: 129 return n 130 131 case ODOT, OLEN, OCAP: 132 l := ordersafeexpr(n.Left, order) 133 if l == n.Left { 134 return n 135 } 136 a := *n 137 a.Orig = &a 138 a.Left = l 139 return typecheck(&a, Erv) 140 141 case ODOTPTR, OIND: 142 l := ordercheapexpr(n.Left, order) 143 if l == n.Left { 144 return n 145 } 146 a := *n 147 a.Orig = &a 148 a.Left = l 149 return typecheck(&a, Erv) 150 151 case OINDEX, OINDEXMAP: 152 var l *Node 153 if n.Left.Type.IsArray() { 154 l = ordersafeexpr(n.Left, order) 155 } else { 156 l = ordercheapexpr(n.Left, order) 157 } 158 r := ordercheapexpr(n.Right, order) 159 if l == n.Left && r == n.Right { 160 return n 161 } 162 a := *n 163 a.Orig = &a 164 a.Left = l 165 a.Right = r 166 return typecheck(&a, Erv) 167 default: 168 Fatalf("ordersafeexpr %v", n.Op) 169 return nil // not reached 170 } 171 } 172 173 // Istemp reports whether n is a temporary variable. 174 func istemp(n *Node) bool { 175 if n.Op != ONAME { 176 return false 177 } 178 return strings.HasPrefix(n.Sym.Name, "autotmp_") 179 } 180 181 // Isaddrokay reports whether it is okay to pass n's address to runtime routines. 182 // Taking the address of a variable makes the liveness and optimization analyses 183 // lose track of where the variable's lifetime ends. To avoid hurting the analyses 184 // of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay, 185 // because we emit explicit VARKILL instructions marking the end of those 186 // temporaries' lifetimes. 187 func isaddrokay(n *Node) bool { 188 return islvalue(n) && (n.Op != ONAME || n.Class == PEXTERN || istemp(n)) 189 } 190 191 // Orderaddrtemp ensures that *np is okay to pass by address to runtime routines. 192 // If the original argument *np is not okay, orderaddrtemp creates a tmp, emits 193 // tmp = *np, and then sets *np to the tmp variable. 194 func orderaddrtemp(n *Node, order *Order) *Node { 195 if isaddrokay(n) { 196 return n 197 } 198 return ordercopyexpr(n, n.Type, order, 0) 199 } 200 201 type ordermarker int 202 203 // Marktemp returns the top of the temporary variable stack. 204 func marktemp(order *Order) ordermarker { 205 return ordermarker(len(order.temp)) 206 } 207 208 // Poptemp pops temporaries off the stack until reaching the mark, 209 // which must have been returned by marktemp. 210 func poptemp(mark ordermarker, order *Order) { 211 order.temp = order.temp[:mark] 212 } 213 214 // Cleantempnopop emits to *out VARKILL instructions for each temporary 215 // above the mark on the temporary stack, but it does not pop them 216 // from the stack. 217 func cleantempnopop(mark ordermarker, order *Order, out *[]*Node) { 218 var kill *Node 219 220 for i := len(order.temp) - 1; i >= int(mark); i-- { 221 n := order.temp[i] 222 if n.Name.Keepalive { 223 n.Name.Keepalive = false 224 n.Addrtaken = true // ensure SSA keeps the n variable 225 kill = Nod(OVARLIVE, n, nil) 226 kill = typecheck(kill, Etop) 227 *out = append(*out, kill) 228 } 229 kill = Nod(OVARKILL, n, nil) 230 kill = typecheck(kill, Etop) 231 *out = append(*out, kill) 232 } 233 } 234 235 // Cleantemp emits VARKILL instructions for each temporary above the 236 // mark on the temporary stack and removes them from the stack. 237 func cleantemp(top ordermarker, order *Order) { 238 cleantempnopop(top, order, &order.out) 239 poptemp(top, order) 240 } 241 242 // Orderstmtlist orders each of the statements in the list. 243 func orderstmtlist(l Nodes, order *Order) { 244 for _, n := range l.Slice() { 245 orderstmt(n, order) 246 } 247 } 248 249 // Orderblock orders the block of statements l onto a new list, 250 // and returns the ordered list. 251 func orderblock(l Nodes) []*Node { 252 var order Order 253 mark := marktemp(&order) 254 orderstmtlist(l, &order) 255 cleantemp(mark, &order) 256 return order.out 257 } 258 259 // OrderblockNodes orders the block of statements in n into a new slice, 260 // and then replaces the old slice in n with the new slice. 261 func orderblockNodes(n *Nodes) { 262 var order Order 263 mark := marktemp(&order) 264 orderstmtlist(*n, &order) 265 cleantemp(mark, &order) 266 n.Set(order.out) 267 } 268 269 // Orderexprinplace orders the side effects in *np and 270 // leaves them as the init list of the final *np. 271 // The result of orderexprinplace MUST be assigned back to n, e.g. 272 // n.Left = orderexprinplace(n.Left, outer) 273 func orderexprinplace(n *Node, outer *Order) *Node { 274 var order Order 275 n = orderexpr(n, &order, nil) 276 n = addinit(n, order.out) 277 278 // insert new temporaries from order 279 // at head of outer list. 280 outer.temp = append(outer.temp, order.temp...) 281 return n 282 } 283 284 // Orderstmtinplace orders the side effects of the single statement *np 285 // and replaces it with the resulting statement list. 286 // The result of orderstmtinplace MUST be assigned back to n, e.g. 287 // n.Left = orderstmtinplace(n.Left) 288 func orderstmtinplace(n *Node) *Node { 289 var order Order 290 mark := marktemp(&order) 291 orderstmt(n, &order) 292 cleantemp(mark, &order) 293 return liststmt(order.out) 294 } 295 296 // Orderinit moves n's init list to order->out. 297 func orderinit(n *Node, order *Order) { 298 orderstmtlist(n.Ninit, order) 299 n.Ninit.Set(nil) 300 } 301 302 // Ismulticall reports whether the list l is f() for a multi-value function. 303 // Such an f() could appear as the lone argument to a multi-arg function. 304 func ismulticall(l Nodes) bool { 305 // one arg only 306 if l.Len() != 1 { 307 return false 308 } 309 n := l.First() 310 311 // must be call 312 switch n.Op { 313 default: 314 return false 315 316 case OCALLFUNC, OCALLMETH, OCALLINTER: 317 break 318 } 319 320 // call must return multiple values 321 return n.Left.Type.Results().NumFields() > 1 322 } 323 324 // Copyret emits t1, t2, ... = n, where n is a function call, 325 // and then returns the list t1, t2, .... 326 func copyret(n *Node, order *Order) []*Node { 327 if !n.Type.IsFuncArgStruct() { 328 Fatalf("copyret %v %d", n.Type, n.Left.Type.Results().NumFields()) 329 } 330 331 var l1 []*Node 332 var l2 []*Node 333 for _, t := range n.Type.Fields().Slice() { 334 tmp := temp(t.Type) 335 l1 = append(l1, tmp) 336 l2 = append(l2, tmp) 337 } 338 339 as := Nod(OAS2, nil, nil) 340 as.List.Set(l1) 341 as.Rlist.Set1(n) 342 as = typecheck(as, Etop) 343 orderstmt(as, order) 344 345 return l2 346 } 347 348 // Ordercallargs orders the list of call arguments *l. 349 func ordercallargs(l *Nodes, order *Order) { 350 if ismulticall(*l) { 351 // return f() where f() is multiple values. 352 l.Set(copyret(l.First(), order)) 353 } else { 354 orderexprlist(*l, order) 355 } 356 } 357 358 // Ordercall orders the call expression n. 359 // n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY. 360 func ordercall(n *Node, order *Order) { 361 n.Left = orderexpr(n.Left, order, nil) 362 n.Right = orderexpr(n.Right, order, nil) // ODDDARG temp 363 ordercallargs(&n.List, order) 364 365 if n.Op == OCALLFUNC { 366 t, it := IterFields(n.Left.Type.Params()) 367 for i := range n.List.Slice() { 368 // Check for "unsafe-uintptr" tag provided by escape analysis. 369 // If present and the argument is really a pointer being converted 370 // to uintptr, arrange for the pointer to be kept alive until the call 371 // returns, by copying it into a temp and marking that temp 372 // still alive when we pop the temp stack. 373 if t == nil { 374 break 375 } 376 if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag { 377 xp := n.List.Addr(i) 378 for (*xp).Op == OCONVNOP && !(*xp).Type.IsPtr() { 379 xp = &(*xp).Left 380 } 381 x := *xp 382 if x.Type.IsPtr() { 383 x = ordercopyexpr(x, x.Type, order, 0) 384 x.Name.Keepalive = true 385 *xp = x 386 } 387 } 388 next := it.Next() 389 if next == nil && t.Isddd && t.Note == uintptrEscapesTag { 390 next = t 391 } 392 t = next 393 } 394 } 395 } 396 397 // Ordermapassign appends n to order->out, introducing temporaries 398 // to make sure that all map assignments have the form m[k] = x, 399 // where x is addressable. 400 // (Orderexpr has already been called on n, so we know k is addressable.) 401 // 402 // If n is m[k] = x where x is not addressable, the rewrite is: 403 // tmp = x 404 // m[k] = tmp 405 // 406 // If n is the multiple assignment form ..., m[k], ... = ..., the rewrite is 407 // t1 = m 408 // t2 = k 409 // ...., t3, ... = x 410 // t1[t2] = t3 411 // 412 // The temporaries t1, t2 are needed in case the ... being assigned 413 // contain m or k. They are usually unnecessary, but in the unnecessary 414 // cases they are also typically registerizable, so not much harm done. 415 // And this only applies to the multiple-assignment form. 416 // We could do a more precise analysis if needed, like in walk.go. 417 // 418 // Ordermapassign also inserts these temporaries if needed for 419 // calling writebarrierfat with a pointer to n->right. 420 func ordermapassign(n *Node, order *Order) { 421 switch n.Op { 422 default: 423 Fatalf("ordermapassign %v", n.Op) 424 425 case OAS: 426 order.out = append(order.out, n) 427 428 // We call writebarrierfat only for values > 4 pointers long. See walk.go. 429 // TODO(mdempsky): writebarrierfat doesn't exist anymore, but removing that 430 // logic causes net/http's tests to become flaky; see CL 21242. 431 if (n.Left.Op == OINDEXMAP || (needwritebarrier(n.Left, n.Right) && n.Left.Type.Width > int64(4*Widthptr))) && !isaddrokay(n.Right) { 432 m := n.Left 433 n.Left = ordertemp(m.Type, order, false) 434 a := Nod(OAS, m, n.Left) 435 a = typecheck(a, Etop) 436 order.out = append(order.out, a) 437 } 438 439 case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC: 440 var post []*Node 441 var m *Node 442 var a *Node 443 for i1, n1 := range n.List.Slice() { 444 if n1.Op == OINDEXMAP { 445 m = n1 446 if !istemp(m.Left) { 447 m.Left = ordercopyexpr(m.Left, m.Left.Type, order, 0) 448 } 449 if !istemp(m.Right) { 450 m.Right = ordercopyexpr(m.Right, m.Right.Type, order, 0) 451 } 452 n.List.SetIndex(i1, ordertemp(m.Type, order, false)) 453 a = Nod(OAS, m, n.List.Index(i1)) 454 a = typecheck(a, Etop) 455 post = append(post, a) 456 } else if instrumenting && n.Op == OAS2FUNC && !isblank(n.List.Index(i1)) { 457 m = n.List.Index(i1) 458 t := ordertemp(m.Type, order, false) 459 n.List.SetIndex(i1, t) 460 a = Nod(OAS, m, t) 461 a = typecheck(a, Etop) 462 post = append(post, a) 463 } 464 } 465 466 order.out = append(order.out, n) 467 order.out = append(order.out, post...) 468 } 469 } 470 471 // Orderstmt orders the statement n, appending to order->out. 472 // Temporaries created during the statement are cleaned 473 // up using VARKILL instructions as possible. 474 func orderstmt(n *Node, order *Order) { 475 if n == nil { 476 return 477 } 478 479 lno := setlineno(n) 480 481 orderinit(n, order) 482 483 switch n.Op { 484 default: 485 Fatalf("orderstmt %v", n.Op) 486 487 case OVARKILL, OVARLIVE: 488 order.out = append(order.out, n) 489 490 case OAS: 491 t := marktemp(order) 492 n.Left = orderexpr(n.Left, order, nil) 493 n.Right = orderexpr(n.Right, order, n.Left) 494 ordermapassign(n, order) 495 cleantemp(t, order) 496 497 case OAS2, 498 OCLOSE, 499 OCOPY, 500 OPRINT, 501 OPRINTN, 502 ORECOVER, 503 ORECV: 504 t := marktemp(order) 505 n.Left = orderexpr(n.Left, order, nil) 506 n.Right = orderexpr(n.Right, order, nil) 507 orderexprlist(n.List, order) 508 orderexprlist(n.Rlist, order) 509 switch n.Op { 510 case OAS2, OAS2DOTTYPE: 511 ordermapassign(n, order) 512 default: 513 order.out = append(order.out, n) 514 } 515 cleantemp(t, order) 516 517 case OASOP: 518 // Special: rewrite l op= r into l = l op r. 519 // This simplifies quite a few operations; 520 // most important is that it lets us separate 521 // out map read from map write when l is 522 // a map index expression. 523 t := marktemp(order) 524 525 n.Left = orderexpr(n.Left, order, nil) 526 n.Left = ordersafeexpr(n.Left, order) 527 tmp1 := treecopy(n.Left, 0) 528 if tmp1.Op == OINDEXMAP { 529 tmp1.Etype = 0 // now an rvalue not an lvalue 530 } 531 tmp1 = ordercopyexpr(tmp1, n.Left.Type, order, 0) 532 // TODO(marvin): Fix Node.EType type union. 533 n.Right = Nod(Op(n.Etype), tmp1, n.Right) 534 n.Right = typecheck(n.Right, Erv) 535 n.Right = orderexpr(n.Right, order, nil) 536 n.Etype = 0 537 n.Op = OAS 538 ordermapassign(n, order) 539 cleantemp(t, order) 540 541 // Special: make sure key is addressable, 542 // and make sure OINDEXMAP is not copied out. 543 case OAS2MAPR: 544 t := marktemp(order) 545 546 orderexprlist(n.List, order) 547 r := n.Rlist.First() 548 r.Left = orderexpr(r.Left, order, nil) 549 r.Right = orderexpr(r.Right, order, nil) 550 551 // See case OINDEXMAP below. 552 if r.Right.Op == OARRAYBYTESTR { 553 r.Right.Op = OARRAYBYTESTRTMP 554 } 555 r.Right = orderaddrtemp(r.Right, order) 556 ordermapassign(n, order) 557 cleantemp(t, order) 558 559 // Special: avoid copy of func call n->rlist->n. 560 case OAS2FUNC: 561 t := marktemp(order) 562 563 orderexprlist(n.List, order) 564 ordercall(n.Rlist.First(), order) 565 ordermapassign(n, order) 566 cleantemp(t, order) 567 568 // Special: use temporary variables to hold result, 569 // so that assertI2Tetc can take address of temporary. 570 // No temporary for blank assignment. 571 case OAS2DOTTYPE: 572 t := marktemp(order) 573 574 orderexprlist(n.List, order) 575 n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // i in i.(T) 576 if isblank(n.List.First()) { 577 order.out = append(order.out, n) 578 } else { 579 typ := n.Rlist.First().Type 580 tmp1 := ordertemp(typ, order, haspointers(typ)) 581 order.out = append(order.out, n) 582 r := Nod(OAS, n.List.First(), tmp1) 583 r = typecheck(r, Etop) 584 ordermapassign(r, order) 585 n.List.Set([]*Node{tmp1, n.List.Second()}) 586 } 587 588 cleantemp(t, order) 589 590 // Special: use temporary variables to hold result, 591 // so that chanrecv can take address of temporary. 592 case OAS2RECV: 593 t := marktemp(order) 594 595 orderexprlist(n.List, order) 596 n.Rlist.First().Left = orderexpr(n.Rlist.First().Left, order, nil) // arg to recv 597 ch := n.Rlist.First().Left.Type 598 tmp1 := ordertemp(ch.Elem(), order, haspointers(ch.Elem())) 599 var tmp2 *Node 600 if !isblank(n.List.Second()) { 601 tmp2 = ordertemp(n.List.Second().Type, order, false) 602 } else { 603 tmp2 = ordertemp(Types[TBOOL], order, false) 604 } 605 order.out = append(order.out, n) 606 r := Nod(OAS, n.List.First(), tmp1) 607 r = typecheck(r, Etop) 608 ordermapassign(r, order) 609 r = Nod(OAS, n.List.Second(), tmp2) 610 r = typecheck(r, Etop) 611 ordermapassign(r, order) 612 n.List.Set([]*Node{tmp1, tmp2}) 613 cleantemp(t, order) 614 615 // Special: does not save n onto out. 616 case OBLOCK, OEMPTY: 617 orderstmtlist(n.List, order) 618 619 // Special: n->left is not an expression; save as is. 620 case OBREAK, 621 OCONTINUE, 622 ODCL, 623 ODCLCONST, 624 ODCLTYPE, 625 OFALL, 626 OXFALL, 627 OGOTO, 628 OLABEL, 629 ORETJMP: 630 order.out = append(order.out, n) 631 632 // Special: handle call arguments. 633 case OCALLFUNC, OCALLINTER, OCALLMETH: 634 t := marktemp(order) 635 636 ordercall(n, order) 637 order.out = append(order.out, n) 638 cleantemp(t, order) 639 640 // Special: order arguments to inner call but not call itself. 641 case ODEFER, OPROC: 642 t := marktemp(order) 643 644 switch n.Left.Op { 645 // Delete will take the address of the key. 646 // Copy key into new temp and do not clean it 647 // (it persists beyond the statement). 648 case ODELETE: 649 orderexprlist(n.Left.List, order) 650 651 t1 := marktemp(order) 652 np := n.Left.List.Addr(1) // map key 653 *np = ordercopyexpr(*np, (*np).Type, order, 0) 654 poptemp(t1, order) 655 656 default: 657 ordercall(n.Left, order) 658 } 659 660 order.out = append(order.out, n) 661 cleantemp(t, order) 662 663 case ODELETE: 664 t := marktemp(order) 665 n.List.SetIndex(0, orderexpr(n.List.Index(0), order, nil)) 666 n.List.SetIndex(1, orderexpr(n.List.Index(1), order, nil)) 667 n.List.SetIndex(1, orderaddrtemp(n.List.Index(1), order)) // map key 668 order.out = append(order.out, n) 669 cleantemp(t, order) 670 671 // Clean temporaries from condition evaluation at 672 // beginning of loop body and after for statement. 673 case OFOR: 674 t := marktemp(order) 675 676 n.Left = orderexprinplace(n.Left, order) 677 var l []*Node 678 cleantempnopop(t, order, &l) 679 n.Nbody.Set(append(l, n.Nbody.Slice()...)) 680 orderblockNodes(&n.Nbody) 681 n.Right = orderstmtinplace(n.Right) 682 order.out = append(order.out, n) 683 cleantemp(t, order) 684 685 // Clean temporaries from condition at 686 // beginning of both branches. 687 case OIF: 688 t := marktemp(order) 689 690 n.Left = orderexprinplace(n.Left, order) 691 var l []*Node 692 cleantempnopop(t, order, &l) 693 n.Nbody.Set(append(l, n.Nbody.Slice()...)) 694 l = nil 695 cleantempnopop(t, order, &l) 696 n.Rlist.Set(append(l, n.Rlist.Slice()...)) 697 poptemp(t, order) 698 orderblockNodes(&n.Nbody) 699 n.Rlist.Set(orderblock(n.Rlist)) 700 order.out = append(order.out, n) 701 702 // Special: argument will be converted to interface using convT2E 703 // so make sure it is an addressable temporary. 704 case OPANIC: 705 t := marktemp(order) 706 707 n.Left = orderexpr(n.Left, order, nil) 708 if !n.Left.Type.IsInterface() { 709 n.Left = orderaddrtemp(n.Left, order) 710 } 711 order.out = append(order.out, n) 712 cleantemp(t, order) 713 714 case ORANGE: 715 // n.Right is the expression being ranged over. 716 // order it, and then make a copy if we need one. 717 // We almost always do, to ensure that we don't 718 // see any value changes made during the loop. 719 // Usually the copy is cheap (e.g., array pointer, 720 // chan, slice, string are all tiny). 721 // The exception is ranging over an array value 722 // (not a slice, not a pointer to array), 723 // which must make a copy to avoid seeing updates made during 724 // the range body. Ranging over an array value is uncommon though. 725 726 // Mark []byte(str) range expression to reuse string backing storage. 727 // It is safe because the storage cannot be mutated. 728 if n.Right.Op == OSTRARRAYBYTE { 729 n.Right.Op = OSTRARRAYBYTETMP 730 } 731 732 t := marktemp(order) 733 n.Right = orderexpr(n.Right, order, nil) 734 switch n.Type.Etype { 735 default: 736 Fatalf("orderstmt range %v", n.Type) 737 738 case TARRAY, TSLICE: 739 if n.List.Len() < 2 || isblank(n.List.Second()) { 740 // for i := range x will only use x once, to compute len(x). 741 // No need to copy it. 742 break 743 } 744 fallthrough 745 746 case TCHAN, TSTRING: 747 // chan, string, slice, array ranges use value multiple times. 748 // make copy. 749 r := n.Right 750 751 if r.Type.IsString() && r.Type != Types[TSTRING] { 752 r = Nod(OCONV, r, nil) 753 r.Type = Types[TSTRING] 754 r = typecheck(r, Erv) 755 } 756 757 n.Right = ordercopyexpr(r, r.Type, order, 0) 758 759 case TMAP: 760 // copy the map value in case it is a map literal. 761 // TODO(rsc): Make tmp = literal expressions reuse tmp. 762 // For maps tmp is just one word so it hardly matters. 763 r := n.Right 764 n.Right = ordercopyexpr(r, r.Type, order, 0) 765 766 // n->alloc is the temp for the iterator. 767 prealloc[n] = ordertemp(Types[TUINT8], order, true) 768 } 769 for i := range n.List.Slice() { 770 n.List.SetIndex(i, orderexprinplace(n.List.Index(i), order)) 771 } 772 orderblockNodes(&n.Nbody) 773 order.out = append(order.out, n) 774 cleantemp(t, order) 775 776 case ORETURN: 777 ordercallargs(&n.List, order) 778 order.out = append(order.out, n) 779 780 // Special: clean case temporaries in each block entry. 781 // Select must enter one of its blocks, so there is no 782 // need for a cleaning at the end. 783 // Doubly special: evaluation order for select is stricter 784 // than ordinary expressions. Even something like p.c 785 // has to be hoisted into a temporary, so that it cannot be 786 // reordered after the channel evaluation for a different 787 // case (if p were nil, then the timing of the fault would 788 // give this away). 789 case OSELECT: 790 t := marktemp(order) 791 792 var tmp1 *Node 793 var tmp2 *Node 794 var r *Node 795 for _, n2 := range n.List.Slice() { 796 if n2.Op != OXCASE { 797 Fatalf("order select case %v", n2.Op) 798 } 799 r = n2.Left 800 setlineno(n2) 801 802 // Append any new body prologue to ninit. 803 // The next loop will insert ninit into nbody. 804 if n2.Ninit.Len() != 0 { 805 Fatalf("order select ninit") 806 } 807 if r != nil { 808 switch r.Op { 809 default: 810 Yyerror("unknown op in select %v", r.Op) 811 Dump("select case", r) 812 813 // If this is case x := <-ch or case x, y := <-ch, the case has 814 // the ODCL nodes to declare x and y. We want to delay that 815 // declaration (and possible allocation) until inside the case body. 816 // Delete the ODCL nodes here and recreate them inside the body below. 817 case OSELRECV, OSELRECV2: 818 if r.Colas { 819 i := 0 820 if r.Ninit.Len() != 0 && r.Ninit.First().Op == ODCL && r.Ninit.First().Left == r.Left { 821 i++ 822 } 823 if i < r.Ninit.Len() && r.Ninit.Index(i).Op == ODCL && r.List.Len() != 0 && r.Ninit.Index(i).Left == r.List.First() { 824 i++ 825 } 826 if i >= r.Ninit.Len() { 827 r.Ninit.Set(nil) 828 } 829 } 830 831 if r.Ninit.Len() != 0 { 832 Yyerror("ninit on select recv") 833 dumplist("ninit", r.Ninit) 834 } 835 836 // case x = <-c 837 // case x, ok = <-c 838 // r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c. 839 // r->left == N means 'case <-c'. 840 // c is always evaluated; x and ok are only evaluated when assigned. 841 r.Right.Left = orderexpr(r.Right.Left, order, nil) 842 843 if r.Right.Left.Op != ONAME { 844 r.Right.Left = ordercopyexpr(r.Right.Left, r.Right.Left.Type, order, 0) 845 } 846 847 // Introduce temporary for receive and move actual copy into case body. 848 // avoids problems with target being addressed, as usual. 849 // NOTE: If we wanted to be clever, we could arrange for just one 850 // temporary per distinct type, sharing the temp among all receives 851 // with that temp. Similarly one ok bool could be shared among all 852 // the x,ok receives. Not worth doing until there's a clear need. 853 if r.Left != nil && isblank(r.Left) { 854 r.Left = nil 855 } 856 if r.Left != nil { 857 // use channel element type for temporary to avoid conversions, 858 // such as in case interfacevalue = <-intchan. 859 // the conversion happens in the OAS instead. 860 tmp1 = r.Left 861 862 if r.Colas { 863 tmp2 = Nod(ODCL, tmp1, nil) 864 tmp2 = typecheck(tmp2, Etop) 865 n2.Ninit.Append(tmp2) 866 } 867 868 r.Left = ordertemp(r.Right.Left.Type.Elem(), order, haspointers(r.Right.Left.Type.Elem())) 869 tmp2 = Nod(OAS, tmp1, r.Left) 870 tmp2 = typecheck(tmp2, Etop) 871 n2.Ninit.Append(tmp2) 872 } 873 874 if r.List.Len() != 0 && isblank(r.List.First()) { 875 r.List.Set(nil) 876 } 877 if r.List.Len() != 0 { 878 tmp1 = r.List.First() 879 if r.Colas { 880 tmp2 = Nod(ODCL, tmp1, nil) 881 tmp2 = typecheck(tmp2, Etop) 882 n2.Ninit.Append(tmp2) 883 } 884 885 r.List.Set1(ordertemp(tmp1.Type, order, false)) 886 tmp2 = Nod(OAS, tmp1, r.List.First()) 887 tmp2 = typecheck(tmp2, Etop) 888 n2.Ninit.Append(tmp2) 889 } 890 n2.Ninit.Set(orderblock(n2.Ninit)) 891 892 case OSEND: 893 if r.Ninit.Len() != 0 { 894 Yyerror("ninit on select send") 895 dumplist("ninit", r.Ninit) 896 } 897 898 // case c <- x 899 // r->left is c, r->right is x, both are always evaluated. 900 r.Left = orderexpr(r.Left, order, nil) 901 902 if !istemp(r.Left) { 903 r.Left = ordercopyexpr(r.Left, r.Left.Type, order, 0) 904 } 905 r.Right = orderexpr(r.Right, order, nil) 906 if !istemp(r.Right) { 907 r.Right = ordercopyexpr(r.Right, r.Right.Type, order, 0) 908 } 909 } 910 } 911 912 orderblockNodes(&n2.Nbody) 913 } 914 // Now that we have accumulated all the temporaries, clean them. 915 // Also insert any ninit queued during the previous loop. 916 // (The temporary cleaning must follow that ninit work.) 917 for _, n3 := range n.List.Slice() { 918 s := n3.Ninit.Slice() 919 cleantempnopop(t, order, &s) 920 n3.Nbody.Set(append(s, n3.Nbody.Slice()...)) 921 n3.Ninit.Set(nil) 922 } 923 924 order.out = append(order.out, n) 925 poptemp(t, order) 926 927 // Special: value being sent is passed as a pointer; make it addressable. 928 case OSEND: 929 t := marktemp(order) 930 931 n.Left = orderexpr(n.Left, order, nil) 932 n.Right = orderexpr(n.Right, order, nil) 933 n.Right = orderaddrtemp(n.Right, order) 934 order.out = append(order.out, n) 935 cleantemp(t, order) 936 937 // TODO(rsc): Clean temporaries more aggressively. 938 // Note that because walkswitch will rewrite some of the 939 // switch into a binary search, this is not as easy as it looks. 940 // (If we ran that code here we could invoke orderstmt on 941 // the if-else chain instead.) 942 // For now just clean all the temporaries at the end. 943 // In practice that's fine. 944 case OSWITCH: 945 t := marktemp(order) 946 947 n.Left = orderexpr(n.Left, order, nil) 948 for _, n4 := range n.List.Slice() { 949 if n4.Op != OXCASE { 950 Fatalf("order switch case %v", n4.Op) 951 } 952 orderexprlistinplace(n4.List, order) 953 orderblockNodes(&n4.Nbody) 954 } 955 956 order.out = append(order.out, n) 957 cleantemp(t, order) 958 } 959 960 lineno = lno 961 } 962 963 // Orderexprlist orders the expression list l into order. 964 func orderexprlist(l Nodes, order *Order) { 965 s := l.Slice() 966 for i := range s { 967 s[i] = orderexpr(s[i], order, nil) 968 } 969 } 970 971 // Orderexprlist orders the expression list l but saves 972 // the side effects on the individual expression ninit lists. 973 func orderexprlistinplace(l Nodes, order *Order) { 974 s := l.Slice() 975 for i := range s { 976 s[i] = orderexprinplace(s[i], order) 977 } 978 } 979 980 // prealloc[x] records the allocation to use for x. 981 var prealloc = map[*Node]*Node{} 982 983 // Orderexpr orders a single expression, appending side 984 // effects to order->out as needed. 985 // If this is part of an assignment lhs = *np, lhs is given. 986 // Otherwise lhs == nil. (When lhs != nil it may be possible 987 // to avoid copying the result of the expression to a temporary.) 988 // The result of orderexpr MUST be assigned back to n, e.g. 989 // n.Left = orderexpr(n.Left, order, lhs) 990 func orderexpr(n *Node, order *Order, lhs *Node) *Node { 991 if n == nil { 992 return n 993 } 994 995 lno := setlineno(n) 996 orderinit(n, order) 997 998 switch n.Op { 999 default: 1000 n.Left = orderexpr(n.Left, order, nil) 1001 n.Right = orderexpr(n.Right, order, nil) 1002 orderexprlist(n.List, order) 1003 orderexprlist(n.Rlist, order) 1004 1005 // Addition of strings turns into a function call. 1006 // Allocate a temporary to hold the strings. 1007 // Fewer than 5 strings use direct runtime helpers. 1008 case OADDSTR: 1009 orderexprlist(n.List, order) 1010 1011 if n.List.Len() > 5 { 1012 t := typArray(Types[TSTRING], int64(n.List.Len())) 1013 prealloc[n] = ordertemp(t, order, false) 1014 } 1015 1016 // Mark string(byteSlice) arguments to reuse byteSlice backing 1017 // buffer during conversion. String concatenation does not 1018 // memorize the strings for later use, so it is safe. 1019 // However, we can do it only if there is at least one non-empty string literal. 1020 // Otherwise if all other arguments are empty strings, 1021 // concatstrings will return the reference to the temp string 1022 // to the caller. 1023 hasbyte := false 1024 1025 haslit := false 1026 for _, n1 := range n.List.Slice() { 1027 hasbyte = hasbyte || n1.Op == OARRAYBYTESTR 1028 haslit = haslit || n1.Op == OLITERAL && len(n1.Val().U.(string)) != 0 1029 } 1030 1031 if haslit && hasbyte { 1032 for _, n2 := range n.List.Slice() { 1033 if n2.Op == OARRAYBYTESTR { 1034 n2.Op = OARRAYBYTESTRTMP 1035 } 1036 } 1037 } 1038 1039 case OCMPSTR: 1040 n.Left = orderexpr(n.Left, order, nil) 1041 n.Right = orderexpr(n.Right, order, nil) 1042 1043 // Mark string(byteSlice) arguments to reuse byteSlice backing 1044 // buffer during conversion. String comparison does not 1045 // memorize the strings for later use, so it is safe. 1046 if n.Left.Op == OARRAYBYTESTR { 1047 n.Left.Op = OARRAYBYTESTRTMP 1048 } 1049 if n.Right.Op == OARRAYBYTESTR { 1050 n.Right.Op = OARRAYBYTESTRTMP 1051 } 1052 1053 // key must be addressable 1054 case OINDEXMAP: 1055 n.Left = orderexpr(n.Left, order, nil) 1056 1057 n.Right = orderexpr(n.Right, order, nil) 1058 1059 // For x = m[string(k)] where k is []byte, the allocation of 1060 // backing bytes for the string can be avoided by reusing 1061 // the []byte backing array. This is a special case that it 1062 // would be nice to handle more generally, but because 1063 // there are no []byte-keyed maps, this specific case comes 1064 // up in important cases in practice. See issue 3512. 1065 // Nothing can change the []byte we are not copying before 1066 // the map index, because the map access is going to 1067 // be forced to happen immediately following this 1068 // conversion (by the ordercopyexpr a few lines below). 1069 if n.Etype == 0 && n.Right.Op == OARRAYBYTESTR { 1070 n.Right.Op = OARRAYBYTESTRTMP 1071 } 1072 1073 n.Right = orderaddrtemp(n.Right, order) 1074 if n.Etype == 0 { 1075 // use of value (not being assigned); 1076 // make copy in temporary. 1077 n = ordercopyexpr(n, n.Type, order, 0) 1078 } 1079 1080 // concrete type (not interface) argument must be addressable 1081 // temporary to pass to runtime. 1082 case OCONVIFACE: 1083 n.Left = orderexpr(n.Left, order, nil) 1084 1085 if !n.Left.Type.IsInterface() { 1086 n.Left = orderaddrtemp(n.Left, order) 1087 } 1088 1089 case OCONVNOP: 1090 if n.Type.IsKind(TUNSAFEPTR) && n.Left.Type.IsKind(TUINTPTR) && (n.Left.Op == OCALLFUNC || n.Left.Op == OCALLINTER || n.Left.Op == OCALLMETH) { 1091 // When reordering unsafe.Pointer(f()) into a separate 1092 // statement, the conversion and function call must stay 1093 // together. See golang.org/issue/15329. 1094 orderinit(n.Left, order) 1095 ordercall(n.Left, order) 1096 if lhs == nil || lhs.Op != ONAME || instrumenting { 1097 n = ordercopyexpr(n, n.Type, order, 0) 1098 } 1099 } else { 1100 n.Left = orderexpr(n.Left, order, nil) 1101 } 1102 1103 case OANDAND, OOROR: 1104 mark := marktemp(order) 1105 n.Left = orderexpr(n.Left, order, nil) 1106 1107 // Clean temporaries from first branch at beginning of second. 1108 // Leave them on the stack so that they can be killed in the outer 1109 // context in case the short circuit is taken. 1110 var s []*Node 1111 1112 cleantempnopop(mark, order, &s) 1113 n.Right.Ninit.Set(append(s, n.Right.Ninit.Slice()...)) 1114 n.Right = orderexprinplace(n.Right, order) 1115 1116 case OCALLFUNC, 1117 OCALLINTER, 1118 OCALLMETH, 1119 OCAP, 1120 OCOMPLEX, 1121 OCOPY, 1122 OIMAG, 1123 OLEN, 1124 OMAKECHAN, 1125 OMAKEMAP, 1126 OMAKESLICE, 1127 ONEW, 1128 OREAL, 1129 ORECOVER, 1130 OSTRARRAYBYTE, 1131 OSTRARRAYBYTETMP, 1132 OSTRARRAYRUNE: 1133 ordercall(n, order) 1134 if lhs == nil || lhs.Op != ONAME || instrumenting { 1135 n = ordercopyexpr(n, n.Type, order, 0) 1136 } 1137 1138 case OAPPEND: 1139 ordercallargs(&n.List, order) 1140 if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) { 1141 n = ordercopyexpr(n, n.Type, order, 0) 1142 } 1143 1144 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: 1145 n.Left = orderexpr(n.Left, order, nil) 1146 low, high, max := n.SliceBounds() 1147 low = orderexpr(low, order, nil) 1148 low = ordercheapexpr(low, order) 1149 high = orderexpr(high, order, nil) 1150 high = ordercheapexpr(high, order) 1151 max = orderexpr(max, order, nil) 1152 max = ordercheapexpr(max, order) 1153 n.SetSliceBounds(low, high, max) 1154 if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { 1155 n = ordercopyexpr(n, n.Type, order, 0) 1156 } 1157 1158 case OCLOSURE: 1159 if n.Noescape && n.Func.Cvars.Len() > 0 { 1160 prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type 1161 } 1162 1163 case OARRAYLIT, OCALLPART: 1164 n.Left = orderexpr(n.Left, order, nil) 1165 n.Right = orderexpr(n.Right, order, nil) 1166 orderexprlist(n.List, order) 1167 orderexprlist(n.Rlist, order) 1168 if n.Noescape { 1169 prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type 1170 } 1171 1172 case ODDDARG: 1173 if n.Noescape { 1174 // The ddd argument does not live beyond the call it is created for. 1175 // Allocate a temporary that will be cleaned up when this statement 1176 // completes. We could be more aggressive and try to arrange for it 1177 // to be cleaned up when the call completes. 1178 prealloc[n] = ordertemp(n.Type.Elem(), order, false) 1179 } 1180 1181 case ODOTTYPE, ODOTTYPE2: 1182 n.Left = orderexpr(n.Left, order, nil) 1183 // TODO(rsc): The Isfat is for consistency with componentgen and walkexpr. 1184 // It needs to be removed in all three places. 1185 // That would allow inlining x.(struct{*int}) the same as x.(*int). 1186 if !isdirectiface(n.Type) || Isfat(n.Type) || instrumenting { 1187 n = ordercopyexpr(n, n.Type, order, 1) 1188 } 1189 1190 case ORECV: 1191 n.Left = orderexpr(n.Left, order, nil) 1192 n = ordercopyexpr(n, n.Type, order, 1) 1193 1194 case OEQ, ONE: 1195 n.Left = orderexpr(n.Left, order, nil) 1196 n.Right = orderexpr(n.Right, order, nil) 1197 t := n.Left.Type 1198 if t.IsStruct() || t.IsArray() { 1199 // for complex comparisons, we need both args to be 1200 // addressable so we can pass them to the runtime. 1201 n.Left = orderaddrtemp(n.Left, order) 1202 n.Right = orderaddrtemp(n.Right, order) 1203 } 1204 } 1205 1206 lineno = lno 1207 return n 1208 }