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