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