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