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 staticinit.Schedule.StaticAssign's OCONVIFACE case for comments.
   157  		if base.Ctxt.IsFIPS() && base.Ctxt.Flag_shared {
   158  			return false
   159  		}
   160  		n := n.(*ir.ConvExpr)
   161  		val := ir.Node(n)
   162  		for val.Op() == ir.OCONVIFACE {
   163  			val = val.(*ir.ConvExpr).X
   164  		}
   165  		if val.Type().IsInterface() {
   166  			return val.Op() == ir.ONIL
   167  		}
   168  		if types.IsDirectIface(val.Type()) && val.Op() == ir.ONIL {
   169  			return true
   170  		}
   171  		return isStaticCompositeLiteral(val)
   172  	}
   173  	return false
   174  }
   175  
   176  // initKind is a kind of static initialization: static, dynamic, or local.
   177  // Static initialization represents literals and
   178  // literal components of composite literals.
   179  // Dynamic initialization represents non-literals and
   180  // non-literal components of composite literals.
   181  // LocalCode initialization represents initialization
   182  // that occurs purely in generated code local to the function of use.
   183  // Initialization code is sometimes generated in passes,
   184  // first static then dynamic.
   185  type initKind uint8
   186  
   187  const (
   188  	initKindStatic initKind = iota + 1
   189  	initKindDynamic
   190  	initKindLocalCode
   191  )
   192  
   193  // fixedlit handles struct, array, and slice literals.
   194  // TODO: expand documentation.
   195  func fixedlit(ctxt initContext, kind initKind, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) {
   196  	isBlank := var_ == ir.BlankNode
   197  	var splitnode func(ir.Node) (a ir.Node, value ir.Node)
   198  	switch n.Op() {
   199  	case ir.OARRAYLIT, ir.OSLICELIT:
   200  		var k int64
   201  		splitnode = func(r ir.Node) (ir.Node, ir.Node) {
   202  			if r.Op() == ir.OKEY {
   203  				kv := r.(*ir.KeyExpr)
   204  				k = typecheck.IndexConst(kv.Key)
   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  			value = kv.Value
   376  		}
   377  		a := ir.NewIndexExpr(base.Pos, vauto, ir.NewInt(base.Pos, index))
   378  		a.SetBounded(true)
   379  		index++
   380  
   381  		// TODO need to check bounds?
   382  
   383  		switch value.Op() {
   384  		case ir.OSLICELIT:
   385  			break
   386  
   387  		case ir.OARRAYLIT, ir.OSTRUCTLIT:
   388  			value := value.(*ir.CompLitExpr)
   389  			k := initKindDynamic
   390  			if vstat == nil {
   391  				// Generate both static and dynamic initializations.
   392  				// See issue #31987.
   393  				k = initKindLocalCode
   394  			}
   395  			fixedlit(ctxt, k, value, a, init)
   396  			continue
   397  		}
   398  
   399  		if vstat != nil && ir.IsConstNode(value) { // already set by copy from static value
   400  			continue
   401  		}
   402  
   403  		// build list of vauto[c] = expr
   404  		ir.SetPos(value)
   405  		as := ir.NewAssignStmt(base.Pos, a, value)
   406  		appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(as), map[string][]*ir.Name{}))
   407  	}
   408  
   409  	// make slice out of heap (6)
   410  	a = ir.NewAssignStmt(base.Pos, var_, ir.NewSliceExpr(base.Pos, ir.OSLICE, vauto, nil, nil, nil))
   411  	appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(a), map[string][]*ir.Name{}))
   412  }
   413  
   414  func maplit(n *ir.CompLitExpr, m ir.Node, init *ir.Nodes) {
   415  	// make the map var
   416  	args := []ir.Node{ir.TypeNode(n.Type()), ir.NewInt(base.Pos, n.Len+int64(len(n.List)))}
   417  	a := typecheck.Expr(ir.NewCallExpr(base.Pos, ir.OMAKE, nil, args)).(*ir.MakeExpr)
   418  	a.RType = n.RType
   419  	a.SetEsc(n.Esc())
   420  	appendWalkStmt(init, ir.NewAssignStmt(base.Pos, m, a))
   421  
   422  	entries := n.List
   423  
   424  	// The order pass already removed any dynamic (runtime-computed) entries.
   425  	// All remaining entries are static. Double-check that.
   426  	for _, r := range entries {
   427  		r := r.(*ir.KeyExpr)
   428  		if !isStaticCompositeLiteral(r.Key) || !isStaticCompositeLiteral(r.Value) {
   429  			base.Fatalf("maplit: entry is not a literal: %v", r)
   430  		}
   431  	}
   432  
   433  	if len(entries) > 25 {
   434  		// For a large number of entries, put them in an array and loop.
   435  
   436  		// build types [count]Tindex and [count]Tvalue
   437  		tk := types.NewArray(n.Type().Key(), int64(len(entries)))
   438  		te := types.NewArray(n.Type().Elem(), int64(len(entries)))
   439  
   440  		// TODO(#47904): mark tk and te NoAlg here once the
   441  		// compiler/linker can handle NoAlg types correctly.
   442  
   443  		types.CalcSize(tk)
   444  		types.CalcSize(te)
   445  
   446  		// make and initialize static arrays
   447  		vstatk := readonlystaticname(tk)
   448  		vstate := readonlystaticname(te)
   449  
   450  		datak := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
   451  		datae := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
   452  		for _, r := range entries {
   453  			r := r.(*ir.KeyExpr)
   454  			datak.List.Append(r.Key)
   455  			datae.List.Append(r.Value)
   456  		}
   457  		fixedlit(inInitFunction, initKindStatic, datak, vstatk, init)
   458  		fixedlit(inInitFunction, initKindStatic, datae, vstate, init)
   459  
   460  		// loop adding structure elements to map
   461  		// for i = 0; i < len(vstatk); i++ {
   462  		//	map[vstatk[i]] = vstate[i]
   463  		// }
   464  		i := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
   465  		rhs := ir.NewIndexExpr(base.Pos, vstate, i)
   466  		rhs.SetBounded(true)
   467  
   468  		kidx := ir.NewIndexExpr(base.Pos, vstatk, i)
   469  		kidx.SetBounded(true)
   470  
   471  		// typechecker rewrites OINDEX to OINDEXMAP
   472  		lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, kidx)).(*ir.IndexExpr)
   473  		base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
   474  		lhs.RType = n.RType
   475  
   476  		zero := ir.NewAssignStmt(base.Pos, i, ir.NewInt(base.Pos, 0))
   477  		cond := ir.NewBinaryExpr(base.Pos, ir.OLT, i, ir.NewInt(base.Pos, tk.NumElem()))
   478  		incr := ir.NewAssignStmt(base.Pos, i, ir.NewBinaryExpr(base.Pos, ir.OADD, i, ir.NewInt(base.Pos, 1)))
   479  
   480  		var body ir.Node = ir.NewAssignStmt(base.Pos, lhs, rhs)
   481  		body = typecheck.Stmt(body)
   482  		body = orderStmtInPlace(body, map[string][]*ir.Name{})
   483  
   484  		loop := ir.NewForStmt(base.Pos, nil, cond, incr, nil, false)
   485  		loop.Body = []ir.Node{body}
   486  		loop.SetInit([]ir.Node{zero})
   487  
   488  		appendWalkStmt(init, loop)
   489  		return
   490  	}
   491  	// For a small number of entries, just add them directly.
   492  
   493  	// Build list of var[c] = expr.
   494  	// Use temporaries so that mapassign1 can have addressable key, elem.
   495  	// TODO(josharian): avoid map key temporaries for mapfast_* assignments with literal keys.
   496  	// TODO(khr): assign these temps in order phase so we can reuse them across multiple maplits?
   497  	tmpkey := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Key())
   498  	tmpelem := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Elem())
   499  
   500  	for _, r := range entries {
   501  		r := r.(*ir.KeyExpr)
   502  		index, elem := r.Key, r.Value
   503  
   504  		ir.SetPos(index)
   505  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpkey, index))
   506  
   507  		ir.SetPos(elem)
   508  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpelem, elem))
   509  
   510  		ir.SetPos(tmpelem)
   511  
   512  		// typechecker rewrites OINDEX to OINDEXMAP
   513  		lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, tmpkey)).(*ir.IndexExpr)
   514  		base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
   515  		lhs.RType = n.RType
   516  
   517  		var a ir.Node = ir.NewAssignStmt(base.Pos, lhs, tmpelem)
   518  		a = typecheck.Stmt(a)
   519  		a = orderStmtInPlace(a, map[string][]*ir.Name{})
   520  		appendWalkStmt(init, a)
   521  	}
   522  }
   523  
   524  func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
   525  	t := n.Type()
   526  	switch n.Op() {
   527  	default:
   528  		base.Fatalf("anylit: not lit, op=%v node=%v", n.Op(), n)
   529  
   530  	case ir.ONAME:
   531  		n := n.(*ir.Name)
   532  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
   533  
   534  	case ir.OMETHEXPR:
   535  		n := n.(*ir.SelectorExpr)
   536  		anylit(n.FuncName(), var_, init)
   537  
   538  	case ir.OPTRLIT:
   539  		n := n.(*ir.AddrExpr)
   540  		if !t.IsPtr() {
   541  			base.Fatalf("anylit: not ptr")
   542  		}
   543  
   544  		var r ir.Node
   545  		if n.Prealloc != nil {
   546  			// n.Prealloc is stack temporary used as backing store.
   547  			r = initStackTemp(init, n.Prealloc, nil)
   548  		} else {
   549  			r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type()))
   550  			r.SetEsc(n.Esc())
   551  		}
   552  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, r))
   553  
   554  		var_ = ir.NewStarExpr(base.Pos, var_)
   555  		var_ = typecheck.AssignExpr(var_)
   556  		anylit(n.X, var_, init)
   557  
   558  	case ir.OSTRUCTLIT, ir.OARRAYLIT:
   559  		n := n.(*ir.CompLitExpr)
   560  		if !t.IsStruct() && !t.IsArray() {
   561  			base.Fatalf("anylit: not struct/array")
   562  		}
   563  
   564  		if isSimpleName(var_) && len(n.List) > 4 {
   565  			// lay out static data
   566  			vstat := readonlystaticname(t)
   567  
   568  			ctxt := inInitFunction
   569  			if n.Op() == ir.OARRAYLIT {
   570  				ctxt = inNonInitFunction
   571  			}
   572  			fixedlit(ctxt, initKindStatic, n, vstat, init)
   573  
   574  			// copy static to var
   575  			appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, vstat))
   576  
   577  			// add expressions to automatic
   578  			fixedlit(inInitFunction, initKindDynamic, n, var_, init)
   579  			break
   580  		}
   581  
   582  		var components int64
   583  		if n.Op() == ir.OARRAYLIT {
   584  			components = t.NumElem()
   585  		} else {
   586  			components = int64(t.NumFields())
   587  		}
   588  		// initialization of an array or struct with unspecified components (missing fields or arrays)
   589  		if isSimpleName(var_) || int64(len(n.List)) < components {
   590  			appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil))
   591  		}
   592  
   593  		fixedlit(inInitFunction, initKindLocalCode, n, var_, init)
   594  
   595  	case ir.OSLICELIT:
   596  		n := n.(*ir.CompLitExpr)
   597  		slicelit(inInitFunction, n, var_, init)
   598  
   599  	case ir.OMAPLIT:
   600  		n := n.(*ir.CompLitExpr)
   601  		if !t.IsMap() {
   602  			base.Fatalf("anylit: not map")
   603  		}
   604  		maplit(n, var_, init)
   605  	}
   606  }
   607  
   608  // oaslit handles special composite literal assignments.
   609  // It returns true if n's effects have been added to init,
   610  // in which case n should be dropped from the program by the caller.
   611  func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
   612  	if n.X == nil || n.Y == nil {
   613  		// not a special composite literal assignment
   614  		return false
   615  	}
   616  	if n.X.Type() == nil || n.Y.Type() == nil {
   617  		// not a special composite literal assignment
   618  		return false
   619  	}
   620  	if !isSimpleName(n.X) {
   621  		// not a special composite literal assignment
   622  		return false
   623  	}
   624  	x := n.X.(*ir.Name)
   625  	if !types.Identical(n.X.Type(), n.Y.Type()) {
   626  		// not a special composite literal assignment
   627  		return false
   628  	}
   629  	if x.Addrtaken() {
   630  		// If x is address-taken, the RHS may (implicitly) uses LHS.
   631  		// Not safe to do a special composite literal assignment
   632  		// (which may expand to multiple assignments).
   633  		return false
   634  	}
   635  
   636  	switch n.Y.Op() {
   637  	default:
   638  		// not a special composite literal assignment
   639  		return false
   640  
   641  	case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
   642  		if ir.Any(n.Y, func(y ir.Node) bool { return ir.Uses(y, x) }) {
   643  			// not safe to do a special composite literal assignment if RHS uses LHS.
   644  			return false
   645  		}
   646  		anylit(n.Y, n.X, init)
   647  	}
   648  
   649  	return true
   650  }
   651  
   652  func genAsStatic(as *ir.AssignStmt) {
   653  	if as.X.Type() == nil {
   654  		base.Fatalf("genAsStatic as.Left not typechecked")
   655  	}
   656  
   657  	name, offset, ok := staticinit.StaticLoc(as.X)
   658  	if !ok || (name.Class != ir.PEXTERN && as.X != ir.BlankNode) {
   659  		base.Fatalf("genAsStatic: lhs %v", as.X)
   660  	}
   661  
   662  	switch r := as.Y; r.Op() {
   663  	case ir.OLITERAL:
   664  		staticdata.InitConst(name, offset, r, int(r.Type().Size()))
   665  		return
   666  	case ir.OMETHEXPR:
   667  		r := r.(*ir.SelectorExpr)
   668  		staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r.FuncName()))
   669  		return
   670  	case ir.ONAME:
   671  		r := r.(*ir.Name)
   672  		if r.Offset_ != 0 {
   673  			base.Fatalf("genAsStatic %+v", as)
   674  		}
   675  		if r.Class == ir.PFUNC {
   676  			staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r))
   677  			return
   678  		}
   679  	}
   680  	base.Fatalf("genAsStatic: rhs %v", as.Y)
   681  }
   682  

View as plain text