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