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