github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/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 case ONAME: 382 return staticcopy(l, r, out) 383 384 case OLITERAL: 385 if iszero(r) { 386 return true 387 } 388 gdata(l, r, int(l.Type.Width)) 389 return true 390 391 case OADDR: 392 var nam Node 393 if stataddr(&nam, r.Left) { 394 n := *r 395 n.Left = &nam 396 gdata(l, &n, int(l.Type.Width)) 397 return true 398 } 399 fallthrough 400 401 case OPTRLIT: 402 switch r.Left.Op { 403 case OARRAYLIT, OMAPLIT, OSTRUCTLIT: 404 // Init pointer. 405 a := staticname(r.Left.Type, 1) 406 407 inittemps[r] = a 408 gdata(l, Nod(OADDR, a, nil), int(l.Type.Width)) 409 410 // Init underlying literal. 411 if !staticassign(a, r.Left, out) { 412 *out = list(*out, Nod(OAS, a, r.Left)) 413 } 414 return true 415 } 416 //dump("not static ptrlit", r); 417 418 case OSTRARRAYBYTE: 419 if l.Class == PEXTERN && r.Left.Op == OLITERAL { 420 sval := r.Left.Val().U.(string) 421 slicebytes(l, sval, len(sval)) 422 return true 423 } 424 425 case OARRAYLIT: 426 initplan(r) 427 if Isslice(r.Type) { 428 // Init slice. 429 ta := typ(TARRAY) 430 431 ta.Type = r.Type.Type 432 ta.Bound = Mpgetfix(r.Right.Val().U.(*Mpint)) 433 a := staticname(ta, 1) 434 inittemps[r] = a 435 n := *l 436 n.Xoffset = l.Xoffset + int64(Array_array) 437 gdata(&n, Nod(OADDR, a, nil), Widthptr) 438 n.Xoffset = l.Xoffset + int64(Array_nel) 439 gdata(&n, r.Right, Widthint) 440 n.Xoffset = l.Xoffset + int64(Array_cap) 441 gdata(&n, r.Right, Widthint) 442 443 // Fall through to init underlying array. 444 l = a 445 } 446 fallthrough 447 448 case OSTRUCTLIT: 449 initplan(r) 450 451 p := initplans[r] 452 n := *l 453 for i := range p.E { 454 e := &p.E[i] 455 n.Xoffset = l.Xoffset + e.Xoffset 456 n.Type = e.Expr.Type 457 if e.Expr.Op == OLITERAL { 458 gdata(&n, e.Expr, int(n.Type.Width)) 459 } else { 460 setlineno(e.Expr) 461 a := Nod(OXXX, nil, nil) 462 *a = n 463 a.Orig = a // completely separate copy 464 if !staticassign(a, e.Expr, out) { 465 *out = list(*out, Nod(OAS, a, e.Expr)) 466 } 467 } 468 } 469 470 return true 471 472 case OMAPLIT: 473 // TODO: Table-driven map insert. 474 break 475 476 case OCLOSURE: 477 if r.Func.Cvars == nil { 478 // Closures with no captured variables are globals, 479 // so the assignment can be done at link time. 480 n := *l 481 gdata(&n, r.Func.Closure.Func.Nname, Widthptr) 482 return true 483 } 484 } 485 486 //dump("not static", r); 487 return false 488 } 489 490 // from here down is the walk analysis 491 // of composite literals. 492 // most of the work is to generate 493 // data statements for the constant 494 // part of the composite literal. 495 func staticname(t *Type, ctxt int) *Node { 496 n := newname(Lookupf("statictmp_%.4d", statuniqgen)) 497 statuniqgen++ 498 if ctxt == 0 { 499 n.Name.Readonly = true 500 } 501 addvar(n, t, PEXTERN) 502 return n 503 } 504 505 func isliteral(n *Node) bool { 506 if n.Op == OLITERAL { 507 if n.Val().Ctype() != CTNIL { 508 return true 509 } 510 } 511 return false 512 } 513 514 func simplename(n *Node) bool { 515 if n.Op != ONAME { 516 return false 517 } 518 if !n.Addable { 519 return false 520 } 521 if n.Class&PHEAP != 0 { 522 return false 523 } 524 if n.Class == PPARAMREF { 525 return false 526 } 527 return true 528 } 529 530 func litas(l *Node, r *Node, init **NodeList) { 531 a := Nod(OAS, l, r) 532 typecheck(&a, Etop) 533 walkexpr(&a, init) 534 *init = list(*init, a) 535 } 536 537 const ( 538 MODEDYNAM = 1 539 MODECONST = 2 540 ) 541 542 func getdyn(n *Node, top int) int { 543 mode := 0 544 switch n.Op { 545 default: 546 if isliteral(n) { 547 return MODECONST 548 } 549 return MODEDYNAM 550 551 case OARRAYLIT: 552 if top == 0 && n.Type.Bound < 0 { 553 return MODEDYNAM 554 } 555 fallthrough 556 557 case OSTRUCTLIT: 558 break 559 } 560 561 for nl := n.List; nl != nil; nl = nl.Next { 562 value := nl.N.Right 563 mode |= getdyn(value, 0) 564 if mode == MODEDYNAM|MODECONST { 565 break 566 } 567 } 568 569 return mode 570 } 571 572 func structlit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) { 573 for nl := n.List; nl != nil; nl = nl.Next { 574 r := nl.N 575 if r.Op != OKEY { 576 Fatalf("structlit: rhs not OKEY: %v", r) 577 } 578 index := r.Left 579 value := r.Right 580 581 var a *Node 582 583 switch value.Op { 584 case OARRAYLIT: 585 if value.Type.Bound < 0 { 586 if pass == 1 && ctxt != 0 { 587 a = Nod(ODOT, var_, newname(index.Sym)) 588 slicelit(ctxt, value, a, init) 589 } else if pass == 2 && ctxt == 0 { 590 a = Nod(ODOT, var_, newname(index.Sym)) 591 slicelit(ctxt, value, a, init) 592 } else if pass == 3 { 593 break 594 } 595 continue 596 } 597 598 a = Nod(ODOT, var_, newname(index.Sym)) 599 arraylit(ctxt, pass, value, a, init) 600 continue 601 602 case OSTRUCTLIT: 603 a = Nod(ODOT, var_, newname(index.Sym)) 604 structlit(ctxt, pass, value, a, init) 605 continue 606 } 607 608 if isliteral(value) { 609 if pass == 2 { 610 continue 611 } 612 } else if pass == 1 { 613 continue 614 } 615 616 // build list of var.field = expr 617 setlineno(value) 618 a = Nod(ODOT, var_, newname(index.Sym)) 619 620 a = Nod(OAS, a, value) 621 typecheck(&a, Etop) 622 if pass == 1 { 623 walkexpr(&a, init) // add any assignments in r to top 624 if a.Op != OAS { 625 Fatalf("structlit: not as") 626 } 627 a.Dodata = 2 628 } else { 629 orderstmtinplace(&a) 630 walkstmt(&a) 631 } 632 633 *init = list(*init, a) 634 } 635 } 636 637 func arraylit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) { 638 for l := n.List; l != nil; l = l.Next { 639 r := l.N 640 if r.Op != OKEY { 641 Fatalf("arraylit: rhs not OKEY: %v", r) 642 } 643 index := r.Left 644 value := r.Right 645 646 var a *Node 647 648 switch value.Op { 649 case OARRAYLIT: 650 if value.Type.Bound < 0 { 651 if pass == 1 && ctxt != 0 { 652 a = Nod(OINDEX, var_, index) 653 slicelit(ctxt, value, a, init) 654 } else if pass == 2 && ctxt == 0 { 655 a = Nod(OINDEX, var_, index) 656 slicelit(ctxt, value, a, init) 657 } else if pass == 3 { 658 break 659 } 660 continue 661 } 662 663 a = Nod(OINDEX, var_, index) 664 arraylit(ctxt, pass, value, a, init) 665 continue 666 667 case OSTRUCTLIT: 668 a = Nod(OINDEX, var_, index) 669 structlit(ctxt, pass, value, a, init) 670 continue 671 } 672 673 if isliteral(index) && isliteral(value) { 674 if pass == 2 { 675 continue 676 } 677 } else if pass == 1 { 678 continue 679 } 680 681 // build list of var[index] = value 682 setlineno(value) 683 a = Nod(OINDEX, var_, index) 684 685 a = Nod(OAS, a, value) 686 typecheck(&a, Etop) 687 if pass == 1 { 688 walkexpr(&a, init) 689 if a.Op != OAS { 690 Fatalf("arraylit: not as") 691 } 692 a.Dodata = 2 693 } else { 694 orderstmtinplace(&a) 695 walkstmt(&a) 696 } 697 698 *init = list(*init, a) 699 } 700 } 701 702 func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) { 703 // make an array type 704 t := shallow(n.Type) 705 706 t.Bound = Mpgetfix(n.Right.Val().U.(*Mpint)) 707 t.Width = 0 708 t.Sym = nil 709 t.Haspointers = 0 710 dowidth(t) 711 712 if ctxt != 0 { 713 // put everything into static array 714 vstat := staticname(t, ctxt) 715 716 arraylit(ctxt, 1, n, vstat, init) 717 arraylit(ctxt, 2, n, vstat, init) 718 719 // copy static to slice 720 a := Nod(OSLICE, vstat, Nod(OKEY, nil, nil)) 721 722 a = Nod(OAS, var_, a) 723 typecheck(&a, Etop) 724 a.Dodata = 2 725 *init = list(*init, a) 726 return 727 } 728 729 // recipe for var = []t{...} 730 // 1. make a static array 731 // var vstat [...]t 732 // 2. assign (data statements) the constant part 733 // vstat = constpart{} 734 // 3. make an auto pointer to array and allocate heap to it 735 // var vauto *[...]t = new([...]t) 736 // 4. copy the static array to the auto array 737 // *vauto = vstat 738 // 5. assign slice of allocated heap to var 739 // var = [0:]*auto 740 // 6. for each dynamic part assign to the slice 741 // var[i] = dynamic part 742 // 743 // an optimization is done if there is no constant part 744 // 3. var vauto *[...]t = new([...]t) 745 // 5. var = [0:]*auto 746 // 6. var[i] = dynamic part 747 748 // if the literal contains constants, 749 // make static initialized array (1),(2) 750 var vstat *Node 751 752 mode := getdyn(n, 1) 753 if mode&MODECONST != 0 { 754 vstat = staticname(t, ctxt) 755 arraylit(ctxt, 1, n, vstat, init) 756 } 757 758 // make new auto *array (3 declare) 759 vauto := temp(Ptrto(t)) 760 761 // set auto to point at new temp or heap (3 assign) 762 var a *Node 763 if x := prealloc[n]; x != nil { 764 // temp allocated during order.go for dddarg 765 x.Type = t 766 767 if vstat == nil { 768 a = Nod(OAS, x, nil) 769 typecheck(&a, Etop) 770 *init = list(*init, a) // zero new temp 771 } 772 773 a = Nod(OADDR, x, nil) 774 } else if n.Esc == EscNone { 775 a = temp(t) 776 if vstat == nil { 777 a = Nod(OAS, temp(t), nil) 778 typecheck(&a, Etop) 779 *init = list(*init, a) // zero new temp 780 a = a.Left 781 } 782 783 a = Nod(OADDR, a, nil) 784 } else { 785 a = Nod(ONEW, nil, nil) 786 a.List = list1(typenod(t)) 787 } 788 789 a = Nod(OAS, vauto, a) 790 typecheck(&a, Etop) 791 walkexpr(&a, init) 792 *init = list(*init, a) 793 794 if vstat != nil { 795 // copy static to heap (4) 796 a = Nod(OIND, vauto, nil) 797 798 a = Nod(OAS, a, vstat) 799 typecheck(&a, Etop) 800 walkexpr(&a, init) 801 *init = list(*init, a) 802 } 803 804 // make slice out of heap (5) 805 a = Nod(OAS, var_, Nod(OSLICE, vauto, Nod(OKEY, nil, nil))) 806 807 typecheck(&a, Etop) 808 orderstmtinplace(&a) 809 walkstmt(&a) 810 *init = list(*init, a) 811 812 // put dynamics into slice (6) 813 for l := n.List; l != nil; l = l.Next { 814 r := l.N 815 if r.Op != OKEY { 816 Fatalf("slicelit: rhs not OKEY: %v", r) 817 } 818 index := r.Left 819 value := r.Right 820 a := Nod(OINDEX, var_, index) 821 a.Bounded = true 822 823 // TODO need to check bounds? 824 825 switch value.Op { 826 case OARRAYLIT: 827 if value.Type.Bound < 0 { 828 break 829 } 830 arraylit(ctxt, 2, value, a, init) 831 continue 832 833 case OSTRUCTLIT: 834 structlit(ctxt, 2, value, a, init) 835 continue 836 } 837 838 if isliteral(index) && isliteral(value) { 839 continue 840 } 841 842 // build list of var[c] = expr 843 setlineno(value) 844 a = Nod(OAS, a, value) 845 846 typecheck(&a, Etop) 847 orderstmtinplace(&a) 848 walkstmt(&a) 849 *init = list(*init, a) 850 } 851 } 852 853 func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) { 854 ctxt = 0 855 856 // make the map var 857 nerr := nerrors 858 859 a := Nod(OMAKE, nil, nil) 860 a.List = list1(typenod(n.Type)) 861 litas(var_, a, init) 862 863 // count the initializers 864 b := int64(0) 865 866 for l := n.List; l != nil; l = l.Next { 867 r := l.N 868 if r.Op != OKEY { 869 Fatalf("maplit: rhs not OKEY: %v", r) 870 } 871 index := r.Left 872 value := r.Right 873 874 if isliteral(index) && isliteral(value) { 875 b++ 876 } 877 } 878 879 if b != 0 { 880 // build type [count]struct { a Tindex, b Tvalue } 881 t := n.Type 882 883 tk := t.Down 884 tv := t.Type 885 886 symb := Lookup("b") 887 t = typ(TFIELD) 888 t.Type = tv 889 t.Sym = symb 890 891 syma := Lookup("a") 892 t1 := t 893 t = typ(TFIELD) 894 t.Type = tk 895 t.Sym = syma 896 t.Down = t1 897 898 t1 = t 899 t = typ(TSTRUCT) 900 t.Type = t1 901 902 t1 = t 903 t = typ(TARRAY) 904 t.Bound = b 905 t.Type = t1 906 907 dowidth(t) 908 909 // make and initialize static array 910 vstat := staticname(t, ctxt) 911 912 b := int64(0) 913 for l := n.List; l != nil; l = l.Next { 914 r := l.N 915 916 if r.Op != OKEY { 917 Fatalf("maplit: rhs not OKEY: %v", r) 918 } 919 index := r.Left 920 value := r.Right 921 922 if isliteral(index) && isliteral(value) { 923 // build vstat[b].a = key; 924 setlineno(index) 925 a = Nodintconst(b) 926 927 a = Nod(OINDEX, vstat, a) 928 a = Nod(ODOT, a, newname(syma)) 929 a = Nod(OAS, a, index) 930 typecheck(&a, Etop) 931 walkexpr(&a, init) 932 a.Dodata = 2 933 *init = list(*init, a) 934 935 // build vstat[b].b = value; 936 setlineno(value) 937 a = Nodintconst(b) 938 939 a = Nod(OINDEX, vstat, a) 940 a = Nod(ODOT, a, newname(symb)) 941 a = Nod(OAS, a, value) 942 typecheck(&a, Etop) 943 walkexpr(&a, init) 944 a.Dodata = 2 945 *init = list(*init, a) 946 947 b++ 948 } 949 } 950 951 // loop adding structure elements to map 952 // for i = 0; i < len(vstat); i++ { 953 // map[vstat[i].a] = vstat[i].b 954 // } 955 index := temp(Types[TINT]) 956 957 a = Nod(OINDEX, vstat, index) 958 a.Bounded = true 959 a = Nod(ODOT, a, newname(symb)) 960 961 r := Nod(OINDEX, vstat, index) 962 r.Bounded = true 963 r = Nod(ODOT, r, newname(syma)) 964 r = Nod(OINDEX, var_, r) 965 966 r = Nod(OAS, r, a) 967 968 a = Nod(OFOR, nil, nil) 969 a.Nbody = list1(r) 970 971 a.Ninit = list1(Nod(OAS, index, Nodintconst(0))) 972 a.Left = Nod(OLT, index, Nodintconst(t.Bound)) 973 a.Right = Nod(OAS, index, Nod(OADD, index, Nodintconst(1))) 974 975 typecheck(&a, Etop) 976 walkstmt(&a) 977 *init = list(*init, a) 978 } 979 980 // put in dynamic entries one-at-a-time 981 var key *Node 982 983 var val *Node 984 for l := n.List; l != nil; l = l.Next { 985 r := l.N 986 987 if r.Op != OKEY { 988 Fatalf("maplit: rhs not OKEY: %v", r) 989 } 990 index := r.Left 991 value := r.Right 992 993 if isliteral(index) && isliteral(value) { 994 continue 995 } 996 997 // build list of var[c] = expr. 998 // use temporary so that mapassign1 can have addressable key, val. 999 if key == nil { 1000 key = temp(var_.Type.Down) 1001 val = temp(var_.Type.Type) 1002 } 1003 1004 setlineno(r.Left) 1005 a = Nod(OAS, key, r.Left) 1006 typecheck(&a, Etop) 1007 walkstmt(&a) 1008 *init = list(*init, a) 1009 setlineno(r.Right) 1010 a = Nod(OAS, val, r.Right) 1011 typecheck(&a, Etop) 1012 walkstmt(&a) 1013 *init = list(*init, a) 1014 1015 setlineno(val) 1016 a = Nod(OAS, Nod(OINDEX, var_, key), val) 1017 typecheck(&a, Etop) 1018 walkstmt(&a) 1019 *init = list(*init, a) 1020 1021 if nerr != nerrors { 1022 break 1023 } 1024 } 1025 1026 if key != nil { 1027 a = Nod(OVARKILL, key, nil) 1028 typecheck(&a, Etop) 1029 *init = list(*init, a) 1030 a = Nod(OVARKILL, val, nil) 1031 typecheck(&a, Etop) 1032 *init = list(*init, a) 1033 } 1034 } 1035 1036 func anylit(ctxt int, n *Node, var_ *Node, init **NodeList) { 1037 t := n.Type 1038 switch n.Op { 1039 default: 1040 Fatalf("anylit: not lit") 1041 1042 case OPTRLIT: 1043 if !Isptr[t.Etype] { 1044 Fatalf("anylit: not ptr") 1045 } 1046 1047 var r *Node 1048 if n.Right != nil { 1049 r = Nod(OADDR, n.Right, nil) 1050 typecheck(&r, Erv) 1051 } else { 1052 r = Nod(ONEW, nil, nil) 1053 r.Typecheck = 1 1054 r.Type = t 1055 r.Esc = n.Esc 1056 } 1057 1058 walkexpr(&r, init) 1059 a := Nod(OAS, var_, r) 1060 1061 typecheck(&a, Etop) 1062 *init = list(*init, a) 1063 1064 var_ = Nod(OIND, var_, nil) 1065 typecheck(&var_, Erv|Easgn) 1066 anylit(ctxt, n.Left, var_, init) 1067 1068 case OSTRUCTLIT: 1069 if t.Etype != TSTRUCT { 1070 Fatalf("anylit: not struct") 1071 } 1072 1073 if simplename(var_) && count(n.List) > 4 { 1074 if ctxt == 0 { 1075 // lay out static data 1076 vstat := staticname(t, ctxt) 1077 1078 structlit(ctxt, 1, n, vstat, init) 1079 1080 // copy static to var 1081 a := Nod(OAS, var_, vstat) 1082 1083 typecheck(&a, Etop) 1084 walkexpr(&a, init) 1085 *init = list(*init, a) 1086 1087 // add expressions to automatic 1088 structlit(ctxt, 2, n, var_, init) 1089 1090 break 1091 } 1092 1093 structlit(ctxt, 1, n, var_, init) 1094 structlit(ctxt, 2, n, var_, init) 1095 break 1096 } 1097 1098 // initialize of not completely specified 1099 if simplename(var_) || count(n.List) < structcount(t) { 1100 a := Nod(OAS, var_, nil) 1101 typecheck(&a, Etop) 1102 walkexpr(&a, init) 1103 *init = list(*init, a) 1104 } 1105 1106 structlit(ctxt, 3, n, var_, init) 1107 1108 case OARRAYLIT: 1109 if t.Etype != TARRAY { 1110 Fatalf("anylit: not array") 1111 } 1112 if t.Bound < 0 { 1113 slicelit(ctxt, n, var_, init) 1114 break 1115 } 1116 1117 if simplename(var_) && count(n.List) > 4 { 1118 if ctxt == 0 { 1119 // lay out static data 1120 vstat := staticname(t, ctxt) 1121 1122 arraylit(1, 1, n, vstat, init) 1123 1124 // copy static to automatic 1125 a := Nod(OAS, var_, vstat) 1126 1127 typecheck(&a, Etop) 1128 walkexpr(&a, init) 1129 *init = list(*init, a) 1130 1131 // add expressions to automatic 1132 arraylit(ctxt, 2, n, var_, init) 1133 1134 break 1135 } 1136 1137 arraylit(ctxt, 1, n, var_, init) 1138 arraylit(ctxt, 2, n, var_, init) 1139 break 1140 } 1141 1142 // initialize of not completely specified 1143 if simplename(var_) || int64(count(n.List)) < t.Bound { 1144 a := Nod(OAS, var_, nil) 1145 typecheck(&a, Etop) 1146 walkexpr(&a, init) 1147 *init = list(*init, a) 1148 } 1149 1150 arraylit(ctxt, 3, n, var_, init) 1151 1152 case OMAPLIT: 1153 if t.Etype != TMAP { 1154 Fatalf("anylit: not map") 1155 } 1156 maplit(ctxt, n, var_, init) 1157 } 1158 } 1159 1160 func oaslit(n *Node, init **NodeList) bool { 1161 if n.Left == nil || n.Right == nil { 1162 // not a special composit literal assignment 1163 return false 1164 } 1165 if n.Left.Type == nil || n.Right.Type == nil { 1166 // not a special composit literal assignment 1167 return false 1168 } 1169 if !simplename(n.Left) { 1170 // not a special composit literal assignment 1171 return false 1172 } 1173 if !Eqtype(n.Left.Type, n.Right.Type) { 1174 // not a special composit literal assignment 1175 return false 1176 } 1177 1178 // context is init() function. 1179 // implies generated data executed 1180 // exactly once and not subject to races. 1181 ctxt := 0 1182 1183 // if(n->dodata == 1) 1184 // ctxt = 1; 1185 1186 switch n.Right.Op { 1187 default: 1188 // not a special composit literal assignment 1189 return false 1190 1191 case OSTRUCTLIT, OARRAYLIT, OMAPLIT: 1192 if vmatch1(n.Left, n.Right) { 1193 // not a special composit literal assignment 1194 return false 1195 } 1196 anylit(ctxt, n.Right, n.Left, init) 1197 } 1198 1199 n.Op = OEMPTY 1200 n.Right = nil 1201 return true 1202 } 1203 1204 func getlit(lit *Node) int { 1205 if Smallintconst(lit) { 1206 return int(Mpgetfix(lit.Val().U.(*Mpint))) 1207 } 1208 return -1 1209 } 1210 1211 func stataddr(nam *Node, n *Node) bool { 1212 if n == nil { 1213 return false 1214 } 1215 1216 switch n.Op { 1217 case ONAME: 1218 *nam = *n 1219 return n.Addable 1220 1221 case ODOT: 1222 if !stataddr(nam, n.Left) { 1223 break 1224 } 1225 nam.Xoffset += n.Xoffset 1226 nam.Type = n.Type 1227 return true 1228 1229 case OINDEX: 1230 if n.Left.Type.Bound < 0 { 1231 break 1232 } 1233 if !stataddr(nam, n.Left) { 1234 break 1235 } 1236 l := getlit(n.Right) 1237 if l < 0 { 1238 break 1239 } 1240 1241 // Check for overflow. 1242 if n.Type.Width != 0 && Thearch.MAXWIDTH/n.Type.Width <= int64(l) { 1243 break 1244 } 1245 nam.Xoffset += int64(l) * n.Type.Width 1246 nam.Type = n.Type 1247 return true 1248 } 1249 1250 return false 1251 } 1252 1253 func initplan(n *Node) { 1254 if initplans[n] != nil { 1255 return 1256 } 1257 p := new(InitPlan) 1258 initplans[n] = p 1259 switch n.Op { 1260 default: 1261 Fatalf("initplan") 1262 1263 case OARRAYLIT: 1264 for l := n.List; l != nil; l = l.Next { 1265 a := l.N 1266 if a.Op != OKEY || !Smallintconst(a.Left) { 1267 Fatalf("initplan arraylit") 1268 } 1269 addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val().U.(*Mpint)), nil, a.Right) 1270 } 1271 1272 case OSTRUCTLIT: 1273 for l := n.List; l != nil; l = l.Next { 1274 a := l.N 1275 if a.Op != OKEY || a.Left.Type == nil { 1276 Fatalf("initplan structlit") 1277 } 1278 addvalue(p, a.Left.Type.Width, nil, a.Right) 1279 } 1280 1281 case OMAPLIT: 1282 for l := n.List; l != nil; l = l.Next { 1283 a := l.N 1284 if a.Op != OKEY { 1285 Fatalf("initplan maplit") 1286 } 1287 addvalue(p, -1, a.Left, a.Right) 1288 } 1289 } 1290 } 1291 1292 func addvalue(p *InitPlan, xoffset int64, key *Node, n *Node) { 1293 // special case: zero can be dropped entirely 1294 if iszero(n) { 1295 p.Zero += n.Type.Width 1296 return 1297 } 1298 1299 // special case: inline struct and array (not slice) literals 1300 if isvaluelit(n) { 1301 initplan(n) 1302 q := initplans[n] 1303 for _, qe := range q.E { 1304 e := entry(p) 1305 *e = qe 1306 e.Xoffset += xoffset 1307 } 1308 return 1309 } 1310 1311 // add to plan 1312 if n.Op == OLITERAL { 1313 p.Lit += n.Type.Width 1314 } else { 1315 p.Expr += n.Type.Width 1316 } 1317 1318 e := entry(p) 1319 e.Xoffset = xoffset 1320 e.Expr = n 1321 } 1322 1323 func iszero(n *Node) bool { 1324 switch n.Op { 1325 case OLITERAL: 1326 switch n.Val().Ctype() { 1327 default: 1328 Dump("unexpected literal", n) 1329 Fatalf("iszero") 1330 1331 case CTNIL: 1332 return true 1333 1334 case CTSTR: 1335 return n.Val().U.(string) == "" 1336 1337 case CTBOOL: 1338 return !n.Val().U.(bool) 1339 1340 case CTINT, CTRUNE: 1341 return mpcmpfixc(n.Val().U.(*Mpint), 0) == 0 1342 1343 case CTFLT: 1344 return mpcmpfltc(n.Val().U.(*Mpflt), 0) == 0 1345 1346 case CTCPLX: 1347 return mpcmpfltc(&n.Val().U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&n.Val().U.(*Mpcplx).Imag, 0) == 0 1348 } 1349 1350 case OARRAYLIT: 1351 if Isslice(n.Type) { 1352 break 1353 } 1354 fallthrough 1355 1356 // fall through 1357 case OSTRUCTLIT: 1358 for l := n.List; l != nil; l = l.Next { 1359 if !iszero(l.N.Right) { 1360 return false 1361 } 1362 } 1363 return true 1364 } 1365 1366 return false 1367 } 1368 1369 func isvaluelit(n *Node) bool { 1370 return (n.Op == OARRAYLIT && Isfixedarray(n.Type)) || n.Op == OSTRUCTLIT 1371 } 1372 1373 func entry(p *InitPlan) *InitEntry { 1374 p.E = append(p.E, InitEntry{}) 1375 return &p.E[len(p.E)-1] 1376 } 1377 1378 func gen_as_init(n *Node) bool { 1379 var nr *Node 1380 var nl *Node 1381 var nam Node 1382 1383 if n.Dodata == 0 { 1384 goto no 1385 } 1386 1387 nr = n.Right 1388 nl = n.Left 1389 if nr == nil { 1390 var nam Node 1391 if !stataddr(&nam, nl) { 1392 goto no 1393 } 1394 if nam.Class != PEXTERN { 1395 goto no 1396 } 1397 return true 1398 } 1399 1400 if nr.Type == nil || !Eqtype(nl.Type, nr.Type) { 1401 goto no 1402 } 1403 1404 if !stataddr(&nam, nl) { 1405 goto no 1406 } 1407 1408 if nam.Class != PEXTERN { 1409 goto no 1410 } 1411 1412 switch nr.Op { 1413 default: 1414 goto no 1415 1416 case OCONVNOP: 1417 nr = nr.Left 1418 if nr == nil || nr.Op != OSLICEARR { 1419 goto no 1420 } 1421 fallthrough 1422 1423 // fall through 1424 case OSLICEARR: 1425 if nr.Right.Op == OKEY && nr.Right.Left == nil && nr.Right.Right == nil { 1426 nr = nr.Left 1427 gused(nil) // in case the data is the dest of a goto 1428 nl := nr 1429 if nr == nil || nr.Op != OADDR { 1430 goto no 1431 } 1432 nr = nr.Left 1433 if nr == nil || nr.Op != ONAME { 1434 goto no 1435 } 1436 1437 // nr is the array being converted to a slice 1438 if nr.Type == nil || nr.Type.Etype != TARRAY || nr.Type.Bound < 0 { 1439 goto no 1440 } 1441 1442 nam.Xoffset += int64(Array_array) 1443 gdata(&nam, nl, int(Types[Tptr].Width)) 1444 1445 nam.Xoffset += int64(Array_nel) - int64(Array_array) 1446 var nod1 Node 1447 Nodconst(&nod1, Types[TINT], nr.Type.Bound) 1448 gdata(&nam, &nod1, Widthint) 1449 1450 nam.Xoffset += int64(Array_cap) - int64(Array_nel) 1451 gdata(&nam, &nod1, Widthint) 1452 1453 return true 1454 } 1455 1456 goto no 1457 1458 case OLITERAL: 1459 break 1460 } 1461 1462 switch nr.Type.Etype { 1463 default: 1464 goto no 1465 1466 case TBOOL, 1467 TINT8, 1468 TUINT8, 1469 TINT16, 1470 TUINT16, 1471 TINT32, 1472 TUINT32, 1473 TINT64, 1474 TUINT64, 1475 TINT, 1476 TUINT, 1477 TUINTPTR, 1478 TPTR32, 1479 TPTR64, 1480 TFLOAT32, 1481 TFLOAT64: 1482 gdata(&nam, nr, int(nr.Type.Width)) 1483 1484 case TCOMPLEX64, TCOMPLEX128: 1485 gdatacomplex(&nam, nr.Val().U.(*Mpcplx)) 1486 1487 case TSTRING: 1488 gdatastring(&nam, nr.Val().U.(string)) 1489 } 1490 1491 return true 1492 1493 no: 1494 if n.Dodata == 2 { 1495 Dump("\ngen_as_init", n) 1496 Fatalf("gen_as_init couldnt make data statement") 1497 } 1498 1499 return false 1500 }