github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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  	"github.com/gagliardetto/golang-go/cmd/compile/internal/types"
     9  	"fmt"
    10  )
    11  
    12  type InitEntry struct {
    13  	Xoffset int64 // struct, array only
    14  	Expr    *Node // bytes of run-time computed expressions
    15  }
    16  
    17  type InitPlan struct {
    18  	E []InitEntry
    19  }
    20  
    21  // An InitSchedule is used to decompose assignment statements into
    22  // static and dynamic initialization parts. Static initializations are
    23  // handled by populating variables' linker symbol data, while dynamic
    24  // initializations are accumulated to be executed in order.
    25  type InitSchedule struct {
    26  	// out is the ordered list of dynamic initialization
    27  	// statements.
    28  	out []*Node
    29  
    30  	initplans map[*Node]*InitPlan
    31  	inittemps map[*Node]*Node
    32  }
    33  
    34  func (s *InitSchedule) append(n *Node) {
    35  	s.out = append(s.out, n)
    36  }
    37  
    38  // staticInit adds an initialization statement n to the schedule.
    39  func (s *InitSchedule) staticInit(n *Node) {
    40  	if !s.tryStaticInit(n) {
    41  		if Debug['%'] != 0 {
    42  			Dump("nonstatic", n)
    43  		}
    44  		s.append(n)
    45  	}
    46  }
    47  
    48  // tryStaticInit attempts to statically execute an initialization
    49  // statement and reports whether it succeeded.
    50  func (s *InitSchedule) tryStaticInit(n *Node) bool {
    51  	// Only worry about simple "l = r" assignments. Multiple
    52  	// variable/expression OAS2 assignments have already been
    53  	// replaced by multiple simple OAS assignments, and the other
    54  	// OAS2* assignments mostly necessitate dynamic execution
    55  	// anyway.
    56  	if n.Op != OAS {
    57  		return false
    58  	}
    59  	if n.Left.isBlank() && candiscard(n.Right) {
    60  		return true
    61  	}
    62  	lno := setlineno(n)
    63  	defer func() { lineno = lno }()
    64  	return s.staticassign(n.Left, n.Right)
    65  }
    66  
    67  // like staticassign but we are copying an already
    68  // initialized value r.
    69  func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
    70  	if r.Op != ONAME {
    71  		return false
    72  	}
    73  	if r.Class() == PFUNC {
    74  		gdata(l, r, Widthptr)
    75  		return true
    76  	}
    77  	if r.Class() != PEXTERN || r.Sym.Pkg != localpkg {
    78  		return false
    79  	}
    80  	if r.Name.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
    81  		return false
    82  	}
    83  	if r.Name.Defn.Op != OAS {
    84  		return false
    85  	}
    86  	if r.Type.IsString() { // perhaps overwritten by cmd/link -X (#34675)
    87  		return false
    88  	}
    89  	orig := r
    90  	r = r.Name.Defn.Right
    91  
    92  	for r.Op == OCONVNOP && !types.Identical(r.Type, l.Type) {
    93  		r = r.Left
    94  	}
    95  
    96  	switch r.Op {
    97  	case ONAME:
    98  		if s.staticcopy(l, r) {
    99  			return true
   100  		}
   101  		// We may have skipped past one or more OCONVNOPs, so
   102  		// use conv to ensure r is assignable to l (#13263).
   103  		s.append(nod(OAS, l, conv(r, l.Type)))
   104  		return true
   105  
   106  	case OLITERAL:
   107  		if isZero(r) {
   108  			return true
   109  		}
   110  		gdata(l, r, int(l.Type.Width))
   111  		return true
   112  
   113  	case OADDR:
   114  		switch r.Left.Op {
   115  		case ONAME:
   116  			gdata(l, r, int(l.Type.Width))
   117  			return true
   118  		}
   119  
   120  	case OPTRLIT:
   121  		switch r.Left.Op {
   122  		case OARRAYLIT, OSLICELIT, OSTRUCTLIT, OMAPLIT:
   123  			// copy pointer
   124  			gdata(l, nod(OADDR, s.inittemps[r], nil), int(l.Type.Width))
   125  			return true
   126  		}
   127  
   128  	case OSLICELIT:
   129  		// copy slice
   130  		a := s.inittemps[r]
   131  
   132  		n := l.copy()
   133  		n.Xoffset = l.Xoffset + int64(slice_array)
   134  		gdata(n, nod(OADDR, a, nil), Widthptr)
   135  		n.Xoffset = l.Xoffset + int64(slice_nel)
   136  		gdata(n, r.Right, Widthptr)
   137  		n.Xoffset = l.Xoffset + int64(slice_cap)
   138  		gdata(n, r.Right, Widthptr)
   139  		return true
   140  
   141  	case OARRAYLIT, OSTRUCTLIT:
   142  		p := s.initplans[r]
   143  
   144  		n := l.copy()
   145  		for i := range p.E {
   146  			e := &p.E[i]
   147  			n.Xoffset = l.Xoffset + e.Xoffset
   148  			n.Type = e.Expr.Type
   149  			if e.Expr.Op == OLITERAL {
   150  				gdata(n, e.Expr, int(n.Type.Width))
   151  				continue
   152  			}
   153  			ll := n.sepcopy()
   154  			if s.staticcopy(ll, e.Expr) {
   155  				continue
   156  			}
   157  			// Requires computation, but we're
   158  			// copying someone else's computation.
   159  			rr := orig.sepcopy()
   160  			rr.Type = ll.Type
   161  			rr.Xoffset += e.Xoffset
   162  			setlineno(rr)
   163  			s.append(nod(OAS, ll, rr))
   164  		}
   165  
   166  		return true
   167  	}
   168  
   169  	return false
   170  }
   171  
   172  func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
   173  	for r.Op == OCONVNOP {
   174  		r = r.Left
   175  	}
   176  
   177  	switch r.Op {
   178  	case ONAME:
   179  		return s.staticcopy(l, r)
   180  
   181  	case OLITERAL:
   182  		if isZero(r) {
   183  			return true
   184  		}
   185  		gdata(l, r, int(l.Type.Width))
   186  		return true
   187  
   188  	case OADDR:
   189  		var nam Node
   190  		if stataddr(&nam, r.Left) {
   191  			n := *r
   192  			n.Left = &nam
   193  			gdata(l, &n, int(l.Type.Width))
   194  			return true
   195  		}
   196  		fallthrough
   197  
   198  	case OPTRLIT:
   199  		switch r.Left.Op {
   200  		case OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT:
   201  			// Init pointer.
   202  			a := staticname(r.Left.Type)
   203  
   204  			s.inittemps[r] = a
   205  			gdata(l, nod(OADDR, a, nil), int(l.Type.Width))
   206  
   207  			// Init underlying literal.
   208  			if !s.staticassign(a, r.Left) {
   209  				s.append(nod(OAS, a, r.Left))
   210  			}
   211  			return true
   212  		}
   213  		//dump("not static ptrlit", r);
   214  
   215  	case OSTR2BYTES:
   216  		if l.Class() == PEXTERN && r.Left.Op == OLITERAL {
   217  			sval := strlit(r.Left)
   218  			slicebytes(l, sval, len(sval))
   219  			return true
   220  		}
   221  
   222  	case OSLICELIT:
   223  		s.initplan(r)
   224  		// Init slice.
   225  		bound := r.Right.Int64()
   226  		ta := types.NewArray(r.Type.Elem(), bound)
   227  		a := staticname(ta)
   228  		s.inittemps[r] = a
   229  		n := l.copy()
   230  		n.Xoffset = l.Xoffset + int64(slice_array)
   231  		gdata(n, nod(OADDR, a, nil), Widthptr)
   232  		n.Xoffset = l.Xoffset + int64(slice_nel)
   233  		gdata(n, r.Right, Widthptr)
   234  		n.Xoffset = l.Xoffset + int64(slice_cap)
   235  		gdata(n, r.Right, Widthptr)
   236  
   237  		// Fall through to init underlying array.
   238  		l = a
   239  		fallthrough
   240  
   241  	case OARRAYLIT, OSTRUCTLIT:
   242  		s.initplan(r)
   243  
   244  		p := s.initplans[r]
   245  		n := l.copy()
   246  		for i := range p.E {
   247  			e := &p.E[i]
   248  			n.Xoffset = l.Xoffset + e.Xoffset
   249  			n.Type = e.Expr.Type
   250  			if e.Expr.Op == OLITERAL {
   251  				gdata(n, e.Expr, int(n.Type.Width))
   252  				continue
   253  			}
   254  			setlineno(e.Expr)
   255  			a := n.sepcopy()
   256  			if !s.staticassign(a, e.Expr) {
   257  				s.append(nod(OAS, a, e.Expr))
   258  			}
   259  		}
   260  
   261  		return true
   262  
   263  	case OMAPLIT:
   264  		break
   265  
   266  	case OCLOSURE:
   267  		if hasemptycvars(r) {
   268  			if Debug_closure > 0 {
   269  				Warnl(r.Pos, "closure converted to global")
   270  			}
   271  			// Closures with no captured variables are globals,
   272  			// so the assignment can be done at link time.
   273  			gdata(l, r.Func.Closure.Func.Nname, Widthptr)
   274  			return true
   275  		}
   276  		closuredebugruntimecheck(r)
   277  
   278  	case OCONVIFACE:
   279  		// This logic is mirrored in isStaticCompositeLiteral.
   280  		// If you change something here, change it there, and vice versa.
   281  
   282  		// Determine the underlying concrete type and value we are converting from.
   283  		val := r
   284  		for val.Op == OCONVIFACE {
   285  			val = val.Left
   286  		}
   287  		if val.Type.IsInterface() {
   288  			// val is an interface type.
   289  			// If val is nil, we can statically initialize l;
   290  			// both words are zero and so there no work to do, so report success.
   291  			// If val is non-nil, we have no concrete type to record,
   292  			// and we won't be able to statically initialize its value, so report failure.
   293  			return Isconst(val, CTNIL)
   294  		}
   295  
   296  		var itab *Node
   297  		if l.Type.IsEmptyInterface() {
   298  			itab = typename(val.Type)
   299  		} else {
   300  			itab = itabname(val.Type, l.Type)
   301  		}
   302  
   303  		// Create a copy of l to modify while we emit data.
   304  		n := l.copy()
   305  
   306  		// Emit itab, advance offset.
   307  		gdata(n, itab, Widthptr)
   308  		n.Xoffset += int64(Widthptr)
   309  
   310  		// Emit data.
   311  		if isdirectiface(val.Type) {
   312  			if Isconst(val, CTNIL) {
   313  				// Nil is zero, nothing to do.
   314  				return true
   315  			}
   316  			// Copy val directly into n.
   317  			n.Type = val.Type
   318  			setlineno(val)
   319  			a := n.sepcopy()
   320  			if !s.staticassign(a, val) {
   321  				s.append(nod(OAS, a, val))
   322  			}
   323  		} else {
   324  			// Construct temp to hold val, write pointer to temp into n.
   325  			a := staticname(val.Type)
   326  			s.inittemps[val] = a
   327  			if !s.staticassign(a, val) {
   328  				s.append(nod(OAS, a, val))
   329  			}
   330  			ptr := nod(OADDR, a, nil)
   331  			n.Type = types.NewPtr(val.Type)
   332  			gdata(n, ptr, Widthptr)
   333  		}
   334  
   335  		return true
   336  	}
   337  
   338  	//dump("not static", r);
   339  	return false
   340  }
   341  
   342  // initContext is the context in which static data is populated.
   343  // It is either in an init function or in any other function.
   344  // Static data populated in an init function will be written either
   345  // zero times (as a readonly, static data symbol) or
   346  // one time (during init function execution).
   347  // Either way, there is no opportunity for races or further modification,
   348  // so the data can be written to a (possibly readonly) data symbol.
   349  // Static data populated in any other function needs to be local to
   350  // that function to allow multiple instances of that function
   351  // to execute concurrently without clobbering each others' data.
   352  type initContext uint8
   353  
   354  const (
   355  	inInitFunction initContext = iota
   356  	inNonInitFunction
   357  )
   358  
   359  func (c initContext) String() string {
   360  	if c == inInitFunction {
   361  		return "inInitFunction"
   362  	}
   363  	return "inNonInitFunction"
   364  }
   365  
   366  // from here down is the walk analysis
   367  // of composite literals.
   368  // most of the work is to generate
   369  // data statements for the constant
   370  // part of the composite literal.
   371  
   372  var statuniqgen int // name generator for static temps
   373  
   374  // staticname returns a name backed by a static data symbol.
   375  // Callers should call n.Name.SetReadonly(true) on the
   376  // returned node for readonly nodes.
   377  func staticname(t *types.Type) *Node {
   378  	// Don't use lookupN; it interns the resulting string, but these are all unique.
   379  	n := newname(lookup(fmt.Sprintf(".stmp_%d", statuniqgen)))
   380  	statuniqgen++
   381  	addvar(n, t, PEXTERN)
   382  	return n
   383  }
   384  
   385  func isLiteral(n *Node) bool {
   386  	// Treat nils as zeros rather than literals.
   387  	return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
   388  }
   389  
   390  func (n *Node) isSimpleName() bool {
   391  	return n.Op == ONAME && n.Class() != PAUTOHEAP && n.Class() != PEXTERN
   392  }
   393  
   394  func litas(l *Node, r *Node, init *Nodes) {
   395  	a := nod(OAS, l, r)
   396  	a = typecheck(a, ctxStmt)
   397  	a = walkexpr(a, init)
   398  	init.Append(a)
   399  }
   400  
   401  // initGenType is a bitmap indicating the types of generation that will occur for a static value.
   402  type initGenType uint8
   403  
   404  const (
   405  	initDynamic initGenType = 1 << iota // contains some dynamic values, for which init code will be generated
   406  	initConst                           // contains some constant values, which may be written into data symbols
   407  )
   408  
   409  // getdyn calculates the initGenType for n.
   410  // If top is false, getdyn is recursing.
   411  func getdyn(n *Node, top bool) initGenType {
   412  	switch n.Op {
   413  	default:
   414  		if isLiteral(n) {
   415  			return initConst
   416  		}
   417  		return initDynamic
   418  
   419  	case OSLICELIT:
   420  		if !top {
   421  			return initDynamic
   422  		}
   423  		if n.Right.Int64()/4 > int64(n.List.Len()) {
   424  			// <25% of entries have explicit values.
   425  			// Very rough estimation, it takes 4 bytes of instructions
   426  			// to initialize 1 byte of result. So don't use a static
   427  			// initializer if the dynamic initialization code would be
   428  			// smaller than the static value.
   429  			// See issue 23780.
   430  			return initDynamic
   431  		}
   432  
   433  	case OARRAYLIT, OSTRUCTLIT:
   434  	}
   435  
   436  	var mode initGenType
   437  	for _, n1 := range n.List.Slice() {
   438  		switch n1.Op {
   439  		case OKEY:
   440  			n1 = n1.Right
   441  		case OSTRUCTKEY:
   442  			n1 = n1.Left
   443  		}
   444  		mode |= getdyn(n1, false)
   445  		if mode == initDynamic|initConst {
   446  			break
   447  		}
   448  	}
   449  	return mode
   450  }
   451  
   452  // isStaticCompositeLiteral reports whether n is a compile-time constant.
   453  func isStaticCompositeLiteral(n *Node) bool {
   454  	switch n.Op {
   455  	case OSLICELIT:
   456  		return false
   457  	case OARRAYLIT:
   458  		for _, r := range n.List.Slice() {
   459  			if r.Op == OKEY {
   460  				r = r.Right
   461  			}
   462  			if !isStaticCompositeLiteral(r) {
   463  				return false
   464  			}
   465  		}
   466  		return true
   467  	case OSTRUCTLIT:
   468  		for _, r := range n.List.Slice() {
   469  			if r.Op != OSTRUCTKEY {
   470  				Fatalf("isStaticCompositeLiteral: rhs not OSTRUCTKEY: %v", r)
   471  			}
   472  			if !isStaticCompositeLiteral(r.Left) {
   473  				return false
   474  			}
   475  		}
   476  		return true
   477  	case OLITERAL:
   478  		return true
   479  	case OCONVIFACE:
   480  		// See staticassign's OCONVIFACE case for comments.
   481  		val := n
   482  		for val.Op == OCONVIFACE {
   483  			val = val.Left
   484  		}
   485  		if val.Type.IsInterface() {
   486  			return Isconst(val, CTNIL)
   487  		}
   488  		if isdirectiface(val.Type) && Isconst(val, CTNIL) {
   489  			return true
   490  		}
   491  		return isStaticCompositeLiteral(val)
   492  	}
   493  	return false
   494  }
   495  
   496  // initKind is a kind of static initialization: static, dynamic, or local.
   497  // Static initialization represents literals and
   498  // literal components of composite literals.
   499  // Dynamic initialization represents non-literals and
   500  // non-literal components of composite literals.
   501  // LocalCode initialization represents initialization
   502  // that occurs purely in generated code local to the function of use.
   503  // Initialization code is sometimes generated in passes,
   504  // first static then dynamic.
   505  type initKind uint8
   506  
   507  const (
   508  	initKindStatic initKind = iota + 1
   509  	initKindDynamic
   510  	initKindLocalCode
   511  )
   512  
   513  // fixedlit handles struct, array, and slice literals.
   514  // TODO: expand documentation.
   515  func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes) {
   516  	var splitnode func(*Node) (a *Node, value *Node)
   517  	switch n.Op {
   518  	case OARRAYLIT, OSLICELIT:
   519  		var k int64
   520  		splitnode = func(r *Node) (*Node, *Node) {
   521  			if r.Op == OKEY {
   522  				k = indexconst(r.Left)
   523  				if k < 0 {
   524  					Fatalf("fixedlit: invalid index %v", r.Left)
   525  				}
   526  				r = r.Right
   527  			}
   528  			a := nod(OINDEX, var_, nodintconst(k))
   529  			k++
   530  			return a, r
   531  		}
   532  	case OSTRUCTLIT:
   533  		splitnode = func(r *Node) (*Node, *Node) {
   534  			if r.Op != OSTRUCTKEY {
   535  				Fatalf("fixedlit: rhs not OSTRUCTKEY: %v", r)
   536  			}
   537  			if r.Sym.IsBlank() {
   538  				return nblank, r.Left
   539  			}
   540  			setlineno(r)
   541  			return nodSym(ODOT, var_, r.Sym), r.Left
   542  		}
   543  	default:
   544  		Fatalf("fixedlit bad op: %v", n.Op)
   545  	}
   546  
   547  	for _, r := range n.List.Slice() {
   548  		a, value := splitnode(r)
   549  
   550  		switch value.Op {
   551  		case OSLICELIT:
   552  			if (kind == initKindStatic && ctxt == inNonInitFunction) || (kind == initKindDynamic && ctxt == inInitFunction) {
   553  				slicelit(ctxt, value, a, init)
   554  				continue
   555  			}
   556  
   557  		case OARRAYLIT, OSTRUCTLIT:
   558  			fixedlit(ctxt, kind, value, a, init)
   559  			continue
   560  		}
   561  
   562  		islit := isLiteral(value)
   563  		if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
   564  			continue
   565  		}
   566  
   567  		// build list of assignments: var[index] = expr
   568  		setlineno(a)
   569  		a = nod(OAS, a, value)
   570  		a = typecheck(a, ctxStmt)
   571  		switch kind {
   572  		case initKindStatic:
   573  			genAsStatic(a)
   574  		case initKindDynamic, initKindLocalCode:
   575  			a = orderStmtInPlace(a, map[string][]*Node{})
   576  			a = walkstmt(a)
   577  			init.Append(a)
   578  		default:
   579  			Fatalf("fixedlit: bad kind %d", kind)
   580  		}
   581  
   582  	}
   583  }
   584  
   585  func isSmallSliceLit(n *Node) bool {
   586  	if n.Op != OSLICELIT {
   587  		return false
   588  	}
   589  
   590  	r := n.Right
   591  
   592  	return smallintconst(r) && (n.Type.Elem().Width == 0 || r.Int64() <= smallArrayBytes/n.Type.Elem().Width)
   593  }
   594  
   595  func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
   596  	// make an array type corresponding the number of elements we have
   597  	t := types.NewArray(n.Type.Elem(), n.Right.Int64())
   598  	dowidth(t)
   599  
   600  	if ctxt == inNonInitFunction {
   601  		// put everything into static array
   602  		vstat := staticname(t)
   603  
   604  		fixedlit(ctxt, initKindStatic, n, vstat, init)
   605  		fixedlit(ctxt, initKindDynamic, n, vstat, init)
   606  
   607  		// copy static to slice
   608  		var_ = typecheck(var_, ctxExpr|ctxAssign)
   609  		var nam Node
   610  		if !stataddr(&nam, var_) || nam.Class() != PEXTERN {
   611  			Fatalf("slicelit: %v", var_)
   612  		}
   613  
   614  		var v Node
   615  		v.Type = types.Types[TINT]
   616  		setintconst(&v, t.NumElem())
   617  
   618  		nam.Xoffset += int64(slice_array)
   619  		gdata(&nam, nod(OADDR, vstat, nil), Widthptr)
   620  		nam.Xoffset += int64(slice_nel) - int64(slice_array)
   621  		gdata(&nam, &v, Widthptr)
   622  		nam.Xoffset += int64(slice_cap) - int64(slice_nel)
   623  		gdata(&nam, &v, Widthptr)
   624  
   625  		return
   626  	}
   627  
   628  	// recipe for var = []t{...}
   629  	// 1. make a static array
   630  	//	var vstat [...]t
   631  	// 2. assign (data statements) the constant part
   632  	//	vstat = constpart{}
   633  	// 3. make an auto pointer to array and allocate heap to it
   634  	//	var vauto *[...]t = new([...]t)
   635  	// 4. copy the static array to the auto array
   636  	//	*vauto = vstat
   637  	// 5. for each dynamic part assign to the array
   638  	//	vauto[i] = dynamic part
   639  	// 6. assign slice of allocated heap to var
   640  	//	var = vauto[:]
   641  	//
   642  	// an optimization is done if there is no constant part
   643  	//	3. var vauto *[...]t = new([...]t)
   644  	//	5. vauto[i] = dynamic part
   645  	//	6. var = vauto[:]
   646  
   647  	// if the literal contains constants,
   648  	// make static initialized array (1),(2)
   649  	var vstat *Node
   650  
   651  	mode := getdyn(n, true)
   652  	if mode&initConst != 0 && !isSmallSliceLit(n) {
   653  		vstat = staticname(t)
   654  		if ctxt == inInitFunction {
   655  			vstat.Name.SetReadonly(true)
   656  		}
   657  		fixedlit(ctxt, initKindStatic, n, vstat, init)
   658  	}
   659  
   660  	// make new auto *array (3 declare)
   661  	vauto := temp(types.NewPtr(t))
   662  
   663  	// set auto to point at new temp or heap (3 assign)
   664  	var a *Node
   665  	if x := prealloc[n]; x != nil {
   666  		// temp allocated during order.go for dddarg
   667  		if !types.Identical(t, x.Type) {
   668  			panic("dotdotdot base type does not match order's assigned type")
   669  		}
   670  
   671  		if vstat == nil {
   672  			a = nod(OAS, x, nil)
   673  			a = typecheck(a, ctxStmt)
   674  			init.Append(a) // zero new temp
   675  		} else {
   676  			// Declare that we're about to initialize all of x.
   677  			// (Which happens at the *vauto = vstat below.)
   678  			init.Append(nod(OVARDEF, x, nil))
   679  		}
   680  
   681  		a = nod(OADDR, x, nil)
   682  	} else if n.Esc == EscNone {
   683  		a = temp(t)
   684  		if vstat == nil {
   685  			a = nod(OAS, temp(t), nil)
   686  			a = typecheck(a, ctxStmt)
   687  			init.Append(a) // zero new temp
   688  			a = a.Left
   689  		} else {
   690  			init.Append(nod(OVARDEF, a, nil))
   691  		}
   692  
   693  		a = nod(OADDR, a, nil)
   694  	} else {
   695  		a = nod(ONEW, nil, nil)
   696  		a.List.Set1(typenod(t))
   697  	}
   698  
   699  	a = nod(OAS, vauto, a)
   700  	a = typecheck(a, ctxStmt)
   701  	a = walkexpr(a, init)
   702  	init.Append(a)
   703  
   704  	if vstat != nil {
   705  		// copy static to heap (4)
   706  		a = nod(ODEREF, vauto, nil)
   707  
   708  		a = nod(OAS, a, vstat)
   709  		a = typecheck(a, ctxStmt)
   710  		a = walkexpr(a, init)
   711  		init.Append(a)
   712  	}
   713  
   714  	// put dynamics into array (5)
   715  	var index int64
   716  	for _, value := range n.List.Slice() {
   717  		if value.Op == OKEY {
   718  			index = indexconst(value.Left)
   719  			if index < 0 {
   720  				Fatalf("slicelit: invalid index %v", value.Left)
   721  			}
   722  			value = value.Right
   723  		}
   724  		a := nod(OINDEX, vauto, nodintconst(index))
   725  		a.SetBounded(true)
   726  		index++
   727  
   728  		// TODO need to check bounds?
   729  
   730  		switch value.Op {
   731  		case OSLICELIT:
   732  			break
   733  
   734  		case OARRAYLIT, OSTRUCTLIT:
   735  			k := initKindDynamic
   736  			if vstat == nil {
   737  				// Generate both static and dynamic initializations.
   738  				// See issue #31987.
   739  				k = initKindLocalCode
   740  			}
   741  			fixedlit(ctxt, k, value, a, init)
   742  			continue
   743  		}
   744  
   745  		if vstat != nil && isLiteral(value) { // already set by copy from static value
   746  			continue
   747  		}
   748  
   749  		// build list of vauto[c] = expr
   750  		setlineno(value)
   751  		a = nod(OAS, a, value)
   752  
   753  		a = typecheck(a, ctxStmt)
   754  		a = orderStmtInPlace(a, map[string][]*Node{})
   755  		a = walkstmt(a)
   756  		init.Append(a)
   757  	}
   758  
   759  	// make slice out of heap (6)
   760  	a = nod(OAS, var_, nod(OSLICE, vauto, nil))
   761  
   762  	a = typecheck(a, ctxStmt)
   763  	a = orderStmtInPlace(a, map[string][]*Node{})
   764  	a = walkstmt(a)
   765  	init.Append(a)
   766  }
   767  
   768  func maplit(n *Node, m *Node, init *Nodes) {
   769  	// make the map var
   770  	a := nod(OMAKE, nil, nil)
   771  	a.Esc = n.Esc
   772  	a.List.Set2(typenod(n.Type), nodintconst(int64(n.List.Len())))
   773  	litas(m, a, init)
   774  
   775  	entries := n.List.Slice()
   776  
   777  	// The order pass already removed any dynamic (runtime-computed) entries.
   778  	// All remaining entries are static. Double-check that.
   779  	for _, r := range entries {
   780  		if !isStaticCompositeLiteral(r.Left) || !isStaticCompositeLiteral(r.Right) {
   781  			Fatalf("maplit: entry is not a literal: %v", r)
   782  		}
   783  	}
   784  
   785  	if len(entries) > 25 {
   786  		// For a large number of entries, put them in an array and loop.
   787  
   788  		// build types [count]Tindex and [count]Tvalue
   789  		tk := types.NewArray(n.Type.Key(), int64(len(entries)))
   790  		te := types.NewArray(n.Type.Elem(), int64(len(entries)))
   791  
   792  		// TODO(josharian): suppress alg generation for these types?
   793  		dowidth(tk)
   794  		dowidth(te)
   795  
   796  		// make and initialize static arrays
   797  		vstatk := staticname(tk)
   798  		vstatk.Name.SetReadonly(true)
   799  		vstate := staticname(te)
   800  		vstate.Name.SetReadonly(true)
   801  
   802  		datak := nod(OARRAYLIT, nil, nil)
   803  		datae := nod(OARRAYLIT, nil, nil)
   804  		for _, r := range entries {
   805  			datak.List.Append(r.Left)
   806  			datae.List.Append(r.Right)
   807  		}
   808  		fixedlit(inInitFunction, initKindStatic, datak, vstatk, init)
   809  		fixedlit(inInitFunction, initKindStatic, datae, vstate, init)
   810  
   811  		// loop adding structure elements to map
   812  		// for i = 0; i < len(vstatk); i++ {
   813  		//	map[vstatk[i]] = vstate[i]
   814  		// }
   815  		i := temp(types.Types[TINT])
   816  		rhs := nod(OINDEX, vstate, i)
   817  		rhs.SetBounded(true)
   818  
   819  		kidx := nod(OINDEX, vstatk, i)
   820  		kidx.SetBounded(true)
   821  		lhs := nod(OINDEX, m, kidx)
   822  
   823  		zero := nod(OAS, i, nodintconst(0))
   824  		cond := nod(OLT, i, nodintconst(tk.NumElem()))
   825  		incr := nod(OAS, i, nod(OADD, i, nodintconst(1)))
   826  		body := nod(OAS, lhs, rhs)
   827  
   828  		loop := nod(OFOR, cond, incr)
   829  		loop.Nbody.Set1(body)
   830  		loop.Ninit.Set1(zero)
   831  
   832  		loop = typecheck(loop, ctxStmt)
   833  		loop = walkstmt(loop)
   834  		init.Append(loop)
   835  		return
   836  	}
   837  	// For a small number of entries, just add them directly.
   838  
   839  	// Build list of var[c] = expr.
   840  	// Use temporaries so that mapassign1 can have addressable key, elem.
   841  	// TODO(josharian): avoid map key temporaries for mapfast_* assignments with literal keys.
   842  	tmpkey := temp(m.Type.Key())
   843  	tmpelem := temp(m.Type.Elem())
   844  
   845  	for _, r := range entries {
   846  		index, elem := r.Left, r.Right
   847  
   848  		setlineno(index)
   849  		a := nod(OAS, tmpkey, index)
   850  		a = typecheck(a, ctxStmt)
   851  		a = walkstmt(a)
   852  		init.Append(a)
   853  
   854  		setlineno(elem)
   855  		a = nod(OAS, tmpelem, elem)
   856  		a = typecheck(a, ctxStmt)
   857  		a = walkstmt(a)
   858  		init.Append(a)
   859  
   860  		setlineno(tmpelem)
   861  		a = nod(OAS, nod(OINDEX, m, tmpkey), tmpelem)
   862  		a = typecheck(a, ctxStmt)
   863  		a = walkstmt(a)
   864  		init.Append(a)
   865  	}
   866  
   867  	a = nod(OVARKILL, tmpkey, nil)
   868  	a = typecheck(a, ctxStmt)
   869  	init.Append(a)
   870  	a = nod(OVARKILL, tmpelem, nil)
   871  	a = typecheck(a, ctxStmt)
   872  	init.Append(a)
   873  }
   874  
   875  func anylit(n *Node, var_ *Node, init *Nodes) {
   876  	t := n.Type
   877  	switch n.Op {
   878  	default:
   879  		Fatalf("anylit: not lit, op=%v node=%v", n.Op, n)
   880  
   881  	case ONAME:
   882  		a := nod(OAS, var_, n)
   883  		a = typecheck(a, ctxStmt)
   884  		init.Append(a)
   885  
   886  	case OPTRLIT:
   887  		if !t.IsPtr() {
   888  			Fatalf("anylit: not ptr")
   889  		}
   890  
   891  		var r *Node
   892  		if n.Right != nil {
   893  			// n.Right is stack temporary used as backing store.
   894  			init.Append(nod(OAS, n.Right, nil)) // zero backing store, just in case (#18410)
   895  			r = nod(OADDR, n.Right, nil)
   896  			r = typecheck(r, ctxExpr)
   897  		} else {
   898  			r = nod(ONEW, nil, nil)
   899  			r.SetTypecheck(1)
   900  			r.Type = t
   901  			r.Esc = n.Esc
   902  		}
   903  
   904  		r = walkexpr(r, init)
   905  		a := nod(OAS, var_, r)
   906  
   907  		a = typecheck(a, ctxStmt)
   908  		init.Append(a)
   909  
   910  		var_ = nod(ODEREF, var_, nil)
   911  		var_ = typecheck(var_, ctxExpr|ctxAssign)
   912  		anylit(n.Left, var_, init)
   913  
   914  	case OSTRUCTLIT, OARRAYLIT:
   915  		if !t.IsStruct() && !t.IsArray() {
   916  			Fatalf("anylit: not struct/array")
   917  		}
   918  
   919  		if var_.isSimpleName() && n.List.Len() > 4 {
   920  			// lay out static data
   921  			vstat := staticname(t)
   922  			vstat.Name.SetReadonly(true)
   923  
   924  			ctxt := inInitFunction
   925  			if n.Op == OARRAYLIT {
   926  				ctxt = inNonInitFunction
   927  			}
   928  			fixedlit(ctxt, initKindStatic, n, vstat, init)
   929  
   930  			// copy static to var
   931  			a := nod(OAS, var_, vstat)
   932  
   933  			a = typecheck(a, ctxStmt)
   934  			a = walkexpr(a, init)
   935  			init.Append(a)
   936  
   937  			// add expressions to automatic
   938  			fixedlit(inInitFunction, initKindDynamic, n, var_, init)
   939  			break
   940  		}
   941  
   942  		var components int64
   943  		if n.Op == OARRAYLIT {
   944  			components = t.NumElem()
   945  		} else {
   946  			components = int64(t.NumFields())
   947  		}
   948  		// initialization of an array or struct with unspecified components (missing fields or arrays)
   949  		if var_.isSimpleName() || int64(n.List.Len()) < components {
   950  			a := nod(OAS, var_, nil)
   951  			a = typecheck(a, ctxStmt)
   952  			a = walkexpr(a, init)
   953  			init.Append(a)
   954  		}
   955  
   956  		fixedlit(inInitFunction, initKindLocalCode, n, var_, init)
   957  
   958  	case OSLICELIT:
   959  		slicelit(inInitFunction, n, var_, init)
   960  
   961  	case OMAPLIT:
   962  		if !t.IsMap() {
   963  			Fatalf("anylit: not map")
   964  		}
   965  		maplit(n, var_, init)
   966  	}
   967  }
   968  
   969  func oaslit(n *Node, init *Nodes) bool {
   970  	if n.Left == nil || n.Right == nil {
   971  		// not a special composite literal assignment
   972  		return false
   973  	}
   974  	if n.Left.Type == nil || n.Right.Type == nil {
   975  		// not a special composite literal assignment
   976  		return false
   977  	}
   978  	if !n.Left.isSimpleName() {
   979  		// not a special composite literal assignment
   980  		return false
   981  	}
   982  	if !types.Identical(n.Left.Type, n.Right.Type) {
   983  		// not a special composite literal assignment
   984  		return false
   985  	}
   986  
   987  	switch n.Right.Op {
   988  	default:
   989  		// not a special composite literal assignment
   990  		return false
   991  
   992  	case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
   993  		if vmatch1(n.Left, n.Right) {
   994  			// not a special composite literal assignment
   995  			return false
   996  		}
   997  		anylit(n.Right, n.Left, init)
   998  	}
   999  
  1000  	n.Op = OEMPTY
  1001  	n.Right = nil
  1002  	return true
  1003  }
  1004  
  1005  func getlit(lit *Node) int {
  1006  	if smallintconst(lit) {
  1007  		return int(lit.Int64())
  1008  	}
  1009  	return -1
  1010  }
  1011  
  1012  // stataddr sets nam to the static address of n and reports whether it succeeded.
  1013  func stataddr(nam *Node, n *Node) bool {
  1014  	if n == nil {
  1015  		return false
  1016  	}
  1017  
  1018  	switch n.Op {
  1019  	case ONAME:
  1020  		*nam = *n
  1021  		return true
  1022  
  1023  	case ODOT:
  1024  		if !stataddr(nam, n.Left) {
  1025  			break
  1026  		}
  1027  		nam.Xoffset += n.Xoffset
  1028  		nam.Type = n.Type
  1029  		return true
  1030  
  1031  	case OINDEX:
  1032  		if n.Left.Type.IsSlice() {
  1033  			break
  1034  		}
  1035  		if !stataddr(nam, n.Left) {
  1036  			break
  1037  		}
  1038  		l := getlit(n.Right)
  1039  		if l < 0 {
  1040  			break
  1041  		}
  1042  
  1043  		// Check for overflow.
  1044  		if n.Type.Width != 0 && thearch.MAXWIDTH/n.Type.Width <= int64(l) {
  1045  			break
  1046  		}
  1047  		nam.Xoffset += int64(l) * n.Type.Width
  1048  		nam.Type = n.Type
  1049  		return true
  1050  	}
  1051  
  1052  	return false
  1053  }
  1054  
  1055  func (s *InitSchedule) initplan(n *Node) {
  1056  	if s.initplans[n] != nil {
  1057  		return
  1058  	}
  1059  	p := new(InitPlan)
  1060  	s.initplans[n] = p
  1061  	switch n.Op {
  1062  	default:
  1063  		Fatalf("initplan")
  1064  
  1065  	case OARRAYLIT, OSLICELIT:
  1066  		var k int64
  1067  		for _, a := range n.List.Slice() {
  1068  			if a.Op == OKEY {
  1069  				k = indexconst(a.Left)
  1070  				if k < 0 {
  1071  					Fatalf("initplan arraylit: invalid index %v", a.Left)
  1072  				}
  1073  				a = a.Right
  1074  			}
  1075  			s.addvalue(p, k*n.Type.Elem().Width, a)
  1076  			k++
  1077  		}
  1078  
  1079  	case OSTRUCTLIT:
  1080  		for _, a := range n.List.Slice() {
  1081  			if a.Op != OSTRUCTKEY {
  1082  				Fatalf("initplan structlit")
  1083  			}
  1084  			if a.Sym.IsBlank() {
  1085  				continue
  1086  			}
  1087  			s.addvalue(p, a.Xoffset, a.Left)
  1088  		}
  1089  
  1090  	case OMAPLIT:
  1091  		for _, a := range n.List.Slice() {
  1092  			if a.Op != OKEY {
  1093  				Fatalf("initplan maplit")
  1094  			}
  1095  			s.addvalue(p, -1, a.Right)
  1096  		}
  1097  	}
  1098  }
  1099  
  1100  func (s *InitSchedule) addvalue(p *InitPlan, xoffset int64, n *Node) {
  1101  	// special case: zero can be dropped entirely
  1102  	if isZero(n) {
  1103  		return
  1104  	}
  1105  
  1106  	// special case: inline struct and array (not slice) literals
  1107  	if isvaluelit(n) {
  1108  		s.initplan(n)
  1109  		q := s.initplans[n]
  1110  		for _, qe := range q.E {
  1111  			// qe is a copy; we are not modifying entries in q.E
  1112  			qe.Xoffset += xoffset
  1113  			p.E = append(p.E, qe)
  1114  		}
  1115  		return
  1116  	}
  1117  
  1118  	// add to plan
  1119  	p.E = append(p.E, InitEntry{Xoffset: xoffset, Expr: n})
  1120  }
  1121  
  1122  func isZero(n *Node) bool {
  1123  	switch n.Op {
  1124  	case OLITERAL:
  1125  		switch u := n.Val().U.(type) {
  1126  		default:
  1127  			Dump("unexpected literal", n)
  1128  			Fatalf("isZero")
  1129  		case *NilVal:
  1130  			return true
  1131  		case string:
  1132  			return u == ""
  1133  		case bool:
  1134  			return !u
  1135  		case *Mpint:
  1136  			return u.CmpInt64(0) == 0
  1137  		case *Mpflt:
  1138  			return u.CmpFloat64(0) == 0
  1139  		case *Mpcplx:
  1140  			return u.Real.CmpFloat64(0) == 0 && u.Imag.CmpFloat64(0) == 0
  1141  		}
  1142  
  1143  	case OARRAYLIT:
  1144  		for _, n1 := range n.List.Slice() {
  1145  			if n1.Op == OKEY {
  1146  				n1 = n1.Right
  1147  			}
  1148  			if !isZero(n1) {
  1149  				return false
  1150  			}
  1151  		}
  1152  		return true
  1153  
  1154  	case OSTRUCTLIT:
  1155  		for _, n1 := range n.List.Slice() {
  1156  			if !isZero(n1.Left) {
  1157  				return false
  1158  			}
  1159  		}
  1160  		return true
  1161  	}
  1162  
  1163  	return false
  1164  }
  1165  
  1166  func isvaluelit(n *Node) bool {
  1167  	return n.Op == OARRAYLIT || n.Op == OSTRUCTLIT
  1168  }
  1169  
  1170  func genAsStatic(as *Node) {
  1171  	if as.Left.Type == nil {
  1172  		Fatalf("genAsStatic as.Left not typechecked")
  1173  	}
  1174  
  1175  	var nam Node
  1176  	if !stataddr(&nam, as.Left) || (nam.Class() != PEXTERN && as.Left != nblank) {
  1177  		Fatalf("genAsStatic: lhs %v", as.Left)
  1178  	}
  1179  
  1180  	switch {
  1181  	case as.Right.Op == OLITERAL:
  1182  	case as.Right.Op == ONAME && as.Right.Class() == PFUNC:
  1183  	default:
  1184  		Fatalf("genAsStatic: rhs %v", as.Right)
  1185  	}
  1186  
  1187  	gdata(&nam, as.Right, int(as.Right.Type.Width))
  1188  }