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