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