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