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