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