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