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