github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/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  		// TODO: Table-driven map insert.
   477  		break
   478  
   479  	case OCLOSURE:
   480  		if hasemptycvars(r) {
   481  			if Debug_closure > 0 {
   482  				Warnl(r.Lineno, "closure converted to global")
   483  			}
   484  			// Closures with no captured variables are globals,
   485  			// so the assignment can be done at link time.
   486  			n := *l
   487  			gdata(&n, r.Func.Closure.Func.Nname, Widthptr)
   488  			return true
   489  		} else {
   490  			closuredebugruntimecheck(r)
   491  		}
   492  	}
   493  
   494  	//dump("not static", r);
   495  	return false
   496  }
   497  
   498  // from here down is the walk analysis
   499  // of composite literals.
   500  // most of the work is to generate
   501  // data statements for the constant
   502  // part of the composite literal.
   503  func staticname(t *Type, ctxt int) *Node {
   504  	n := newname(LookupN("statictmp_", statuniqgen))
   505  	statuniqgen++
   506  	if ctxt == 0 {
   507  		n.Name.Readonly = true
   508  	}
   509  	addvar(n, t, PEXTERN)
   510  	return n
   511  }
   512  
   513  func isliteral(n *Node) bool {
   514  	// Treat nils as zeros rather than literals.
   515  	return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
   516  }
   517  
   518  func (n *Node) isSimpleName() bool {
   519  	return n.Op == ONAME && n.Addable && n.Class != PAUTOHEAP
   520  }
   521  
   522  func litas(l *Node, r *Node, init *Nodes) {
   523  	a := Nod(OAS, l, r)
   524  	a = typecheck(a, Etop)
   525  	a = walkexpr(a, init)
   526  	init.Append(a)
   527  }
   528  
   529  // initGenType is a bitmap indicating the types of generation that will occur for a static value.
   530  type initGenType uint8
   531  
   532  const (
   533  	initDynamic initGenType = 1 << iota // contains some dynamic values, for which init code will be generated
   534  	initConst                           // contains some constant values, which may be written into data symbols
   535  )
   536  
   537  func getdyn(n *Node, top int) initGenType {
   538  	switch n.Op {
   539  	default:
   540  		if isliteral(n) {
   541  			return initConst
   542  		}
   543  		return initDynamic
   544  
   545  	case OARRAYLIT:
   546  		if top == 0 && n.Type.IsSlice() {
   547  			return initDynamic
   548  		}
   549  
   550  	case OSTRUCTLIT:
   551  	}
   552  
   553  	var mode initGenType
   554  	for _, n1 := range n.List.Slice() {
   555  		value := n1.Right
   556  		mode |= getdyn(value, 0)
   557  		if mode == initDynamic|initConst {
   558  			break
   559  		}
   560  	}
   561  	return mode
   562  }
   563  
   564  // isStaticCompositeLiteral reports whether n is a compile-time constant.
   565  func isStaticCompositeLiteral(n *Node) bool {
   566  	switch n.Op {
   567  	case OARRAYLIT:
   568  		if n.Type.IsSlice() {
   569  			return false
   570  		}
   571  	case OSTRUCTLIT:
   572  	case OLITERAL:
   573  		return true
   574  	default:
   575  		return false
   576  	}
   577  	for _, r := range n.List.Slice() {
   578  		if r.Op != OKEY {
   579  			Fatalf("isStaticCompositeLiteral: rhs not OKEY: %v", r)
   580  		}
   581  		index := r.Left
   582  		if n.Op == OARRAYLIT && index.Op != OLITERAL {
   583  			return false
   584  		}
   585  		value := r.Right
   586  		if !isStaticCompositeLiteral(value) {
   587  			return false
   588  		}
   589  	}
   590  	return true
   591  }
   592  
   593  func structlit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
   594  	for _, r := range n.List.Slice() {
   595  		if r.Op != OKEY {
   596  			Fatalf("structlit: rhs not OKEY: %v", r)
   597  		}
   598  		index := r.Left
   599  		value := r.Right
   600  
   601  		switch value.Op {
   602  		case OARRAYLIT:
   603  			if value.Type.IsSlice() {
   604  				if pass == 1 && ctxt != 0 {
   605  					a := NodSym(ODOT, var_, index.Sym)
   606  					slicelit(ctxt, value, a, init)
   607  				} else if pass == 2 && ctxt == 0 {
   608  					a := NodSym(ODOT, var_, index.Sym)
   609  					slicelit(ctxt, value, a, init)
   610  				} else if pass == 3 {
   611  					break
   612  				}
   613  				continue
   614  			}
   615  
   616  			a := NodSym(ODOT, var_, index.Sym)
   617  			arraylit(ctxt, pass, value, a, init)
   618  			continue
   619  
   620  		case OSTRUCTLIT:
   621  			a := NodSym(ODOT, var_, index.Sym)
   622  			structlit(ctxt, pass, value, a, init)
   623  			continue
   624  		}
   625  
   626  		if isliteral(value) {
   627  			if pass == 2 {
   628  				continue
   629  			}
   630  		} else if pass == 1 {
   631  			continue
   632  		}
   633  
   634  		// build list of var.field = expr
   635  		setlineno(value)
   636  		a := NodSym(ODOT, var_, index.Sym)
   637  
   638  		a = Nod(OAS, a, value)
   639  		a = typecheck(a, Etop)
   640  		if pass == 1 {
   641  			a = walkexpr(a, init) // add any assignments in r to top
   642  			if a.Op != OAS {
   643  				Fatalf("structlit: not as")
   644  			}
   645  			a.Dodata = 2
   646  		} else {
   647  			a = orderstmtinplace(a)
   648  			a = walkstmt(a)
   649  		}
   650  
   651  		init.Append(a)
   652  	}
   653  }
   654  
   655  func arraylit(ctxt int, pass int, n *Node, var_ *Node, init *Nodes) {
   656  	for _, r := range n.List.Slice() {
   657  		if r.Op != OKEY {
   658  			Fatalf("arraylit: rhs not OKEY: %v", r)
   659  		}
   660  		index := r.Left
   661  		value := r.Right
   662  
   663  		switch value.Op {
   664  		case OARRAYLIT:
   665  			if value.Type.IsSlice() {
   666  				if pass == 1 && ctxt != 0 {
   667  					a := Nod(OINDEX, var_, index)
   668  					slicelit(ctxt, value, a, init)
   669  				} else if pass == 2 && ctxt == 0 {
   670  					a := Nod(OINDEX, var_, index)
   671  					slicelit(ctxt, value, a, init)
   672  				} else if pass == 3 {
   673  					break
   674  				}
   675  				continue
   676  			}
   677  
   678  			a := Nod(OINDEX, var_, index)
   679  			arraylit(ctxt, pass, value, a, init)
   680  			continue
   681  
   682  		case OSTRUCTLIT:
   683  			a := Nod(OINDEX, var_, index)
   684  			structlit(ctxt, pass, value, a, init)
   685  			continue
   686  		}
   687  
   688  		if isliteral(index) && isliteral(value) {
   689  			if pass == 2 {
   690  				continue
   691  			}
   692  		} else if pass == 1 {
   693  			continue
   694  		}
   695  
   696  		// build list of var[index] = value
   697  		setlineno(value)
   698  		a := Nod(OINDEX, var_, index)
   699  
   700  		a = Nod(OAS, a, value)
   701  		a = typecheck(a, Etop)
   702  		if pass == 1 {
   703  			a = walkexpr(a, init)
   704  			if a.Op != OAS {
   705  				Fatalf("arraylit: not as")
   706  			}
   707  			a.Dodata = 2
   708  		} else {
   709  			a = orderstmtinplace(a)
   710  			a = walkstmt(a)
   711  		}
   712  
   713  		init.Append(a)
   714  	}
   715  }
   716  
   717  func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
   718  	// make an array type corresponding the number of elements we have
   719  	t := typArray(n.Type.Elem(), n.Right.Int64())
   720  	dowidth(t)
   721  
   722  	if ctxt != 0 {
   723  		// put everything into static array
   724  		vstat := staticname(t, ctxt)
   725  
   726  		arraylit(ctxt, 1, n, vstat, init)
   727  		arraylit(ctxt, 2, n, vstat, init)
   728  
   729  		// copy static to slice
   730  		a := Nod(OSLICE, vstat, nil)
   731  
   732  		a = Nod(OAS, var_, a)
   733  		a = typecheck(a, Etop)
   734  		a.Dodata = 2
   735  		init.Append(a)
   736  		return
   737  	}
   738  
   739  	// recipe for var = []t{...}
   740  	// 1. make a static array
   741  	//	var vstat [...]t
   742  	// 2. assign (data statements) the constant part
   743  	//	vstat = constpart{}
   744  	// 3. make an auto pointer to array and allocate heap to it
   745  	//	var vauto *[...]t = new([...]t)
   746  	// 4. copy the static array to the auto array
   747  	//	*vauto = vstat
   748  	// 5. for each dynamic part assign to the array
   749  	//	vauto[i] = dynamic part
   750  	// 6. assign slice of allocated heap to var
   751  	//	var = vauto[:]
   752  	//
   753  	// an optimization is done if there is no constant part
   754  	//	3. var vauto *[...]t = new([...]t)
   755  	//	5. vauto[i] = dynamic part
   756  	//	6. var = vauto[:]
   757  
   758  	// if the literal contains constants,
   759  	// make static initialized array (1),(2)
   760  	var vstat *Node
   761  
   762  	mode := getdyn(n, 1)
   763  	if mode&initConst != 0 {
   764  		vstat = staticname(t, ctxt)
   765  		arraylit(ctxt, 1, n, vstat, init)
   766  	}
   767  
   768  	// make new auto *array (3 declare)
   769  	vauto := temp(Ptrto(t))
   770  
   771  	// set auto to point at new temp or heap (3 assign)
   772  	var a *Node
   773  	if x := prealloc[n]; x != nil {
   774  		// temp allocated during order.go for dddarg
   775  		x.Type = t
   776  
   777  		if vstat == nil {
   778  			a = Nod(OAS, x, nil)
   779  			a = typecheck(a, Etop)
   780  			init.Append(a) // zero new temp
   781  		}
   782  
   783  		a = Nod(OADDR, x, nil)
   784  	} else if n.Esc == EscNone {
   785  		a = temp(t)
   786  		if vstat == nil {
   787  			a = Nod(OAS, temp(t), nil)
   788  			a = typecheck(a, Etop)
   789  			init.Append(a) // zero new temp
   790  			a = a.Left
   791  		}
   792  
   793  		a = Nod(OADDR, a, nil)
   794  	} else {
   795  		a = Nod(ONEW, nil, nil)
   796  		a.List.Set1(typenod(t))
   797  	}
   798  
   799  	a = Nod(OAS, vauto, a)
   800  	a = typecheck(a, Etop)
   801  	a = walkexpr(a, init)
   802  	init.Append(a)
   803  
   804  	if vstat != nil {
   805  		// copy static to heap (4)
   806  		a = Nod(OIND, vauto, nil)
   807  
   808  		a = Nod(OAS, a, vstat)
   809  		a = typecheck(a, Etop)
   810  		a = walkexpr(a, init)
   811  		init.Append(a)
   812  	}
   813  
   814  	// put dynamics into array (5)
   815  	for _, r := range n.List.Slice() {
   816  		if r.Op != OKEY {
   817  			Fatalf("slicelit: rhs not OKEY: %v", r)
   818  		}
   819  		index := r.Left
   820  		value := r.Right
   821  		a := Nod(OINDEX, vauto, index)
   822  		a.Bounded = true
   823  
   824  		// TODO need to check bounds?
   825  
   826  		switch value.Op {
   827  		case OARRAYLIT:
   828  			if value.Type.IsSlice() {
   829  				break
   830  			}
   831  			arraylit(ctxt, 2, value, a, init)
   832  			continue
   833  
   834  		case OSTRUCTLIT:
   835  			structlit(ctxt, 2, value, a, init)
   836  			continue
   837  		}
   838  
   839  		if isliteral(index) && isliteral(value) {
   840  			continue
   841  		}
   842  
   843  		// build list of vauto[c] = expr
   844  		setlineno(value)
   845  		a = Nod(OAS, a, value)
   846  
   847  		a = typecheck(a, Etop)
   848  		a = orderstmtinplace(a)
   849  		a = walkstmt(a)
   850  		init.Append(a)
   851  	}
   852  
   853  	// make slice out of heap (6)
   854  	a = Nod(OAS, var_, Nod(OSLICE, vauto, nil))
   855  
   856  	a = typecheck(a, Etop)
   857  	a = orderstmtinplace(a)
   858  	a = walkstmt(a)
   859  	init.Append(a)
   860  }
   861  
   862  func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) {
   863  	ctxt = 0
   864  
   865  	// make the map var
   866  	nerr := nerrors
   867  
   868  	a := Nod(OMAKE, nil, nil)
   869  	a.List.Set1(typenod(n.Type))
   870  	litas(var_, a, init)
   871  
   872  	// count the initializers
   873  	b := 0
   874  	for _, r := range n.List.Slice() {
   875  		if r.Op != OKEY {
   876  			Fatalf("maplit: rhs not OKEY: %v", r)
   877  		}
   878  		index := r.Left
   879  		value := r.Right
   880  
   881  		if isliteral(index) && isliteral(value) {
   882  			b++
   883  		}
   884  	}
   885  
   886  	if b != 0 {
   887  		// build type [count]struct { a Tindex, b Tvalue }
   888  		t := n.Type
   889  		tk := t.Key()
   890  		tv := t.Val()
   891  
   892  		syma := Lookup("a")
   893  		symb := Lookup("b")
   894  
   895  		var fields [2]*Field
   896  		fields[0] = newField()
   897  		fields[0].Type = tk
   898  		fields[0].Sym = syma
   899  		fields[1] = newField()
   900  		fields[1].Type = tv
   901  		fields[1].Sym = symb
   902  
   903  		tstruct := typ(TSTRUCT)
   904  		tstruct.SetFields(fields[:])
   905  
   906  		tarr := typArray(tstruct, int64(b))
   907  
   908  		// TODO(josharian): suppress alg generation for these types?
   909  		dowidth(tarr)
   910  
   911  		// make and initialize static array
   912  		vstat := staticname(tarr, ctxt)
   913  
   914  		b := int64(0)
   915  		for _, r := range n.List.Slice() {
   916  			if r.Op != OKEY {
   917  				Fatalf("maplit: rhs not OKEY: %v", r)
   918  			}
   919  			index := r.Left
   920  			value := r.Right
   921  
   922  			if isliteral(index) && isliteral(value) {
   923  				// build vstat[b].a = key;
   924  				setlineno(index)
   925  				a = Nodintconst(b)
   926  
   927  				a = Nod(OINDEX, vstat, a)
   928  				a = NodSym(ODOT, a, syma)
   929  				a = Nod(OAS, a, index)
   930  				a = typecheck(a, Etop)
   931  				a = walkexpr(a, init)
   932  				a.Dodata = 2
   933  				init.Append(a)
   934  
   935  				// build vstat[b].b = value;
   936  				setlineno(value)
   937  				a = Nodintconst(b)
   938  
   939  				a = Nod(OINDEX, vstat, a)
   940  				a = NodSym(ODOT, a, symb)
   941  				a = Nod(OAS, a, value)
   942  				a = typecheck(a, Etop)
   943  				a = walkexpr(a, init)
   944  				a.Dodata = 2
   945  				init.Append(a)
   946  
   947  				b++
   948  			}
   949  		}
   950  
   951  		// loop adding structure elements to map
   952  		// for i = 0; i < len(vstat); i++ {
   953  		//	map[vstat[i].a] = vstat[i].b
   954  		// }
   955  		index := temp(Types[TINT])
   956  
   957  		a = Nod(OINDEX, vstat, index)
   958  		a.Bounded = true
   959  		a = NodSym(ODOT, a, symb)
   960  
   961  		r := Nod(OINDEX, vstat, index)
   962  		r.Bounded = true
   963  		r = NodSym(ODOT, r, syma)
   964  		r = Nod(OINDEX, var_, r)
   965  
   966  		r = Nod(OAS, r, a)
   967  
   968  		a = Nod(OFOR, nil, nil)
   969  		a.Nbody.Set1(r)
   970  
   971  		a.Ninit.Set1(Nod(OAS, index, Nodintconst(0)))
   972  		a.Left = Nod(OLT, index, Nodintconst(tarr.NumElem()))
   973  		a.Right = Nod(OAS, index, Nod(OADD, index, Nodintconst(1)))
   974  
   975  		a = typecheck(a, Etop)
   976  		a = walkstmt(a)
   977  		init.Append(a)
   978  	}
   979  
   980  	// put in dynamic entries one-at-a-time
   981  	var key, val *Node
   982  	for _, r := range n.List.Slice() {
   983  		if r.Op != OKEY {
   984  			Fatalf("maplit: rhs not OKEY: %v", r)
   985  		}
   986  		index := r.Left
   987  		value := r.Right
   988  
   989  		if isliteral(index) && isliteral(value) {
   990  			continue
   991  		}
   992  
   993  		// build list of var[c] = expr.
   994  		// use temporary so that mapassign1 can have addressable key, val.
   995  		if key == nil {
   996  			key = temp(var_.Type.Key())
   997  			val = temp(var_.Type.Val())
   998  		}
   999  
  1000  		setlineno(r.Left)
  1001  		a = Nod(OAS, key, r.Left)
  1002  		a = typecheck(a, Etop)
  1003  		a = walkstmt(a)
  1004  		init.Append(a)
  1005  		setlineno(r.Right)
  1006  		a = Nod(OAS, val, r.Right)
  1007  		a = typecheck(a, Etop)
  1008  		a = walkstmt(a)
  1009  		init.Append(a)
  1010  
  1011  		setlineno(val)
  1012  		a = Nod(OAS, Nod(OINDEX, var_, key), val)
  1013  		a = typecheck(a, Etop)
  1014  		a = walkstmt(a)
  1015  		init.Append(a)
  1016  
  1017  		if nerr != nerrors {
  1018  			break
  1019  		}
  1020  	}
  1021  
  1022  	if key != nil {
  1023  		a = Nod(OVARKILL, key, nil)
  1024  		a = typecheck(a, Etop)
  1025  		init.Append(a)
  1026  		a = Nod(OVARKILL, val, nil)
  1027  		a = typecheck(a, Etop)
  1028  		init.Append(a)
  1029  	}
  1030  }
  1031  
  1032  func anylit(ctxt int, n *Node, var_ *Node, init *Nodes) {
  1033  	t := n.Type
  1034  	switch n.Op {
  1035  	default:
  1036  		Fatalf("anylit: not lit, op=%v node=%v", n.Op, n)
  1037  
  1038  	case OPTRLIT:
  1039  		if !t.IsPtr() {
  1040  			Fatalf("anylit: not ptr")
  1041  		}
  1042  
  1043  		var r *Node
  1044  		if n.Right != nil {
  1045  			r = Nod(OADDR, n.Right, nil)
  1046  			r = typecheck(r, Erv)
  1047  		} else {
  1048  			r = Nod(ONEW, nil, nil)
  1049  			r.Typecheck = 1
  1050  			r.Type = t
  1051  			r.Esc = n.Esc
  1052  		}
  1053  
  1054  		r = walkexpr(r, init)
  1055  		a := Nod(OAS, var_, r)
  1056  
  1057  		a = typecheck(a, Etop)
  1058  		init.Append(a)
  1059  
  1060  		var_ = Nod(OIND, var_, nil)
  1061  		var_ = typecheck(var_, Erv|Easgn)
  1062  		anylit(ctxt, n.Left, var_, init)
  1063  
  1064  	case OSTRUCTLIT:
  1065  		if !t.IsStruct() {
  1066  			Fatalf("anylit: not struct")
  1067  		}
  1068  
  1069  		if var_.isSimpleName() && n.List.Len() > 4 {
  1070  			if ctxt == 0 {
  1071  				// lay out static data
  1072  				vstat := staticname(t, ctxt)
  1073  
  1074  				structlit(ctxt, 1, n, vstat, init)
  1075  
  1076  				// copy static to var
  1077  				a := Nod(OAS, var_, vstat)
  1078  
  1079  				a = typecheck(a, Etop)
  1080  				a = walkexpr(a, init)
  1081  				init.Append(a)
  1082  
  1083  				// add expressions to automatic
  1084  				structlit(ctxt, 2, n, var_, init)
  1085  
  1086  				break
  1087  			}
  1088  
  1089  			structlit(ctxt, 1, n, var_, init)
  1090  			structlit(ctxt, 2, n, var_, init)
  1091  			break
  1092  		}
  1093  
  1094  		// initialize of not completely specified
  1095  		if var_.isSimpleName() || n.List.Len() < t.NumFields() {
  1096  			a := Nod(OAS, var_, nil)
  1097  			a = typecheck(a, Etop)
  1098  			a = walkexpr(a, init)
  1099  			init.Append(a)
  1100  		}
  1101  
  1102  		structlit(ctxt, 3, n, var_, init)
  1103  
  1104  	case OARRAYLIT:
  1105  		if t.IsSlice() {
  1106  			slicelit(ctxt, n, var_, init)
  1107  			break
  1108  		}
  1109  		if !t.IsArray() {
  1110  			Fatalf("anylit: not array")
  1111  		}
  1112  
  1113  		if var_.isSimpleName() && n.List.Len() > 4 {
  1114  			if ctxt == 0 {
  1115  				// lay out static data
  1116  				vstat := staticname(t, ctxt)
  1117  
  1118  				arraylit(1, 1, n, vstat, init)
  1119  
  1120  				// copy static to automatic
  1121  				a := Nod(OAS, var_, vstat)
  1122  
  1123  				a = typecheck(a, Etop)
  1124  				a = walkexpr(a, init)
  1125  				init.Append(a)
  1126  
  1127  				// add expressions to automatic
  1128  				arraylit(ctxt, 2, n, var_, init)
  1129  
  1130  				break
  1131  			}
  1132  
  1133  			arraylit(ctxt, 1, n, var_, init)
  1134  			arraylit(ctxt, 2, n, var_, init)
  1135  			break
  1136  		}
  1137  
  1138  		// initialize of not completely specified
  1139  		if var_.isSimpleName() || int64(n.List.Len()) < t.NumElem() {
  1140  			a := Nod(OAS, var_, nil)
  1141  			a = typecheck(a, Etop)
  1142  			a = walkexpr(a, init)
  1143  			init.Append(a)
  1144  		}
  1145  
  1146  		arraylit(ctxt, 3, n, var_, init)
  1147  
  1148  	case OMAPLIT:
  1149  		if !t.IsMap() {
  1150  			Fatalf("anylit: not map")
  1151  		}
  1152  		maplit(ctxt, 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 composit literal assignment
  1159  		return false
  1160  	}
  1161  	if n.Left.Type == nil || n.Right.Type == nil {
  1162  		// not a special composit literal assignment
  1163  		return false
  1164  	}
  1165  	if !n.Left.isSimpleName() {
  1166  		// not a special composit literal assignment
  1167  		return false
  1168  	}
  1169  	if !Eqtype(n.Left.Type, n.Right.Type) {
  1170  		// not a special composit literal assignment
  1171  		return false
  1172  	}
  1173  
  1174  	// context is init() function.
  1175  	// implies generated data executed
  1176  	// exactly once and not subject to races.
  1177  	ctxt := 0
  1178  
  1179  	//	if(n->dodata == 1)
  1180  	//		ctxt = 1;
  1181  
  1182  	switch n.Right.Op {
  1183  	default:
  1184  		// not a special composit literal assignment
  1185  		return false
  1186  
  1187  	case OSTRUCTLIT, OARRAYLIT, OMAPLIT:
  1188  		if vmatch1(n.Left, n.Right) {
  1189  			// not a special composit literal assignment
  1190  			return false
  1191  		}
  1192  		anylit(ctxt, n.Right, n.Left, init)
  1193  	}
  1194  
  1195  	n.Op = OEMPTY
  1196  	n.Right = nil
  1197  	return true
  1198  }
  1199  
  1200  func getlit(lit *Node) int {
  1201  	if Smallintconst(lit) {
  1202  		return int(lit.Int64())
  1203  	}
  1204  	return -1
  1205  }
  1206  
  1207  // stataddr sets nam to the static address of n and reports whether it succeeeded.
  1208  func stataddr(nam *Node, n *Node) bool {
  1209  	if n == nil {
  1210  		return false
  1211  	}
  1212  
  1213  	switch n.Op {
  1214  	case ONAME:
  1215  		*nam = *n
  1216  		return n.Addable
  1217  
  1218  	case ODOT:
  1219  		if !stataddr(nam, n.Left) {
  1220  			break
  1221  		}
  1222  		nam.Xoffset += n.Xoffset
  1223  		nam.Type = n.Type
  1224  		return true
  1225  
  1226  	case OINDEX:
  1227  		if n.Left.Type.IsSlice() {
  1228  			break
  1229  		}
  1230  		if !stataddr(nam, n.Left) {
  1231  			break
  1232  		}
  1233  		l := getlit(n.Right)
  1234  		if l < 0 {
  1235  			break
  1236  		}
  1237  
  1238  		// Check for overflow.
  1239  		if n.Type.Width != 0 && Thearch.MAXWIDTH/n.Type.Width <= int64(l) {
  1240  			break
  1241  		}
  1242  		nam.Xoffset += int64(l) * n.Type.Width
  1243  		nam.Type = n.Type
  1244  		return true
  1245  	}
  1246  
  1247  	return false
  1248  }
  1249  
  1250  func initplan(n *Node) {
  1251  	if initplans[n] != nil {
  1252  		return
  1253  	}
  1254  	p := new(InitPlan)
  1255  	initplans[n] = p
  1256  	switch n.Op {
  1257  	default:
  1258  		Fatalf("initplan")
  1259  
  1260  	case OARRAYLIT:
  1261  		for _, a := range n.List.Slice() {
  1262  			if a.Op != OKEY || !Smallintconst(a.Left) {
  1263  				Fatalf("initplan arraylit")
  1264  			}
  1265  			addvalue(p, n.Type.Elem().Width*a.Left.Int64(), a.Right)
  1266  		}
  1267  
  1268  	case OSTRUCTLIT:
  1269  		for _, a := range n.List.Slice() {
  1270  			if a.Op != OKEY || a.Left.Type != structkey {
  1271  				Fatalf("initplan structlit")
  1272  			}
  1273  			addvalue(p, a.Left.Xoffset, a.Right)
  1274  		}
  1275  
  1276  	case OMAPLIT:
  1277  		for _, a := range n.List.Slice() {
  1278  			if a.Op != OKEY {
  1279  				Fatalf("initplan maplit")
  1280  			}
  1281  			addvalue(p, -1, a.Right)
  1282  		}
  1283  	}
  1284  }
  1285  
  1286  func addvalue(p *InitPlan, xoffset int64, n *Node) {
  1287  	// special case: zero can be dropped entirely
  1288  	if iszero(n) {
  1289  		return
  1290  	}
  1291  
  1292  	// special case: inline struct and array (not slice) literals
  1293  	if isvaluelit(n) {
  1294  		initplan(n)
  1295  		q := initplans[n]
  1296  		for _, qe := range q.E {
  1297  			// qe is a copy; we are not modifying entries in q.E
  1298  			qe.Xoffset += xoffset
  1299  			p.E = append(p.E, qe)
  1300  		}
  1301  		return
  1302  	}
  1303  
  1304  	// add to plan
  1305  	p.E = append(p.E, InitEntry{Xoffset: xoffset, Expr: n})
  1306  }
  1307  
  1308  func iszero(n *Node) bool {
  1309  	switch n.Op {
  1310  	case OLITERAL:
  1311  		switch u := n.Val().U.(type) {
  1312  		default:
  1313  			Dump("unexpected literal", n)
  1314  			Fatalf("iszero")
  1315  		case *NilVal:
  1316  			return true
  1317  		case string:
  1318  			return u == ""
  1319  		case bool:
  1320  			return !u
  1321  		case *Mpint:
  1322  			return u.CmpInt64(0) == 0
  1323  		case *Mpflt:
  1324  			return u.CmpFloat64(0) == 0
  1325  		case *Mpcplx:
  1326  			return u.Real.CmpFloat64(0) == 0 && u.Imag.CmpFloat64(0) == 0
  1327  		}
  1328  
  1329  	case OARRAYLIT:
  1330  		if n.Type.IsSlice() {
  1331  			break
  1332  		}
  1333  		fallthrough
  1334  	case OSTRUCTLIT:
  1335  		for _, n1 := range n.List.Slice() {
  1336  			if !iszero(n1.Right) {
  1337  				return false
  1338  			}
  1339  		}
  1340  		return true
  1341  	}
  1342  
  1343  	return false
  1344  }
  1345  
  1346  func isvaluelit(n *Node) bool {
  1347  	return (n.Op == OARRAYLIT && n.Type.IsArray()) || n.Op == OSTRUCTLIT
  1348  }
  1349  
  1350  // gen_as_init attempts to emit static data for n and reports whether it succeeded.
  1351  // If reportOnly is true, it does not emit static data and does not modify the AST.
  1352  func gen_as_init(n *Node, reportOnly bool) bool {
  1353  	success := genAsInitNoCheck(n, reportOnly)
  1354  	if !success && n.Dodata == 2 {
  1355  		Dump("\ngen_as_init", n)
  1356  		Fatalf("gen_as_init couldn't make data statement")
  1357  	}
  1358  	return success
  1359  }
  1360  
  1361  func genAsInitNoCheck(n *Node, reportOnly bool) bool {
  1362  	if n.Dodata == 0 {
  1363  		return false
  1364  	}
  1365  
  1366  	nr := n.Right
  1367  	nl := n.Left
  1368  	if nr == nil {
  1369  		var nam Node
  1370  		return stataddr(&nam, nl) && nam.Class == PEXTERN
  1371  	}
  1372  
  1373  	if nr.Type == nil || !Eqtype(nl.Type, nr.Type) {
  1374  		return false
  1375  	}
  1376  
  1377  	var nam Node
  1378  	if !stataddr(&nam, nl) || nam.Class != PEXTERN {
  1379  		return false
  1380  	}
  1381  
  1382  	switch nr.Op {
  1383  	default:
  1384  		return false
  1385  
  1386  	case OCONVNOP:
  1387  		nr = nr.Left
  1388  		if nr == nil || nr.Op != OSLICEARR {
  1389  			return false
  1390  		}
  1391  		fallthrough
  1392  
  1393  	case OSLICEARR:
  1394  		low, high, _ := nr.SliceBounds()
  1395  		if low != nil || high != nil {
  1396  			return false
  1397  		}
  1398  		nr = nr.Left
  1399  		if nr == nil || nr.Op != OADDR {
  1400  			return false
  1401  		}
  1402  		ptr := nr
  1403  		nr = nr.Left
  1404  		if nr == nil || nr.Op != ONAME {
  1405  			return false
  1406  		}
  1407  
  1408  		// nr is the array being converted to a slice
  1409  		if nr.Type == nil || !nr.Type.IsArray() {
  1410  			return false
  1411  		}
  1412  
  1413  		if !reportOnly {
  1414  			nam.Xoffset += int64(Array_array)
  1415  			gdata(&nam, ptr, Widthptr)
  1416  
  1417  			nam.Xoffset += int64(Array_nel) - int64(Array_array)
  1418  			var nod1 Node
  1419  			Nodconst(&nod1, Types[TINT], nr.Type.NumElem())
  1420  			gdata(&nam, &nod1, Widthint)
  1421  
  1422  			nam.Xoffset += int64(Array_cap) - int64(Array_nel)
  1423  			gdata(&nam, &nod1, Widthint)
  1424  		}
  1425  
  1426  		return true
  1427  
  1428  	case OLITERAL:
  1429  		break
  1430  	}
  1431  
  1432  	switch nr.Type.Etype {
  1433  	default:
  1434  		return false
  1435  
  1436  	case TBOOL, TINT8, TUINT8, TINT16, TUINT16,
  1437  		TINT32, TUINT32, TINT64, TUINT64,
  1438  		TINT, TUINT, TUINTPTR,
  1439  		TPTR32, TPTR64,
  1440  		TFLOAT32, TFLOAT64:
  1441  		if !reportOnly {
  1442  			gdata(&nam, nr, int(nr.Type.Width))
  1443  		}
  1444  
  1445  	case TCOMPLEX64, TCOMPLEX128:
  1446  		if !reportOnly {
  1447  			gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
  1448  		}
  1449  
  1450  	case TSTRING:
  1451  		if !reportOnly {
  1452  			gdatastring(&nam, nr.Val().U.(string))
  1453  		}
  1454  	}
  1455  
  1456  	return true
  1457  }