github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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.Lineno 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.Lineno, "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 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 == OASWB { 756 // Static initialization never needs 757 // write barriers. 758 a.Op = OAS 759 } 760 if a.Op != OAS { 761 Fatalf("fixedlit: not as, is %v", a) 762 } 763 a.IsStatic = true 764 case initKindDynamic, initKindLocalCode: 765 a = orderstmtinplace(a) 766 a = walkstmt(a) 767 default: 768 Fatalf("fixedlit: bad kind %d", kind) 769 } 770 771 init.Append(a) 772 } 773 } 774 775 func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) { 776 // make an array type corresponding the number of elements we have 777 t := typArray(n.Type.Elem(), n.Right.Int64()) 778 dowidth(t) 779 780 if ctxt == inNonInitFunction { 781 // put everything into static array 782 vstat := staticname(t) 783 784 fixedlit(ctxt, initKindStatic, n, vstat, init) 785 fixedlit(ctxt, initKindDynamic, n, vstat, init) 786 787 // copy static to slice 788 a := nod(OSLICE, vstat, nil) 789 790 a = nod(OAS, var_, a) 791 a = typecheck(a, Etop) 792 a.IsStatic = true 793 init.Append(a) 794 return 795 } 796 797 // recipe for var = []t{...} 798 // 1. make a static array 799 // var vstat [...]t 800 // 2. assign (data statements) the constant part 801 // vstat = constpart{} 802 // 3. make an auto pointer to array and allocate heap to it 803 // var vauto *[...]t = new([...]t) 804 // 4. copy the static array to the auto array 805 // *vauto = vstat 806 // 5. for each dynamic part assign to the array 807 // vauto[i] = dynamic part 808 // 6. assign slice of allocated heap to var 809 // var = vauto[:] 810 // 811 // an optimization is done if there is no constant part 812 // 3. var vauto *[...]t = new([...]t) 813 // 5. vauto[i] = dynamic part 814 // 6. var = vauto[:] 815 816 // if the literal contains constants, 817 // make static initialized array (1),(2) 818 var vstat *Node 819 820 mode := getdyn(n, true) 821 if mode&initConst != 0 { 822 vstat = staticname(t) 823 if ctxt == inInitFunction { 824 vstat.Name.Readonly = true 825 } 826 fixedlit(ctxt, initKindStatic, n, vstat, init) 827 } 828 829 // make new auto *array (3 declare) 830 vauto := temp(ptrto(t)) 831 832 // set auto to point at new temp or heap (3 assign) 833 var a *Node 834 if x := prealloc[n]; x != nil { 835 // temp allocated during order.go for dddarg 836 x.Type = t 837 838 if vstat == nil { 839 a = nod(OAS, x, nil) 840 a = typecheck(a, Etop) 841 init.Append(a) // zero new temp 842 } 843 844 a = nod(OADDR, x, nil) 845 } else if n.Esc == EscNone { 846 a = temp(t) 847 if vstat == nil { 848 a = nod(OAS, temp(t), nil) 849 a = typecheck(a, Etop) 850 init.Append(a) // zero new temp 851 a = a.Left 852 } 853 854 a = nod(OADDR, a, nil) 855 } else { 856 a = nod(ONEW, nil, nil) 857 a.List.Set1(typenod(t)) 858 } 859 860 a = nod(OAS, vauto, a) 861 a = typecheck(a, Etop) 862 a = walkexpr(a, init) 863 init.Append(a) 864 865 if vstat != nil { 866 // copy static to heap (4) 867 a = nod(OIND, vauto, nil) 868 869 a = nod(OAS, a, vstat) 870 a = typecheck(a, Etop) 871 a = walkexpr(a, init) 872 init.Append(a) 873 } 874 875 // put dynamics into array (5) 876 var index int64 877 for _, r := range n.List.Slice() { 878 value := r 879 if r.Op == OKEY { 880 index = nonnegintconst(r.Left) 881 value = r.Right 882 } 883 a := nod(OINDEX, vauto, nodintconst(index)) 884 a.Bounded = true 885 index++ 886 887 // TODO need to check bounds? 888 889 switch value.Op { 890 case OSLICELIT: 891 break 892 893 case OARRAYLIT, OSTRUCTLIT: 894 fixedlit(ctxt, initKindDynamic, value, a, init) 895 continue 896 } 897 898 if isliteral(value) { 899 continue 900 } 901 902 // build list of vauto[c] = expr 903 setlineno(value) 904 a = nod(OAS, a, value) 905 906 a = typecheck(a, Etop) 907 a = orderstmtinplace(a) 908 a = walkstmt(a) 909 init.Append(a) 910 } 911 912 // make slice out of heap (6) 913 a = nod(OAS, var_, nod(OSLICE, vauto, nil)) 914 915 a = typecheck(a, Etop) 916 a = orderstmtinplace(a) 917 a = walkstmt(a) 918 init.Append(a) 919 } 920 921 func maplit(n *Node, m *Node, init *Nodes) { 922 // make the map var 923 nerr := nerrors 924 925 a := nod(OMAKE, nil, nil) 926 a.List.Set2(typenod(n.Type), nodintconst(int64(len(n.List.Slice())))) 927 litas(m, a, init) 928 929 // count the initializers 930 b := 0 931 for _, r := range n.List.Slice() { 932 if r.Op != OKEY { 933 Fatalf("maplit: rhs not OKEY: %v", r) 934 } 935 index := r.Left 936 value := r.Right 937 938 if isliteral(index) && isliteral(value) { 939 b++ 940 } 941 } 942 943 if b != 0 { 944 // build types [count]Tindex and [count]Tvalue 945 tk := typArray(n.Type.Key(), int64(b)) 946 tv := typArray(n.Type.Val(), int64(b)) 947 948 // TODO(josharian): suppress alg generation for these types? 949 dowidth(tk) 950 dowidth(tv) 951 952 // make and initialize static arrays 953 vstatk := staticname(tk) 954 vstatk.Name.Readonly = true 955 vstatv := staticname(tv) 956 vstatv.Name.Readonly = true 957 958 b := int64(0) 959 for _, r := range n.List.Slice() { 960 if r.Op != OKEY { 961 Fatalf("maplit: rhs not OKEY: %v", r) 962 } 963 index := r.Left 964 value := r.Right 965 966 if isliteral(index) && isliteral(value) { 967 // build vstatk[b] = index 968 setlineno(index) 969 lhs := nod(OINDEX, vstatk, nodintconst(b)) 970 as := nod(OAS, lhs, index) 971 as = typecheck(as, Etop) 972 as = walkexpr(as, init) 973 as.IsStatic = true 974 init.Append(as) 975 976 // build vstatv[b] = value 977 setlineno(value) 978 lhs = nod(OINDEX, vstatv, nodintconst(b)) 979 as = nod(OAS, lhs, value) 980 as = typecheck(as, Etop) 981 as = walkexpr(as, init) 982 as.IsStatic = true 983 init.Append(as) 984 985 b++ 986 } 987 } 988 989 // loop adding structure elements to map 990 // for i = 0; i < len(vstatk); i++ { 991 // map[vstatk[i]] = vstatv[i] 992 // } 993 i := temp(Types[TINT]) 994 rhs := nod(OINDEX, vstatv, i) 995 rhs.Bounded = true 996 997 kidx := nod(OINDEX, vstatk, i) 998 kidx.Bounded = true 999 lhs := nod(OINDEX, m, kidx) 1000 1001 zero := nod(OAS, i, nodintconst(0)) 1002 cond := nod(OLT, i, nodintconst(tk.NumElem())) 1003 incr := nod(OAS, i, nod(OADD, i, nodintconst(1))) 1004 body := nod(OAS, lhs, rhs) 1005 1006 loop := nod(OFOR, cond, incr) 1007 loop.Nbody.Set1(body) 1008 loop.Ninit.Set1(zero) 1009 1010 loop = typecheck(loop, Etop) 1011 loop = walkstmt(loop) 1012 init.Append(loop) 1013 } 1014 1015 // put in dynamic entries one-at-a-time 1016 var key, val *Node 1017 for _, r := range n.List.Slice() { 1018 if r.Op != OKEY { 1019 Fatalf("maplit: rhs not OKEY: %v", r) 1020 } 1021 index := r.Left 1022 value := r.Right 1023 1024 if isliteral(index) && isliteral(value) { 1025 continue 1026 } 1027 1028 // build list of var[c] = expr. 1029 // use temporary so that mapassign1 can have addressable key, val. 1030 if key == nil { 1031 key = temp(m.Type.Key()) 1032 val = temp(m.Type.Val()) 1033 } 1034 1035 setlineno(index) 1036 a = nod(OAS, key, index) 1037 a = typecheck(a, Etop) 1038 a = walkstmt(a) 1039 init.Append(a) 1040 1041 setlineno(value) 1042 a = nod(OAS, val, value) 1043 a = typecheck(a, Etop) 1044 a = walkstmt(a) 1045 init.Append(a) 1046 1047 setlineno(val) 1048 a = nod(OAS, nod(OINDEX, m, key), val) 1049 a = typecheck(a, Etop) 1050 a = walkstmt(a) 1051 init.Append(a) 1052 1053 if nerr != nerrors { 1054 break 1055 } 1056 } 1057 1058 if key != nil { 1059 a = nod(OVARKILL, key, nil) 1060 a = typecheck(a, Etop) 1061 init.Append(a) 1062 a = nod(OVARKILL, val, nil) 1063 a = typecheck(a, Etop) 1064 init.Append(a) 1065 } 1066 } 1067 1068 func anylit(n *Node, var_ *Node, init *Nodes) { 1069 t := n.Type 1070 switch n.Op { 1071 default: 1072 Fatalf("anylit: not lit, op=%v node=%v", n.Op, n) 1073 1074 case OPTRLIT: 1075 if !t.IsPtr() { 1076 Fatalf("anylit: not ptr") 1077 } 1078 1079 var r *Node 1080 if n.Right != nil { 1081 // n.Right is stack temporary used as backing store. 1082 init.Append(nod(OAS, n.Right, nil)) // zero backing store, just in case (#18410) 1083 r = nod(OADDR, n.Right, nil) 1084 r = typecheck(r, Erv) 1085 } else { 1086 r = nod(ONEW, nil, nil) 1087 r.Typecheck = 1 1088 r.Type = t 1089 r.Esc = n.Esc 1090 } 1091 1092 r = walkexpr(r, init) 1093 a := nod(OAS, var_, r) 1094 1095 a = typecheck(a, Etop) 1096 init.Append(a) 1097 1098 var_ = nod(OIND, var_, nil) 1099 var_ = typecheck(var_, Erv|Easgn) 1100 anylit(n.Left, var_, init) 1101 1102 case OSTRUCTLIT, OARRAYLIT: 1103 if !t.IsStruct() && !t.IsArray() { 1104 Fatalf("anylit: not struct/array") 1105 } 1106 1107 if var_.isSimpleName() && n.List.Len() > 4 { 1108 // lay out static data 1109 vstat := staticname(t) 1110 vstat.Name.Readonly = true 1111 1112 ctxt := inInitFunction 1113 if n.Op == OARRAYLIT { 1114 ctxt = inNonInitFunction 1115 } 1116 fixedlit(ctxt, initKindStatic, n, vstat, init) 1117 1118 // copy static to var 1119 a := nod(OAS, var_, vstat) 1120 1121 a = typecheck(a, Etop) 1122 a = walkexpr(a, init) 1123 init.Append(a) 1124 1125 // add expressions to automatic 1126 fixedlit(inInitFunction, initKindDynamic, n, var_, init) 1127 break 1128 } 1129 1130 var components int64 1131 if n.Op == OARRAYLIT { 1132 components = t.NumElem() 1133 } else { 1134 components = int64(t.NumFields()) 1135 } 1136 // initialization of an array or struct with unspecified components (missing fields or arrays) 1137 if var_.isSimpleName() || int64(n.List.Len()) < components { 1138 a := nod(OAS, var_, nil) 1139 a = typecheck(a, Etop) 1140 a = walkexpr(a, init) 1141 init.Append(a) 1142 } 1143 1144 fixedlit(inInitFunction, initKindLocalCode, n, var_, init) 1145 1146 case OSLICELIT: 1147 slicelit(inInitFunction, n, var_, init) 1148 1149 case OMAPLIT: 1150 if !t.IsMap() { 1151 Fatalf("anylit: not map") 1152 } 1153 maplit(n, var_, init) 1154 } 1155 } 1156 1157 func oaslit(n *Node, init *Nodes) bool { 1158 if n.Left == nil || n.Right == nil { 1159 // not a special composite literal assignment 1160 return false 1161 } 1162 if n.Left.Type == nil || n.Right.Type == nil { 1163 // not a special composite literal assignment 1164 return false 1165 } 1166 if !n.Left.isSimpleName() { 1167 // not a special composite literal assignment 1168 return false 1169 } 1170 if !eqtype(n.Left.Type, n.Right.Type) { 1171 // not a special composite literal assignment 1172 return false 1173 } 1174 1175 switch n.Right.Op { 1176 default: 1177 // not a special composite literal assignment 1178 return false 1179 1180 case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT: 1181 if vmatch1(n.Left, n.Right) { 1182 // not a special composite literal assignment 1183 return false 1184 } 1185 anylit(n.Right, n.Left, init) 1186 } 1187 1188 n.Op = OEMPTY 1189 n.Right = nil 1190 return true 1191 } 1192 1193 func getlit(lit *Node) int { 1194 if smallintconst(lit) { 1195 return int(lit.Int64()) 1196 } 1197 return -1 1198 } 1199 1200 // stataddr sets nam to the static address of n and reports whether it succeeded. 1201 func stataddr(nam *Node, n *Node) bool { 1202 if n == nil { 1203 return false 1204 } 1205 1206 switch n.Op { 1207 case ONAME: 1208 *nam = *n 1209 return n.Addable 1210 1211 case ODOT: 1212 if !stataddr(nam, n.Left) { 1213 break 1214 } 1215 nam.Xoffset += n.Xoffset 1216 nam.Type = n.Type 1217 return true 1218 1219 case OINDEX: 1220 if n.Left.Type.IsSlice() { 1221 break 1222 } 1223 if !stataddr(nam, n.Left) { 1224 break 1225 } 1226 l := getlit(n.Right) 1227 if l < 0 { 1228 break 1229 } 1230 1231 // Check for overflow. 1232 if n.Type.Width != 0 && Thearch.MAXWIDTH/n.Type.Width <= int64(l) { 1233 break 1234 } 1235 nam.Xoffset += int64(l) * n.Type.Width 1236 nam.Type = n.Type 1237 return true 1238 } 1239 1240 return false 1241 } 1242 1243 func initplan(n *Node) { 1244 if initplans[n] != nil { 1245 return 1246 } 1247 p := new(InitPlan) 1248 initplans[n] = p 1249 switch n.Op { 1250 default: 1251 Fatalf("initplan") 1252 1253 case OARRAYLIT, OSLICELIT: 1254 var k int64 1255 for _, a := range n.List.Slice() { 1256 if a.Op == OKEY { 1257 k = nonnegintconst(a.Left) 1258 a = a.Right 1259 } 1260 addvalue(p, k*n.Type.Elem().Width, a) 1261 k++ 1262 } 1263 1264 case OSTRUCTLIT: 1265 for _, a := range n.List.Slice() { 1266 if a.Op != OSTRUCTKEY { 1267 Fatalf("initplan fixedlit") 1268 } 1269 addvalue(p, a.Xoffset, a.Left) 1270 } 1271 1272 case OMAPLIT: 1273 for _, a := range n.List.Slice() { 1274 if a.Op != OKEY { 1275 Fatalf("initplan maplit") 1276 } 1277 addvalue(p, -1, a.Right) 1278 } 1279 } 1280 } 1281 1282 func addvalue(p *InitPlan, xoffset int64, n *Node) { 1283 // special case: zero can be dropped entirely 1284 if iszero(n) { 1285 return 1286 } 1287 1288 // special case: inline struct and array (not slice) literals 1289 if isvaluelit(n) { 1290 initplan(n) 1291 q := initplans[n] 1292 for _, qe := range q.E { 1293 // qe is a copy; we are not modifying entries in q.E 1294 qe.Xoffset += xoffset 1295 p.E = append(p.E, qe) 1296 } 1297 return 1298 } 1299 1300 // add to plan 1301 p.E = append(p.E, InitEntry{Xoffset: xoffset, Expr: n}) 1302 } 1303 1304 func iszero(n *Node) bool { 1305 switch n.Op { 1306 case OLITERAL: 1307 switch u := n.Val().U.(type) { 1308 default: 1309 Dump("unexpected literal", n) 1310 Fatalf("iszero") 1311 case *NilVal: 1312 return true 1313 case string: 1314 return u == "" 1315 case bool: 1316 return !u 1317 case *Mpint: 1318 return u.CmpInt64(0) == 0 1319 case *Mpflt: 1320 return u.CmpFloat64(0) == 0 1321 case *Mpcplx: 1322 return u.Real.CmpFloat64(0) == 0 && u.Imag.CmpFloat64(0) == 0 1323 } 1324 1325 case OARRAYLIT: 1326 for _, n1 := range n.List.Slice() { 1327 if n1.Op == OKEY { 1328 n1 = n1.Right 1329 } 1330 if !iszero(n1) { 1331 return false 1332 } 1333 } 1334 return true 1335 1336 case OSTRUCTLIT: 1337 for _, n1 := range n.List.Slice() { 1338 if !iszero(n1.Left) { 1339 return false 1340 } 1341 } 1342 return true 1343 } 1344 1345 return false 1346 } 1347 1348 func isvaluelit(n *Node) bool { 1349 return n.Op == OARRAYLIT || n.Op == OSTRUCTLIT 1350 } 1351 1352 // gen_as_init attempts to emit static data for n and reports whether it succeeded. 1353 // If reportOnly is true, it does not emit static data and does not modify the AST. 1354 func gen_as_init(n *Node, reportOnly bool) bool { 1355 success := genAsInitNoCheck(n, reportOnly) 1356 if !success && n.IsStatic { 1357 Dump("\ngen_as_init", n) 1358 Fatalf("gen_as_init couldn't generate static data") 1359 } 1360 return success 1361 } 1362 1363 func genAsInitNoCheck(n *Node, reportOnly bool) bool { 1364 if !n.IsStatic { 1365 return false 1366 } 1367 1368 nr := n.Right 1369 nl := n.Left 1370 if nr == nil { 1371 var nam Node 1372 return stataddr(&nam, nl) && nam.Class == PEXTERN 1373 } 1374 1375 if nr.Type == nil || !eqtype(nl.Type, nr.Type) { 1376 return false 1377 } 1378 1379 var nam Node 1380 if !stataddr(&nam, nl) || nam.Class != PEXTERN { 1381 return false 1382 } 1383 1384 switch nr.Op { 1385 default: 1386 return false 1387 1388 case OCONVNOP: 1389 nr = nr.Left 1390 if nr == nil || nr.Op != OSLICEARR { 1391 return false 1392 } 1393 fallthrough 1394 1395 case OSLICEARR: 1396 low, high, _ := nr.SliceBounds() 1397 if low != nil || high != nil { 1398 return false 1399 } 1400 nr = nr.Left 1401 if nr == nil || nr.Op != OADDR { 1402 return false 1403 } 1404 ptr := nr 1405 nr = nr.Left 1406 if nr == nil || nr.Op != ONAME { 1407 return false 1408 } 1409 1410 // nr is the array being converted to a slice 1411 if nr.Type == nil || !nr.Type.IsArray() { 1412 return false 1413 } 1414 1415 if !reportOnly { 1416 nam.Xoffset += int64(array_array) 1417 gdata(&nam, ptr, Widthptr) 1418 1419 nam.Xoffset += int64(array_nel) - int64(array_array) 1420 var nod1 Node 1421 Nodconst(&nod1, Types[TINT], nr.Type.NumElem()) 1422 gdata(&nam, &nod1, Widthint) 1423 1424 nam.Xoffset += int64(array_cap) - int64(array_nel) 1425 gdata(&nam, &nod1, Widthint) 1426 } 1427 1428 return true 1429 1430 case OLITERAL: 1431 if !reportOnly { 1432 gdata(&nam, nr, int(nr.Type.Width)) 1433 } 1434 return true 1435 } 1436 }