github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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 "github.com/gagliardetto/golang-go/cmd/compile/internal/types" 9 "fmt" 10 ) 11 12 type InitEntry struct { 13 Xoffset int64 // struct, array only 14 Expr *Node // bytes of run-time computed expressions 15 } 16 17 type InitPlan struct { 18 E []InitEntry 19 } 20 21 // An InitSchedule is used to decompose assignment statements into 22 // static and dynamic initialization parts. Static initializations are 23 // handled by populating variables' linker symbol data, while dynamic 24 // initializations are accumulated to be executed in order. 25 type InitSchedule struct { 26 // out is the ordered list of dynamic initialization 27 // statements. 28 out []*Node 29 30 initplans map[*Node]*InitPlan 31 inittemps map[*Node]*Node 32 } 33 34 func (s *InitSchedule) append(n *Node) { 35 s.out = append(s.out, n) 36 } 37 38 // staticInit adds an initialization statement n to the schedule. 39 func (s *InitSchedule) staticInit(n *Node) { 40 if !s.tryStaticInit(n) { 41 if Debug['%'] != 0 { 42 Dump("nonstatic", n) 43 } 44 s.append(n) 45 } 46 } 47 48 // tryStaticInit attempts to statically execute an initialization 49 // statement and reports whether it succeeded. 50 func (s *InitSchedule) tryStaticInit(n *Node) bool { 51 // Only worry about simple "l = r" assignments. Multiple 52 // variable/expression OAS2 assignments have already been 53 // replaced by multiple simple OAS assignments, and the other 54 // OAS2* assignments mostly necessitate dynamic execution 55 // anyway. 56 if n.Op != OAS { 57 return false 58 } 59 if n.Left.isBlank() && candiscard(n.Right) { 60 return true 61 } 62 lno := setlineno(n) 63 defer func() { lineno = lno }() 64 return s.staticassign(n.Left, n.Right) 65 } 66 67 // like staticassign but we are copying an already 68 // initialized value r. 69 func (s *InitSchedule) staticcopy(l *Node, r *Node) bool { 70 if r.Op != ONAME { 71 return false 72 } 73 if r.Class() == PFUNC { 74 gdata(l, r, Widthptr) 75 return true 76 } 77 if r.Class() != PEXTERN || r.Sym.Pkg != localpkg { 78 return false 79 } 80 if r.Name.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value 81 return false 82 } 83 if r.Name.Defn.Op != OAS { 84 return false 85 } 86 if r.Type.IsString() { // perhaps overwritten by cmd/link -X (#34675) 87 return false 88 } 89 orig := r 90 r = r.Name.Defn.Right 91 92 for r.Op == OCONVNOP && !types.Identical(r.Type, l.Type) { 93 r = r.Left 94 } 95 96 switch r.Op { 97 case ONAME: 98 if s.staticcopy(l, r) { 99 return true 100 } 101 // We may have skipped past one or more OCONVNOPs, so 102 // use conv to ensure r is assignable to l (#13263). 103 s.append(nod(OAS, l, conv(r, l.Type))) 104 return true 105 106 case OLITERAL: 107 if isZero(r) { 108 return true 109 } 110 gdata(l, r, int(l.Type.Width)) 111 return true 112 113 case OADDR: 114 switch r.Left.Op { 115 case ONAME: 116 gdata(l, r, int(l.Type.Width)) 117 return true 118 } 119 120 case OPTRLIT: 121 switch r.Left.Op { 122 case OARRAYLIT, OSLICELIT, OSTRUCTLIT, OMAPLIT: 123 // copy pointer 124 gdata(l, nod(OADDR, s.inittemps[r], nil), int(l.Type.Width)) 125 return true 126 } 127 128 case OSLICELIT: 129 // copy slice 130 a := s.inittemps[r] 131 132 n := l.copy() 133 n.Xoffset = l.Xoffset + int64(slice_array) 134 gdata(n, nod(OADDR, a, nil), Widthptr) 135 n.Xoffset = l.Xoffset + int64(slice_nel) 136 gdata(n, r.Right, Widthptr) 137 n.Xoffset = l.Xoffset + int64(slice_cap) 138 gdata(n, r.Right, Widthptr) 139 return true 140 141 case OARRAYLIT, OSTRUCTLIT: 142 p := s.initplans[r] 143 144 n := l.copy() 145 for i := range p.E { 146 e := &p.E[i] 147 n.Xoffset = l.Xoffset + e.Xoffset 148 n.Type = e.Expr.Type 149 if e.Expr.Op == OLITERAL { 150 gdata(n, e.Expr, int(n.Type.Width)) 151 continue 152 } 153 ll := n.sepcopy() 154 if s.staticcopy(ll, e.Expr) { 155 continue 156 } 157 // Requires computation, but we're 158 // copying someone else's computation. 159 rr := orig.sepcopy() 160 rr.Type = ll.Type 161 rr.Xoffset += e.Xoffset 162 setlineno(rr) 163 s.append(nod(OAS, ll, rr)) 164 } 165 166 return true 167 } 168 169 return false 170 } 171 172 func (s *InitSchedule) staticassign(l *Node, r *Node) bool { 173 for r.Op == OCONVNOP { 174 r = r.Left 175 } 176 177 switch r.Op { 178 case ONAME: 179 return s.staticcopy(l, r) 180 181 case OLITERAL: 182 if isZero(r) { 183 return true 184 } 185 gdata(l, r, int(l.Type.Width)) 186 return true 187 188 case OADDR: 189 var nam Node 190 if stataddr(&nam, r.Left) { 191 n := *r 192 n.Left = &nam 193 gdata(l, &n, int(l.Type.Width)) 194 return true 195 } 196 fallthrough 197 198 case OPTRLIT: 199 switch r.Left.Op { 200 case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT: 201 // Init pointer. 202 a := staticname(r.Left.Type) 203 204 s.inittemps[r] = a 205 gdata(l, nod(OADDR, a, nil), int(l.Type.Width)) 206 207 // Init underlying literal. 208 if !s.staticassign(a, r.Left) { 209 s.append(nod(OAS, a, r.Left)) 210 } 211 return true 212 } 213 //dump("not static ptrlit", r); 214 215 case OSTR2BYTES: 216 if l.Class() == PEXTERN && r.Left.Op == OLITERAL { 217 sval := strlit(r.Left) 218 slicebytes(l, sval, len(sval)) 219 return true 220 } 221 222 case OSLICELIT: 223 s.initplan(r) 224 // Init slice. 225 bound := r.Right.Int64() 226 ta := types.NewArray(r.Type.Elem(), bound) 227 a := staticname(ta) 228 s.inittemps[r] = a 229 n := l.copy() 230 n.Xoffset = l.Xoffset + int64(slice_array) 231 gdata(n, nod(OADDR, a, nil), Widthptr) 232 n.Xoffset = l.Xoffset + int64(slice_nel) 233 gdata(n, r.Right, Widthptr) 234 n.Xoffset = l.Xoffset + int64(slice_cap) 235 gdata(n, r.Right, Widthptr) 236 237 // Fall through to init underlying array. 238 l = a 239 fallthrough 240 241 case OARRAYLIT, OSTRUCTLIT: 242 s.initplan(r) 243 244 p := s.initplans[r] 245 n := l.copy() 246 for i := range p.E { 247 e := &p.E[i] 248 n.Xoffset = l.Xoffset + e.Xoffset 249 n.Type = e.Expr.Type 250 if e.Expr.Op == OLITERAL { 251 gdata(n, e.Expr, int(n.Type.Width)) 252 continue 253 } 254 setlineno(e.Expr) 255 a := n.sepcopy() 256 if !s.staticassign(a, e.Expr) { 257 s.append(nod(OAS, a, e.Expr)) 258 } 259 } 260 261 return true 262 263 case OMAPLIT: 264 break 265 266 case OCLOSURE: 267 if hasemptycvars(r) { 268 if Debug_closure > 0 { 269 Warnl(r.Pos, "closure converted to global") 270 } 271 // Closures with no captured variables are globals, 272 // so the assignment can be done at link time. 273 gdata(l, r.Func.Closure.Func.Nname, Widthptr) 274 return true 275 } 276 closuredebugruntimecheck(r) 277 278 case OCONVIFACE: 279 // This logic is mirrored in isStaticCompositeLiteral. 280 // If you change something here, change it there, and vice versa. 281 282 // Determine the underlying concrete type and value we are converting from. 283 val := r 284 for val.Op == OCONVIFACE { 285 val = val.Left 286 } 287 if val.Type.IsInterface() { 288 // val is an interface type. 289 // If val is nil, we can statically initialize l; 290 // both words are zero and so there no work to do, so report success. 291 // If val is non-nil, we have no concrete type to record, 292 // and we won't be able to statically initialize its value, so report failure. 293 return Isconst(val, CTNIL) 294 } 295 296 var itab *Node 297 if l.Type.IsEmptyInterface() { 298 itab = typename(val.Type) 299 } else { 300 itab = itabname(val.Type, l.Type) 301 } 302 303 // Create a copy of l to modify while we emit data. 304 n := l.copy() 305 306 // Emit itab, advance offset. 307 gdata(n, itab, Widthptr) 308 n.Xoffset += int64(Widthptr) 309 310 // Emit data. 311 if isdirectiface(val.Type) { 312 if Isconst(val, CTNIL) { 313 // Nil is zero, nothing to do. 314 return true 315 } 316 // Copy val directly into n. 317 n.Type = val.Type 318 setlineno(val) 319 a := n.sepcopy() 320 if !s.staticassign(a, val) { 321 s.append(nod(OAS, a, val)) 322 } 323 } else { 324 // Construct temp to hold val, write pointer to temp into n. 325 a := staticname(val.Type) 326 s.inittemps[val] = a 327 if !s.staticassign(a, val) { 328 s.append(nod(OAS, a, val)) 329 } 330 ptr := nod(OADDR, a, nil) 331 n.Type = types.NewPtr(val.Type) 332 gdata(n, ptr, Widthptr) 333 } 334 335 return true 336 } 337 338 //dump("not static", r); 339 return false 340 } 341 342 // initContext is the context in which static data is populated. 343 // It is either in an init function or in any other function. 344 // Static data populated in an init function will be written either 345 // zero times (as a readonly, static data symbol) or 346 // one time (during init function execution). 347 // Either way, there is no opportunity for races or further modification, 348 // so the data can be written to a (possibly readonly) data symbol. 349 // Static data populated in any other function needs to be local to 350 // that function to allow multiple instances of that function 351 // to execute concurrently without clobbering each others' data. 352 type initContext uint8 353 354 const ( 355 inInitFunction initContext = iota 356 inNonInitFunction 357 ) 358 359 func (c initContext) String() string { 360 if c == inInitFunction { 361 return "inInitFunction" 362 } 363 return "inNonInitFunction" 364 } 365 366 // from here down is the walk analysis 367 // of composite literals. 368 // most of the work is to generate 369 // data statements for the constant 370 // part of the composite literal. 371 372 var statuniqgen int // name generator for static temps 373 374 // staticname returns a name backed by a static data symbol. 375 // Callers should call n.Name.SetReadonly(true) on the 376 // returned node for readonly nodes. 377 func staticname(t *types.Type) *Node { 378 // Don't use lookupN; it interns the resulting string, but these are all unique. 379 n := newname(lookup(fmt.Sprintf(".stmp_%d", statuniqgen))) 380 statuniqgen++ 381 addvar(n, t, PEXTERN) 382 return n 383 } 384 385 func isLiteral(n *Node) bool { 386 // Treat nils as zeros rather than literals. 387 return n.Op == OLITERAL && n.Val().Ctype() != CTNIL 388 } 389 390 func (n *Node) isSimpleName() bool { 391 return n.Op == ONAME && n.Class() != PAUTOHEAP && n.Class() != PEXTERN 392 } 393 394 func litas(l *Node, r *Node, init *Nodes) { 395 a := nod(OAS, l, r) 396 a = typecheck(a, ctxStmt) 397 a = walkexpr(a, init) 398 init.Append(a) 399 } 400 401 // initGenType is a bitmap indicating the types of generation that will occur for a static value. 402 type initGenType uint8 403 404 const ( 405 initDynamic initGenType = 1 << iota // contains some dynamic values, for which init code will be generated 406 initConst // contains some constant values, which may be written into data symbols 407 ) 408 409 // getdyn calculates the initGenType for n. 410 // If top is false, getdyn is recursing. 411 func getdyn(n *Node, top bool) initGenType { 412 switch n.Op { 413 default: 414 if isLiteral(n) { 415 return initConst 416 } 417 return initDynamic 418 419 case OSLICELIT: 420 if !top { 421 return initDynamic 422 } 423 if n.Right.Int64()/4 > int64(n.List.Len()) { 424 // <25% of entries have explicit values. 425 // Very rough estimation, it takes 4 bytes of instructions 426 // to initialize 1 byte of result. So don't use a static 427 // initializer if the dynamic initialization code would be 428 // smaller than the static value. 429 // See issue 23780. 430 return initDynamic 431 } 432 433 case OARRAYLIT, OSTRUCTLIT: 434 } 435 436 var mode initGenType 437 for _, n1 := range n.List.Slice() { 438 switch n1.Op { 439 case OKEY: 440 n1 = n1.Right 441 case OSTRUCTKEY: 442 n1 = n1.Left 443 } 444 mode |= getdyn(n1, false) 445 if mode == initDynamic|initConst { 446 break 447 } 448 } 449 return mode 450 } 451 452 // isStaticCompositeLiteral reports whether n is a compile-time constant. 453 func isStaticCompositeLiteral(n *Node) bool { 454 switch n.Op { 455 case OSLICELIT: 456 return false 457 case OARRAYLIT: 458 for _, r := range n.List.Slice() { 459 if r.Op == OKEY { 460 r = r.Right 461 } 462 if !isStaticCompositeLiteral(r) { 463 return false 464 } 465 } 466 return true 467 case OSTRUCTLIT: 468 for _, r := range n.List.Slice() { 469 if r.Op != OSTRUCTKEY { 470 Fatalf("isStaticCompositeLiteral: rhs not OSTRUCTKEY: %v", r) 471 } 472 if !isStaticCompositeLiteral(r.Left) { 473 return false 474 } 475 } 476 return true 477 case OLITERAL: 478 return true 479 case OCONVIFACE: 480 // See staticassign's OCONVIFACE case for comments. 481 val := n 482 for val.Op == OCONVIFACE { 483 val = val.Left 484 } 485 if val.Type.IsInterface() { 486 return Isconst(val, CTNIL) 487 } 488 if isdirectiface(val.Type) && Isconst(val, CTNIL) { 489 return true 490 } 491 return isStaticCompositeLiteral(val) 492 } 493 return false 494 } 495 496 // initKind is a kind of static initialization: static, dynamic, or local. 497 // Static initialization represents literals and 498 // literal components of composite literals. 499 // Dynamic initialization represents non-literals and 500 // non-literal components of composite literals. 501 // LocalCode initialization represents initialization 502 // that occurs purely in generated code local to the function of use. 503 // Initialization code is sometimes generated in passes, 504 // first static then dynamic. 505 type initKind uint8 506 507 const ( 508 initKindStatic initKind = iota + 1 509 initKindDynamic 510 initKindLocalCode 511 ) 512 513 // fixedlit handles struct, array, and slice literals. 514 // TODO: expand documentation. 515 func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes) { 516 var splitnode func(*Node) (a *Node, value *Node) 517 switch n.Op { 518 case OARRAYLIT, OSLICELIT: 519 var k int64 520 splitnode = func(r *Node) (*Node, *Node) { 521 if r.Op == OKEY { 522 k = indexconst(r.Left) 523 if k < 0 { 524 Fatalf("fixedlit: invalid index %v", r.Left) 525 } 526 r = r.Right 527 } 528 a := nod(OINDEX, var_, nodintconst(k)) 529 k++ 530 return a, r 531 } 532 case OSTRUCTLIT: 533 splitnode = func(r *Node) (*Node, *Node) { 534 if r.Op != OSTRUCTKEY { 535 Fatalf("fixedlit: rhs not OSTRUCTKEY: %v", r) 536 } 537 if r.Sym.IsBlank() { 538 return nblank, r.Left 539 } 540 setlineno(r) 541 return nodSym(ODOT, var_, r.Sym), r.Left 542 } 543 default: 544 Fatalf("fixedlit bad op: %v", n.Op) 545 } 546 547 for _, r := range n.List.Slice() { 548 a, value := splitnode(r) 549 550 switch value.Op { 551 case OSLICELIT: 552 if (kind == initKindStatic && ctxt == inNonInitFunction) || (kind == initKindDynamic && ctxt == inInitFunction) { 553 slicelit(ctxt, value, a, init) 554 continue 555 } 556 557 case OARRAYLIT, OSTRUCTLIT: 558 fixedlit(ctxt, kind, value, a, init) 559 continue 560 } 561 562 islit := isLiteral(value) 563 if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) { 564 continue 565 } 566 567 // build list of assignments: var[index] = expr 568 setlineno(a) 569 a = nod(OAS, a, value) 570 a = typecheck(a, ctxStmt) 571 switch kind { 572 case initKindStatic: 573 genAsStatic(a) 574 case initKindDynamic, initKindLocalCode: 575 a = orderStmtInPlace(a, map[string][]*Node{}) 576 a = walkstmt(a) 577 init.Append(a) 578 default: 579 Fatalf("fixedlit: bad kind %d", kind) 580 } 581 582 } 583 } 584 585 func isSmallSliceLit(n *Node) bool { 586 if n.Op != OSLICELIT { 587 return false 588 } 589 590 r := n.Right 591 592 return smallintconst(r) && (n.Type.Elem().Width == 0 || r.Int64() <= smallArrayBytes/n.Type.Elem().Width) 593 } 594 595 func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) { 596 // make an array type corresponding the number of elements we have 597 t := types.NewArray(n.Type.Elem(), n.Right.Int64()) 598 dowidth(t) 599 600 if ctxt == inNonInitFunction { 601 // put everything into static array 602 vstat := staticname(t) 603 604 fixedlit(ctxt, initKindStatic, n, vstat, init) 605 fixedlit(ctxt, initKindDynamic, n, vstat, init) 606 607 // copy static to slice 608 var_ = typecheck(var_, ctxExpr|ctxAssign) 609 var nam Node 610 if !stataddr(&nam, var_) || nam.Class() != PEXTERN { 611 Fatalf("slicelit: %v", var_) 612 } 613 614 var v Node 615 v.Type = types.Types[TINT] 616 setintconst(&v, t.NumElem()) 617 618 nam.Xoffset += int64(slice_array) 619 gdata(&nam, nod(OADDR, vstat, nil), Widthptr) 620 nam.Xoffset += int64(slice_nel) - int64(slice_array) 621 gdata(&nam, &v, Widthptr) 622 nam.Xoffset += int64(slice_cap) - int64(slice_nel) 623 gdata(&nam, &v, Widthptr) 624 625 return 626 } 627 628 // recipe for var = []t{...} 629 // 1. make a static array 630 // var vstat [...]t 631 // 2. assign (data statements) the constant part 632 // vstat = constpart{} 633 // 3. make an auto pointer to array and allocate heap to it 634 // var vauto *[...]t = new([...]t) 635 // 4. copy the static array to the auto array 636 // *vauto = vstat 637 // 5. for each dynamic part assign to the array 638 // vauto[i] = dynamic part 639 // 6. assign slice of allocated heap to var 640 // var = vauto[:] 641 // 642 // an optimization is done if there is no constant part 643 // 3. var vauto *[...]t = new([...]t) 644 // 5. vauto[i] = dynamic part 645 // 6. var = vauto[:] 646 647 // if the literal contains constants, 648 // make static initialized array (1),(2) 649 var vstat *Node 650 651 mode := getdyn(n, true) 652 if mode&initConst != 0 && !isSmallSliceLit(n) { 653 vstat = staticname(t) 654 if ctxt == inInitFunction { 655 vstat.Name.SetReadonly(true) 656 } 657 fixedlit(ctxt, initKindStatic, n, vstat, init) 658 } 659 660 // make new auto *array (3 declare) 661 vauto := temp(types.NewPtr(t)) 662 663 // set auto to point at new temp or heap (3 assign) 664 var a *Node 665 if x := prealloc[n]; x != nil { 666 // temp allocated during order.go for dddarg 667 if !types.Identical(t, x.Type) { 668 panic("dotdotdot base type does not match order's assigned type") 669 } 670 671 if vstat == nil { 672 a = nod(OAS, x, nil) 673 a = typecheck(a, ctxStmt) 674 init.Append(a) // zero new temp 675 } else { 676 // Declare that we're about to initialize all of x. 677 // (Which happens at the *vauto = vstat below.) 678 init.Append(nod(OVARDEF, x, nil)) 679 } 680 681 a = nod(OADDR, x, nil) 682 } else if n.Esc == EscNone { 683 a = temp(t) 684 if vstat == nil { 685 a = nod(OAS, temp(t), nil) 686 a = typecheck(a, ctxStmt) 687 init.Append(a) // zero new temp 688 a = a.Left 689 } else { 690 init.Append(nod(OVARDEF, a, nil)) 691 } 692 693 a = nod(OADDR, a, nil) 694 } else { 695 a = nod(ONEW, nil, nil) 696 a.List.Set1(typenod(t)) 697 } 698 699 a = nod(OAS, vauto, a) 700 a = typecheck(a, ctxStmt) 701 a = walkexpr(a, init) 702 init.Append(a) 703 704 if vstat != nil { 705 // copy static to heap (4) 706 a = nod(ODEREF, vauto, nil) 707 708 a = nod(OAS, a, vstat) 709 a = typecheck(a, ctxStmt) 710 a = walkexpr(a, init) 711 init.Append(a) 712 } 713 714 // put dynamics into array (5) 715 var index int64 716 for _, value := range n.List.Slice() { 717 if value.Op == OKEY { 718 index = indexconst(value.Left) 719 if index < 0 { 720 Fatalf("slicelit: invalid index %v", value.Left) 721 } 722 value = value.Right 723 } 724 a := nod(OINDEX, vauto, nodintconst(index)) 725 a.SetBounded(true) 726 index++ 727 728 // TODO need to check bounds? 729 730 switch value.Op { 731 case OSLICELIT: 732 break 733 734 case OARRAYLIT, OSTRUCTLIT: 735 k := initKindDynamic 736 if vstat == nil { 737 // Generate both static and dynamic initializations. 738 // See issue #31987. 739 k = initKindLocalCode 740 } 741 fixedlit(ctxt, k, value, a, init) 742 continue 743 } 744 745 if vstat != nil && isLiteral(value) { // already set by copy from static value 746 continue 747 } 748 749 // build list of vauto[c] = expr 750 setlineno(value) 751 a = nod(OAS, a, value) 752 753 a = typecheck(a, ctxStmt) 754 a = orderStmtInPlace(a, map[string][]*Node{}) 755 a = walkstmt(a) 756 init.Append(a) 757 } 758 759 // make slice out of heap (6) 760 a = nod(OAS, var_, nod(OSLICE, vauto, nil)) 761 762 a = typecheck(a, ctxStmt) 763 a = orderStmtInPlace(a, map[string][]*Node{}) 764 a = walkstmt(a) 765 init.Append(a) 766 } 767 768 func maplit(n *Node, m *Node, init *Nodes) { 769 // make the map var 770 a := nod(OMAKE, nil, nil) 771 a.Esc = n.Esc 772 a.List.Set2(typenod(n.Type), nodintconst(int64(n.List.Len()))) 773 litas(m, a, init) 774 775 entries := n.List.Slice() 776 777 // The order pass already removed any dynamic (runtime-computed) entries. 778 // All remaining entries are static. Double-check that. 779 for _, r := range entries { 780 if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) { 781 Fatalf("maplit: entry is not a literal: %v", r) 782 } 783 } 784 785 if len(entries) > 25 { 786 // For a large number of entries, put them in an array and loop. 787 788 // build types [count]Tindex and [count]Tvalue 789 tk := types.NewArray(n.Type.Key(), int64(len(entries))) 790 te := types.NewArray(n.Type.Elem(), int64(len(entries))) 791 792 // TODO(josharian): suppress alg generation for these types? 793 dowidth(tk) 794 dowidth(te) 795 796 // make and initialize static arrays 797 vstatk := staticname(tk) 798 vstatk.Name.SetReadonly(true) 799 vstate := staticname(te) 800 vstate.Name.SetReadonly(true) 801 802 datak := nod(OARRAYLIT, nil, nil) 803 datae := nod(OARRAYLIT, nil, nil) 804 for _, r := range entries { 805 datak.List.Append(r.Left) 806 datae.List.Append(r.Right) 807 } 808 fixedlit(inInitFunction, initKindStatic, datak, vstatk, init) 809 fixedlit(inInitFunction, initKindStatic, datae, vstate, init) 810 811 // loop adding structure elements to map 812 // for i = 0; i < len(vstatk); i++ { 813 // map[vstatk[i]] = vstate[i] 814 // } 815 i := temp(types.Types[TINT]) 816 rhs := nod(OINDEX, vstate, i) 817 rhs.SetBounded(true) 818 819 kidx := nod(OINDEX, vstatk, i) 820 kidx.SetBounded(true) 821 lhs := nod(OINDEX, m, kidx) 822 823 zero := nod(OAS, i, nodintconst(0)) 824 cond := nod(OLT, i, nodintconst(tk.NumElem())) 825 incr := nod(OAS, i, nod(OADD, i, nodintconst(1))) 826 body := nod(OAS, lhs, rhs) 827 828 loop := nod(OFOR, cond, incr) 829 loop.Nbody.Set1(body) 830 loop.Ninit.Set1(zero) 831 832 loop = typecheck(loop, ctxStmt) 833 loop = walkstmt(loop) 834 init.Append(loop) 835 return 836 } 837 // For a small number of entries, just add them directly. 838 839 // Build list of var[c] = expr. 840 // Use temporaries so that mapassign1 can have addressable key, elem. 841 // TODO(josharian): avoid map key temporaries for mapfast_* assignments with literal keys. 842 tmpkey := temp(m.Type.Key()) 843 tmpelem := temp(m.Type.Elem()) 844 845 for _, r := range entries { 846 index, elem := r.Left, r.Right 847 848 setlineno(index) 849 a := nod(OAS, tmpkey, index) 850 a = typecheck(a, ctxStmt) 851 a = walkstmt(a) 852 init.Append(a) 853 854 setlineno(elem) 855 a = nod(OAS, tmpelem, elem) 856 a = typecheck(a, ctxStmt) 857 a = walkstmt(a) 858 init.Append(a) 859 860 setlineno(tmpelem) 861 a = nod(OAS, nod(OINDEX, m, tmpkey), tmpelem) 862 a = typecheck(a, ctxStmt) 863 a = walkstmt(a) 864 init.Append(a) 865 } 866 867 a = nod(OVARKILL, tmpkey, nil) 868 a = typecheck(a, ctxStmt) 869 init.Append(a) 870 a = nod(OVARKILL, tmpelem, nil) 871 a = typecheck(a, ctxStmt) 872 init.Append(a) 873 } 874 875 func anylit(n *Node, var_ *Node, init *Nodes) { 876 t := n.Type 877 switch n.Op { 878 default: 879 Fatalf("anylit: not lit, op=%v node=%v", n.Op, n) 880 881 case ONAME: 882 a := nod(OAS, var_, n) 883 a = typecheck(a, ctxStmt) 884 init.Append(a) 885 886 case OPTRLIT: 887 if !t.IsPtr() { 888 Fatalf("anylit: not ptr") 889 } 890 891 var r *Node 892 if n.Right != nil { 893 // n.Right is stack temporary used as backing store. 894 init.Append(nod(OAS, n.Right, nil)) // zero backing store, just in case (#18410) 895 r = nod(OADDR, n.Right, nil) 896 r = typecheck(r, ctxExpr) 897 } else { 898 r = nod(ONEW, nil, nil) 899 r.SetTypecheck(1) 900 r.Type = t 901 r.Esc = n.Esc 902 } 903 904 r = walkexpr(r, init) 905 a := nod(OAS, var_, r) 906 907 a = typecheck(a, ctxStmt) 908 init.Append(a) 909 910 var_ = nod(ODEREF, var_, nil) 911 var_ = typecheck(var_, ctxExpr|ctxAssign) 912 anylit(n.Left, var_, init) 913 914 case OSTRUCTLIT, OARRAYLIT: 915 if !t.IsStruct() && !t.IsArray() { 916 Fatalf("anylit: not struct/array") 917 } 918 919 if var_.isSimpleName() && n.List.Len() > 4 { 920 // lay out static data 921 vstat := staticname(t) 922 vstat.Name.SetReadonly(true) 923 924 ctxt := inInitFunction 925 if n.Op == OARRAYLIT { 926 ctxt = inNonInitFunction 927 } 928 fixedlit(ctxt, initKindStatic, n, vstat, init) 929 930 // copy static to var 931 a := nod(OAS, var_, vstat) 932 933 a = typecheck(a, ctxStmt) 934 a = walkexpr(a, init) 935 init.Append(a) 936 937 // add expressions to automatic 938 fixedlit(inInitFunction, initKindDynamic, n, var_, init) 939 break 940 } 941 942 var components int64 943 if n.Op == OARRAYLIT { 944 components = t.NumElem() 945 } else { 946 components = int64(t.NumFields()) 947 } 948 // initialization of an array or struct with unspecified components (missing fields or arrays) 949 if var_.isSimpleName() || int64(n.List.Len()) < components { 950 a := nod(OAS, var_, nil) 951 a = typecheck(a, ctxStmt) 952 a = walkexpr(a, init) 953 init.Append(a) 954 } 955 956 fixedlit(inInitFunction, initKindLocalCode, n, var_, init) 957 958 case OSLICELIT: 959 slicelit(inInitFunction, n, var_, init) 960 961 case OMAPLIT: 962 if !t.IsMap() { 963 Fatalf("anylit: not map") 964 } 965 maplit(n, var_, init) 966 } 967 } 968 969 func oaslit(n *Node, init *Nodes) bool { 970 if n.Left == nil || n.Right == nil { 971 // not a special composite literal assignment 972 return false 973 } 974 if n.Left.Type == nil || n.Right.Type == nil { 975 // not a special composite literal assignment 976 return false 977 } 978 if !n.Left.isSimpleName() { 979 // not a special composite literal assignment 980 return false 981 } 982 if !types.Identical(n.Left.Type, n.Right.Type) { 983 // not a special composite literal assignment 984 return false 985 } 986 987 switch n.Right.Op { 988 default: 989 // not a special composite literal assignment 990 return false 991 992 case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT: 993 if vmatch1(n.Left, n.Right) { 994 // not a special composite literal assignment 995 return false 996 } 997 anylit(n.Right, n.Left, init) 998 } 999 1000 n.Op = OEMPTY 1001 n.Right = nil 1002 return true 1003 } 1004 1005 func getlit(lit *Node) int { 1006 if smallintconst(lit) { 1007 return int(lit.Int64()) 1008 } 1009 return -1 1010 } 1011 1012 // stataddr sets nam to the static address of n and reports whether it succeeded. 1013 func stataddr(nam *Node, n *Node) bool { 1014 if n == nil { 1015 return false 1016 } 1017 1018 switch n.Op { 1019 case ONAME: 1020 *nam = *n 1021 return true 1022 1023 case ODOT: 1024 if !stataddr(nam, n.Left) { 1025 break 1026 } 1027 nam.Xoffset += n.Xoffset 1028 nam.Type = n.Type 1029 return true 1030 1031 case OINDEX: 1032 if n.Left.Type.IsSlice() { 1033 break 1034 } 1035 if !stataddr(nam, n.Left) { 1036 break 1037 } 1038 l := getlit(n.Right) 1039 if l < 0 { 1040 break 1041 } 1042 1043 // Check for overflow. 1044 if n.Type.Width != 0 && thearch.MAXWIDTH/n.Type.Width <= int64(l) { 1045 break 1046 } 1047 nam.Xoffset += int64(l) * n.Type.Width 1048 nam.Type = n.Type 1049 return true 1050 } 1051 1052 return false 1053 } 1054 1055 func (s *InitSchedule) initplan(n *Node) { 1056 if s.initplans[n] != nil { 1057 return 1058 } 1059 p := new(InitPlan) 1060 s.initplans[n] = p 1061 switch n.Op { 1062 default: 1063 Fatalf("initplan") 1064 1065 case OARRAYLIT, OSLICELIT: 1066 var k int64 1067 for _, a := range n.List.Slice() { 1068 if a.Op == OKEY { 1069 k = indexconst(a.Left) 1070 if k < 0 { 1071 Fatalf("initplan arraylit: invalid index %v", a.Left) 1072 } 1073 a = a.Right 1074 } 1075 s.addvalue(p, k*n.Type.Elem().Width, a) 1076 k++ 1077 } 1078 1079 case OSTRUCTLIT: 1080 for _, a := range n.List.Slice() { 1081 if a.Op != OSTRUCTKEY { 1082 Fatalf("initplan structlit") 1083 } 1084 if a.Sym.IsBlank() { 1085 continue 1086 } 1087 s.addvalue(p, a.Xoffset, a.Left) 1088 } 1089 1090 case OMAPLIT: 1091 for _, a := range n.List.Slice() { 1092 if a.Op != OKEY { 1093 Fatalf("initplan maplit") 1094 } 1095 s.addvalue(p, -1, a.Right) 1096 } 1097 } 1098 } 1099 1100 func (s *InitSchedule) addvalue(p *InitPlan, xoffset int64, n *Node) { 1101 // special case: zero can be dropped entirely 1102 if isZero(n) { 1103 return 1104 } 1105 1106 // special case: inline struct and array (not slice) literals 1107 if isvaluelit(n) { 1108 s.initplan(n) 1109 q := s.initplans[n] 1110 for _, qe := range q.E { 1111 // qe is a copy; we are not modifying entries in q.E 1112 qe.Xoffset += xoffset 1113 p.E = append(p.E, qe) 1114 } 1115 return 1116 } 1117 1118 // add to plan 1119 p.E = append(p.E, InitEntry{Xoffset: xoffset, Expr: n}) 1120 } 1121 1122 func isZero(n *Node) bool { 1123 switch n.Op { 1124 case OLITERAL: 1125 switch u := n.Val().U.(type) { 1126 default: 1127 Dump("unexpected literal", n) 1128 Fatalf("isZero") 1129 case *NilVal: 1130 return true 1131 case string: 1132 return u == "" 1133 case bool: 1134 return !u 1135 case *Mpint: 1136 return u.CmpInt64(0) == 0 1137 case *Mpflt: 1138 return u.CmpFloat64(0) == 0 1139 case *Mpcplx: 1140 return u.Real.CmpFloat64(0) == 0 && u.Imag.CmpFloat64(0) == 0 1141 } 1142 1143 case OARRAYLIT: 1144 for _, n1 := range n.List.Slice() { 1145 if n1.Op == OKEY { 1146 n1 = n1.Right 1147 } 1148 if !isZero(n1) { 1149 return false 1150 } 1151 } 1152 return true 1153 1154 case OSTRUCTLIT: 1155 for _, n1 := range n.List.Slice() { 1156 if !isZero(n1.Left) { 1157 return false 1158 } 1159 } 1160 return true 1161 } 1162 1163 return false 1164 } 1165 1166 func isvaluelit(n *Node) bool { 1167 return n.Op == OARRAYLIT || n.Op == OSTRUCTLIT 1168 } 1169 1170 func genAsStatic(as *Node) { 1171 if as.Left.Type == nil { 1172 Fatalf("genAsStatic as.Left not typechecked") 1173 } 1174 1175 var nam Node 1176 if !stataddr(&nam, as.Left) || (nam.Class() != PEXTERN && as.Left != nblank) { 1177 Fatalf("genAsStatic: lhs %v", as.Left) 1178 } 1179 1180 switch { 1181 case as.Right.Op == OLITERAL: 1182 case as.Right.Op == ONAME && as.Right.Class() == PFUNC: 1183 default: 1184 Fatalf("genAsStatic: rhs %v", as.Right) 1185 } 1186 1187 gdata(&nam, as.Right, int(as.Right.Type.Width)) 1188 }