github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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 "github.com/gagliardetto/golang-go/cmd/compile/internal/types" 9 "github.com/gagliardetto/golang-go/cmd/internal/src" 10 "fmt" 11 ) 12 13 // Rewrite tree to use separate statements to enforce 14 // order of evaluation. Makes walk easier, because it 15 // can (after this runs) reorder at will within an expression. 16 // 17 // Rewrite m[k] op= r into m[k] = m[k] op r if op is / or %. 18 // 19 // Introduce temporaries as needed by runtime routines. 20 // For example, the map runtime routines take the map key 21 // by reference, so make sure all map keys are addressable 22 // by copying them to temporaries as needed. 23 // The same is true for channel operations. 24 // 25 // Arrange that map index expressions only appear in direct 26 // assignments x = m[k] or m[k] = x, never in larger expressions. 27 // 28 // Arrange that receive expressions only appear in direct assignments 29 // x = <-c or as standalone statements <-c, never in larger expressions. 30 31 // TODO(rsc): The temporary introduction during multiple assignments 32 // should be moved into this file, so that the temporaries can be cleaned 33 // and so that conversions implicit in the OAS2FUNC and OAS2RECV 34 // nodes can be made explicit and then have their temporaries cleaned. 35 36 // TODO(rsc): Goto and multilevel break/continue can jump over 37 // inserted VARKILL annotations. Work out a way to handle these. 38 // The current implementation is safe, in that it will execute correctly. 39 // But it won't reuse temporaries as aggressively as it might, and 40 // it can result in unnecessary zeroing of those variables in the function 41 // prologue. 42 43 // Order holds state during the ordering process. 44 type Order struct { 45 out []*Node // list of generated statements 46 temp []*Node // stack of temporary variables 47 free map[string][]*Node // free list of unused temporaries, by type.LongString(). 48 } 49 50 // Order rewrites fn.Nbody to apply the ordering constraints 51 // described in the comment at the top of the file. 52 func order(fn *Node) { 53 if Debug['W'] > 1 { 54 s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym) 55 dumplist(s, fn.Nbody) 56 } 57 58 orderBlock(&fn.Nbody, map[string][]*Node{}) 59 } 60 61 // newTemp allocates a new temporary with the given type, 62 // pushes it onto the temp stack, and returns it. 63 // If clear is true, newTemp emits code to zero the temporary. 64 func (o *Order) newTemp(t *types.Type, clear bool) *Node { 65 var v *Node 66 // Note: LongString is close to the type equality we want, 67 // but not exactly. We still need to double-check with types.Identical. 68 key := t.LongString() 69 a := o.free[key] 70 for i, n := range a { 71 if types.Identical(t, n.Type) { 72 v = a[i] 73 a[i] = a[len(a)-1] 74 a = a[:len(a)-1] 75 o.free[key] = a 76 break 77 } 78 } 79 if v == nil { 80 v = temp(t) 81 } 82 if clear { 83 a := nod(OAS, v, nil) 84 a = typecheck(a, ctxStmt) 85 o.out = append(o.out, a) 86 } 87 88 o.temp = append(o.temp, v) 89 return v 90 } 91 92 // copyExpr behaves like newTemp but also emits 93 // code to initialize the temporary to the value n. 94 // 95 // The clear argument is provided for use when the evaluation 96 // of tmp = n turns into a function call that is passed a pointer 97 // to the temporary as the output space. If the call blocks before 98 // tmp has been written, the garbage collector will still treat the 99 // temporary as live, so we must zero it before entering that call. 100 // Today, this only happens for channel receive operations. 101 // (The other candidate would be map access, but map access 102 // returns a pointer to the result data instead of taking a pointer 103 // to be filled in.) 104 func (o *Order) copyExpr(n *Node, t *types.Type, clear bool) *Node { 105 v := o.newTemp(t, clear) 106 a := nod(OAS, v, n) 107 a = typecheck(a, ctxStmt) 108 o.out = append(o.out, a) 109 return v 110 } 111 112 // cheapExpr returns a cheap version of n. 113 // The definition of cheap is that n is a variable or constant. 114 // If not, cheapExpr allocates a new tmp, emits tmp = n, 115 // and then returns tmp. 116 func (o *Order) cheapExpr(n *Node) *Node { 117 if n == nil { 118 return nil 119 } 120 121 switch n.Op { 122 case ONAME, OLITERAL: 123 return n 124 case OLEN, OCAP: 125 l := o.cheapExpr(n.Left) 126 if l == n.Left { 127 return n 128 } 129 a := n.sepcopy() 130 a.Left = l 131 return typecheck(a, ctxExpr) 132 } 133 134 return o.copyExpr(n, n.Type, false) 135 } 136 137 // safeExpr returns a safe version of n. 138 // The definition of safe is that n can appear multiple times 139 // without violating the semantics of the original program, 140 // and that assigning to the safe version has the same effect 141 // as assigning to the original n. 142 // 143 // The intended use is to apply to x when rewriting x += y into x = x + y. 144 func (o *Order) safeExpr(n *Node) *Node { 145 switch n.Op { 146 case ONAME, OLITERAL: 147 return n 148 149 case ODOT, OLEN, OCAP: 150 l := o.safeExpr(n.Left) 151 if l == n.Left { 152 return n 153 } 154 a := n.sepcopy() 155 a.Left = l 156 return typecheck(a, ctxExpr) 157 158 case ODOTPTR, ODEREF: 159 l := o.cheapExpr(n.Left) 160 if l == n.Left { 161 return n 162 } 163 a := n.sepcopy() 164 a.Left = l 165 return typecheck(a, ctxExpr) 166 167 case OINDEX, OINDEXMAP: 168 var l *Node 169 if n.Left.Type.IsArray() { 170 l = o.safeExpr(n.Left) 171 } else { 172 l = o.cheapExpr(n.Left) 173 } 174 r := o.cheapExpr(n.Right) 175 if l == n.Left && r == n.Right { 176 return n 177 } 178 a := n.sepcopy() 179 a.Left = l 180 a.Right = r 181 return typecheck(a, ctxExpr) 182 183 default: 184 Fatalf("order.safeExpr %v", n.Op) 185 return nil // not reached 186 } 187 } 188 189 // isaddrokay reports whether it is okay to pass n's address to runtime routines. 190 // Taking the address of a variable makes the liveness and optimization analyses 191 // lose track of where the variable's lifetime ends. To avoid hurting the analyses 192 // of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay, 193 // because we emit explicit VARKILL instructions marking the end of those 194 // temporaries' lifetimes. 195 func isaddrokay(n *Node) bool { 196 return islvalue(n) && (n.Op != ONAME || n.Class() == PEXTERN || n.IsAutoTmp()) 197 } 198 199 // addrTemp ensures that n is okay to pass by address to runtime routines. 200 // If the original argument n is not okay, addrTemp creates a tmp, emits 201 // tmp = n, and then returns tmp. 202 // The result of addrTemp MUST be assigned back to n, e.g. 203 // n.Left = o.addrTemp(n.Left) 204 func (o *Order) addrTemp(n *Node) *Node { 205 if consttype(n) != CTxxx { 206 // TODO: expand this to all static composite literal nodes? 207 n = defaultlit(n, nil) 208 dowidth(n.Type) 209 vstat := staticname(n.Type) 210 vstat.Name.SetReadonly(true) 211 var s InitSchedule 212 s.staticassign(vstat, n) 213 if s.out != nil { 214 Fatalf("staticassign of const generated code: %+v", n) 215 } 216 vstat = typecheck(vstat, ctxExpr) 217 return vstat 218 } 219 if isaddrokay(n) { 220 return n 221 } 222 return o.copyExpr(n, n.Type, false) 223 } 224 225 // mapKeyTemp prepares n to be a key in a map runtime call and returns n. 226 // It should only be used for map runtime calls which have *_fast* versions. 227 func (o *Order) mapKeyTemp(t *types.Type, n *Node) *Node { 228 // Most map calls need to take the address of the key. 229 // Exception: map*_fast* calls. See golang.org/issue/19015. 230 if mapfast(t) == mapslow { 231 return o.addrTemp(n) 232 } 233 return n 234 } 235 236 // mapKeyReplaceStrConv replaces OBYTES2STR by OBYTES2STRTMP 237 // in n to avoid string allocations for keys in map lookups. 238 // Returns a bool that signals if a modification was made. 239 // 240 // For: 241 // x = m[string(k)] 242 // x = m[T1{... Tn{..., string(k), ...}] 243 // where k is []byte, T1 to Tn is a nesting of struct and array literals, 244 // the allocation of backing bytes for the string can be avoided 245 // by reusing the []byte backing array. These are special cases 246 // for avoiding allocations when converting byte slices to strings. 247 // It would be nice to handle these generally, but because 248 // []byte keys are not allowed in maps, the use of string(k) 249 // comes up in important cases in practice. See issue 3512. 250 func mapKeyReplaceStrConv(n *Node) bool { 251 var replaced bool 252 switch n.Op { 253 case OBYTES2STR: 254 n.Op = OBYTES2STRTMP 255 replaced = true 256 case OSTRUCTLIT: 257 for _, elem := range n.List.Slice() { 258 if mapKeyReplaceStrConv(elem.Left) { 259 replaced = true 260 } 261 } 262 case OARRAYLIT: 263 for _, elem := range n.List.Slice() { 264 if elem.Op == OKEY { 265 elem = elem.Right 266 } 267 if mapKeyReplaceStrConv(elem) { 268 replaced = true 269 } 270 } 271 } 272 return replaced 273 } 274 275 type ordermarker int 276 277 // markTemp returns the top of the temporary variable stack. 278 func (o *Order) markTemp() ordermarker { 279 return ordermarker(len(o.temp)) 280 } 281 282 // popTemp pops temporaries off the stack until reaching the mark, 283 // which must have been returned by markTemp. 284 func (o *Order) popTemp(mark ordermarker) { 285 for _, n := range o.temp[mark:] { 286 key := n.Type.LongString() 287 o.free[key] = append(o.free[key], n) 288 } 289 o.temp = o.temp[:mark] 290 } 291 292 // cleanTempNoPop emits VARKILL and if needed VARLIVE instructions 293 // to *out for each temporary above the mark on the temporary stack. 294 // It does not pop the temporaries from the stack. 295 func (o *Order) cleanTempNoPop(mark ordermarker) []*Node { 296 var out []*Node 297 for i := len(o.temp) - 1; i >= int(mark); i-- { 298 n := o.temp[i] 299 if n.Name.Keepalive() { 300 n.Name.SetKeepalive(false) 301 n.Name.SetAddrtaken(true) // ensure SSA keeps the n variable 302 live := nod(OVARLIVE, n, nil) 303 live = typecheck(live, ctxStmt) 304 out = append(out, live) 305 } 306 kill := nod(OVARKILL, n, nil) 307 kill = typecheck(kill, ctxStmt) 308 out = append(out, kill) 309 } 310 return out 311 } 312 313 // cleanTemp emits VARKILL instructions for each temporary above the 314 // mark on the temporary stack and removes them from the stack. 315 func (o *Order) cleanTemp(top ordermarker) { 316 o.out = append(o.out, o.cleanTempNoPop(top)...) 317 o.popTemp(top) 318 } 319 320 // stmtList orders each of the statements in the list. 321 func (o *Order) stmtList(l Nodes) { 322 for _, n := range l.Slice() { 323 o.stmt(n) 324 } 325 } 326 327 // edge inserts coverage instrumentation for libfuzzer. 328 func (o *Order) edge() { 329 if Debug_libfuzzer == 0 { 330 return 331 } 332 333 // Create a new uint8 counter to be allocated in section 334 // __libfuzzer_extra_counters. 335 counter := staticname(types.Types[TUINT8]) 336 counter.Name.SetLibfuzzerExtraCounter(true) 337 338 // counter += 1 339 incr := nod(OASOP, counter, nodintconst(1)) 340 incr.SetSubOp(OADD) 341 incr = typecheck(incr, ctxStmt) 342 343 o.out = append(o.out, incr) 344 } 345 346 // orderBlock orders the block of statements in n into a new slice, 347 // and then replaces the old slice in n with the new slice. 348 // free is a map that can be used to obtain temporary variables by type. 349 func orderBlock(n *Nodes, free map[string][]*Node) { 350 var order Order 351 order.free = free 352 mark := order.markTemp() 353 order.edge() 354 order.stmtList(*n) 355 order.cleanTemp(mark) 356 n.Set(order.out) 357 } 358 359 // exprInPlace orders the side effects in *np and 360 // leaves them as the init list of the final *np. 361 // The result of exprInPlace MUST be assigned back to n, e.g. 362 // n.Left = o.exprInPlace(n.Left) 363 func (o *Order) exprInPlace(n *Node) *Node { 364 var order Order 365 order.free = o.free 366 n = order.expr(n, nil) 367 n = addinit(n, order.out) 368 369 // insert new temporaries from order 370 // at head of outer list. 371 o.temp = append(o.temp, order.temp...) 372 return n 373 } 374 375 // orderStmtInPlace orders the side effects of the single statement *np 376 // and replaces it with the resulting statement list. 377 // The result of orderStmtInPlace MUST be assigned back to n, e.g. 378 // n.Left = orderStmtInPlace(n.Left) 379 // free is a map that can be used to obtain temporary variables by type. 380 func orderStmtInPlace(n *Node, free map[string][]*Node) *Node { 381 var order Order 382 order.free = free 383 mark := order.markTemp() 384 order.stmt(n) 385 order.cleanTemp(mark) 386 return liststmt(order.out) 387 } 388 389 // init moves n's init list to o.out. 390 func (o *Order) init(n *Node) { 391 if n.mayBeShared() { 392 // For concurrency safety, don't mutate potentially shared nodes. 393 // First, ensure that no work is required here. 394 if n.Ninit.Len() > 0 { 395 Fatalf("order.init shared node with ninit") 396 } 397 return 398 } 399 o.stmtList(n.Ninit) 400 n.Ninit.Set(nil) 401 } 402 403 // call orders the call expression n. 404 // n.Op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY. 405 func (o *Order) call(n *Node) { 406 if n.Ninit.Len() > 0 { 407 // Caller should have already called o.init(n). 408 Fatalf("%v with unexpected ninit", n.Op) 409 } 410 n.Left = o.expr(n.Left, nil) 411 n.Right = o.expr(n.Right, nil) // ODDDARG temp 412 o.exprList(n.List) 413 414 if n.Op != OCALLFUNC && n.Op != OCALLMETH { 415 return 416 } 417 keepAlive := func(i int) { 418 // If the argument is really a pointer being converted to uintptr, 419 // arrange for the pointer to be kept alive until the call returns, 420 // by copying it into a temp and marking that temp 421 // still alive when we pop the temp stack. 422 xp := n.List.Addr(i) 423 for (*xp).Op == OCONVNOP && !(*xp).Type.IsUnsafePtr() { 424 xp = &(*xp).Left 425 } 426 x := *xp 427 if x.Type.IsUnsafePtr() { 428 x = o.copyExpr(x, x.Type, false) 429 x.Name.SetKeepalive(true) 430 *xp = x 431 } 432 } 433 434 for i, t := range n.Left.Type.Params().FieldSlice() { 435 // Check for "unsafe-uintptr" tag provided by escape analysis. 436 if t.IsDDD() && !n.IsDDD() { 437 if t.Note == uintptrEscapesTag { 438 for ; i < n.List.Len(); i++ { 439 keepAlive(i) 440 } 441 } 442 } else { 443 if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag { 444 keepAlive(i) 445 } 446 } 447 } 448 } 449 450 // mapAssign appends n to o.out, introducing temporaries 451 // to make sure that all map assignments have the form m[k] = x. 452 // (Note: expr has already been called on n, so we know k is addressable.) 453 // 454 // If n is the multiple assignment form ..., m[k], ... = ..., x, ..., the rewrite is 455 // t1 = m 456 // t2 = k 457 // ...., t3, ... = ..., x, ... 458 // t1[t2] = t3 459 // 460 // The temporaries t1, t2 are needed in case the ... being assigned 461 // contain m or k. They are usually unnecessary, but in the unnecessary 462 // cases they are also typically registerizable, so not much harm done. 463 // And this only applies to the multiple-assignment form. 464 // We could do a more precise analysis if needed, like in walk.go. 465 func (o *Order) mapAssign(n *Node) { 466 switch n.Op { 467 default: 468 Fatalf("order.mapAssign %v", n.Op) 469 470 case OAS, OASOP: 471 if n.Left.Op == OINDEXMAP { 472 // Make sure we evaluate the RHS before starting the map insert. 473 // We need to make sure the RHS won't panic. See issue 22881. 474 if n.Right.Op == OAPPEND { 475 s := n.Right.List.Slice()[1:] 476 for i, n := range s { 477 s[i] = o.cheapExpr(n) 478 } 479 } else { 480 n.Right = o.cheapExpr(n.Right) 481 } 482 } 483 o.out = append(o.out, n) 484 485 case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC: 486 var post []*Node 487 for i, m := range n.List.Slice() { 488 switch { 489 case m.Op == OINDEXMAP: 490 if !m.Left.IsAutoTmp() { 491 m.Left = o.copyExpr(m.Left, m.Left.Type, false) 492 } 493 if !m.Right.IsAutoTmp() { 494 m.Right = o.copyExpr(m.Right, m.Right.Type, false) 495 } 496 fallthrough 497 case instrumenting && n.Op == OAS2FUNC && !m.isBlank(): 498 t := o.newTemp(m.Type, false) 499 n.List.SetIndex(i, t) 500 a := nod(OAS, m, t) 501 a = typecheck(a, ctxStmt) 502 post = append(post, a) 503 } 504 } 505 506 o.out = append(o.out, n) 507 o.out = append(o.out, post...) 508 } 509 } 510 511 // stmt orders the statement n, appending to o.out. 512 // Temporaries created during the statement are cleaned 513 // up using VARKILL instructions as possible. 514 func (o *Order) stmt(n *Node) { 515 if n == nil { 516 return 517 } 518 519 lno := setlineno(n) 520 o.init(n) 521 522 switch n.Op { 523 default: 524 Fatalf("order.stmt %v", n.Op) 525 526 case OVARKILL, OVARLIVE, OINLMARK: 527 o.out = append(o.out, n) 528 529 case OAS: 530 t := o.markTemp() 531 n.Left = o.expr(n.Left, nil) 532 n.Right = o.expr(n.Right, n.Left) 533 o.mapAssign(n) 534 o.cleanTemp(t) 535 536 case OASOP: 537 t := o.markTemp() 538 n.Left = o.expr(n.Left, nil) 539 n.Right = o.expr(n.Right, nil) 540 541 if instrumenting || n.Left.Op == OINDEXMAP && (n.SubOp() == ODIV || n.SubOp() == OMOD) { 542 // Rewrite m[k] op= r into m[k] = m[k] op r so 543 // that we can ensure that if op panics 544 // because r is zero, the panic happens before 545 // the map assignment. 546 547 n.Left = o.safeExpr(n.Left) 548 549 l := treecopy(n.Left, src.NoXPos) 550 if l.Op == OINDEXMAP { 551 l.SetIndexMapLValue(false) 552 } 553 l = o.copyExpr(l, n.Left.Type, false) 554 n.Right = nod(n.SubOp(), l, n.Right) 555 n.Right = typecheck(n.Right, ctxExpr) 556 n.Right = o.expr(n.Right, nil) 557 558 n.Op = OAS 559 n.ResetAux() 560 } 561 562 o.mapAssign(n) 563 o.cleanTemp(t) 564 565 case OAS2: 566 t := o.markTemp() 567 o.exprList(n.List) 568 o.exprList(n.Rlist) 569 o.mapAssign(n) 570 o.cleanTemp(t) 571 572 // Special: avoid copy of func call n.Right 573 case OAS2FUNC: 574 t := o.markTemp() 575 o.exprList(n.List) 576 o.init(n.Right) 577 o.call(n.Right) 578 o.as2(n) 579 o.cleanTemp(t) 580 581 // Special: use temporary variables to hold result, 582 // so that runtime can take address of temporary. 583 // No temporary for blank assignment. 584 // 585 // OAS2MAPR: make sure key is addressable if needed, 586 // and make sure OINDEXMAP is not copied out. 587 case OAS2DOTTYPE, OAS2RECV, OAS2MAPR: 588 t := o.markTemp() 589 o.exprList(n.List) 590 591 switch r := n.Right; r.Op { 592 case ODOTTYPE2, ORECV: 593 r.Left = o.expr(r.Left, nil) 594 case OINDEXMAP: 595 r.Left = o.expr(r.Left, nil) 596 r.Right = o.expr(r.Right, nil) 597 // See similar conversion for OINDEXMAP below. 598 _ = mapKeyReplaceStrConv(r.Right) 599 r.Right = o.mapKeyTemp(r.Left.Type, r.Right) 600 default: 601 Fatalf("order.stmt: %v", r.Op) 602 } 603 604 o.okAs2(n) 605 o.cleanTemp(t) 606 607 // Special: does not save n onto out. 608 case OBLOCK, OEMPTY: 609 o.stmtList(n.List) 610 611 // Special: n->left is not an expression; save as is. 612 case OBREAK, 613 OCONTINUE, 614 ODCL, 615 ODCLCONST, 616 ODCLTYPE, 617 OFALL, 618 OGOTO, 619 OLABEL, 620 ORETJMP: 621 o.out = append(o.out, n) 622 623 // Special: handle call arguments. 624 case OCALLFUNC, OCALLINTER, OCALLMETH: 625 t := o.markTemp() 626 o.call(n) 627 o.out = append(o.out, n) 628 o.cleanTemp(t) 629 630 case OCLOSE, 631 OCOPY, 632 OPRINT, 633 OPRINTN, 634 ORECOVER, 635 ORECV: 636 t := o.markTemp() 637 n.Left = o.expr(n.Left, nil) 638 n.Right = o.expr(n.Right, nil) 639 o.exprList(n.List) 640 o.exprList(n.Rlist) 641 o.out = append(o.out, n) 642 o.cleanTemp(t) 643 644 // Special: order arguments to inner call but not call itself. 645 case ODEFER, OGO: 646 t := o.markTemp() 647 o.init(n.Left) 648 o.call(n.Left) 649 o.out = append(o.out, n) 650 o.cleanTemp(t) 651 652 case ODELETE: 653 t := o.markTemp() 654 n.List.SetFirst(o.expr(n.List.First(), nil)) 655 n.List.SetSecond(o.expr(n.List.Second(), nil)) 656 n.List.SetSecond(o.mapKeyTemp(n.List.First().Type, n.List.Second())) 657 o.out = append(o.out, n) 658 o.cleanTemp(t) 659 660 // Clean temporaries from condition evaluation at 661 // beginning of loop body and after for statement. 662 case OFOR: 663 t := o.markTemp() 664 n.Left = o.exprInPlace(n.Left) 665 n.Nbody.Prepend(o.cleanTempNoPop(t)...) 666 orderBlock(&n.Nbody, o.free) 667 n.Right = orderStmtInPlace(n.Right, o.free) 668 o.out = append(o.out, n) 669 o.cleanTemp(t) 670 671 // Clean temporaries from condition at 672 // beginning of both branches. 673 case OIF: 674 t := o.markTemp() 675 n.Left = o.exprInPlace(n.Left) 676 n.Nbody.Prepend(o.cleanTempNoPop(t)...) 677 n.Rlist.Prepend(o.cleanTempNoPop(t)...) 678 o.popTemp(t) 679 orderBlock(&n.Nbody, o.free) 680 orderBlock(&n.Rlist, o.free) 681 o.out = append(o.out, n) 682 683 // Special: argument will be converted to interface using convT2E 684 // so make sure it is an addressable temporary. 685 case OPANIC: 686 t := o.markTemp() 687 n.Left = o.expr(n.Left, nil) 688 if !n.Left.Type.IsInterface() { 689 n.Left = o.addrTemp(n.Left) 690 } 691 o.out = append(o.out, n) 692 o.cleanTemp(t) 693 694 case ORANGE: 695 // n.Right is the expression being ranged over. 696 // order it, and then make a copy if we need one. 697 // We almost always do, to ensure that we don't 698 // see any value changes made during the loop. 699 // Usually the copy is cheap (e.g., array pointer, 700 // chan, slice, string are all tiny). 701 // The exception is ranging over an array value 702 // (not a slice, not a pointer to array), 703 // which must make a copy to avoid seeing updates made during 704 // the range body. Ranging over an array value is uncommon though. 705 706 // Mark []byte(str) range expression to reuse string backing storage. 707 // It is safe because the storage cannot be mutated. 708 if n.Right.Op == OSTR2BYTES { 709 n.Right.Op = OSTR2BYTESTMP 710 } 711 712 t := o.markTemp() 713 n.Right = o.expr(n.Right, nil) 714 715 orderBody := true 716 switch n.Type.Etype { 717 default: 718 Fatalf("order.stmt range %v", n.Type) 719 720 case TARRAY, TSLICE: 721 if n.List.Len() < 2 || n.List.Second().isBlank() { 722 // for i := range x will only use x once, to compute len(x). 723 // No need to copy it. 724 break 725 } 726 fallthrough 727 728 case TCHAN, TSTRING: 729 // chan, string, slice, array ranges use value multiple times. 730 // make copy. 731 r := n.Right 732 733 if r.Type.IsString() && r.Type != types.Types[TSTRING] { 734 r = nod(OCONV, r, nil) 735 r.Type = types.Types[TSTRING] 736 r = typecheck(r, ctxExpr) 737 } 738 739 n.Right = o.copyExpr(r, r.Type, false) 740 741 case TMAP: 742 if isMapClear(n) { 743 // Preserve the body of the map clear pattern so it can 744 // be detected during walk. The loop body will not be used 745 // when optimizing away the range loop to a runtime call. 746 orderBody = false 747 break 748 } 749 750 // copy the map value in case it is a map literal. 751 // TODO(rsc): Make tmp = literal expressions reuse tmp. 752 // For maps tmp is just one word so it hardly matters. 753 r := n.Right 754 n.Right = o.copyExpr(r, r.Type, false) 755 756 // prealloc[n] is the temp for the iterator. 757 // hiter contains pointers and needs to be zeroed. 758 prealloc[n] = o.newTemp(hiter(n.Type), true) 759 } 760 o.exprListInPlace(n.List) 761 if orderBody { 762 orderBlock(&n.Nbody, o.free) 763 } 764 o.out = append(o.out, n) 765 o.cleanTemp(t) 766 767 case ORETURN: 768 o.exprList(n.List) 769 o.out = append(o.out, n) 770 771 // Special: clean case temporaries in each block entry. 772 // Select must enter one of its blocks, so there is no 773 // need for a cleaning at the end. 774 // Doubly special: evaluation order for select is stricter 775 // than ordinary expressions. Even something like p.c 776 // has to be hoisted into a temporary, so that it cannot be 777 // reordered after the channel evaluation for a different 778 // case (if p were nil, then the timing of the fault would 779 // give this away). 780 case OSELECT: 781 t := o.markTemp() 782 783 for _, n2 := range n.List.Slice() { 784 if n2.Op != OCASE { 785 Fatalf("order select case %v", n2.Op) 786 } 787 r := n2.Left 788 setlineno(n2) 789 790 // Append any new body prologue to ninit. 791 // The next loop will insert ninit into nbody. 792 if n2.Ninit.Len() != 0 { 793 Fatalf("order select ninit") 794 } 795 if r == nil { 796 continue 797 } 798 switch r.Op { 799 default: 800 Dump("select case", r) 801 Fatalf("unknown op in select %v", r.Op) 802 803 // If this is case x := <-ch or case x, y := <-ch, the case has 804 // the ODCL nodes to declare x and y. We want to delay that 805 // declaration (and possible allocation) until inside the case body. 806 // Delete the ODCL nodes here and recreate them inside the body below. 807 case OSELRECV, OSELRECV2: 808 if r.Colas() { 809 i := 0 810 if r.Ninit.Len() != 0 && r.Ninit.First().Op == ODCL && r.Ninit.First().Left == r.Left { 811 i++ 812 } 813 if i < r.Ninit.Len() && r.Ninit.Index(i).Op == ODCL && r.List.Len() != 0 && r.Ninit.Index(i).Left == r.List.First() { 814 i++ 815 } 816 if i >= r.Ninit.Len() { 817 r.Ninit.Set(nil) 818 } 819 } 820 821 if r.Ninit.Len() != 0 { 822 dumplist("ninit", r.Ninit) 823 Fatalf("ninit on select recv") 824 } 825 826 // case x = <-c 827 // case x, ok = <-c 828 // r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c. 829 // r->left == N means 'case <-c'. 830 // c is always evaluated; x and ok are only evaluated when assigned. 831 r.Right.Left = o.expr(r.Right.Left, nil) 832 833 if r.Right.Left.Op != ONAME { 834 r.Right.Left = o.copyExpr(r.Right.Left, r.Right.Left.Type, false) 835 } 836 837 // Introduce temporary for receive and move actual copy into case body. 838 // avoids problems with target being addressed, as usual. 839 // NOTE: If we wanted to be clever, we could arrange for just one 840 // temporary per distinct type, sharing the temp among all receives 841 // with that temp. Similarly one ok bool could be shared among all 842 // the x,ok receives. Not worth doing until there's a clear need. 843 if r.Left != nil && r.Left.isBlank() { 844 r.Left = nil 845 } 846 if r.Left != nil { 847 // use channel element type for temporary to avoid conversions, 848 // such as in case interfacevalue = <-intchan. 849 // the conversion happens in the OAS instead. 850 tmp1 := r.Left 851 852 if r.Colas() { 853 tmp2 := nod(ODCL, tmp1, nil) 854 tmp2 = typecheck(tmp2, ctxStmt) 855 n2.Ninit.Append(tmp2) 856 } 857 858 r.Left = o.newTemp(r.Right.Left.Type.Elem(), types.Haspointers(r.Right.Left.Type.Elem())) 859 tmp2 := nod(OAS, tmp1, r.Left) 860 tmp2 = typecheck(tmp2, ctxStmt) 861 n2.Ninit.Append(tmp2) 862 } 863 864 if r.List.Len() != 0 && r.List.First().isBlank() { 865 r.List.Set(nil) 866 } 867 if r.List.Len() != 0 { 868 tmp1 := r.List.First() 869 if r.Colas() { 870 tmp2 := nod(ODCL, tmp1, nil) 871 tmp2 = typecheck(tmp2, ctxStmt) 872 n2.Ninit.Append(tmp2) 873 } 874 875 r.List.Set1(o.newTemp(types.Types[TBOOL], false)) 876 tmp2 := okas(tmp1, r.List.First()) 877 tmp2 = typecheck(tmp2, ctxStmt) 878 n2.Ninit.Append(tmp2) 879 } 880 orderBlock(&n2.Ninit, o.free) 881 882 case OSEND: 883 if r.Ninit.Len() != 0 { 884 dumplist("ninit", r.Ninit) 885 Fatalf("ninit on select send") 886 } 887 888 // case c <- x 889 // r->left is c, r->right is x, both are always evaluated. 890 r.Left = o.expr(r.Left, nil) 891 892 if !r.Left.IsAutoTmp() { 893 r.Left = o.copyExpr(r.Left, r.Left.Type, false) 894 } 895 r.Right = o.expr(r.Right, nil) 896 if !r.Right.IsAutoTmp() { 897 r.Right = o.copyExpr(r.Right, r.Right.Type, false) 898 } 899 } 900 } 901 // Now that we have accumulated all the temporaries, clean them. 902 // Also insert any ninit queued during the previous loop. 903 // (The temporary cleaning must follow that ninit work.) 904 for _, n3 := range n.List.Slice() { 905 orderBlock(&n3.Nbody, o.free) 906 n3.Nbody.Prepend(o.cleanTempNoPop(t)...) 907 908 // TODO(mdempsky): Is this actually necessary? 909 // walkselect appears to walk Ninit. 910 n3.Nbody.Prepend(n3.Ninit.Slice()...) 911 n3.Ninit.Set(nil) 912 } 913 914 o.out = append(o.out, n) 915 o.popTemp(t) 916 917 // Special: value being sent is passed as a pointer; make it addressable. 918 case OSEND: 919 t := o.markTemp() 920 n.Left = o.expr(n.Left, nil) 921 n.Right = o.expr(n.Right, nil) 922 if instrumenting { 923 // Force copying to the stack so that (chan T)(nil) <- x 924 // is still instrumented as a read of x. 925 n.Right = o.copyExpr(n.Right, n.Right.Type, false) 926 } else { 927 n.Right = o.addrTemp(n.Right) 928 } 929 o.out = append(o.out, n) 930 o.cleanTemp(t) 931 932 // TODO(rsc): Clean temporaries more aggressively. 933 // Note that because walkswitch will rewrite some of the 934 // switch into a binary search, this is not as easy as it looks. 935 // (If we ran that code here we could invoke order.stmt on 936 // the if-else chain instead.) 937 // For now just clean all the temporaries at the end. 938 // In practice that's fine. 939 case OSWITCH: 940 if Debug_libfuzzer != 0 && !hasDefaultCase(n) { 941 // Add empty "default:" case for instrumentation. 942 n.List.Append(nod(OCASE, nil, nil)) 943 } 944 945 t := o.markTemp() 946 n.Left = o.expr(n.Left, nil) 947 for _, ncas := range n.List.Slice() { 948 if ncas.Op != OCASE { 949 Fatalf("order switch case %v", ncas.Op) 950 } 951 o.exprListInPlace(ncas.List) 952 orderBlock(&ncas.Nbody, o.free) 953 } 954 955 o.out = append(o.out, n) 956 o.cleanTemp(t) 957 } 958 959 lineno = lno 960 } 961 962 func hasDefaultCase(n *Node) bool { 963 for _, ncas := range n.List.Slice() { 964 if ncas.Op != OCASE { 965 Fatalf("expected case, found %v", ncas.Op) 966 } 967 if ncas.List.Len() == 0 { 968 return true 969 } 970 } 971 return false 972 } 973 974 // exprList orders the expression list l into o. 975 func (o *Order) exprList(l Nodes) { 976 s := l.Slice() 977 for i := range s { 978 s[i] = o.expr(s[i], nil) 979 } 980 } 981 982 // exprListInPlace orders the expression list l but saves 983 // the side effects on the individual expression ninit lists. 984 func (o *Order) exprListInPlace(l Nodes) { 985 s := l.Slice() 986 for i := range s { 987 s[i] = o.exprInPlace(s[i]) 988 } 989 } 990 991 // prealloc[x] records the allocation to use for x. 992 var prealloc = map[*Node]*Node{} 993 994 // expr orders a single expression, appending side 995 // effects to o.out as needed. 996 // If this is part of an assignment lhs = *np, lhs is given. 997 // Otherwise lhs == nil. (When lhs != nil it may be possible 998 // to avoid copying the result of the expression to a temporary.) 999 // The result of expr MUST be assigned back to n, e.g. 1000 // n.Left = o.expr(n.Left, lhs) 1001 func (o *Order) expr(n, lhs *Node) *Node { 1002 if n == nil { 1003 return n 1004 } 1005 1006 lno := setlineno(n) 1007 o.init(n) 1008 1009 switch n.Op { 1010 default: 1011 n.Left = o.expr(n.Left, nil) 1012 n.Right = o.expr(n.Right, nil) 1013 o.exprList(n.List) 1014 o.exprList(n.Rlist) 1015 1016 // Addition of strings turns into a function call. 1017 // Allocate a temporary to hold the strings. 1018 // Fewer than 5 strings use direct runtime helpers. 1019 case OADDSTR: 1020 o.exprList(n.List) 1021 1022 if n.List.Len() > 5 { 1023 t := types.NewArray(types.Types[TSTRING], int64(n.List.Len())) 1024 prealloc[n] = o.newTemp(t, false) 1025 } 1026 1027 // Mark string(byteSlice) arguments to reuse byteSlice backing 1028 // buffer during conversion. String concatenation does not 1029 // memorize the strings for later use, so it is safe. 1030 // However, we can do it only if there is at least one non-empty string literal. 1031 // Otherwise if all other arguments are empty strings, 1032 // concatstrings will return the reference to the temp string 1033 // to the caller. 1034 hasbyte := false 1035 1036 haslit := false 1037 for _, n1 := range n.List.Slice() { 1038 hasbyte = hasbyte || n1.Op == OBYTES2STR 1039 haslit = haslit || n1.Op == OLITERAL && len(strlit(n1)) != 0 1040 } 1041 1042 if haslit && hasbyte { 1043 for _, n2 := range n.List.Slice() { 1044 if n2.Op == OBYTES2STR { 1045 n2.Op = OBYTES2STRTMP 1046 } 1047 } 1048 } 1049 1050 case OINDEXMAP: 1051 n.Left = o.expr(n.Left, nil) 1052 n.Right = o.expr(n.Right, nil) 1053 needCopy := false 1054 1055 if !n.IndexMapLValue() { 1056 // Enforce that any []byte slices we are not copying 1057 // can not be changed before the map index by forcing 1058 // the map index to happen immediately following the 1059 // conversions. See copyExpr a few lines below. 1060 needCopy = mapKeyReplaceStrConv(n.Right) 1061 1062 if instrumenting { 1063 // Race detector needs the copy so it can 1064 // call treecopy on the result. 1065 needCopy = true 1066 } 1067 } 1068 1069 // key must be addressable 1070 n.Right = o.mapKeyTemp(n.Left.Type, n.Right) 1071 if needCopy { 1072 n = o.copyExpr(n, n.Type, false) 1073 } 1074 1075 // concrete type (not interface) argument might need an addressable 1076 // temporary to pass to the runtime conversion routine. 1077 case OCONVIFACE: 1078 n.Left = o.expr(n.Left, nil) 1079 if n.Left.Type.IsInterface() { 1080 break 1081 } 1082 if _, needsaddr := convFuncName(n.Left.Type, n.Type); needsaddr || isStaticCompositeLiteral(n.Left) { 1083 // Need a temp if we need to pass the address to the conversion function. 1084 // We also process static composite literal node here, making a named static global 1085 // whose address we can put directly in an interface (see OCONVIFACE case in walk). 1086 n.Left = o.addrTemp(n.Left) 1087 } 1088 1089 case OCONVNOP: 1090 if n.Type.IsKind(TUNSAFEPTR) && n.Left.Type.IsKind(TUINTPTR) && (n.Left.Op == OCALLFUNC || n.Left.Op == OCALLINTER || n.Left.Op == OCALLMETH) { 1091 // When reordering unsafe.Pointer(f()) into a separate 1092 // statement, the conversion and function call must stay 1093 // together. See golang.org/issue/15329. 1094 o.init(n.Left) 1095 o.call(n.Left) 1096 if lhs == nil || lhs.Op != ONAME || instrumenting { 1097 n = o.copyExpr(n, n.Type, false) 1098 } 1099 } else { 1100 n.Left = o.expr(n.Left, nil) 1101 } 1102 1103 case OANDAND, OOROR: 1104 // ... = LHS && RHS 1105 // 1106 // var r bool 1107 // r = LHS 1108 // if r { // or !r, for OROR 1109 // r = RHS 1110 // } 1111 // ... = r 1112 1113 r := o.newTemp(n.Type, false) 1114 1115 // Evaluate left-hand side. 1116 lhs := o.expr(n.Left, nil) 1117 o.out = append(o.out, typecheck(nod(OAS, r, lhs), ctxStmt)) 1118 1119 // Evaluate right-hand side, save generated code. 1120 saveout := o.out 1121 o.out = nil 1122 t := o.markTemp() 1123 o.edge() 1124 rhs := o.expr(n.Right, nil) 1125 o.out = append(o.out, typecheck(nod(OAS, r, rhs), ctxStmt)) 1126 o.cleanTemp(t) 1127 gen := o.out 1128 o.out = saveout 1129 1130 // If left-hand side doesn't cause a short-circuit, issue right-hand side. 1131 nif := nod(OIF, r, nil) 1132 if n.Op == OANDAND { 1133 nif.Nbody.Set(gen) 1134 } else { 1135 nif.Rlist.Set(gen) 1136 } 1137 o.out = append(o.out, nif) 1138 n = r 1139 1140 case OCALLFUNC, 1141 OCALLINTER, 1142 OCALLMETH, 1143 OCAP, 1144 OCOMPLEX, 1145 OCOPY, 1146 OIMAG, 1147 OLEN, 1148 OMAKECHAN, 1149 OMAKEMAP, 1150 OMAKESLICE, 1151 ONEW, 1152 OREAL, 1153 ORECOVER, 1154 OSTR2BYTES, 1155 OSTR2BYTESTMP, 1156 OSTR2RUNES: 1157 1158 if isRuneCount(n) { 1159 // len([]rune(s)) is rewritten to runtime.countrunes(s) later. 1160 n.Left.Left = o.expr(n.Left.Left, nil) 1161 } else { 1162 o.call(n) 1163 } 1164 1165 if lhs == nil || lhs.Op != ONAME || instrumenting { 1166 n = o.copyExpr(n, n.Type, false) 1167 } 1168 1169 case OAPPEND: 1170 // Check for append(x, make([]T, y)...) . 1171 if isAppendOfMake(n) { 1172 n.List.SetFirst(o.expr(n.List.First(), nil)) // order x 1173 n.List.Second().Left = o.expr(n.List.Second().Left, nil) // order y 1174 } else { 1175 o.exprList(n.List) 1176 } 1177 1178 if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.First()) { 1179 n = o.copyExpr(n, n.Type, false) 1180 } 1181 1182 case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR: 1183 n.Left = o.expr(n.Left, nil) 1184 low, high, max := n.SliceBounds() 1185 low = o.expr(low, nil) 1186 low = o.cheapExpr(low) 1187 high = o.expr(high, nil) 1188 high = o.cheapExpr(high) 1189 max = o.expr(max, nil) 1190 max = o.cheapExpr(max) 1191 n.SetSliceBounds(low, high, max) 1192 if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { 1193 n = o.copyExpr(n, n.Type, false) 1194 } 1195 1196 case OCLOSURE: 1197 if n.Transient() && n.Func.Closure.Func.Cvars.Len() > 0 { 1198 prealloc[n] = o.newTemp(closureType(n), false) 1199 } 1200 1201 case OSLICELIT, OCALLPART: 1202 n.Left = o.expr(n.Left, nil) 1203 n.Right = o.expr(n.Right, nil) 1204 o.exprList(n.List) 1205 o.exprList(n.Rlist) 1206 if n.Transient() { 1207 var t *types.Type 1208 switch n.Op { 1209 case OSLICELIT: 1210 t = types.NewArray(n.Type.Elem(), n.Right.Int64()) 1211 case OCALLPART: 1212 t = partialCallType(n) 1213 } 1214 prealloc[n] = o.newTemp(t, false) 1215 } 1216 1217 case ODDDARG: 1218 if n.Transient() { 1219 // The ddd argument does not live beyond the call it is created for. 1220 // Allocate a temporary that will be cleaned up when this statement 1221 // completes. We could be more aggressive and try to arrange for it 1222 // to be cleaned up when the call completes. 1223 prealloc[n] = o.newTemp(n.Type.Elem(), false) 1224 } 1225 1226 case ODOTTYPE, ODOTTYPE2: 1227 n.Left = o.expr(n.Left, nil) 1228 if !isdirectiface(n.Type) || instrumenting { 1229 n = o.copyExpr(n, n.Type, true) 1230 } 1231 1232 case ORECV: 1233 n.Left = o.expr(n.Left, nil) 1234 n = o.copyExpr(n, n.Type, true) 1235 1236 case OEQ, ONE, OLT, OLE, OGT, OGE: 1237 n.Left = o.expr(n.Left, nil) 1238 n.Right = o.expr(n.Right, nil) 1239 1240 t := n.Left.Type 1241 switch { 1242 case t.IsString(): 1243 // Mark string(byteSlice) arguments to reuse byteSlice backing 1244 // buffer during conversion. String comparison does not 1245 // memorize the strings for later use, so it is safe. 1246 if n.Left.Op == OBYTES2STR { 1247 n.Left.Op = OBYTES2STRTMP 1248 } 1249 if n.Right.Op == OBYTES2STR { 1250 n.Right.Op = OBYTES2STRTMP 1251 } 1252 1253 case t.IsStruct() || t.IsArray(): 1254 // for complex comparisons, we need both args to be 1255 // addressable so we can pass them to the runtime. 1256 n.Left = o.addrTemp(n.Left) 1257 n.Right = o.addrTemp(n.Right) 1258 } 1259 case OMAPLIT: 1260 // Order map by converting: 1261 // map[int]int{ 1262 // a(): b(), 1263 // c(): d(), 1264 // e(): f(), 1265 // } 1266 // to 1267 // m := map[int]int{} 1268 // m[a()] = b() 1269 // m[c()] = d() 1270 // m[e()] = f() 1271 // Then order the result. 1272 // Without this special case, order would otherwise compute all 1273 // the keys and values before storing any of them to the map. 1274 // See issue 26552. 1275 entries := n.List.Slice() 1276 statics := entries[:0] 1277 var dynamics []*Node 1278 for _, r := range entries { 1279 if r.Op != OKEY { 1280 Fatalf("OMAPLIT entry not OKEY: %v\n", r) 1281 } 1282 1283 if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) { 1284 dynamics = append(dynamics, r) 1285 continue 1286 } 1287 1288 // Recursively ordering some static entries can change them to dynamic; 1289 // e.g., OCONVIFACE nodes. See #31777. 1290 r = o.expr(r, nil) 1291 if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) { 1292 dynamics = append(dynamics, r) 1293 continue 1294 } 1295 1296 statics = append(statics, r) 1297 } 1298 n.List.Set(statics) 1299 1300 if len(dynamics) == 0 { 1301 break 1302 } 1303 1304 // Emit the creation of the map (with all its static entries). 1305 m := o.newTemp(n.Type, false) 1306 as := nod(OAS, m, n) 1307 typecheck(as, ctxStmt) 1308 o.stmt(as) 1309 n = m 1310 1311 // Emit eval+insert of dynamic entries, one at a time. 1312 for _, r := range dynamics { 1313 as := nod(OAS, nod(OINDEX, n, r.Left), r.Right) 1314 typecheck(as, ctxStmt) // Note: this converts the OINDEX to an OINDEXMAP 1315 o.stmt(as) 1316 } 1317 } 1318 1319 lineno = lno 1320 return n 1321 } 1322 1323 // okas creates and returns an assignment of val to ok, 1324 // including an explicit conversion if necessary. 1325 func okas(ok, val *Node) *Node { 1326 if !ok.isBlank() { 1327 val = conv(val, ok.Type) 1328 } 1329 return nod(OAS, ok, val) 1330 } 1331 1332 // as2 orders OAS2XXXX nodes. It creates temporaries to ensure left-to-right assignment. 1333 // The caller should order the right-hand side of the assignment before calling order.as2. 1334 // It rewrites, 1335 // a, b, a = ... 1336 // as 1337 // tmp1, tmp2, tmp3 = ... 1338 // a, b, a = tmp1, tmp2, tmp3 1339 // This is necessary to ensure left to right assignment order. 1340 func (o *Order) as2(n *Node) { 1341 tmplist := []*Node{} 1342 left := []*Node{} 1343 for ni, l := range n.List.Slice() { 1344 if !l.isBlank() { 1345 tmp := o.newTemp(l.Type, types.Haspointers(l.Type)) 1346 n.List.SetIndex(ni, tmp) 1347 tmplist = append(tmplist, tmp) 1348 left = append(left, l) 1349 } 1350 } 1351 1352 o.out = append(o.out, n) 1353 1354 as := nod(OAS2, nil, nil) 1355 as.List.Set(left) 1356 as.Rlist.Set(tmplist) 1357 as = typecheck(as, ctxStmt) 1358 o.stmt(as) 1359 } 1360 1361 // okAs2 orders OAS2XXX with ok. 1362 // Just like as2, this also adds temporaries to ensure left-to-right assignment. 1363 func (o *Order) okAs2(n *Node) { 1364 var tmp1, tmp2 *Node 1365 if !n.List.First().isBlank() { 1366 typ := n.Right.Type 1367 tmp1 = o.newTemp(typ, types.Haspointers(typ)) 1368 } 1369 1370 if !n.List.Second().isBlank() { 1371 tmp2 = o.newTemp(types.Types[TBOOL], false) 1372 } 1373 1374 o.out = append(o.out, n) 1375 1376 if tmp1 != nil { 1377 r := nod(OAS, n.List.First(), tmp1) 1378 r = typecheck(r, ctxStmt) 1379 o.mapAssign(r) 1380 n.List.SetFirst(tmp1) 1381 } 1382 if tmp2 != nil { 1383 r := okas(n.List.Second(), tmp2) 1384 r = typecheck(r, ctxStmt) 1385 o.mapAssign(r) 1386 n.List.SetSecond(tmp2) 1387 } 1388 }