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