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