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