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