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