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.
9 // static initialization
16 type InitEntry struct {
17 Xoffset int64 // struct, array only
18 Expr *Node // bytes of run-time computed expressions
21 type InitPlan struct {
27 initplans map[*Node]*InitPlan
28 inittemps = make(map[*Node]*Node)
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) {
39 for _, n1 := range n.List.Slice() {
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)
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.
63 if n.Initorder == InitDone {
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.
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.
80 for i := len(initlist) - 1; i >= 0; i-- {
90 // The loop involves only functions, ok.
94 // reached a new unvisited node.
95 n.Initorder = InitPending
96 initlist = append(initlist, n)
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 {
104 Fatalf("init1: bad defn")
107 init2list(defn.Nbody, out)
112 Fatalf("init1: bad defn")
114 if isblank(defn.Left) && candiscard(defn.Right) {
121 init2(defn.Right, out)
123 fmt.Printf("%v\n", n.Sym)
125 if isblank(n) || !staticinit(n, out) {
127 Dump("nonstatic", defn)
129 *out = append(*out, defn)
132 case OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV:
133 if defn.Initorder == InitDone {
136 defn.Initorder = InitPending
137 for _, n2 := range defn.Rlist.Slice() {
141 Dump("nonstatic", defn)
143 *out = append(*out, defn)
144 defn.Initorder = InitDone
148 last := len(initlist) - 1
149 if initlist[last] != n {
150 Fatalf("bad initlist %v", initlist)
152 initlist[last] = nil // allow GC
153 initlist = initlist[:last]
155 n.Initorder = InitDone
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
170 // Find the index of node and visited in the initlist.
171 var nodeindex, visitedindex int
172 for ; initlist[nodeindex] != node; nodeindex++ {
174 for ; initlist[visitedindex] != visited; visitedindex++ {
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())
181 // Print visited -> ... -> n1 -> node.
182 for _, n := range initlist[visitedindex:] {
183 fmt.Printf("\t%v %v refers to\n", n.Line(), n.Sym)
186 // Print node -> ... -> visited.
187 for _, n := range initlist[nodeindex:visitedindex] {
188 fmt.Printf("\t%v %v refers to\n", n.Line(), n.Sym)
191 fmt.Printf("\t%v %v\n", visited.Line(), visited.Sym)
195 // recurse over n, doing init1 everywhere.
196 func init2(n *Node, out *[]*Node) {
197 if n == nil || n.Initorder == InitDone {
201 if n.Op == ONAME && n.Ninit.Len() != 0 {
202 Fatalf("name %v with ninit: %+v\n", n.Sym, n)
208 init2list(n.Ninit, out)
209 init2list(n.List, out)
210 init2list(n.Rlist, out)
211 init2list(n.Nbody, out)
213 if n.Op == OCLOSURE {
214 init2list(n.Func.Closure.Nbody, out)
216 if n.Op == ODOTMETH || n.Op == OCALLPART {
217 init2(n.Type.Nname(), out)
221 func init2list(l Nodes, out *[]*Node) {
222 for _, n := range l.Slice() {
227 func initreorder(l []*Node, out *[]*Node) {
231 case ODCLFUNC, ODCLCONST, ODCLTYPE:
235 initreorder(n.Ninit.Slice(), out)
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 {
246 initplans = make(map[*Node]*InitPlan)
248 initreorder(l, &lout)
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 {
262 l := n.Name.Defn.Left
263 r := n.Name.Defn.Right
264 return staticassign(l, r, out)
267 // like staticassign but we are copying an already
268 // initialized value r.
269 func staticcopy(l *Node, r *Node, out *[]*Node) bool {
273 if r.Class == PFUNC {
274 gdata(l, r, Widthptr)
277 if r.Class != PEXTERN || r.Sym.Pkg != localpkg {
280 if r.Name.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
283 if r.Name.Defn.Op != OAS {
287 r = r.Name.Defn.Right
289 for r.Op == OCONVNOP && !eqtype(r.Type, l.Type) {
295 if staticcopy(l, r, out) {
298 // We may have skipped past one or more OCONVNOPs, so
299 // use conv to ensure r is assignable to l (#13263).
300 *out = append(*out, nod(OAS, l, conv(r, l.Type)))
307 gdata(l, r, int(l.Type.Width))
313 gdata(l, r, int(l.Type.Width))
319 case OARRAYLIT, OSLICELIT, OSTRUCTLIT, OMAPLIT:
321 gdata(l, nod(OADDR, inittemps[r], nil), int(l.Type.Width))
330 n.Xoffset = l.Xoffset + int64(array_array)
331 gdata(&n, nod(OADDR, a, nil), Widthptr)
332 n.Xoffset = l.Xoffset + int64(array_nel)
333 gdata(&n, r.Right, Widthint)
334 n.Xoffset = l.Xoffset + int64(array_cap)
335 gdata(&n, r.Right, Widthint)
338 case OARRAYLIT, OSTRUCTLIT:
344 n.Xoffset = l.Xoffset + e.Xoffset
346 if e.Expr.Op == OLITERAL {
347 gdata(&n, e.Expr, int(n.Type.Width))
349 ll := nod(OXXX, nil, nil)
351 ll.Orig = ll // completely separate copy
352 if !staticassign(ll, e.Expr, out) {
353 // Requires computation, but we're
354 // copying someone else's computation.
355 rr := nod(OXXX, nil, nil)
358 rr.Orig = rr // completely separate copy
360 rr.Xoffset += e.Xoffset
362 *out = append(*out, nod(OAS, ll, rr))
373 func staticassign(l *Node, r *Node, out *[]*Node) bool {
374 for r.Op == OCONVNOP {
380 return staticcopy(l, r, out)
386 gdata(l, r, int(l.Type.Width))
391 if stataddr(&nam, r.Left) {
394 gdata(l, &n, int(l.Type.Width))
401 case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT:
403 a := staticname(r.Left.Type)
406 gdata(l, nod(OADDR, a, nil), int(l.Type.Width))
408 // Init underlying literal.
409 if !staticassign(a, r.Left, out) {
410 *out = append(*out, nod(OAS, a, r.Left))
414 //dump("not static ptrlit", r);
417 if l.Class == PEXTERN && r.Left.Op == OLITERAL {
418 sval := r.Left.Val().U.(string)
419 slicebytes(l, sval, len(sval))
426 bound := r.Right.Int64()
427 ta := typArray(r.Type.Elem(), bound)
431 n.Xoffset = l.Xoffset + int64(array_array)
432 gdata(&n, nod(OADDR, a, nil), Widthptr)
433 n.Xoffset = l.Xoffset + int64(array_nel)
434 gdata(&n, r.Right, Widthint)
435 n.Xoffset = l.Xoffset + int64(array_cap)
436 gdata(&n, r.Right, Widthint)
438 // Fall through to init underlying array.
442 case OARRAYLIT, OSTRUCTLIT:
449 n.Xoffset = l.Xoffset + e.Xoffset
451 if e.Expr.Op == OLITERAL {
452 gdata(&n, e.Expr, int(n.Type.Width))
455 a := nod(OXXX, nil, nil)
457 a.Orig = a // completely separate copy
458 if !staticassign(a, e.Expr, out) {
459 *out = append(*out, nod(OAS, a, e.Expr))
470 if hasemptycvars(r) {
471 if Debug_closure > 0 {
472 Warnl(r.Pos, "closure converted to global")
474 // Closures with no captured variables are globals,
475 // so the assignment can be done at link time.
477 gdata(&n, r.Func.Closure.Func.Nname, Widthptr)
480 closuredebugruntimecheck(r)
484 // This logic is mirrored in isStaticCompositeLiteral.
485 // If you change something here, change it there, and vice versa.
487 // Determine the underlying concrete type and value we are converting from.
489 for val.Op == OCONVIFACE {
492 if val.Type.IsInterface() {
493 // val is an interface type.
494 // If val is nil, we can statically initialize l;
495 // both words are zero and so there no work to do, so report success.
496 // If val is non-nil, we have no concrete type to record,
497 // and we won't be able to statically initialize its value, so report failure.
498 return Isconst(val, CTNIL)
502 if l.Type.IsEmptyInterface() {
503 itab = typename(val.Type)
505 itab = itabname(val.Type, l.Type)
508 // Create a copy of l to modify while we emit data.
511 // Emit itab, advance offset.
512 gdata(&n, itab, Widthptr)
513 n.Xoffset += int64(Widthptr)
516 if isdirectiface(val.Type) {
517 if Isconst(val, CTNIL) {
518 // Nil is zero, nothing to do.
521 // Copy val directly into n.
524 a := nod(OXXX, nil, nil)
527 if !staticassign(a, val, out) {
528 *out = append(*out, nod(OAS, a, val))
531 // Construct temp to hold val, write pointer to temp into n.
532 a := staticname(val.Type)
534 if !staticassign(a, val, out) {
535 *out = append(*out, nod(OAS, a, val))
537 ptr := nod(OADDR, a, nil)
538 n.Type = ptrto(val.Type)
539 gdata(&n, ptr, Widthptr)
545 //dump("not static", r);
549 // initContext is the context in which static data is populated.
550 // It is either in an init function or in any other function.
551 // Static data populated in an init function will be written either
552 // zero times (as a readonly, static data symbol) or
553 // one time (during init function execution).
554 // Either way, there is no opportunity for races or further modification,
555 // so the data can be written to a (possibly readonly) data symbol.
556 // Static data populated in any other function needs to be local to
557 // that function to allow multiple instances of that function
558 // to execute concurrently without clobbering each others' data.
559 type initContext uint8
562 inInitFunction initContext = iota
566 // from here down is the walk analysis
567 // of composite literals.
568 // most of the work is to generate
569 // data statements for the constant
570 // part of the composite literal.
572 // staticname returns a name backed by a static data symbol.
573 // Callers should set n.Name.Readonly = true on the
574 // returned node for readonly nodes.
575 func staticname(t *Type) *Node {
576 n := newname(lookupN("statictmp_", statuniqgen))
578 addvar(n, t, PEXTERN)
582 func isliteral(n *Node) bool {
583 // Treat nils as zeros rather than literals.
584 return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
587 func (n *Node) isSimpleName() bool {
588 return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP
591 func litas(l *Node, r *Node, init *Nodes) {
593 a = typecheck(a, Etop)
594 a = walkexpr(a, init)
598 // initGenType is a bitmap indicating the types of generation that will occur for a static value.
599 type initGenType uint8
602 initDynamic initGenType = 1 << iota // contains some dynamic values, for which init code will be generated
603 initConst // contains some constant values, which may be written into data symbols
606 // getdyn calculates the initGenType for n.
607 // If top is false, getdyn is recursing.
608 func getdyn(n *Node, top bool) initGenType {
621 case OARRAYLIT, OSTRUCTLIT:
625 for _, n1 := range n.List.Slice() {
632 mode |= getdyn(n1, false)
633 if mode == initDynamic|initConst {
640 // isStaticCompositeLiteral reports whether n is a compile-time constant.
641 func isStaticCompositeLiteral(n *Node) bool {
646 for _, r := range n.List.Slice() {
650 if !isStaticCompositeLiteral(r) {
656 for _, r := range n.List.Slice() {
657 if r.Op != OSTRUCTKEY {
658 Fatalf("isStaticCompositeLiteral: rhs not OSTRUCTKEY: %v", r)
660 if !isStaticCompositeLiteral(r.Left) {
668 // See staticassign's OCONVIFACE case for comments.
670 for val.Op == OCONVIFACE {
673 if val.Type.IsInterface() {
674 return Isconst(val, CTNIL)
676 if isdirectiface(val.Type) && Isconst(val, CTNIL) {
679 return isStaticCompositeLiteral(val)
684 // initKind is a kind of static initialization: static, dynamic, or local.
685 // Static initialization represents literals and
686 // literal components of composite literals.
687 // Dynamic initialization represents non-literals and
688 // non-literal components of composite literals.
689 // LocalCode initializion represents initialization
690 // that occurs purely in generated code local to the function of use.
691 // Initialization code is sometimes generated in passes,
692 // first static then dynamic.
696 initKindStatic initKind = iota + 1
701 // fixedlit handles struct, array, and slice literals.
702 // TODO: expand documentation.
703 func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes) {
704 var splitnode func(*Node) (a *Node, value *Node)
706 case OARRAYLIT, OSLICELIT:
708 splitnode = func(r *Node) (*Node, *Node) {
710 k = nonnegintconst(r.Left)
713 a := nod(OINDEX, var_, nodintconst(k))
718 splitnode = func(r *Node) (*Node, *Node) {
719 if r.Op != OSTRUCTKEY {
720 Fatalf("fixedlit: rhs not OSTRUCTKEY: %v", r)
722 return nodSym(ODOT, var_, r.Sym), r.Left
725 Fatalf("fixedlit bad op: %v", n.Op)
728 for _, r := range n.List.Slice() {
729 a, value := splitnode(r)
733 if (kind == initKindStatic && ctxt == inNonInitFunction) || (kind == initKindDynamic && ctxt == inInitFunction) {
734 slicelit(ctxt, value, a, init)
738 case OARRAYLIT, OSTRUCTLIT:
739 fixedlit(ctxt, kind, value, a, init)
743 islit := isliteral(value)
744 if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
748 // build list of assignments: var[index] = expr
750 a = nod(OAS, a, value)
751 a = typecheck(a, Etop)
754 a = walkexpr(a, init) // add any assignments in r to top
756 // Static initialization never needs
761 Fatalf("fixedlit: not as, is %v", a)
764 case initKindDynamic, initKindLocalCode:
765 a = orderstmtinplace(a)
768 Fatalf("fixedlit: bad kind %d", kind)
775 func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
776 // make an array type corresponding the number of elements we have
777 t := typArray(n.Type.Elem(), n.Right.Int64())
780 if ctxt == inNonInitFunction {
781 // put everything into static array
782 vstat := staticname(t)
784 fixedlit(ctxt, initKindStatic, n, vstat, init)
785 fixedlit(ctxt, initKindDynamic, n, vstat, init)
787 // copy static to slice
788 a := nod(OSLICE, vstat, nil)
790 a = nod(OAS, var_, a)
791 a = typecheck(a, Etop)
797 // recipe for var = []t{...}
798 // 1. make a static array
800 // 2. assign (data statements) the constant part
801 // vstat = constpart{}
802 // 3. make an auto pointer to array and allocate heap to it
803 // var vauto *[...]t = new([...]t)
804 // 4. copy the static array to the auto array
806 // 5. for each dynamic part assign to the array
807 // vauto[i] = dynamic part
808 // 6. assign slice of allocated heap to var
811 // an optimization is done if there is no constant part
812 // 3. var vauto *[...]t = new([...]t)
813 // 5. vauto[i] = dynamic part
816 // if the literal contains constants,
817 // make static initialized array (1),(2)
820 mode := getdyn(n, true)
821 if mode&initConst != 0 {
822 vstat = staticname(t)
823 if ctxt == inInitFunction {
824 vstat.Name.Readonly = true
826 fixedlit(ctxt, initKindStatic, n, vstat, init)
829 // make new auto *array (3 declare)
830 vauto := temp(ptrto(t))
832 // set auto to point at new temp or heap (3 assign)
834 if x := prealloc[n]; x != nil {
835 // temp allocated during order.go for dddarg
840 a = typecheck(a, Etop)
841 init.Append(a) // zero new temp
844 a = nod(OADDR, x, nil)
845 } else if n.Esc == EscNone {
848 a = nod(OAS, temp(t), nil)
849 a = typecheck(a, Etop)
850 init.Append(a) // zero new temp
854 a = nod(OADDR, a, nil)
856 a = nod(ONEW, nil, nil)
857 a.List.Set1(typenod(t))
860 a = nod(OAS, vauto, a)
861 a = typecheck(a, Etop)
862 a = walkexpr(a, init)
866 // copy static to heap (4)
867 a = nod(OIND, vauto, nil)
869 a = nod(OAS, a, vstat)
870 a = typecheck(a, Etop)
871 a = walkexpr(a, init)
875 // put dynamics into array (5)
877 for _, r := range n.List.Slice() {
880 index = nonnegintconst(r.Left)
883 a := nod(OINDEX, vauto, nodintconst(index))
887 // TODO need to check bounds?
893 case OARRAYLIT, OSTRUCTLIT:
894 fixedlit(ctxt, initKindDynamic, value, a, init)
898 if isliteral(value) {
902 // build list of vauto[c] = expr
904 a = nod(OAS, a, value)
906 a = typecheck(a, Etop)
907 a = orderstmtinplace(a)
912 // make slice out of heap (6)
913 a = nod(OAS, var_, nod(OSLICE, vauto, nil))
915 a = typecheck(a, Etop)
916 a = orderstmtinplace(a)
921 func maplit(n *Node, m *Node, init *Nodes) {
925 a := nod(OMAKE, nil, nil)
926 a.List.Set2(typenod(n.Type), nodintconst(int64(len(n.List.Slice()))))
929 // count the initializers
931 for _, r := range n.List.Slice() {
933 Fatalf("maplit: rhs not OKEY: %v", r)
938 if isliteral(index) && isliteral(value) {
944 // build types [count]Tindex and [count]Tvalue
945 tk := typArray(n.Type.Key(), int64(b))
946 tv := typArray(n.Type.Val(), int64(b))
948 // TODO(josharian): suppress alg generation for these types?
952 // make and initialize static arrays
953 vstatk := staticname(tk)
954 vstatk.Name.Readonly = true
955 vstatv := staticname(tv)
956 vstatv.Name.Readonly = true
959 for _, r := range n.List.Slice() {
961 Fatalf("maplit: rhs not OKEY: %v", r)
966 if isliteral(index) && isliteral(value) {
967 // build vstatk[b] = index
969 lhs := nod(OINDEX, vstatk, nodintconst(b))
970 as := nod(OAS, lhs, index)
971 as = typecheck(as, Etop)
972 as = walkexpr(as, init)
976 // build vstatv[b] = value
978 lhs = nod(OINDEX, vstatv, nodintconst(b))
979 as = nod(OAS, lhs, value)
980 as = typecheck(as, Etop)
981 as = walkexpr(as, init)
989 // loop adding structure elements to map
990 // for i = 0; i < len(vstatk); i++ {
991 // map[vstatk[i]] = vstatv[i]
993 i := temp(Types[TINT])
994 rhs := nod(OINDEX, vstatv, i)
997 kidx := nod(OINDEX, vstatk, i)
999 lhs := nod(OINDEX, m, kidx)
1001 zero := nod(OAS, i, nodintconst(0))
1002 cond := nod(OLT, i, nodintconst(tk.NumElem()))
1003 incr := nod(OAS, i, nod(OADD, i, nodintconst(1)))
1004 body := nod(OAS, lhs, rhs)
1006 loop := nod(OFOR, cond, incr)
1007 loop.Nbody.Set1(body)
1008 loop.Ninit.Set1(zero)
1010 loop = typecheck(loop, Etop)
1011 loop = walkstmt(loop)
1015 // put in dynamic entries one-at-a-time
1017 for _, r := range n.List.Slice() {
1019 Fatalf("maplit: rhs not OKEY: %v", r)
1024 if isliteral(index) && isliteral(value) {
1028 // build list of var[c] = expr.
1029 // use temporary so that mapassign1 can have addressable key, val.
1031 key = temp(m.Type.Key())
1032 val = temp(m.Type.Val())
1036 a = nod(OAS, key, index)
1037 a = typecheck(a, Etop)
1042 a = nod(OAS, val, value)
1043 a = typecheck(a, Etop)
1048 a = nod(OAS, nod(OINDEX, m, key), val)
1049 a = typecheck(a, Etop)
1053 if nerr != nerrors {
1059 a = nod(OVARKILL, key, nil)
1060 a = typecheck(a, Etop)
1062 a = nod(OVARKILL, val, nil)
1063 a = typecheck(a, Etop)
1068 func anylit(n *Node, var_ *Node, init *Nodes) {
1072 Fatalf("anylit: not lit, op=%v node=%v", n.Op, n)
1076 Fatalf("anylit: not ptr")
1081 // n.Right is stack temporary used as backing store.
1082 init.Append(nod(OAS, n.Right, nil)) // zero backing store, just in case (#18410)
1083 r = nod(OADDR, n.Right, nil)
1084 r = typecheck(r, Erv)
1086 r = nod(ONEW, nil, nil)
1092 r = walkexpr(r, init)
1093 a := nod(OAS, var_, r)
1095 a = typecheck(a, Etop)
1098 var_ = nod(OIND, var_, nil)
1099 var_ = typecheck(var_, Erv|Easgn)
1100 anylit(n.Left, var_, init)
1102 case OSTRUCTLIT, OARRAYLIT:
1103 if !t.IsStruct() && !t.IsArray() {
1104 Fatalf("anylit: not struct/array")
1107 if var_.isSimpleName() && n.List.Len() > 4 {
1108 // lay out static data
1109 vstat := staticname(t)
1110 vstat.Name.Readonly = true
1112 ctxt := inInitFunction
1113 if n.Op == OARRAYLIT {
1114 ctxt = inNonInitFunction
1116 fixedlit(ctxt, initKindStatic, n, vstat, init)
1118 // copy static to var
1119 a := nod(OAS, var_, vstat)
1121 a = typecheck(a, Etop)
1122 a = walkexpr(a, init)
1125 // add expressions to automatic
1126 fixedlit(inInitFunction, initKindDynamic, n, var_, init)
1130 var components int64
1131 if n.Op == OARRAYLIT {
1132 components = t.NumElem()
1134 components = int64(t.NumFields())
1136 // initialization of an array or struct with unspecified components (missing fields or arrays)
1137 if var_.isSimpleName() || int64(n.List.Len()) < components {
1138 a := nod(OAS, var_, nil)
1139 a = typecheck(a, Etop)
1140 a = walkexpr(a, init)
1144 fixedlit(inInitFunction, initKindLocalCode, n, var_, init)
1147 slicelit(inInitFunction, n, var_, init)
1151 Fatalf("anylit: not map")
1153 maplit(n, var_, init)
1157 func oaslit(n *Node, init *Nodes) bool {
1158 if n.Left == nil || n.Right == nil {
1159 // not a special composite literal assignment
1162 if n.Left.Type == nil || n.Right.Type == nil {
1163 // not a special composite literal assignment
1166 if !n.Left.isSimpleName() {
1167 // not a special composite literal assignment
1170 if !eqtype(n.Left.Type, n.Right.Type) {
1171 // not a special composite literal assignment
1177 // not a special composite literal assignment
1180 case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
1181 if vmatch1(n.Left, n.Right) {
1182 // not a special composite literal assignment
1185 anylit(n.Right, n.Left, init)
1193 func getlit(lit *Node) int {
1194 if smallintconst(lit) {
1195 return int(lit.Int64())
1200 // stataddr sets nam to the static address of n and reports whether it succeeded.
1201 func stataddr(nam *Node, n *Node) bool {
1212 if !stataddr(nam, n.Left) {
1215 nam.Xoffset += n.Xoffset
1220 if n.Left.Type.IsSlice() {
1223 if !stataddr(nam, n.Left) {
1226 l := getlit(n.Right)
1231 // Check for overflow.
1232 if n.Type.Width != 0 && Thearch.MAXWIDTH/n.Type.Width <= int64(l) {
1235 nam.Xoffset += int64(l) * n.Type.Width
1243 func initplan(n *Node) {
1244 if initplans[n] != nil {
1253 case OARRAYLIT, OSLICELIT:
1255 for _, a := range n.List.Slice() {
1257 k = nonnegintconst(a.Left)
1260 addvalue(p, k*n.Type.Elem().Width, a)
1265 for _, a := range n.List.Slice() {
1266 if a.Op != OSTRUCTKEY {
1267 Fatalf("initplan fixedlit")
1269 addvalue(p, a.Xoffset, a.Left)
1273 for _, a := range n.List.Slice() {
1275 Fatalf("initplan maplit")
1277 addvalue(p, -1, a.Right)
1282 func addvalue(p *InitPlan, xoffset int64, n *Node) {
1283 // special case: zero can be dropped entirely
1288 // special case: inline struct and array (not slice) literals
1292 for _, qe := range q.E {
1293 // qe is a copy; we are not modifying entries in q.E
1294 qe.Xoffset += xoffset
1295 p.E = append(p.E, qe)
1301 p.E = append(p.E, InitEntry{Xoffset: xoffset, Expr: n})
1304 func iszero(n *Node) bool {
1307 switch u := n.Val().U.(type) {
1309 Dump("unexpected literal", n)
1318 return u.CmpInt64(0) == 0
1320 return u.CmpFloat64(0) == 0
1322 return u.Real.CmpFloat64(0) == 0 && u.Imag.CmpFloat64(0) == 0
1326 for _, n1 := range n.List.Slice() {
1337 for _, n1 := range n.List.Slice() {
1338 if !iszero(n1.Left) {
1348 func isvaluelit(n *Node) bool {
1349 return n.Op == OARRAYLIT || n.Op == OSTRUCTLIT
1352 // gen_as_init attempts to emit static data for n and reports whether it succeeded.
1353 // If reportOnly is true, it does not emit static data and does not modify the AST.
1354 func gen_as_init(n *Node, reportOnly bool) bool {
1355 success := genAsInitNoCheck(n, reportOnly)
1356 if !success && n.IsStatic {
1357 Dump("\ngen_as_init", n)
1358 Fatalf("gen_as_init couldn't generate static data")
1363 func genAsInitNoCheck(n *Node, reportOnly bool) bool {
1372 return stataddr(&nam, nl) && nam.Class == PEXTERN
1375 if nr.Type == nil || !eqtype(nl.Type, nr.Type) {
1380 if !stataddr(&nam, nl) || nam.Class != PEXTERN {
1390 if nr == nil || nr.Op != OSLICEARR {
1396 low, high, _ := nr.SliceBounds()
1397 if low != nil || high != nil {
1401 if nr == nil || nr.Op != OADDR {
1406 if nr == nil || nr.Op != ONAME {
1410 // nr is the array being converted to a slice
1411 if nr.Type == nil || !nr.Type.IsArray() {
1416 nam.Xoffset += int64(array_array)
1417 gdata(&nam, ptr, Widthptr)
1419 nam.Xoffset += int64(array_nel) - int64(array_array)
1421 Nodconst(&nod1, Types[TINT], nr.Type.NumElem())
1422 gdata(&nam, &nod1, Widthint)
1424 nam.Xoffset += int64(array_cap) - int64(array_nel)
1425 gdata(&nam, &nod1, Widthint)
1432 gdata(&nam, nr, int(nr.Type.Width))