github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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 *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 Fatalf("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 { 340 Fatalf("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.go. 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 Fatalf("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.go. 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 instrumenting && 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 Fatalf("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 // TODO(marvin): Fix Node.EType type union. 513 n.Right = Nod(Op(n.Etype), tmp1, n.Right) 514 typecheck(&n.Right, Erv) 515 orderexpr(&n.Right, order, nil) 516 n.Etype = 0 517 n.Op = OAS 518 ordermapassign(n, order) 519 cleantemp(t, order) 520 521 // Special: make sure key is addressable, 522 // and make sure OINDEXMAP is not copied out. 523 case OAS2MAPR: 524 t := marktemp(order) 525 526 orderexprlist(n.List, order) 527 r := n.Rlist.N 528 orderexpr(&r.Left, order, nil) 529 orderexpr(&r.Right, order, nil) 530 531 // See case OINDEXMAP below. 532 if r.Right.Op == OARRAYBYTESTR { 533 r.Right.Op = OARRAYBYTESTRTMP 534 } 535 orderaddrtemp(&r.Right, order) 536 ordermapassign(n, order) 537 cleantemp(t, order) 538 539 // Special: avoid copy of func call n->rlist->n. 540 case OAS2FUNC: 541 t := marktemp(order) 542 543 orderexprlist(n.List, order) 544 ordercall(n.Rlist.N, order) 545 ordermapassign(n, order) 546 cleantemp(t, order) 547 548 // Special: use temporary variables to hold result, 549 // so that assertI2Tetc can take address of temporary. 550 // No temporary for blank assignment. 551 case OAS2DOTTYPE: 552 t := marktemp(order) 553 554 orderexprlist(n.List, order) 555 orderexpr(&n.Rlist.N.Left, order, nil) // i in i.(T) 556 if isblank(n.List.N) { 557 order.out = list(order.out, n) 558 } else { 559 typ := n.Rlist.N.Type 560 tmp1 := ordertemp(typ, order, haspointers(typ)) 561 order.out = list(order.out, n) 562 r := Nod(OAS, n.List.N, tmp1) 563 typecheck(&r, Etop) 564 ordermapassign(r, order) 565 n.List = list(list1(tmp1), n.List.Next.N) 566 } 567 568 cleantemp(t, order) 569 570 // Special: use temporary variables to hold result, 571 // so that chanrecv can take address of temporary. 572 case OAS2RECV: 573 t := marktemp(order) 574 575 orderexprlist(n.List, order) 576 orderexpr(&n.Rlist.N.Left, order, nil) // arg to recv 577 ch := n.Rlist.N.Left.Type 578 tmp1 := ordertemp(ch.Type, order, haspointers(ch.Type)) 579 var tmp2 *Node 580 if !isblank(n.List.Next.N) { 581 tmp2 = ordertemp(n.List.Next.N.Type, order, false) 582 } else { 583 tmp2 = ordertemp(Types[TBOOL], order, false) 584 } 585 order.out = list(order.out, n) 586 r := Nod(OAS, n.List.N, tmp1) 587 typecheck(&r, Etop) 588 ordermapassign(r, order) 589 r = Nod(OAS, n.List.Next.N, tmp2) 590 typecheck(&r, Etop) 591 ordermapassign(r, order) 592 n.List = list(list1(tmp1), tmp2) 593 cleantemp(t, order) 594 595 // Special: does not save n onto out. 596 case OBLOCK, OEMPTY: 597 orderstmtlist(n.List, order) 598 599 // Special: n->left is not an expression; save as is. 600 case OBREAK, 601 OCONTINUE, 602 ODCL, 603 ODCLCONST, 604 ODCLTYPE, 605 OFALL, 606 OXFALL, 607 OGOTO, 608 OLABEL, 609 ORETJMP: 610 order.out = list(order.out, n) 611 612 // Special: handle call arguments. 613 case OCALLFUNC, OCALLINTER, OCALLMETH: 614 t := marktemp(order) 615 616 ordercall(n, order) 617 order.out = list(order.out, n) 618 cleantemp(t, order) 619 620 // Special: order arguments to inner call but not call itself. 621 case ODEFER, OPROC: 622 t := marktemp(order) 623 624 switch n.Left.Op { 625 // Delete will take the address of the key. 626 // Copy key into new temp and do not clean it 627 // (it persists beyond the statement). 628 case ODELETE: 629 orderexprlist(n.Left.List, order) 630 631 t1 := marktemp(order) 632 np := &n.Left.List.Next.N // map key 633 *np = ordercopyexpr(*np, (*np).Type, order, 0) 634 poptemp(t1, order) 635 636 default: 637 ordercall(n.Left, order) 638 } 639 640 order.out = list(order.out, n) 641 cleantemp(t, order) 642 643 case ODELETE: 644 t := marktemp(order) 645 orderexpr(&n.List.N, order, nil) 646 orderexpr(&n.List.Next.N, order, nil) 647 orderaddrtemp(&n.List.Next.N, order) // map key 648 order.out = list(order.out, n) 649 cleantemp(t, order) 650 651 // Clean temporaries from condition evaluation at 652 // beginning of loop body and after for statement. 653 case OFOR: 654 t := marktemp(order) 655 656 orderexprinplace(&n.Left, order) 657 var l *NodeList 658 cleantempnopop(t, order, &l) 659 n.Nbody = concat(l, n.Nbody) 660 orderblock(&n.Nbody) 661 orderstmtinplace(&n.Right) 662 order.out = list(order.out, n) 663 cleantemp(t, order) 664 665 // Clean temporaries from condition at 666 // beginning of both branches. 667 case OIF: 668 t := marktemp(order) 669 670 orderexprinplace(&n.Left, order) 671 var l *NodeList 672 cleantempnopop(t, order, &l) 673 n.Nbody = concat(l, n.Nbody) 674 l = nil 675 cleantempnopop(t, order, &l) 676 n.Rlist = concat(l, n.Rlist) 677 poptemp(t, order) 678 orderblock(&n.Nbody) 679 orderblock(&n.Rlist) 680 order.out = list(order.out, n) 681 682 // Special: argument will be converted to interface using convT2E 683 // so make sure it is an addressable temporary. 684 case OPANIC: 685 t := marktemp(order) 686 687 orderexpr(&n.Left, order, nil) 688 if !Isinter(n.Left.Type) { 689 orderaddrtemp(&n.Left, order) 690 } 691 order.out = list(order.out, n) 692 cleantemp(t, order) 693 694 // n->right is the expression being ranged over. 695 // order it, and then make a copy if we need one. 696 // We almost always do, to ensure that we don't 697 // see any value changes made during the loop. 698 // Usually the copy is cheap (e.g., array pointer, chan, slice, string are all tiny). 699 // The exception is ranging over an array value (not a slice, not a pointer to array), 700 // which must make a copy to avoid seeing updates made during 701 // the range body. Ranging over an array value is uncommon though. 702 case ORANGE: 703 t := marktemp(order) 704 705 orderexpr(&n.Right, order, nil) 706 switch n.Type.Etype { 707 default: 708 Fatalf("orderstmt range %v", n.Type) 709 710 // Mark []byte(str) range expression to reuse string backing storage. 711 // It is safe because the storage cannot be mutated. 712 case TARRAY: 713 if n.Right.Op == OSTRARRAYBYTE { 714 n.Right.Op = OSTRARRAYBYTETMP 715 } 716 if count(n.List) < 2 || isblank(n.List.Next.N) { 717 // for i := range x will only use x once, to compute len(x). 718 // No need to copy it. 719 break 720 } 721 fallthrough 722 723 // chan, string, slice, array ranges use value multiple times. 724 // make copy. 725 // fall through 726 case TCHAN, TSTRING: 727 r := n.Right 728 729 if r.Type.Etype == TSTRING && r.Type != Types[TSTRING] { 730 r = Nod(OCONV, r, nil) 731 r.Type = Types[TSTRING] 732 typecheck(&r, Erv) 733 } 734 735 n.Right = ordercopyexpr(r, r.Type, order, 0) 736 737 // copy the map value in case it is a map literal. 738 // TODO(rsc): Make tmp = literal expressions reuse tmp. 739 // For maps tmp is just one word so it hardly matters. 740 case TMAP: 741 r := n.Right 742 743 n.Right = ordercopyexpr(r, r.Type, order, 0) 744 745 // n->alloc is the temp for the iterator. 746 prealloc[n] = ordertemp(Types[TUINT8], order, true) 747 } 748 749 for l := n.List; l != nil; l = l.Next { 750 orderexprinplace(&l.N, order) 751 } 752 orderblock(&n.Nbody) 753 order.out = list(order.out, n) 754 cleantemp(t, order) 755 756 case ORETURN: 757 ordercallargs(&n.List, order) 758 order.out = list(order.out, n) 759 760 // Special: clean case temporaries in each block entry. 761 // Select must enter one of its blocks, so there is no 762 // need for a cleaning at the end. 763 // Doubly special: evaluation order for select is stricter 764 // than ordinary expressions. Even something like p.c 765 // has to be hoisted into a temporary, so that it cannot be 766 // reordered after the channel evaluation for a different 767 // case (if p were nil, then the timing of the fault would 768 // give this away). 769 case OSELECT: 770 t := marktemp(order) 771 772 var tmp1 *Node 773 var tmp2 *Node 774 var r *Node 775 for l := n.List; l != nil; l = l.Next { 776 if l.N.Op != OXCASE { 777 Fatalf("order select case %v", Oconv(int(l.N.Op), 0)) 778 } 779 r = l.N.Left 780 setlineno(l.N) 781 782 // Append any new body prologue to ninit. 783 // The next loop will insert ninit into nbody. 784 if l.N.Ninit != nil { 785 Fatalf("order select ninit") 786 } 787 if r != nil { 788 switch r.Op { 789 default: 790 Yyerror("unknown op in select %v", Oconv(int(r.Op), 0)) 791 Dump("select case", r) 792 793 // If this is case x := <-ch or case x, y := <-ch, the case has 794 // the ODCL nodes to declare x and y. We want to delay that 795 // declaration (and possible allocation) until inside the case body. 796 // Delete the ODCL nodes here and recreate them inside the body below. 797 case OSELRECV, OSELRECV2: 798 if r.Colas { 799 t = r.Ninit 800 if t != nil && t.N.Op == ODCL && t.N.Left == r.Left { 801 t = t.Next 802 } 803 if t != nil && t.N.Op == ODCL && r.List != nil && t.N.Left == r.List.N { 804 t = t.Next 805 } 806 if t == nil { 807 r.Ninit = nil 808 } 809 } 810 811 if r.Ninit != nil { 812 Yyerror("ninit on select recv") 813 dumplist("ninit", r.Ninit) 814 } 815 816 // case x = <-c 817 // case x, ok = <-c 818 // r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c. 819 // r->left == N means 'case <-c'. 820 // c is always evaluated; x and ok are only evaluated when assigned. 821 orderexpr(&r.Right.Left, order, nil) 822 823 if r.Right.Left.Op != ONAME { 824 r.Right.Left = ordercopyexpr(r.Right.Left, r.Right.Left.Type, order, 0) 825 } 826 827 // Introduce temporary for receive and move actual copy into case body. 828 // avoids problems with target being addressed, as usual. 829 // NOTE: If we wanted to be clever, we could arrange for just one 830 // temporary per distinct type, sharing the temp among all receives 831 // with that temp. Similarly one ok bool could be shared among all 832 // the x,ok receives. Not worth doing until there's a clear need. 833 if r.Left != nil && isblank(r.Left) { 834 r.Left = nil 835 } 836 if r.Left != nil { 837 // use channel element type for temporary to avoid conversions, 838 // such as in case interfacevalue = <-intchan. 839 // the conversion happens in the OAS instead. 840 tmp1 = r.Left 841 842 if r.Colas { 843 tmp2 = Nod(ODCL, tmp1, nil) 844 typecheck(&tmp2, Etop) 845 l.N.Ninit = list(l.N.Ninit, tmp2) 846 } 847 848 r.Left = ordertemp(r.Right.Left.Type.Type, order, haspointers(r.Right.Left.Type.Type)) 849 tmp2 = Nod(OAS, tmp1, r.Left) 850 typecheck(&tmp2, Etop) 851 l.N.Ninit = list(l.N.Ninit, tmp2) 852 } 853 854 if r.List != nil && isblank(r.List.N) { 855 r.List = nil 856 } 857 if r.List != nil { 858 tmp1 = r.List.N 859 if r.Colas { 860 tmp2 = Nod(ODCL, tmp1, nil) 861 typecheck(&tmp2, Etop) 862 l.N.Ninit = list(l.N.Ninit, tmp2) 863 } 864 865 r.List = list1(ordertemp(tmp1.Type, order, false)) 866 tmp2 = Nod(OAS, tmp1, r.List.N) 867 typecheck(&tmp2, Etop) 868 l.N.Ninit = list(l.N.Ninit, tmp2) 869 } 870 871 orderblock(&l.N.Ninit) 872 873 case OSEND: 874 if r.Ninit != nil { 875 Yyerror("ninit on select send") 876 dumplist("ninit", r.Ninit) 877 } 878 879 // case c <- x 880 // r->left is c, r->right is x, both are always evaluated. 881 orderexpr(&r.Left, order, nil) 882 883 if !istemp(r.Left) { 884 r.Left = ordercopyexpr(r.Left, r.Left.Type, order, 0) 885 } 886 orderexpr(&r.Right, order, nil) 887 if !istemp(r.Right) { 888 r.Right = ordercopyexpr(r.Right, r.Right.Type, order, 0) 889 } 890 } 891 } 892 893 orderblock(&l.N.Nbody) 894 } 895 896 // Now that we have accumulated all the temporaries, clean them. 897 // Also insert any ninit queued during the previous loop. 898 // (The temporary cleaning must follow that ninit work.) 899 for l := n.List; l != nil; l = l.Next { 900 cleantempnopop(t, order, &l.N.Ninit) 901 l.N.Nbody = concat(l.N.Ninit, l.N.Nbody) 902 l.N.Ninit = nil 903 } 904 905 order.out = list(order.out, n) 906 poptemp(t, order) 907 908 // Special: value being sent is passed as a pointer; make it addressable. 909 case OSEND: 910 t := marktemp(order) 911 912 orderexpr(&n.Left, order, nil) 913 orderexpr(&n.Right, order, nil) 914 orderaddrtemp(&n.Right, order) 915 order.out = list(order.out, n) 916 cleantemp(t, order) 917 918 // TODO(rsc): Clean temporaries more aggressively. 919 // Note that because walkswitch will rewrite some of the 920 // switch into a binary search, this is not as easy as it looks. 921 // (If we ran that code here we could invoke orderstmt on 922 // the if-else chain instead.) 923 // For now just clean all the temporaries at the end. 924 // In practice that's fine. 925 case OSWITCH: 926 t := marktemp(order) 927 928 orderexpr(&n.Left, order, nil) 929 for l := n.List; l != nil; l = l.Next { 930 if l.N.Op != OXCASE { 931 Fatalf("order switch case %v", Oconv(int(l.N.Op), 0)) 932 } 933 orderexprlistinplace(l.N.List, order) 934 orderblock(&l.N.Nbody) 935 } 936 937 order.out = list(order.out, n) 938 cleantemp(t, order) 939 } 940 941 lineno = int32(lno) 942 } 943 944 // Orderexprlist orders the expression list l into order. 945 func orderexprlist(l *NodeList, order *Order) { 946 for ; l != nil; l = l.Next { 947 orderexpr(&l.N, order, nil) 948 } 949 } 950 951 // Orderexprlist orders the expression list l but saves 952 // the side effects on the individual expression ninit lists. 953 func orderexprlistinplace(l *NodeList, order *Order) { 954 for ; l != nil; l = l.Next { 955 orderexprinplace(&l.N, order) 956 } 957 } 958 959 // prealloc[x] records the allocation to use for x. 960 var prealloc = map[*Node]*Node{} 961 962 // Orderexpr orders a single expression, appending side 963 // effects to order->out as needed. 964 // If this is part of an assignment lhs = *np, lhs is given. 965 // Otherwise lhs == nil. (When lhs != nil it may be possible 966 // to avoid copying the result of the expression to a temporary.) 967 func orderexpr(np **Node, order *Order, lhs *Node) { 968 n := *np 969 if n == nil { 970 return 971 } 972 973 lno := int(setlineno(n)) 974 orderinit(n, order) 975 976 switch n.Op { 977 default: 978 orderexpr(&n.Left, order, nil) 979 orderexpr(&n.Right, order, nil) 980 orderexprlist(n.List, order) 981 orderexprlist(n.Rlist, order) 982 983 // Addition of strings turns into a function call. 984 // Allocate a temporary to hold the strings. 985 // Fewer than 5 strings use direct runtime helpers. 986 case OADDSTR: 987 orderexprlist(n.List, order) 988 989 if count(n.List) > 5 { 990 t := typ(TARRAY) 991 t.Bound = int64(count(n.List)) 992 t.Type = Types[TSTRING] 993 prealloc[n] = ordertemp(t, order, false) 994 } 995 996 // Mark string(byteSlice) arguments to reuse byteSlice backing 997 // buffer during conversion. String concatenation does not 998 // memorize the strings for later use, so it is safe. 999 // However, we can do it only if there is at least one non-empty string literal. 1000 // Otherwise if all other arguments are empty strings, 1001 // concatstrings will return the reference to the temp string 1002 // to the caller. 1003 hasbyte := false 1004 1005 haslit := false 1006 for l := n.List; l != nil; l = l.Next { 1007 hasbyte = hasbyte || l.N.Op == OARRAYBYTESTR 1008 haslit = haslit || l.N.Op == OLITERAL && len(l.N.Val().U.(string)) != 0 1009 } 1010 1011 if haslit && hasbyte { 1012 for l := n.List; l != nil; l = l.Next { 1013 if l.N.Op == OARRAYBYTESTR { 1014 l.N.Op = OARRAYBYTESTRTMP 1015 } 1016 } 1017 } 1018 1019 case OCMPSTR: 1020 orderexpr(&n.Left, order, nil) 1021 orderexpr(&n.Right, order, nil) 1022 1023 // Mark string(byteSlice) arguments to reuse byteSlice backing 1024 // buffer during conversion. String comparison does not 1025 // memorize the strings for later use, so it is safe. 1026 if n.Left.Op == OARRAYBYTESTR { 1027 n.Left.Op = OARRAYBYTESTRTMP 1028 } 1029 if n.Right.Op == OARRAYBYTESTR { 1030 n.Right.Op = OARRAYBYTESTRTMP 1031 } 1032 1033 // key must be addressable 1034 case OINDEXMAP: 1035 orderexpr(&n.Left, order, nil) 1036 1037 orderexpr(&n.Right, order, nil) 1038 1039 // For x = m[string(k)] where k is []byte, the allocation of 1040 // backing bytes for the string can be avoided by reusing 1041 // the []byte backing array. This is a special case that it 1042 // would be nice to handle more generally, but because 1043 // there are no []byte-keyed maps, this specific case comes 1044 // up in important cases in practice. See issue 3512. 1045 // Nothing can change the []byte we are not copying before 1046 // the map index, because the map access is going to 1047 // be forced to happen immediately following this 1048 // conversion (by the ordercopyexpr a few lines below). 1049 if n.Etype == 0 && n.Right.Op == OARRAYBYTESTR { 1050 n.Right.Op = OARRAYBYTESTRTMP 1051 } 1052 1053 orderaddrtemp(&n.Right, order) 1054 if n.Etype == 0 { 1055 // use of value (not being assigned); 1056 // make copy in temporary. 1057 n = ordercopyexpr(n, n.Type, order, 0) 1058 } 1059 1060 // concrete type (not interface) argument must be addressable 1061 // temporary to pass to runtime. 1062 case OCONVIFACE: 1063 orderexpr(&n.Left, order, nil) 1064 1065 if !Isinter(n.Left.Type) { 1066 orderaddrtemp(&n.Left, order) 1067 } 1068 1069 case OANDAND, OOROR: 1070 mark := marktemp(order) 1071 orderexpr(&n.Left, order, nil) 1072 1073 // Clean temporaries from first branch at beginning of second. 1074 // Leave them on the stack so that they can be killed in the outer 1075 // context in case the short circuit is taken. 1076 var l *NodeList 1077 1078 cleantempnopop(mark, order, &l) 1079 n.Right.Ninit = concat(l, n.Right.Ninit) 1080 orderexprinplace(&n.Right, order) 1081 1082 case OCALLFUNC, 1083 OCALLINTER, 1084 OCALLMETH, 1085 OCAP, 1086 OCOMPLEX, 1087 OCOPY, 1088 OIMAG, 1089 OLEN, 1090 OMAKECHAN, 1091 OMAKEMAP, 1092 OMAKESLICE, 1093 ONEW, 1094 OREAL, 1095 ORECOVER, 1096 OSTRARRAYBYTE, 1097 OSTRARRAYBYTETMP, 1098 OSTRARRAYRUNE: 1099 ordercall(n, order) 1100 if lhs == nil || lhs.Op != ONAME || instrumenting { 1101 n = ordercopyexpr(n, n.Type, order, 0) 1102 } 1103 1104 case OAPPEND: 1105 ordercallargs(&n.List, order) 1106 if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.N) { 1107 n = ordercopyexpr(n, n.Type, order, 0) 1108 } 1109 1110 case OSLICE, OSLICEARR, OSLICESTR: 1111 orderexpr(&n.Left, order, nil) 1112 orderexpr(&n.Right.Left, order, nil) 1113 n.Right.Left = ordercheapexpr(n.Right.Left, order) 1114 orderexpr(&n.Right.Right, order, nil) 1115 n.Right.Right = ordercheapexpr(n.Right.Right, order) 1116 if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { 1117 n = ordercopyexpr(n, n.Type, order, 0) 1118 } 1119 1120 case OSLICE3, OSLICE3ARR: 1121 orderexpr(&n.Left, order, nil) 1122 orderexpr(&n.Right.Left, order, nil) 1123 n.Right.Left = ordercheapexpr(n.Right.Left, order) 1124 orderexpr(&n.Right.Right.Left, order, nil) 1125 n.Right.Right.Left = ordercheapexpr(n.Right.Right.Left, order) 1126 orderexpr(&n.Right.Right.Right, order, nil) 1127 n.Right.Right.Right = ordercheapexpr(n.Right.Right.Right, order) 1128 if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { 1129 n = ordercopyexpr(n, n.Type, order, 0) 1130 } 1131 1132 case OCLOSURE: 1133 if n.Noescape && n.Func.Cvars != nil { 1134 prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type 1135 } 1136 1137 case OARRAYLIT, OCALLPART: 1138 orderexpr(&n.Left, order, nil) 1139 orderexpr(&n.Right, order, nil) 1140 orderexprlist(n.List, order) 1141 orderexprlist(n.Rlist, order) 1142 if n.Noescape { 1143 prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type 1144 } 1145 1146 case ODDDARG: 1147 if n.Noescape { 1148 // The ddd argument does not live beyond the call it is created for. 1149 // Allocate a temporary that will be cleaned up when this statement 1150 // completes. We could be more aggressive and try to arrange for it 1151 // to be cleaned up when the call completes. 1152 prealloc[n] = ordertemp(n.Type.Type, order, false) 1153 } 1154 1155 case ODOTTYPE, ODOTTYPE2: 1156 orderexpr(&n.Left, order, nil) 1157 // TODO(rsc): The Isfat is for consistency with componentgen and walkexpr. 1158 // It needs to be removed in all three places. 1159 // That would allow inlining x.(struct{*int}) the same as x.(*int). 1160 if !isdirectiface(n.Type) || Isfat(n.Type) || instrumenting { 1161 n = ordercopyexpr(n, n.Type, order, 1) 1162 } 1163 1164 case ORECV: 1165 orderexpr(&n.Left, order, nil) 1166 n = ordercopyexpr(n, n.Type, order, 1) 1167 1168 case OEQ, ONE: 1169 orderexpr(&n.Left, order, nil) 1170 orderexpr(&n.Right, order, nil) 1171 t := n.Left.Type 1172 if t.Etype == TSTRUCT || Isfixedarray(t) { 1173 // for complex comparisons, we need both args to be 1174 // addressable so we can pass them to the runtime. 1175 orderaddrtemp(&n.Left, order) 1176 orderaddrtemp(&n.Right, order) 1177 } 1178 } 1179 1180 lineno = int32(lno) 1181 1182 *np = n 1183 }