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