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