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