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