github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/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 ordercall(n, order) 1097 if lhs == nil || lhs.Op != ONAME || instrumenting { 1098 n = ordercopyexpr(n, n.Type, order, 0) 1099 } 1100 1101 case OAPPEND: 1102 ordercallargs(&n.List, order) 1103 if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.N) { 1104 n = ordercopyexpr(n, n.Type, order, 0) 1105 } 1106 1107 case OSLICE, OSLICEARR, OSLICESTR: 1108 orderexpr(&n.Left, order, nil) 1109 orderexpr(&n.Right.Left, order, nil) 1110 n.Right.Left = ordercheapexpr(n.Right.Left, order) 1111 orderexpr(&n.Right.Right, order, nil) 1112 n.Right.Right = ordercheapexpr(n.Right.Right, order) 1113 if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { 1114 n = ordercopyexpr(n, n.Type, order, 0) 1115 } 1116 1117 case OSLICE3, OSLICE3ARR: 1118 orderexpr(&n.Left, order, nil) 1119 orderexpr(&n.Right.Left, order, nil) 1120 n.Right.Left = ordercheapexpr(n.Right.Left, order) 1121 orderexpr(&n.Right.Right.Left, order, nil) 1122 n.Right.Right.Left = ordercheapexpr(n.Right.Right.Left, order) 1123 orderexpr(&n.Right.Right.Right, order, nil) 1124 n.Right.Right.Right = ordercheapexpr(n.Right.Right.Right, order) 1125 if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { 1126 n = ordercopyexpr(n, n.Type, order, 0) 1127 } 1128 1129 case OCLOSURE: 1130 if n.Noescape && n.Func.Cvars != nil { 1131 prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type 1132 } 1133 1134 case OARRAYLIT, OCALLPART: 1135 orderexpr(&n.Left, order, nil) 1136 orderexpr(&n.Right, order, nil) 1137 orderexprlist(n.List, order) 1138 orderexprlist(n.Rlist, order) 1139 if n.Noescape { 1140 prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type 1141 } 1142 1143 case ODDDARG: 1144 if n.Noescape { 1145 // The ddd argument does not live beyond the call it is created for. 1146 // Allocate a temporary that will be cleaned up when this statement 1147 // completes. We could be more aggressive and try to arrange for it 1148 // to be cleaned up when the call completes. 1149 prealloc[n] = ordertemp(n.Type.Type, order, false) 1150 } 1151 1152 case ODOTTYPE, ODOTTYPE2: 1153 orderexpr(&n.Left, order, nil) 1154 // TODO(rsc): The Isfat is for consistency with componentgen and walkexpr. 1155 // It needs to be removed in all three places. 1156 // That would allow inlining x.(struct{*int}) the same as x.(*int). 1157 if !isdirectiface(n.Type) || Isfat(n.Type) || instrumenting { 1158 n = ordercopyexpr(n, n.Type, order, 1) 1159 } 1160 1161 case ORECV: 1162 orderexpr(&n.Left, order, nil) 1163 n = ordercopyexpr(n, n.Type, order, 1) 1164 1165 case OEQ, ONE: 1166 orderexpr(&n.Left, order, nil) 1167 orderexpr(&n.Right, order, nil) 1168 t := n.Left.Type 1169 if t.Etype == TSTRUCT || Isfixedarray(t) { 1170 // for complex comparisons, we need both args to be 1171 // addressable so we can pass them to the runtime. 1172 orderaddrtemp(&n.Left, order) 1173 orderaddrtemp(&n.Right, order) 1174 } 1175 } 1176 1177 lineno = int32(lno) 1178 1179 *np = n 1180 }