github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/gc/sinit.go (about) 1 // Copyright 2009 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 "cmd/internal/obj" 9 "fmt" 10 ) 11 12 /* 13 * static initialization 14 */ 15 const ( 16 InitNotStarted = 0 17 InitDone = 1 18 InitPending = 2 19 ) 20 21 var initlist *NodeList 22 23 // init1 walks the AST starting at n, and accumulates in out 24 // the list of definitions needing init code in dependency order. 25 func init1(n *Node, out **NodeList) { 26 if n == nil { 27 return 28 } 29 init1(n.Left, out) 30 init1(n.Right, out) 31 for l := n.List; l != nil; l = l.Next { 32 init1(l.N, out) 33 } 34 35 if n.Left != nil && n.Type != nil && n.Left.Op == OTYPE && n.Class == PFUNC { 36 // Methods called as Type.Method(receiver, ...). 37 // Definitions for method expressions are stored in type->nname. 38 init1(n.Type.Nname, out) 39 } 40 41 if n.Op != ONAME { 42 return 43 } 44 switch n.Class { 45 case PEXTERN, PFUNC: 46 break 47 48 default: 49 if isblank(n) && n.Curfn == nil && n.Defn != nil && n.Defn.Initorder == InitNotStarted { 50 // blank names initialization is part of init() but not 51 // when they are inside a function. 52 break 53 } 54 55 return 56 } 57 58 if n.Initorder == InitDone { 59 return 60 } 61 if n.Initorder == InitPending { 62 // Since mutually recursive sets of functions are allowed, 63 // we don't necessarily raise an error if n depends on a node 64 // which is already waiting for its dependencies to be visited. 65 // 66 // initlist contains a cycle of identifiers referring to each other. 67 // If this cycle contains a variable, then this variable refers to itself. 68 // Conversely, if there exists an initialization cycle involving 69 // a variable in the program, the tree walk will reach a cycle 70 // involving that variable. 71 var nv *Node 72 if n.Class != PFUNC { 73 nv = n 74 goto foundinitloop 75 } 76 77 for l := initlist; l.N != n; l = l.Next { 78 if l.N.Class != PFUNC { 79 nv = l.N 80 goto foundinitloop 81 } 82 } 83 84 // The loop involves only functions, ok. 85 return 86 87 // if there have already been errors printed, 88 // those errors probably confused us and 89 // there might not be a loop. let the user 90 // fix those first. 91 foundinitloop: 92 Flusherrors() 93 94 if nerrors > 0 { 95 errorexit() 96 } 97 98 // There is a loop involving nv. We know about 99 // n and initlist = n1 <- ... <- nv <- ... <- n <- ... 100 fmt.Printf("%v: initialization loop:\n", nv.Line()) 101 102 // Build back pointers in initlist. 103 for l := initlist; l != nil; l = l.Next { 104 if l.Next != nil { 105 l.Next.End = l 106 } 107 } 108 109 // Print nv -> ... -> n1 -> n. 110 var l *NodeList 111 for l = initlist; l.N != nv; l = l.Next { 112 } 113 for ; l != nil; l = l.End { 114 fmt.Printf("\t%v %v refers to\n", l.N.Line(), Sconv(l.N.Sym, 0)) 115 } 116 117 // Print n -> ... -> nv. 118 for l = initlist; l.N != n; l = l.Next { 119 } 120 for ; l.N != nv; l = l.End { 121 fmt.Printf("\t%v %v refers to\n", l.N.Line(), Sconv(l.N.Sym, 0)) 122 } 123 fmt.Printf("\t%v %v\n", nv.Line(), Sconv(nv.Sym, 0)) 124 errorexit() 125 } 126 127 // reached a new unvisited node. 128 n.Initorder = InitPending 129 130 l := new(NodeList) 131 if l == nil { 132 Flusherrors() 133 Yyerror("out of memory") 134 errorexit() 135 } 136 137 l.Next = initlist 138 l.N = n 139 l.End = nil 140 initlist = l 141 142 // make sure that everything n depends on is initialized. 143 // n->defn is an assignment to n 144 if n.Defn != nil { 145 switch n.Defn.Op { 146 default: 147 goto bad 148 149 case ODCLFUNC: 150 init2list(n.Defn.Nbody, out) 151 152 case OAS: 153 if n.Defn.Left != n { 154 goto bad 155 } 156 if isblank(n.Defn.Left) && candiscard(n.Defn.Right) { 157 n.Defn.Op = OEMPTY 158 n.Defn.Left = nil 159 n.Defn.Right = nil 160 break 161 } 162 163 init2(n.Defn.Right, out) 164 if Debug['j'] != 0 { 165 fmt.Printf("%v\n", Sconv(n.Sym, 0)) 166 } 167 if isblank(n) || !staticinit(n, out) { 168 if Debug['%'] != 0 { 169 Dump("nonstatic", n.Defn) 170 } 171 *out = list(*out, n.Defn) 172 } 173 174 case OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV: 175 if n.Defn.Initorder != InitNotStarted { 176 break 177 } 178 n.Defn.Initorder = InitDone 179 for l := n.Defn.Rlist; l != nil; l = l.Next { 180 init1(l.N, out) 181 } 182 if Debug['%'] != 0 { 183 Dump("nonstatic", n.Defn) 184 } 185 *out = list(*out, n.Defn) 186 } 187 } 188 189 l = initlist 190 initlist = l.Next 191 if l.N != n { 192 Fatal("bad initlist") 193 } 194 195 n.Initorder = InitDone 196 return 197 198 bad: 199 Dump("defn", n.Defn) 200 Fatal("init1: bad defn") 201 } 202 203 // recurse over n, doing init1 everywhere. 204 func init2(n *Node, out **NodeList) { 205 if n == nil || n.Initorder == InitDone { 206 return 207 } 208 209 if n.Op == ONAME && n.Ninit != nil { 210 Fatal("name %v with ninit: %v\n", Sconv(n.Sym, 0), Nconv(n, obj.FmtSign)) 211 } 212 213 init1(n, out) 214 init2(n.Left, out) 215 init2(n.Right, out) 216 init2(n.Ntest, out) 217 init2list(n.Ninit, out) 218 init2list(n.List, out) 219 init2list(n.Rlist, out) 220 init2list(n.Nbody, out) 221 init2list(n.Nelse, out) 222 223 if n.Op == OCLOSURE { 224 init2list(n.Closure.Nbody, out) 225 } 226 if n.Op == ODOTMETH || n.Op == OCALLPART { 227 init2(n.Type.Nname, out) 228 } 229 } 230 231 func init2list(l *NodeList, out **NodeList) { 232 for ; l != nil; l = l.Next { 233 init2(l.N, out) 234 } 235 } 236 237 func initreorder(l *NodeList, out **NodeList) { 238 var n *Node 239 240 for ; l != nil; l = l.Next { 241 n = l.N 242 switch n.Op { 243 case ODCLFUNC, ODCLCONST, ODCLTYPE: 244 continue 245 } 246 247 initreorder(n.Ninit, out) 248 n.Ninit = nil 249 init1(n, out) 250 } 251 } 252 253 // initfix computes initialization order for a list l of top-level 254 // declarations and outputs the corresponding list of statements 255 // to include in the init() function body. 256 func initfix(l *NodeList) *NodeList { 257 var lout *NodeList 258 lno := int(lineno) 259 initreorder(l, &lout) 260 lineno = int32(lno) 261 return lout 262 } 263 264 /* 265 * compilation of top-level (static) assignments 266 * into DATA statements if at all possible. 267 */ 268 func staticinit(n *Node, out **NodeList) bool { 269 if n.Op != ONAME || n.Class != PEXTERN || n.Defn == nil || n.Defn.Op != OAS { 270 Fatal("staticinit") 271 } 272 273 lineno = n.Lineno 274 l := n.Defn.Left 275 r := n.Defn.Right 276 return staticassign(l, r, out) 277 } 278 279 // like staticassign but we are copying an already 280 // initialized value r. 281 func staticcopy(l *Node, r *Node, out **NodeList) bool { 282 if r.Op != ONAME { 283 return false 284 } 285 if r.Class == PFUNC { 286 gdata(l, r, Widthptr) 287 return true 288 } 289 if r.Class != PEXTERN || r.Sym.Pkg != localpkg { 290 return false 291 } 292 if r.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value 293 return false 294 } 295 if r.Defn.Op != OAS { 296 return false 297 } 298 orig := r 299 r = r.Defn.Right 300 301 switch r.Op { 302 case ONAME: 303 if staticcopy(l, r, out) { 304 return true 305 } 306 *out = list(*out, Nod(OAS, l, r)) 307 return true 308 309 case OLITERAL: 310 if iszero(r) { 311 return true 312 } 313 gdata(l, r, int(l.Type.Width)) 314 return true 315 316 case OADDR: 317 switch r.Left.Op { 318 case ONAME: 319 gdata(l, r, int(l.Type.Width)) 320 return true 321 } 322 323 case OPTRLIT: 324 switch r.Left.Op { 325 //dump("not static addr", r); 326 default: 327 break 328 329 // copy pointer 330 case OARRAYLIT, OSTRUCTLIT, OMAPLIT: 331 gdata(l, Nod(OADDR, r.Nname, nil), int(l.Type.Width)) 332 333 return true 334 } 335 336 case OARRAYLIT: 337 if Isslice(r.Type) { 338 // copy slice 339 a := r.Nname 340 341 n1 := *l 342 n1.Xoffset = l.Xoffset + int64(Array_array) 343 gdata(&n1, Nod(OADDR, a, nil), Widthptr) 344 n1.Xoffset = l.Xoffset + int64(Array_nel) 345 gdata(&n1, r.Right, Widthint) 346 n1.Xoffset = l.Xoffset + int64(Array_cap) 347 gdata(&n1, r.Right, Widthint) 348 return true 349 } 350 fallthrough 351 352 // fall through 353 case OSTRUCTLIT: 354 p := r.Initplan 355 356 n1 := *l 357 var e *InitEntry 358 var ll *Node 359 var rr *Node 360 for i := 0; i < len(p.E); i++ { 361 e = &p.E[i] 362 n1.Xoffset = l.Xoffset + e.Xoffset 363 n1.Type = e.Expr.Type 364 if e.Expr.Op == OLITERAL { 365 gdata(&n1, e.Expr, int(n1.Type.Width)) 366 } else { 367 ll = Nod(OXXX, nil, nil) 368 *ll = n1 369 ll.Orig = ll // completely separate copy 370 if !staticassign(ll, e.Expr, out) { 371 // Requires computation, but we're 372 // copying someone else's computation. 373 rr = Nod(OXXX, nil, nil) 374 375 *rr = *orig 376 rr.Orig = rr // completely separate copy 377 rr.Type = ll.Type 378 rr.Xoffset += e.Xoffset 379 *out = list(*out, Nod(OAS, ll, rr)) 380 } 381 } 382 } 383 384 return true 385 } 386 387 return false 388 } 389 390 func staticassign(l *Node, r *Node, out **NodeList) bool { 391 var n1 Node 392 393 switch r.Op { 394 //dump("not static", r); 395 default: 396 break 397 398 case ONAME: 399 return staticcopy(l, r, out) 400 401 case OLITERAL: 402 if iszero(r) { 403 return true 404 } 405 gdata(l, r, int(l.Type.Width)) 406 return true 407 408 case OADDR: 409 var nam Node 410 if stataddr(&nam, r.Left) { 411 n1 := *r 412 n1.Left = &nam 413 gdata(l, &n1, int(l.Type.Width)) 414 return true 415 } 416 fallthrough 417 418 case OPTRLIT: 419 switch r.Left.Op { 420 //dump("not static ptrlit", r); 421 default: 422 break 423 424 // Init pointer. 425 case OARRAYLIT, OMAPLIT, OSTRUCTLIT: 426 a := staticname(r.Left.Type, 1) 427 428 r.Nname = a 429 gdata(l, Nod(OADDR, a, nil), int(l.Type.Width)) 430 431 // Init underlying literal. 432 if !staticassign(a, r.Left, out) { 433 *out = list(*out, Nod(OAS, a, r.Left)) 434 } 435 return true 436 } 437 438 case OSTRARRAYBYTE: 439 if l.Class == PEXTERN && r.Left.Op == OLITERAL { 440 sval := r.Left.Val.U.Sval 441 slicebytes(l, sval, len(sval)) 442 return true 443 } 444 445 case OARRAYLIT: 446 initplan(r) 447 if Isslice(r.Type) { 448 // Init slice. 449 ta := typ(TARRAY) 450 451 ta.Type = r.Type.Type 452 ta.Bound = Mpgetfix(r.Right.Val.U.Xval) 453 a := staticname(ta, 1) 454 r.Nname = a 455 n1 = *l 456 n1.Xoffset = l.Xoffset + int64(Array_array) 457 gdata(&n1, Nod(OADDR, a, nil), Widthptr) 458 n1.Xoffset = l.Xoffset + int64(Array_nel) 459 gdata(&n1, r.Right, Widthint) 460 n1.Xoffset = l.Xoffset + int64(Array_cap) 461 gdata(&n1, r.Right, Widthint) 462 463 // Fall through to init underlying array. 464 l = a 465 } 466 fallthrough 467 468 // fall through 469 case OSTRUCTLIT: 470 initplan(r) 471 472 p := r.Initplan 473 n1 = *l 474 var e *InitEntry 475 var a *Node 476 for i := 0; i < len(p.E); i++ { 477 e = &p.E[i] 478 n1.Xoffset = l.Xoffset + e.Xoffset 479 n1.Type = e.Expr.Type 480 if e.Expr.Op == OLITERAL { 481 gdata(&n1, e.Expr, int(n1.Type.Width)) 482 } else { 483 a = Nod(OXXX, nil, nil) 484 *a = n1 485 a.Orig = a // completely separate copy 486 if !staticassign(a, e.Expr, out) { 487 *out = list(*out, Nod(OAS, a, e.Expr)) 488 } 489 } 490 } 491 492 return true 493 494 // TODO: Table-driven map insert. 495 case OMAPLIT: 496 break 497 } 498 499 return false 500 } 501 502 /* 503 * from here down is the walk analysis 504 * of composite literals. 505 * most of the work is to generate 506 * data statements for the constant 507 * part of the composite literal. 508 */ 509 func staticname(t *Type, ctxt int) *Node { 510 n := newname(Lookupf("statictmp_%.4d", statuniqgen)) 511 statuniqgen++ 512 if ctxt == 0 { 513 n.Readonly = true 514 } 515 addvar(n, t, PEXTERN) 516 return n 517 } 518 519 func isliteral(n *Node) bool { 520 if n.Op == OLITERAL { 521 if n.Val.Ctype != CTNIL { 522 return true 523 } 524 } 525 return false 526 } 527 528 func simplename(n *Node) bool { 529 if n.Op != ONAME { 530 return false 531 } 532 if !n.Addable { 533 return false 534 } 535 if n.Class&PHEAP != 0 { 536 return false 537 } 538 if n.Class == PPARAMREF { 539 return false 540 } 541 return true 542 } 543 544 func litas(l *Node, r *Node, init **NodeList) { 545 a := Nod(OAS, l, r) 546 typecheck(&a, Etop) 547 walkexpr(&a, init) 548 *init = list(*init, a) 549 } 550 551 const ( 552 MODEDYNAM = 1 553 MODECONST = 2 554 ) 555 556 func getdyn(n *Node, top int) int { 557 mode := 0 558 switch n.Op { 559 default: 560 if isliteral(n) { 561 return MODECONST 562 } 563 return MODEDYNAM 564 565 case OARRAYLIT: 566 if top == 0 && n.Type.Bound < 0 { 567 return MODEDYNAM 568 } 569 fallthrough 570 571 case OSTRUCTLIT: 572 break 573 } 574 575 var value *Node 576 for nl := n.List; nl != nil; nl = nl.Next { 577 value = nl.N.Right 578 mode |= getdyn(value, 0) 579 if mode == MODEDYNAM|MODECONST { 580 break 581 } 582 } 583 584 return mode 585 } 586 587 func structlit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) { 588 var r *Node 589 var a *Node 590 var index *Node 591 var value *Node 592 593 for nl := n.List; nl != nil; nl = nl.Next { 594 r = nl.N 595 if r.Op != OKEY { 596 Fatal("structlit: rhs not OKEY: %v", Nconv(r, 0)) 597 } 598 index = r.Left 599 value = r.Right 600 601 switch value.Op { 602 case OARRAYLIT: 603 if value.Type.Bound < 0 { 604 if pass == 1 && ctxt != 0 { 605 a = Nod(ODOT, var_, newname(index.Sym)) 606 slicelit(ctxt, value, a, init) 607 } else if pass == 2 && ctxt == 0 { 608 a = Nod(ODOT, var_, newname(index.Sym)) 609 slicelit(ctxt, value, a, init) 610 } else if pass == 3 { 611 break 612 } 613 continue 614 } 615 616 a = Nod(ODOT, var_, newname(index.Sym)) 617 arraylit(ctxt, pass, value, a, init) 618 continue 619 620 case OSTRUCTLIT: 621 a = Nod(ODOT, var_, newname(index.Sym)) 622 structlit(ctxt, pass, value, a, init) 623 continue 624 } 625 626 if isliteral(value) { 627 if pass == 2 { 628 continue 629 } 630 } else if pass == 1 { 631 continue 632 } 633 634 // build list of var.field = expr 635 a = Nod(ODOT, var_, newname(index.Sym)) 636 637 a = Nod(OAS, a, value) 638 typecheck(&a, Etop) 639 if pass == 1 { 640 walkexpr(&a, init) // add any assignments in r to top 641 if a.Op != OAS { 642 Fatal("structlit: not as") 643 } 644 a.Dodata = 2 645 } else { 646 orderstmtinplace(&a) 647 walkstmt(&a) 648 } 649 650 *init = list(*init, a) 651 } 652 } 653 654 func arraylit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) { 655 var r *Node 656 var a *Node 657 var index *Node 658 var value *Node 659 660 for l := n.List; l != nil; l = l.Next { 661 r = l.N 662 if r.Op != OKEY { 663 Fatal("arraylit: rhs not OKEY: %v", Nconv(r, 0)) 664 } 665 index = r.Left 666 value = r.Right 667 668 switch value.Op { 669 case OARRAYLIT: 670 if value.Type.Bound < 0 { 671 if pass == 1 && ctxt != 0 { 672 a = Nod(OINDEX, var_, index) 673 slicelit(ctxt, value, a, init) 674 } else if pass == 2 && ctxt == 0 { 675 a = Nod(OINDEX, var_, index) 676 slicelit(ctxt, value, a, init) 677 } else if pass == 3 { 678 break 679 } 680 continue 681 } 682 683 a = Nod(OINDEX, var_, index) 684 arraylit(ctxt, pass, value, a, init) 685 continue 686 687 case OSTRUCTLIT: 688 a = Nod(OINDEX, var_, index) 689 structlit(ctxt, pass, value, a, init) 690 continue 691 } 692 693 if isliteral(index) && isliteral(value) { 694 if pass == 2 { 695 continue 696 } 697 } else if pass == 1 { 698 continue 699 } 700 701 // build list of var[index] = value 702 a = Nod(OINDEX, var_, index) 703 704 a = Nod(OAS, a, value) 705 typecheck(&a, Etop) 706 if pass == 1 { 707 walkexpr(&a, init) 708 if a.Op != OAS { 709 Fatal("arraylit: not as") 710 } 711 a.Dodata = 2 712 } else { 713 orderstmtinplace(&a) 714 walkstmt(&a) 715 } 716 717 *init = list(*init, a) 718 } 719 } 720 721 func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) { 722 // make an array type 723 t := shallow(n.Type) 724 725 t.Bound = Mpgetfix(n.Right.Val.U.Xval) 726 t.Width = 0 727 t.Sym = nil 728 t.Haspointers = 0 729 dowidth(t) 730 731 if ctxt != 0 { 732 // put everything into static array 733 vstat := staticname(t, ctxt) 734 735 arraylit(ctxt, 1, n, vstat, init) 736 arraylit(ctxt, 2, n, vstat, init) 737 738 // copy static to slice 739 a := Nod(OSLICE, vstat, Nod(OKEY, nil, nil)) 740 741 a = Nod(OAS, var_, a) 742 typecheck(&a, Etop) 743 a.Dodata = 2 744 *init = list(*init, a) 745 return 746 } 747 748 // recipe for var = []t{...} 749 // 1. make a static array 750 // var vstat [...]t 751 // 2. assign (data statements) the constant part 752 // vstat = constpart{} 753 // 3. make an auto pointer to array and allocate heap to it 754 // var vauto *[...]t = new([...]t) 755 // 4. copy the static array to the auto array 756 // *vauto = vstat 757 // 5. assign slice of allocated heap to var 758 // var = [0:]*auto 759 // 6. for each dynamic part assign to the slice 760 // var[i] = dynamic part 761 // 762 // an optimization is done if there is no constant part 763 // 3. var vauto *[...]t = new([...]t) 764 // 5. var = [0:]*auto 765 // 6. var[i] = dynamic part 766 767 // if the literal contains constants, 768 // make static initialized array (1),(2) 769 var vstat *Node 770 771 mode := getdyn(n, 1) 772 if mode&MODECONST != 0 { 773 vstat = staticname(t, ctxt) 774 arraylit(ctxt, 1, n, vstat, init) 775 } 776 777 // make new auto *array (3 declare) 778 vauto := temp(Ptrto(t)) 779 780 // set auto to point at new temp or heap (3 assign) 781 var a *Node 782 if n.Alloc != nil { 783 // temp allocated during order.c for dddarg 784 n.Alloc.Type = t 785 786 if vstat == nil { 787 a = Nod(OAS, n.Alloc, nil) 788 typecheck(&a, Etop) 789 *init = list(*init, a) // zero new temp 790 } 791 792 a = Nod(OADDR, n.Alloc, nil) 793 } else if n.Esc == EscNone { 794 a = temp(t) 795 if vstat == nil { 796 a = Nod(OAS, temp(t), nil) 797 typecheck(&a, Etop) 798 *init = list(*init, a) // zero new temp 799 a = a.Left 800 } 801 802 a = Nod(OADDR, a, nil) 803 } else { 804 a = Nod(ONEW, nil, nil) 805 a.List = list1(typenod(t)) 806 } 807 808 a = Nod(OAS, vauto, a) 809 typecheck(&a, Etop) 810 walkexpr(&a, init) 811 *init = list(*init, a) 812 813 if vstat != nil { 814 // copy static to heap (4) 815 a = Nod(OIND, vauto, nil) 816 817 a = Nod(OAS, a, vstat) 818 typecheck(&a, Etop) 819 walkexpr(&a, init) 820 *init = list(*init, a) 821 } 822 823 // make slice out of heap (5) 824 a = Nod(OAS, var_, Nod(OSLICE, vauto, Nod(OKEY, nil, nil))) 825 826 typecheck(&a, Etop) 827 orderstmtinplace(&a) 828 walkstmt(&a) 829 *init = list(*init, a) 830 831 // put dynamics into slice (6) 832 var value *Node 833 var r *Node 834 var index *Node 835 for l := n.List; l != nil; l = l.Next { 836 r = l.N 837 if r.Op != OKEY { 838 Fatal("slicelit: rhs not OKEY: %v", Nconv(r, 0)) 839 } 840 index = r.Left 841 value = r.Right 842 a = Nod(OINDEX, var_, index) 843 a.Bounded = true 844 845 // TODO need to check bounds? 846 847 switch value.Op { 848 case OARRAYLIT: 849 if value.Type.Bound < 0 { 850 break 851 } 852 arraylit(ctxt, 2, value, a, init) 853 continue 854 855 case OSTRUCTLIT: 856 structlit(ctxt, 2, value, a, init) 857 continue 858 } 859 860 if isliteral(index) && isliteral(value) { 861 continue 862 } 863 864 // build list of var[c] = expr 865 a = Nod(OAS, a, value) 866 867 typecheck(&a, Etop) 868 orderstmtinplace(&a) 869 walkstmt(&a) 870 *init = list(*init, a) 871 } 872 } 873 874 func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) { 875 var r *Node 876 var index *Node 877 var value *Node 878 879 ctxt = 0 880 881 // make the map var 882 nerr := nerrors 883 884 a := Nod(OMAKE, nil, nil) 885 a.List = list1(typenod(n.Type)) 886 litas(var_, a, init) 887 888 // count the initializers 889 b := int64(0) 890 891 for l := n.List; l != nil; l = l.Next { 892 r = l.N 893 894 if r.Op != OKEY { 895 Fatal("maplit: rhs not OKEY: %v", Nconv(r, 0)) 896 } 897 index = r.Left 898 value = r.Right 899 900 if isliteral(index) && isliteral(value) { 901 b++ 902 } 903 } 904 905 if b != 0 { 906 // build type [count]struct { a Tindex, b Tvalue } 907 t := n.Type 908 909 tk := t.Down 910 tv := t.Type 911 912 symb := Lookup("b") 913 t = typ(TFIELD) 914 t.Type = tv 915 t.Sym = symb 916 917 syma := Lookup("a") 918 t1 := t 919 t = typ(TFIELD) 920 t.Type = tk 921 t.Sym = syma 922 t.Down = t1 923 924 t1 = t 925 t = typ(TSTRUCT) 926 t.Type = t1 927 928 t1 = t 929 t = typ(TARRAY) 930 t.Bound = b 931 t.Type = t1 932 933 dowidth(t) 934 935 // make and initialize static array 936 vstat := staticname(t, ctxt) 937 938 b := int64(0) 939 var index *Node 940 var r *Node 941 var value *Node 942 for l := n.List; l != nil; l = l.Next { 943 r = l.N 944 945 if r.Op != OKEY { 946 Fatal("maplit: rhs not OKEY: %v", Nconv(r, 0)) 947 } 948 index = r.Left 949 value = r.Right 950 951 if isliteral(index) && isliteral(value) { 952 // build vstat[b].a = key; 953 a = Nodintconst(b) 954 955 a = Nod(OINDEX, vstat, a) 956 a = Nod(ODOT, a, newname(syma)) 957 a = Nod(OAS, a, index) 958 typecheck(&a, Etop) 959 walkexpr(&a, init) 960 a.Dodata = 2 961 *init = list(*init, a) 962 963 // build vstat[b].b = value; 964 a = Nodintconst(b) 965 966 a = Nod(OINDEX, vstat, a) 967 a = Nod(ODOT, a, newname(symb)) 968 a = Nod(OAS, a, value) 969 typecheck(&a, Etop) 970 walkexpr(&a, init) 971 a.Dodata = 2 972 *init = list(*init, a) 973 974 b++ 975 } 976 } 977 978 // loop adding structure elements to map 979 // for i = 0; i < len(vstat); i++ { 980 // map[vstat[i].a] = vstat[i].b 981 // } 982 index = temp(Types[TINT]) 983 984 a = Nod(OINDEX, vstat, index) 985 a.Bounded = true 986 a = Nod(ODOT, a, newname(symb)) 987 988 r = Nod(OINDEX, vstat, index) 989 r.Bounded = true 990 r = Nod(ODOT, r, newname(syma)) 991 r = Nod(OINDEX, var_, r) 992 993 r = Nod(OAS, r, a) 994 995 a = Nod(OFOR, nil, nil) 996 a.Nbody = list1(r) 997 998 a.Ninit = list1(Nod(OAS, index, Nodintconst(0))) 999 a.Ntest = Nod(OLT, index, Nodintconst(t.Bound)) 1000 a.Nincr = Nod(OAS, index, Nod(OADD, index, Nodintconst(1))) 1001 1002 typecheck(&a, Etop) 1003 walkstmt(&a) 1004 *init = list(*init, a) 1005 } 1006 1007 // put in dynamic entries one-at-a-time 1008 var key *Node 1009 1010 var val *Node 1011 for l := n.List; l != nil; l = l.Next { 1012 r = l.N 1013 1014 if r.Op != OKEY { 1015 Fatal("maplit: rhs not OKEY: %v", Nconv(r, 0)) 1016 } 1017 index = r.Left 1018 value = r.Right 1019 1020 if isliteral(index) && isliteral(value) { 1021 continue 1022 } 1023 1024 // build list of var[c] = expr. 1025 // use temporary so that mapassign1 can have addressable key, val. 1026 if key == nil { 1027 key = temp(var_.Type.Down) 1028 val = temp(var_.Type.Type) 1029 } 1030 1031 a = Nod(OAS, key, r.Left) 1032 typecheck(&a, Etop) 1033 walkstmt(&a) 1034 *init = list(*init, a) 1035 a = Nod(OAS, val, r.Right) 1036 typecheck(&a, Etop) 1037 walkstmt(&a) 1038 *init = list(*init, a) 1039 1040 a = Nod(OAS, Nod(OINDEX, var_, key), val) 1041 typecheck(&a, Etop) 1042 walkstmt(&a) 1043 *init = list(*init, a) 1044 1045 if nerr != nerrors { 1046 break 1047 } 1048 } 1049 1050 if key != nil { 1051 a = Nod(OVARKILL, key, nil) 1052 typecheck(&a, Etop) 1053 *init = list(*init, a) 1054 a = Nod(OVARKILL, val, nil) 1055 typecheck(&a, Etop) 1056 *init = list(*init, a) 1057 } 1058 } 1059 1060 func anylit(ctxt int, n *Node, var_ *Node, init **NodeList) { 1061 t := n.Type 1062 switch n.Op { 1063 default: 1064 Fatal("anylit: not lit") 1065 1066 case OPTRLIT: 1067 if !Isptr[t.Etype] { 1068 Fatal("anylit: not ptr") 1069 } 1070 1071 var r *Node 1072 if n.Right != nil { 1073 r = Nod(OADDR, n.Right, nil) 1074 typecheck(&r, Erv) 1075 } else { 1076 r = Nod(ONEW, nil, nil) 1077 r.Typecheck = 1 1078 r.Type = t 1079 r.Esc = n.Esc 1080 } 1081 1082 walkexpr(&r, init) 1083 a := Nod(OAS, var_, r) 1084 1085 typecheck(&a, Etop) 1086 *init = list(*init, a) 1087 1088 var_ = Nod(OIND, var_, nil) 1089 typecheck(&var_, Erv|Easgn) 1090 anylit(ctxt, n.Left, var_, init) 1091 1092 case OSTRUCTLIT: 1093 if t.Etype != TSTRUCT { 1094 Fatal("anylit: not struct") 1095 } 1096 1097 if simplename(var_) && count(n.List) > 4 { 1098 if ctxt == 0 { 1099 // lay out static data 1100 vstat := staticname(t, ctxt) 1101 1102 structlit(ctxt, 1, n, vstat, init) 1103 1104 // copy static to var 1105 a := Nod(OAS, var_, vstat) 1106 1107 typecheck(&a, Etop) 1108 walkexpr(&a, init) 1109 *init = list(*init, a) 1110 1111 // add expressions to automatic 1112 structlit(ctxt, 2, n, var_, init) 1113 1114 break 1115 } 1116 1117 structlit(ctxt, 1, n, var_, init) 1118 structlit(ctxt, 2, n, var_, init) 1119 break 1120 } 1121 1122 // initialize of not completely specified 1123 if simplename(var_) || count(n.List) < structcount(t) { 1124 a := Nod(OAS, var_, nil) 1125 typecheck(&a, Etop) 1126 walkexpr(&a, init) 1127 *init = list(*init, a) 1128 } 1129 1130 structlit(ctxt, 3, n, var_, init) 1131 1132 case OARRAYLIT: 1133 if t.Etype != TARRAY { 1134 Fatal("anylit: not array") 1135 } 1136 if t.Bound < 0 { 1137 slicelit(ctxt, n, var_, init) 1138 break 1139 } 1140 1141 if simplename(var_) && count(n.List) > 4 { 1142 if ctxt == 0 { 1143 // lay out static data 1144 vstat := staticname(t, ctxt) 1145 1146 arraylit(1, 1, n, vstat, init) 1147 1148 // copy static to automatic 1149 a := Nod(OAS, var_, vstat) 1150 1151 typecheck(&a, Etop) 1152 walkexpr(&a, init) 1153 *init = list(*init, a) 1154 1155 // add expressions to automatic 1156 arraylit(ctxt, 2, n, var_, init) 1157 1158 break 1159 } 1160 1161 arraylit(ctxt, 1, n, var_, init) 1162 arraylit(ctxt, 2, n, var_, init) 1163 break 1164 } 1165 1166 // initialize of not completely specified 1167 if simplename(var_) || int64(count(n.List)) < t.Bound { 1168 a := Nod(OAS, var_, nil) 1169 typecheck(&a, Etop) 1170 walkexpr(&a, init) 1171 *init = list(*init, a) 1172 } 1173 1174 arraylit(ctxt, 3, n, var_, init) 1175 1176 case OMAPLIT: 1177 if t.Etype != TMAP { 1178 Fatal("anylit: not map") 1179 } 1180 maplit(ctxt, n, var_, init) 1181 } 1182 } 1183 1184 func oaslit(n *Node, init **NodeList) bool { 1185 if n.Left == nil || n.Right == nil { 1186 // not a special composit literal assignment 1187 return false 1188 } 1189 if n.Left.Type == nil || n.Right.Type == nil { 1190 // not a special composit literal assignment 1191 return false 1192 } 1193 if !simplename(n.Left) { 1194 // not a special composit literal assignment 1195 return false 1196 } 1197 if !Eqtype(n.Left.Type, n.Right.Type) { 1198 // not a special composit literal assignment 1199 return false 1200 } 1201 1202 // context is init() function. 1203 // implies generated data executed 1204 // exactly once and not subject to races. 1205 ctxt := 0 1206 1207 // if(n->dodata == 1) 1208 // ctxt = 1; 1209 1210 switch n.Right.Op { 1211 default: 1212 // not a special composit literal assignment 1213 return false 1214 1215 case OSTRUCTLIT, OARRAYLIT, OMAPLIT: 1216 if vmatch1(n.Left, n.Right) { 1217 // not a special composit literal assignment 1218 return false 1219 } 1220 anylit(ctxt, n.Right, n.Left, init) 1221 } 1222 1223 n.Op = OEMPTY 1224 return true 1225 } 1226 1227 func getlit(lit *Node) int { 1228 if Smallintconst(lit) { 1229 return int(Mpgetfix(lit.Val.U.Xval)) 1230 } 1231 return -1 1232 } 1233 1234 func stataddr(nam *Node, n *Node) bool { 1235 if n == nil { 1236 return false 1237 } 1238 1239 switch n.Op { 1240 case ONAME: 1241 *nam = *n 1242 return n.Addable 1243 1244 case ODOT: 1245 if !stataddr(nam, n.Left) { 1246 break 1247 } 1248 nam.Xoffset += n.Xoffset 1249 nam.Type = n.Type 1250 return true 1251 1252 case OINDEX: 1253 if n.Left.Type.Bound < 0 { 1254 break 1255 } 1256 if !stataddr(nam, n.Left) { 1257 break 1258 } 1259 l := getlit(n.Right) 1260 if l < 0 { 1261 break 1262 } 1263 1264 // Check for overflow. 1265 if n.Type.Width != 0 && Thearch.MAXWIDTH/n.Type.Width <= int64(l) { 1266 break 1267 } 1268 nam.Xoffset += int64(l) * n.Type.Width 1269 nam.Type = n.Type 1270 return true 1271 } 1272 1273 return false 1274 } 1275 1276 func initplan(n *Node) { 1277 if n.Initplan != nil { 1278 return 1279 } 1280 p := new(InitPlan) 1281 n.Initplan = p 1282 switch n.Op { 1283 default: 1284 Fatal("initplan") 1285 1286 case OARRAYLIT: 1287 var a *Node 1288 for l := n.List; l != nil; l = l.Next { 1289 a = l.N 1290 if a.Op != OKEY || !Smallintconst(a.Left) { 1291 Fatal("initplan arraylit") 1292 } 1293 addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val.U.Xval), nil, a.Right) 1294 } 1295 1296 case OSTRUCTLIT: 1297 var a *Node 1298 for l := n.List; l != nil; l = l.Next { 1299 a = l.N 1300 if a.Op != OKEY || a.Left.Type == nil { 1301 Fatal("initplan structlit") 1302 } 1303 addvalue(p, a.Left.Type.Width, nil, a.Right) 1304 } 1305 1306 case OMAPLIT: 1307 var a *Node 1308 for l := n.List; l != nil; l = l.Next { 1309 a = l.N 1310 if a.Op != OKEY { 1311 Fatal("initplan maplit") 1312 } 1313 addvalue(p, -1, a.Left, a.Right) 1314 } 1315 } 1316 } 1317 1318 func addvalue(p *InitPlan, xoffset int64, key *Node, n *Node) { 1319 // special case: zero can be dropped entirely 1320 if iszero(n) { 1321 p.Zero += n.Type.Width 1322 return 1323 } 1324 1325 // special case: inline struct and array (not slice) literals 1326 if isvaluelit(n) { 1327 initplan(n) 1328 q := n.Initplan 1329 var e *InitEntry 1330 for i := 0; i < len(q.E); i++ { 1331 e = entry(p) 1332 *e = q.E[i] 1333 e.Xoffset += xoffset 1334 } 1335 1336 return 1337 } 1338 1339 // add to plan 1340 if n.Op == OLITERAL { 1341 p.Lit += n.Type.Width 1342 } else { 1343 p.Expr += n.Type.Width 1344 } 1345 1346 e := entry(p) 1347 e.Xoffset = xoffset 1348 e.Expr = n 1349 } 1350 1351 func iszero(n *Node) bool { 1352 switch n.Op { 1353 case OLITERAL: 1354 switch n.Val.Ctype { 1355 default: 1356 Dump("unexpected literal", n) 1357 Fatal("iszero") 1358 1359 case CTNIL: 1360 return true 1361 1362 case CTSTR: 1363 return n.Val.U.Sval == "" 1364 1365 case CTBOOL: 1366 return !n.Val.U.Bval 1367 1368 case CTINT, CTRUNE: 1369 return mpcmpfixc(n.Val.U.Xval, 0) == 0 1370 1371 case CTFLT: 1372 return mpcmpfltc(n.Val.U.Fval, 0) == 0 1373 1374 case CTCPLX: 1375 return mpcmpfltc(&n.Val.U.Cval.Real, 0) == 0 && mpcmpfltc(&n.Val.U.Cval.Imag, 0) == 0 1376 } 1377 1378 case OARRAYLIT: 1379 if Isslice(n.Type) { 1380 break 1381 } 1382 fallthrough 1383 1384 // fall through 1385 case OSTRUCTLIT: 1386 for l := n.List; l != nil; l = l.Next { 1387 if !iszero(l.N.Right) { 1388 return false 1389 } 1390 } 1391 return true 1392 } 1393 1394 return false 1395 } 1396 1397 func isvaluelit(n *Node) bool { 1398 return (n.Op == OARRAYLIT && Isfixedarray(n.Type)) || n.Op == OSTRUCTLIT 1399 } 1400 1401 func entry(p *InitPlan) *InitEntry { 1402 p.E = append(p.E, InitEntry{}) 1403 return &p.E[len(p.E)-1] 1404 } 1405 1406 func gen_as_init(n *Node) bool { 1407 var nr *Node 1408 var nl *Node 1409 var nam Node 1410 1411 if n.Dodata == 0 { 1412 goto no 1413 } 1414 1415 nr = n.Right 1416 nl = n.Left 1417 if nr == nil { 1418 var nam Node 1419 if !stataddr(&nam, nl) { 1420 goto no 1421 } 1422 if nam.Class != PEXTERN { 1423 goto no 1424 } 1425 return true 1426 } 1427 1428 if nr.Type == nil || !Eqtype(nl.Type, nr.Type) { 1429 goto no 1430 } 1431 1432 if !stataddr(&nam, nl) { 1433 goto no 1434 } 1435 1436 if nam.Class != PEXTERN { 1437 goto no 1438 } 1439 1440 switch nr.Op { 1441 default: 1442 goto no 1443 1444 case OCONVNOP: 1445 nr = nr.Left 1446 if nr == nil || nr.Op != OSLICEARR { 1447 goto no 1448 } 1449 fallthrough 1450 1451 // fall through 1452 case OSLICEARR: 1453 if nr.Right.Op == OKEY && nr.Right.Left == nil && nr.Right.Right == nil { 1454 nr = nr.Left 1455 gused(nil) // in case the data is the dest of a goto 1456 nl := nr 1457 if nr == nil || nr.Op != OADDR { 1458 goto no 1459 } 1460 nr = nr.Left 1461 if nr == nil || nr.Op != ONAME { 1462 goto no 1463 } 1464 1465 // nr is the array being converted to a slice 1466 if nr.Type == nil || nr.Type.Etype != TARRAY || nr.Type.Bound < 0 { 1467 goto no 1468 } 1469 1470 nam.Xoffset += int64(Array_array) 1471 gdata(&nam, nl, int(Types[Tptr].Width)) 1472 1473 nam.Xoffset += int64(Array_nel) - int64(Array_array) 1474 var nod1 Node 1475 Nodconst(&nod1, Types[TINT], nr.Type.Bound) 1476 gdata(&nam, &nod1, Widthint) 1477 1478 nam.Xoffset += int64(Array_cap) - int64(Array_nel) 1479 gdata(&nam, &nod1, Widthint) 1480 1481 return true 1482 } 1483 1484 goto no 1485 1486 case OLITERAL: 1487 break 1488 } 1489 1490 switch nr.Type.Etype { 1491 default: 1492 goto no 1493 1494 case TBOOL, 1495 TINT8, 1496 TUINT8, 1497 TINT16, 1498 TUINT16, 1499 TINT32, 1500 TUINT32, 1501 TINT64, 1502 TUINT64, 1503 TINT, 1504 TUINT, 1505 TUINTPTR, 1506 TPTR32, 1507 TPTR64, 1508 TFLOAT32, 1509 TFLOAT64: 1510 gdata(&nam, nr, int(nr.Type.Width)) 1511 1512 case TCOMPLEX64, TCOMPLEX128: 1513 gdatacomplex(&nam, nr.Val.U.Cval) 1514 1515 case TSTRING: 1516 gdatastring(&nam, nr.Val.U.Sval) 1517 } 1518 1519 return true 1520 1521 no: 1522 if n.Dodata == 2 { 1523 Dump("\ngen_as_init", n) 1524 Fatal("gen_as_init couldnt make data statement") 1525 } 1526 1527 return false 1528 }