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