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