Source file src/cmd/compile/internal/walk/complit.go

     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 walk
     6  
     7  import (
     8  	"cmd/compile/internal/base"
     9  	"cmd/compile/internal/ir"
    10  	"cmd/compile/internal/ssa"
    11  	"cmd/compile/internal/staticdata"
    12  	"cmd/compile/internal/staticinit"
    13  	"cmd/compile/internal/typecheck"
    14  	"cmd/compile/internal/types"
    15  	"cmd/internal/obj"
    16  )
    17  
    18  // walkCompLit walks a composite literal node:
    19  // OARRAYLIT, OSLICELIT, OMAPLIT, OSTRUCTLIT (all CompLitExpr), or OPTRLIT (AddrExpr).
    20  func walkCompLit(n ir.Node, init *ir.Nodes) ir.Node {
    21  	if isStaticCompositeLiteral(n) && !ssa.CanSSA(n.Type()) {
    22  		n := n.(*ir.CompLitExpr) // not OPTRLIT
    23  		// n can be directly represented in the read-only data section.
    24  		// Make direct reference to the static data. See issue 12841.
    25  		vstat := readonlystaticname(n.Type())
    26  		fixedlit(inInitFunction, initKindStatic, n, vstat, init)
    27  		return typecheck.Expr(vstat)
    28  	}
    29  	var_ := typecheck.TempAt(base.Pos, ir.CurFunc, n.Type())
    30  	anylit(n, var_, init)
    31  	return var_
    32  }
    33  
    34  // initContext is the context in which static data is populated.
    35  // It is either in an init function or in any other function.
    36  // Static data populated in an init function will be written either
    37  // zero times (as a readonly, static data symbol) or
    38  // one time (during init function execution).
    39  // Either way, there is no opportunity for races or further modification,
    40  // so the data can be written to a (possibly readonly) data symbol.
    41  // Static data populated in any other function needs to be local to
    42  // that function to allow multiple instances of that function
    43  // to execute concurrently without clobbering each others' data.
    44  type initContext uint8
    45  
    46  const (
    47  	inInitFunction initContext = iota
    48  	inNonInitFunction
    49  )
    50  
    51  func (c initContext) String() string {
    52  	if c == inInitFunction {
    53  		return "inInitFunction"
    54  	}
    55  	return "inNonInitFunction"
    56  }
    57  
    58  // readonlystaticname returns a name backed by a read-only static data symbol.
    59  func readonlystaticname(t *types.Type) *ir.Name {
    60  	n := staticinit.StaticName(t)
    61  	n.MarkReadonly()
    62  	n.Linksym().Set(obj.AttrContentAddressable, true)
    63  	n.Linksym().Set(obj.AttrLocal, true)
    64  	return n
    65  }
    66  
    67  func isSimpleName(nn ir.Node) bool {
    68  	if nn.Op() != ir.ONAME || ir.IsBlank(nn) {
    69  		return false
    70  	}
    71  	n := nn.(*ir.Name)
    72  	return n.OnStack()
    73  }
    74  
    75  // initGenType is a bitmap indicating the types of generation that will occur for a static value.
    76  type initGenType uint8
    77  
    78  const (
    79  	initDynamic initGenType = 1 << iota // contains some dynamic values, for which init code will be generated
    80  	initConst                           // contains some constant values, which may be written into data symbols
    81  )
    82  
    83  // getdyn calculates the initGenType for n.
    84  // If top is false, getdyn is recursing.
    85  func getdyn(n ir.Node, top bool) initGenType {
    86  	switch n.Op() {
    87  	default:
    88  		if ir.IsConstNode(n) {
    89  			return initConst
    90  		}
    91  		return initDynamic
    92  
    93  	case ir.OSLICELIT:
    94  		n := n.(*ir.CompLitExpr)
    95  		if !top {
    96  			return initDynamic
    97  		}
    98  		if n.Len/4 > int64(len(n.List)) {
    99  			// <25% of entries have explicit values.
   100  			// Very rough estimation, it takes 4 bytes of instructions
   101  			// to initialize 1 byte of result. So don't use a static
   102  			// initializer if the dynamic initialization code would be
   103  			// smaller than the static value.
   104  			// See issue 23780.
   105  			return initDynamic
   106  		}
   107  
   108  	case ir.OARRAYLIT, ir.OSTRUCTLIT:
   109  	}
   110  	lit := n.(*ir.CompLitExpr)
   111  
   112  	var mode initGenType
   113  	for _, n1 := range lit.List {
   114  		switch n1.Op() {
   115  		case ir.OKEY:
   116  			n1 = n1.(*ir.KeyExpr).Value
   117  		case ir.OSTRUCTKEY:
   118  			n1 = n1.(*ir.StructKeyExpr).Value
   119  		}
   120  		mode |= getdyn(n1, false)
   121  		if mode == initDynamic|initConst {
   122  			break
   123  		}
   124  	}
   125  	return mode
   126  }
   127  
   128  // isStaticCompositeLiteral reports whether n is a compile-time constant.
   129  func isStaticCompositeLiteral(n ir.Node) bool {
   130  	switch n.Op() {
   131  	case ir.OSLICELIT:
   132  		return false
   133  	case ir.OARRAYLIT:
   134  		n := n.(*ir.CompLitExpr)
   135  		for _, r := range n.List {
   136  			if r.Op() == ir.OKEY {
   137  				r = r.(*ir.KeyExpr).Value
   138  			}
   139  			if !isStaticCompositeLiteral(r) {
   140  				return false
   141  			}
   142  		}
   143  		return true
   144  	case ir.OSTRUCTLIT:
   145  		n := n.(*ir.CompLitExpr)
   146  		for _, r := range n.List {
   147  			r := r.(*ir.StructKeyExpr)
   148  			if !isStaticCompositeLiteral(r.Value) {
   149  				return false
   150  			}
   151  		}
   152  		return true
   153  	case ir.OLITERAL, ir.ONIL:
   154  		return true
   155  	case ir.OCONVIFACE:
   156  		// See staticassign's OCONVIFACE case for comments.
   157  		n := n.(*ir.ConvExpr)
   158  		val := ir.Node(n)
   159  		for val.Op() == ir.OCONVIFACE {
   160  			val = val.(*ir.ConvExpr).X
   161  		}
   162  		if val.Type().IsInterface() {
   163  			return val.Op() == ir.ONIL
   164  		}
   165  		if types.IsDirectIface(val.Type()) && val.Op() == ir.ONIL {
   166  			return true
   167  		}
   168  		return isStaticCompositeLiteral(val)
   169  	}
   170  	return false
   171  }
   172  
   173  // initKind is a kind of static initialization: static, dynamic, or local.
   174  // Static initialization represents literals and
   175  // literal components of composite literals.
   176  // Dynamic initialization represents non-literals and
   177  // non-literal components of composite literals.
   178  // LocalCode initialization represents initialization
   179  // that occurs purely in generated code local to the function of use.
   180  // Initialization code is sometimes generated in passes,
   181  // first static then dynamic.
   182  type initKind uint8
   183  
   184  const (
   185  	initKindStatic initKind = iota + 1
   186  	initKindDynamic
   187  	initKindLocalCode
   188  )
   189  
   190  // fixedlit handles struct, array, and slice literals.
   191  // TODO: expand documentation.
   192  func fixedlit(ctxt initContext, kind initKind, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) {
   193  	isBlank := var_ == ir.BlankNode
   194  	var splitnode func(ir.Node) (a ir.Node, value ir.Node)
   195  	switch n.Op() {
   196  	case ir.OARRAYLIT, ir.OSLICELIT:
   197  		var k int64
   198  		splitnode = func(r ir.Node) (ir.Node, ir.Node) {
   199  			if r.Op() == ir.OKEY {
   200  				kv := r.(*ir.KeyExpr)
   201  				k = typecheck.IndexConst(kv.Key)
   202  				if k < 0 {
   203  					base.Fatalf("fixedlit: invalid index %v", kv.Key)
   204  				}
   205  				r = kv.Value
   206  			}
   207  			a := ir.NewIndexExpr(base.Pos, var_, ir.NewInt(base.Pos, k))
   208  			k++
   209  			if isBlank {
   210  				return ir.BlankNode, r
   211  			}
   212  			return a, r
   213  		}
   214  	case ir.OSTRUCTLIT:
   215  		splitnode = func(rn ir.Node) (ir.Node, ir.Node) {
   216  			r := rn.(*ir.StructKeyExpr)
   217  			if r.Sym().IsBlank() || isBlank {
   218  				return ir.BlankNode, r.Value
   219  			}
   220  			ir.SetPos(r)
   221  			return ir.NewSelectorExpr(base.Pos, ir.ODOT, var_, r.Sym()), r.Value
   222  		}
   223  	default:
   224  		base.Fatalf("fixedlit bad op: %v", n.Op())
   225  	}
   226  
   227  	for _, r := range n.List {
   228  		a, value := splitnode(r)
   229  		if a == ir.BlankNode && !staticinit.AnySideEffects(value) {
   230  			// Discard.
   231  			continue
   232  		}
   233  
   234  		switch value.Op() {
   235  		case ir.OSLICELIT:
   236  			value := value.(*ir.CompLitExpr)
   237  			if (kind == initKindStatic && ctxt == inNonInitFunction) || (kind == initKindDynamic && ctxt == inInitFunction) {
   238  				var sinit ir.Nodes
   239  				slicelit(ctxt, value, a, &sinit)
   240  				if kind == initKindStatic {
   241  					// When doing static initialization, init statements may contain dynamic
   242  					// expression, which will be initialized later, causing liveness analysis
   243  					// confuses about variables lifetime. So making sure those expressions
   244  					// are ordered correctly here. See issue #52673.
   245  					orderBlock(&sinit, map[string][]*ir.Name{})
   246  					typecheck.Stmts(sinit)
   247  					walkStmtList(sinit)
   248  				}
   249  				init.Append(sinit...)
   250  				continue
   251  			}
   252  
   253  		case ir.OARRAYLIT, ir.OSTRUCTLIT:
   254  			value := value.(*ir.CompLitExpr)
   255  			fixedlit(ctxt, kind, value, a, init)
   256  			continue
   257  		}
   258  
   259  		islit := ir.IsConstNode(value)
   260  		if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
   261  			continue
   262  		}
   263  
   264  		// build list of assignments: var[index] = expr
   265  		ir.SetPos(a)
   266  		as := ir.NewAssignStmt(base.Pos, a, value)
   267  		as = typecheck.Stmt(as).(*ir.AssignStmt)
   268  		switch kind {
   269  		case initKindStatic:
   270  			genAsStatic(as)
   271  		case initKindDynamic, initKindLocalCode:
   272  			appendWalkStmt(init, orderStmtInPlace(as, map[string][]*ir.Name{}))
   273  		default:
   274  			base.Fatalf("fixedlit: bad kind %d", kind)
   275  		}
   276  
   277  	}
   278  }
   279  
   280  func isSmallSliceLit(n *ir.CompLitExpr) bool {
   281  	if n.Op() != ir.OSLICELIT {
   282  		return false
   283  	}
   284  
   285  	return n.Type().Elem().Size() == 0 || n.Len <= ir.MaxSmallArraySize/n.Type().Elem().Size()
   286  }
   287  
   288  func slicelit(ctxt initContext, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) {
   289  	// make an array type corresponding the number of elements we have
   290  	t := types.NewArray(n.Type().Elem(), n.Len)
   291  	types.CalcSize(t)
   292  
   293  	if ctxt == inNonInitFunction {
   294  		// put everything into static array
   295  		vstat := staticinit.StaticName(t)
   296  
   297  		fixedlit(ctxt, initKindStatic, n, vstat, init)
   298  		fixedlit(ctxt, initKindDynamic, n, vstat, init)
   299  
   300  		// copy static to slice
   301  		var_ = typecheck.AssignExpr(var_)
   302  		name, offset, ok := staticinit.StaticLoc(var_)
   303  		if !ok || name.Class != ir.PEXTERN {
   304  			base.Fatalf("slicelit: %v", var_)
   305  		}
   306  		staticdata.InitSlice(name, offset, vstat.Linksym(), t.NumElem())
   307  		return
   308  	}
   309  
   310  	// recipe for var = []t{...}
   311  	// 1. make a static array
   312  	//	var vstat [...]t
   313  	// 2. assign (data statements) the constant part
   314  	//	vstat = constpart{}
   315  	// 3. make an auto pointer to array and allocate heap to it
   316  	//	var vauto *[...]t = new([...]t)
   317  	// 4. copy the static array to the auto array
   318  	//	*vauto = vstat
   319  	// 5. for each dynamic part assign to the array
   320  	//	vauto[i] = dynamic part
   321  	// 6. assign slice of allocated heap to var
   322  	//	var = vauto[:]
   323  	//
   324  	// an optimization is done if there is no constant part
   325  	//	3. var vauto *[...]t = new([...]t)
   326  	//	5. vauto[i] = dynamic part
   327  	//	6. var = vauto[:]
   328  
   329  	// if the literal contains constants,
   330  	// make static initialized array (1),(2)
   331  	var vstat ir.Node
   332  
   333  	mode := getdyn(n, true)
   334  	if mode&initConst != 0 && !isSmallSliceLit(n) {
   335  		if ctxt == inInitFunction {
   336  			vstat = readonlystaticname(t)
   337  		} else {
   338  			vstat = staticinit.StaticName(t)
   339  		}
   340  		fixedlit(ctxt, initKindStatic, n, vstat, init)
   341  	}
   342  
   343  	// make new auto *array (3 declare)
   344  	vauto := typecheck.TempAt(base.Pos, ir.CurFunc, types.NewPtr(t))
   345  
   346  	// set auto to point at new temp or heap (3 assign)
   347  	var a ir.Node
   348  	if x := n.Prealloc; x != nil {
   349  		// temp allocated during order.go for dddarg
   350  		if !types.Identical(t, x.Type()) {
   351  			panic("dotdotdot base type does not match order's assigned type")
   352  		}
   353  		a = initStackTemp(init, x, vstat)
   354  	} else if n.Esc() == ir.EscNone {
   355  		a = initStackTemp(init, typecheck.TempAt(base.Pos, ir.CurFunc, t), vstat)
   356  	} else {
   357  		a = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(t))
   358  	}
   359  	appendWalkStmt(init, ir.NewAssignStmt(base.Pos, vauto, a))
   360  
   361  	if vstat != nil && n.Prealloc == nil && n.Esc() != ir.EscNone {
   362  		// If we allocated on the heap with ONEW, copy the static to the
   363  		// heap (4). We skip this for stack temporaries, because
   364  		// initStackTemp already handled the copy.
   365  		a = ir.NewStarExpr(base.Pos, vauto)
   366  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, a, vstat))
   367  	}
   368  
   369  	// put dynamics into array (5)
   370  	var index int64
   371  	for _, value := range n.List {
   372  		if value.Op() == ir.OKEY {
   373  			kv := value.(*ir.KeyExpr)
   374  			index = typecheck.IndexConst(kv.Key)
   375  			if index < 0 {
   376  				base.Fatalf("slicelit: invalid index %v", kv.Key)
   377  			}
   378  			value = kv.Value
   379  		}
   380  		a := ir.NewIndexExpr(base.Pos, vauto, ir.NewInt(base.Pos, index))
   381  		a.SetBounded(true)
   382  		index++
   383  
   384  		// TODO need to check bounds?
   385  
   386  		switch value.Op() {
   387  		case ir.OSLICELIT:
   388  			break
   389  
   390  		case ir.OARRAYLIT, ir.OSTRUCTLIT:
   391  			value := value.(*ir.CompLitExpr)
   392  			k := initKindDynamic
   393  			if vstat == nil {
   394  				// Generate both static and dynamic initializations.
   395  				// See issue #31987.
   396  				k = initKindLocalCode
   397  			}
   398  			fixedlit(ctxt, k, value, a, init)
   399  			continue
   400  		}
   401  
   402  		if vstat != nil && ir.IsConstNode(value) { // already set by copy from static value
   403  			continue
   404  		}
   405  
   406  		// build list of vauto[c] = expr
   407  		ir.SetPos(value)
   408  		as := ir.NewAssignStmt(base.Pos, a, value)
   409  		appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(as), map[string][]*ir.Name{}))
   410  	}
   411  
   412  	// make slice out of heap (6)
   413  	a = ir.NewAssignStmt(base.Pos, var_, ir.NewSliceExpr(base.Pos, ir.OSLICE, vauto, nil, nil, nil))
   414  	appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(a), map[string][]*ir.Name{}))
   415  }
   416  
   417  func maplit(n *ir.CompLitExpr, m ir.Node, init *ir.Nodes) {
   418  	// make the map var
   419  	args := []ir.Node{ir.TypeNode(n.Type()), ir.NewInt(base.Pos, n.Len+int64(len(n.List)))}
   420  	a := typecheck.Expr(ir.NewCallExpr(base.Pos, ir.OMAKE, nil, args)).(*ir.MakeExpr)
   421  	a.RType = n.RType
   422  	a.SetEsc(n.Esc())
   423  	appendWalkStmt(init, ir.NewAssignStmt(base.Pos, m, a))
   424  
   425  	entries := n.List
   426  
   427  	// The order pass already removed any dynamic (runtime-computed) entries.
   428  	// All remaining entries are static. Double-check that.
   429  	for _, r := range entries {
   430  		r := r.(*ir.KeyExpr)
   431  		if !isStaticCompositeLiteral(r.Key) || !isStaticCompositeLiteral(r.Value) {
   432  			base.Fatalf("maplit: entry is not a literal: %v", r)
   433  		}
   434  	}
   435  
   436  	if len(entries) > 25 {
   437  		// For a large number of entries, put them in an array and loop.
   438  
   439  		// build types [count]Tindex and [count]Tvalue
   440  		tk := types.NewArray(n.Type().Key(), int64(len(entries)))
   441  		te := types.NewArray(n.Type().Elem(), int64(len(entries)))
   442  
   443  		// TODO(#47904): mark tk and te NoAlg here once the
   444  		// compiler/linker can handle NoAlg types correctly.
   445  
   446  		types.CalcSize(tk)
   447  		types.CalcSize(te)
   448  
   449  		// make and initialize static arrays
   450  		vstatk := readonlystaticname(tk)
   451  		vstate := readonlystaticname(te)
   452  
   453  		datak := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
   454  		datae := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
   455  		for _, r := range entries {
   456  			r := r.(*ir.KeyExpr)
   457  			datak.List.Append(r.Key)
   458  			datae.List.Append(r.Value)
   459  		}
   460  		fixedlit(inInitFunction, initKindStatic, datak, vstatk, init)
   461  		fixedlit(inInitFunction, initKindStatic, datae, vstate, init)
   462  
   463  		// loop adding structure elements to map
   464  		// for i = 0; i < len(vstatk); i++ {
   465  		//	map[vstatk[i]] = vstate[i]
   466  		// }
   467  		i := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
   468  		rhs := ir.NewIndexExpr(base.Pos, vstate, i)
   469  		rhs.SetBounded(true)
   470  
   471  		kidx := ir.NewIndexExpr(base.Pos, vstatk, i)
   472  		kidx.SetBounded(true)
   473  
   474  		// typechecker rewrites OINDEX to OINDEXMAP
   475  		lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, kidx)).(*ir.IndexExpr)
   476  		base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
   477  		lhs.RType = n.RType
   478  
   479  		zero := ir.NewAssignStmt(base.Pos, i, ir.NewInt(base.Pos, 0))
   480  		cond := ir.NewBinaryExpr(base.Pos, ir.OLT, i, ir.NewInt(base.Pos, tk.NumElem()))
   481  		incr := ir.NewAssignStmt(base.Pos, i, ir.NewBinaryExpr(base.Pos, ir.OADD, i, ir.NewInt(base.Pos, 1)))
   482  
   483  		var body ir.Node = ir.NewAssignStmt(base.Pos, lhs, rhs)
   484  		body = typecheck.Stmt(body)
   485  		body = orderStmtInPlace(body, map[string][]*ir.Name{})
   486  
   487  		loop := ir.NewForStmt(base.Pos, nil, cond, incr, nil, false)
   488  		loop.Body = []ir.Node{body}
   489  		loop.SetInit([]ir.Node{zero})
   490  
   491  		appendWalkStmt(init, loop)
   492  		return
   493  	}
   494  	// For a small number of entries, just add them directly.
   495  
   496  	// Build list of var[c] = expr.
   497  	// Use temporaries so that mapassign1 can have addressable key, elem.
   498  	// TODO(josharian): avoid map key temporaries for mapfast_* assignments with literal keys.
   499  	// TODO(khr): assign these temps in order phase so we can reuse them across multiple maplits?
   500  	tmpkey := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Key())
   501  	tmpelem := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Elem())
   502  
   503  	for _, r := range entries {
   504  		r := r.(*ir.KeyExpr)
   505  		index, elem := r.Key, r.Value
   506  
   507  		ir.SetPos(index)
   508  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpkey, index))
   509  
   510  		ir.SetPos(elem)
   511  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpelem, elem))
   512  
   513  		ir.SetPos(tmpelem)
   514  
   515  		// typechecker rewrites OINDEX to OINDEXMAP
   516  		lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, tmpkey)).(*ir.IndexExpr)
   517  		base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
   518  		lhs.RType = n.RType
   519  
   520  		var a ir.Node = ir.NewAssignStmt(base.Pos, lhs, tmpelem)
   521  		a = typecheck.Stmt(a)
   522  		a = orderStmtInPlace(a, map[string][]*ir.Name{})
   523  		appendWalkStmt(init, a)
   524  	}
   525  }
   526  
   527  func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
   528  	t := n.Type()
   529  	switch n.Op() {
   530  	default:
   531  		base.Fatalf("anylit: not lit, op=%v node=%v", n.Op(), n)
   532  
   533  	case ir.ONAME:
   534  		n := n.(*ir.Name)
   535  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
   536  
   537  	case ir.OMETHEXPR:
   538  		n := n.(*ir.SelectorExpr)
   539  		anylit(n.FuncName(), var_, init)
   540  
   541  	case ir.OPTRLIT:
   542  		n := n.(*ir.AddrExpr)
   543  		if !t.IsPtr() {
   544  			base.Fatalf("anylit: not ptr")
   545  		}
   546  
   547  		var r ir.Node
   548  		if n.Prealloc != nil {
   549  			// n.Prealloc is stack temporary used as backing store.
   550  			r = initStackTemp(init, n.Prealloc, nil)
   551  		} else {
   552  			r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type()))
   553  			r.SetEsc(n.Esc())
   554  		}
   555  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, r))
   556  
   557  		var_ = ir.NewStarExpr(base.Pos, var_)
   558  		var_ = typecheck.AssignExpr(var_)
   559  		anylit(n.X, var_, init)
   560  
   561  	case ir.OSTRUCTLIT, ir.OARRAYLIT:
   562  		n := n.(*ir.CompLitExpr)
   563  		if !t.IsStruct() && !t.IsArray() {
   564  			base.Fatalf("anylit: not struct/array")
   565  		}
   566  
   567  		if isSimpleName(var_) && len(n.List) > 4 {
   568  			// lay out static data
   569  			vstat := readonlystaticname(t)
   570  
   571  			ctxt := inInitFunction
   572  			if n.Op() == ir.OARRAYLIT {
   573  				ctxt = inNonInitFunction
   574  			}
   575  			fixedlit(ctxt, initKindStatic, n, vstat, init)
   576  
   577  			// copy static to var
   578  			appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, vstat))
   579  
   580  			// add expressions to automatic
   581  			fixedlit(inInitFunction, initKindDynamic, n, var_, init)
   582  			break
   583  		}
   584  
   585  		var components int64
   586  		if n.Op() == ir.OARRAYLIT {
   587  			components = t.NumElem()
   588  		} else {
   589  			components = int64(t.NumFields())
   590  		}
   591  		// initialization of an array or struct with unspecified components (missing fields or arrays)
   592  		if isSimpleName(var_) || int64(len(n.List)) < components {
   593  			appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil))
   594  		}
   595  
   596  		fixedlit(inInitFunction, initKindLocalCode, n, var_, init)
   597  
   598  	case ir.OSLICELIT:
   599  		n := n.(*ir.CompLitExpr)
   600  		slicelit(inInitFunction, n, var_, init)
   601  
   602  	case ir.OMAPLIT:
   603  		n := n.(*ir.CompLitExpr)
   604  		if !t.IsMap() {
   605  			base.Fatalf("anylit: not map")
   606  		}
   607  		maplit(n, var_, init)
   608  	}
   609  }
   610  
   611  // oaslit handles special composite literal assignments.
   612  // It returns true if n's effects have been added to init,
   613  // in which case n should be dropped from the program by the caller.
   614  func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
   615  	if n.X == nil || n.Y == nil {
   616  		// not a special composite literal assignment
   617  		return false
   618  	}
   619  	if n.X.Type() == nil || n.Y.Type() == nil {
   620  		// not a special composite literal assignment
   621  		return false
   622  	}
   623  	if !isSimpleName(n.X) {
   624  		// not a special composite literal assignment
   625  		return false
   626  	}
   627  	x := n.X.(*ir.Name)
   628  	if !types.Identical(n.X.Type(), n.Y.Type()) {
   629  		// not a special composite literal assignment
   630  		return false
   631  	}
   632  	if x.Addrtaken() {
   633  		// If x is address-taken, the RHS may (implicitly) uses LHS.
   634  		// Not safe to do a special composite literal assignment
   635  		// (which may expand to multiple assignments).
   636  		return false
   637  	}
   638  
   639  	switch n.Y.Op() {
   640  	default:
   641  		// not a special composite literal assignment
   642  		return false
   643  
   644  	case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
   645  		if ir.Any(n.Y, func(y ir.Node) bool { return ir.Uses(y, x) }) {
   646  			// not safe to do a special composite literal assignment if RHS uses LHS.
   647  			return false
   648  		}
   649  		anylit(n.Y, n.X, init)
   650  	}
   651  
   652  	return true
   653  }
   654  
   655  func genAsStatic(as *ir.AssignStmt) {
   656  	if as.X.Type() == nil {
   657  		base.Fatalf("genAsStatic as.Left not typechecked")
   658  	}
   659  
   660  	name, offset, ok := staticinit.StaticLoc(as.X)
   661  	if !ok || (name.Class != ir.PEXTERN && as.X != ir.BlankNode) {
   662  		base.Fatalf("genAsStatic: lhs %v", as.X)
   663  	}
   664  
   665  	switch r := as.Y; r.Op() {
   666  	case ir.OLITERAL:
   667  		staticdata.InitConst(name, offset, r, int(r.Type().Size()))
   668  		return
   669  	case ir.OMETHEXPR:
   670  		r := r.(*ir.SelectorExpr)
   671  		staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r.FuncName()))
   672  		return
   673  	case ir.ONAME:
   674  		r := r.(*ir.Name)
   675  		if r.Offset_ != 0 {
   676  			base.Fatalf("genAsStatic %+v", as)
   677  		}
   678  		if r.Class == ir.PFUNC {
   679  			staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r))
   680  			return
   681  		}
   682  	}
   683  	base.Fatalf("genAsStatic: rhs %v", as.Y)
   684  }
   685  

View as plain text