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