1  
     2  
     3  
     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  
    19  
    20  func walkCompLit(n ir.Node, init *ir.Nodes) ir.Node {
    21  	if isStaticCompositeLiteral(n) && !ssa.CanSSA(n.Type()) {
    22  		n := n.(*ir.CompLitExpr) 
    23  		
    24  		
    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  
    35  
    36  
    37  
    38  
    39  
    40  
    41  
    42  
    43  
    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  
    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  
    76  type initGenType uint8
    77  
    78  const (
    79  	initDynamic initGenType = 1 << iota 
    80  	initConst                           
    81  )
    82  
    83  
    84  
    85  func getdyn(n ir.Node, top bool) initGenType {
    86  	switch n.Op() {
    87  	default:
    88  		
    89  		
    90  		if ir.IsConstNode(n) && (!n.Type().IsString() || !base.Ctxt.IsFIPS()) {
    91  			return initConst
    92  		}
    93  		return initDynamic
    94  
    95  	case ir.OSLICELIT:
    96  		n := n.(*ir.CompLitExpr)
    97  		if !top {
    98  			return initDynamic
    99  		}
   100  		if n.Len/4 > int64(len(n.List)) {
   101  			
   102  			
   103  			
   104  			
   105  			
   106  			
   107  			return initDynamic
   108  		}
   109  
   110  	case ir.OARRAYLIT, ir.OSTRUCTLIT:
   111  	}
   112  	lit := n.(*ir.CompLitExpr)
   113  
   114  	var mode initGenType
   115  	for _, n1 := range lit.List {
   116  		switch n1.Op() {
   117  		case ir.OKEY:
   118  			n1 = n1.(*ir.KeyExpr).Value
   119  		case ir.OSTRUCTKEY:
   120  			n1 = n1.(*ir.StructKeyExpr).Value
   121  		}
   122  		mode |= getdyn(n1, false)
   123  		if mode == initDynamic|initConst {
   124  			break
   125  		}
   126  	}
   127  	return mode
   128  }
   129  
   130  
   131  func isStaticCompositeLiteral(n ir.Node) bool {
   132  	switch n.Op() {
   133  	case ir.OSLICELIT:
   134  		return false
   135  	case ir.OARRAYLIT:
   136  		n := n.(*ir.CompLitExpr)
   137  		for _, r := range n.List {
   138  			if r.Op() == ir.OKEY {
   139  				r = r.(*ir.KeyExpr).Value
   140  			}
   141  			if !isStaticCompositeLiteral(r) {
   142  				return false
   143  			}
   144  		}
   145  		return true
   146  	case ir.OSTRUCTLIT:
   147  		n := n.(*ir.CompLitExpr)
   148  		for _, r := range n.List {
   149  			r := r.(*ir.StructKeyExpr)
   150  			if !isStaticCompositeLiteral(r.Value) {
   151  				return false
   152  			}
   153  		}
   154  		return true
   155  	case ir.OLITERAL, ir.ONIL:
   156  		return true
   157  	case ir.OCONVIFACE:
   158  		
   159  		if base.Ctxt.IsFIPS() && base.Ctxt.Flag_shared {
   160  			return false
   161  		}
   162  		n := n.(*ir.ConvExpr)
   163  		val := ir.Node(n)
   164  		for val.Op() == ir.OCONVIFACE {
   165  			val = val.(*ir.ConvExpr).X
   166  		}
   167  		if val.Type().IsInterface() {
   168  			return val.Op() == ir.ONIL
   169  		}
   170  		if types.IsDirectIface(val.Type()) && val.Op() == ir.ONIL {
   171  			return true
   172  		}
   173  		return isStaticCompositeLiteral(val)
   174  	}
   175  	return false
   176  }
   177  
   178  
   179  
   180  
   181  
   182  
   183  
   184  
   185  
   186  
   187  type initKind uint8
   188  
   189  const (
   190  	initKindStatic initKind = iota + 1
   191  	initKindDynamic
   192  	initKindLocalCode
   193  )
   194  
   195  
   196  
   197  func fixedlit(ctxt initContext, kind initKind, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) {
   198  	isBlank := var_ == ir.BlankNode
   199  	var splitnode func(ir.Node) (a ir.Node, value ir.Node)
   200  	switch n.Op() {
   201  	case ir.OARRAYLIT, ir.OSLICELIT:
   202  		var k int64
   203  		splitnode = func(r ir.Node) (ir.Node, ir.Node) {
   204  			if r.Op() == ir.OKEY {
   205  				kv := r.(*ir.KeyExpr)
   206  				k = typecheck.IndexConst(kv.Key)
   207  				r = kv.Value
   208  			}
   209  			a := ir.NewIndexExpr(base.Pos, var_, ir.NewInt(base.Pos, k))
   210  			k++
   211  			if isBlank {
   212  				return ir.BlankNode, r
   213  			}
   214  			return a, r
   215  		}
   216  	case ir.OSTRUCTLIT:
   217  		splitnode = func(rn ir.Node) (ir.Node, ir.Node) {
   218  			r := rn.(*ir.StructKeyExpr)
   219  			if r.Sym().IsBlank() || isBlank {
   220  				return ir.BlankNode, r.Value
   221  			}
   222  			ir.SetPos(r)
   223  			return ir.NewSelectorExpr(base.Pos, ir.ODOT, var_, r.Sym()), r.Value
   224  		}
   225  	default:
   226  		base.Fatalf("fixedlit bad op: %v", n.Op())
   227  	}
   228  
   229  	for _, r := range n.List {
   230  		a, value := splitnode(r)
   231  		if a == ir.BlankNode && !staticinit.AnySideEffects(value) {
   232  			
   233  			continue
   234  		}
   235  
   236  		switch value.Op() {
   237  		case ir.OSLICELIT:
   238  			value := value.(*ir.CompLitExpr)
   239  			if (kind == initKindStatic && ctxt == inNonInitFunction) || (kind == initKindDynamic && ctxt == inInitFunction) {
   240  				var sinit ir.Nodes
   241  				slicelit(ctxt, value, a, &sinit)
   242  				if kind == initKindStatic {
   243  					
   244  					
   245  					
   246  					
   247  					orderBlock(&sinit, map[string][]*ir.Name{})
   248  					typecheck.Stmts(sinit)
   249  					walkStmtList(sinit)
   250  				}
   251  				init.Append(sinit...)
   252  				continue
   253  			}
   254  
   255  		case ir.OARRAYLIT, ir.OSTRUCTLIT:
   256  			value := value.(*ir.CompLitExpr)
   257  			fixedlit(ctxt, kind, value, a, init)
   258  			continue
   259  		}
   260  
   261  		islit := ir.IsConstNode(value)
   262  		if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
   263  			continue
   264  		}
   265  
   266  		
   267  		ir.SetPos(a)
   268  		as := ir.NewAssignStmt(base.Pos, a, value)
   269  		as = typecheck.Stmt(as).(*ir.AssignStmt)
   270  		switch kind {
   271  		case initKindStatic:
   272  			genAsStatic(as)
   273  		case initKindDynamic, initKindLocalCode:
   274  			appendWalkStmt(init, orderStmtInPlace(as, map[string][]*ir.Name{}))
   275  		default:
   276  			base.Fatalf("fixedlit: bad kind %d", kind)
   277  		}
   278  
   279  	}
   280  }
   281  
   282  func isSmallSliceLit(n *ir.CompLitExpr) bool {
   283  	if n.Op() != ir.OSLICELIT {
   284  		return false
   285  	}
   286  
   287  	return n.Type().Elem().Size() == 0 || n.Len <= ir.MaxSmallArraySize/n.Type().Elem().Size()
   288  }
   289  
   290  func slicelit(ctxt initContext, n *ir.CompLitExpr, var_ ir.Node, init *ir.Nodes) {
   291  	
   292  	t := types.NewArray(n.Type().Elem(), n.Len)
   293  	types.CalcSize(t)
   294  
   295  	if ctxt == inNonInitFunction {
   296  		
   297  		vstat := staticinit.StaticName(t)
   298  
   299  		fixedlit(ctxt, initKindStatic, n, vstat, init)
   300  		fixedlit(ctxt, initKindDynamic, n, vstat, init)
   301  
   302  		
   303  		var_ = typecheck.AssignExpr(var_)
   304  		name, offset, ok := staticinit.StaticLoc(var_)
   305  		if !ok || name.Class != ir.PEXTERN {
   306  			base.Fatalf("slicelit: %v", var_)
   307  		}
   308  		staticdata.InitSlice(name, offset, vstat.Linksym(), t.NumElem())
   309  		return
   310  	}
   311  
   312  	
   313  	
   314  	
   315  	
   316  	
   317  	
   318  	
   319  	
   320  	
   321  	
   322  	
   323  	
   324  	
   325  	
   326  	
   327  	
   328  	
   329  	
   330  
   331  	
   332  	
   333  	var vstat ir.Node
   334  
   335  	mode := getdyn(n, true)
   336  	if mode&initConst != 0 && !isSmallSliceLit(n) {
   337  		if ctxt == inInitFunction {
   338  			vstat = readonlystaticname(t)
   339  		} else {
   340  			vstat = staticinit.StaticName(t)
   341  		}
   342  		fixedlit(ctxt, initKindStatic, n, vstat, init)
   343  	}
   344  
   345  	
   346  	vauto := typecheck.TempAt(base.Pos, ir.CurFunc, types.NewPtr(t))
   347  
   348  	
   349  	var a ir.Node
   350  	if x := n.Prealloc; x != nil {
   351  		
   352  		if !types.Identical(t, x.Type()) {
   353  			panic("dotdotdot base type does not match order's assigned type")
   354  		}
   355  		a = initStackTemp(init, x, vstat)
   356  	} else if n.Esc() == ir.EscNone {
   357  		a = initStackTemp(init, typecheck.TempAt(base.Pos, ir.CurFunc, t), vstat)
   358  	} else {
   359  		a = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(t))
   360  	}
   361  	appendWalkStmt(init, ir.NewAssignStmt(base.Pos, vauto, a))
   362  
   363  	if vstat != nil && n.Prealloc == nil && n.Esc() != ir.EscNone {
   364  		
   365  		
   366  		
   367  		a = ir.NewStarExpr(base.Pos, vauto)
   368  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, a, vstat))
   369  	}
   370  
   371  	
   372  	var index int64
   373  	for _, value := range n.List {
   374  		if value.Op() == ir.OKEY {
   375  			kv := value.(*ir.KeyExpr)
   376  			index = typecheck.IndexConst(kv.Key)
   377  			value = kv.Value
   378  		}
   379  		a := ir.NewIndexExpr(base.Pos, vauto, ir.NewInt(base.Pos, index))
   380  		a.SetBounded(true)
   381  		index++
   382  
   383  		
   384  
   385  		switch value.Op() {
   386  		case ir.OSLICELIT:
   387  			break
   388  
   389  		case ir.OARRAYLIT, ir.OSTRUCTLIT:
   390  			value := value.(*ir.CompLitExpr)
   391  			k := initKindDynamic
   392  			if vstat == nil {
   393  				
   394  				
   395  				k = initKindLocalCode
   396  			}
   397  			fixedlit(ctxt, k, value, a, init)
   398  			continue
   399  		}
   400  
   401  		if vstat != nil && ir.IsConstNode(value) { 
   402  			continue
   403  		}
   404  
   405  		
   406  		ir.SetPos(value)
   407  		as := ir.NewAssignStmt(base.Pos, a, value)
   408  		appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(as), map[string][]*ir.Name{}))
   409  	}
   410  
   411  	
   412  	a = ir.NewAssignStmt(base.Pos, var_, ir.NewSliceExpr(base.Pos, ir.OSLICE, vauto, nil, nil, nil))
   413  	appendWalkStmt(init, orderStmtInPlace(typecheck.Stmt(a), map[string][]*ir.Name{}))
   414  }
   415  
   416  func maplit(n *ir.CompLitExpr, m ir.Node, init *ir.Nodes) {
   417  	
   418  	args := []ir.Node{ir.TypeNode(n.Type()), ir.NewInt(base.Pos, n.Len+int64(len(n.List)))}
   419  	a := typecheck.Expr(ir.NewCallExpr(base.Pos, ir.OMAKE, nil, args)).(*ir.MakeExpr)
   420  	a.RType = n.RType
   421  	a.SetEsc(n.Esc())
   422  	appendWalkStmt(init, ir.NewAssignStmt(base.Pos, m, a))
   423  
   424  	entries := n.List
   425  
   426  	
   427  	
   428  	for _, r := range entries {
   429  		r := r.(*ir.KeyExpr)
   430  		if !isStaticCompositeLiteral(r.Key) || !isStaticCompositeLiteral(r.Value) {
   431  			base.Fatalf("maplit: entry is not a literal: %v", r)
   432  		}
   433  	}
   434  
   435  	if len(entries) > 25 {
   436  		
   437  
   438  		
   439  		tk := types.NewArray(n.Type().Key(), int64(len(entries)))
   440  		te := types.NewArray(n.Type().Elem(), int64(len(entries)))
   441  
   442  		
   443  		
   444  
   445  		types.CalcSize(tk)
   446  		types.CalcSize(te)
   447  
   448  		
   449  		vstatk := readonlystaticname(tk)
   450  		vstate := readonlystaticname(te)
   451  
   452  		datak := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
   453  		datae := ir.NewCompLitExpr(base.Pos, ir.OARRAYLIT, nil, nil)
   454  		for _, r := range entries {
   455  			r := r.(*ir.KeyExpr)
   456  			datak.List.Append(r.Key)
   457  			datae.List.Append(r.Value)
   458  		}
   459  		fixedlit(inInitFunction, initKindStatic, datak, vstatk, init)
   460  		fixedlit(inInitFunction, initKindStatic, datae, vstate, init)
   461  
   462  		
   463  		
   464  		
   465  		
   466  		i := typecheck.TempAt(base.Pos, ir.CurFunc, types.Types[types.TINT])
   467  		rhs := ir.NewIndexExpr(base.Pos, vstate, i)
   468  		rhs.SetBounded(true)
   469  
   470  		kidx := ir.NewIndexExpr(base.Pos, vstatk, i)
   471  		kidx.SetBounded(true)
   472  
   473  		
   474  		lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, kidx)).(*ir.IndexExpr)
   475  		base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
   476  		lhs.RType = n.RType
   477  
   478  		zero := ir.NewAssignStmt(base.Pos, i, ir.NewInt(base.Pos, 0))
   479  		cond := ir.NewBinaryExpr(base.Pos, ir.OLT, i, ir.NewInt(base.Pos, tk.NumElem()))
   480  		incr := ir.NewAssignStmt(base.Pos, i, ir.NewBinaryExpr(base.Pos, ir.OADD, i, ir.NewInt(base.Pos, 1)))
   481  
   482  		var body ir.Node = ir.NewAssignStmt(base.Pos, lhs, rhs)
   483  		body = typecheck.Stmt(body)
   484  		body = orderStmtInPlace(body, map[string][]*ir.Name{})
   485  
   486  		loop := ir.NewForStmt(base.Pos, nil, cond, incr, nil, false)
   487  		loop.Body = []ir.Node{body}
   488  		loop.SetInit([]ir.Node{zero})
   489  
   490  		appendWalkStmt(init, loop)
   491  		return
   492  	}
   493  	
   494  
   495  	
   496  	
   497  	
   498  	
   499  	tmpkey := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Key())
   500  	tmpelem := typecheck.TempAt(base.Pos, ir.CurFunc, m.Type().Elem())
   501  
   502  	for _, r := range entries {
   503  		r := r.(*ir.KeyExpr)
   504  		index, elem := r.Key, r.Value
   505  
   506  		ir.SetPos(index)
   507  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpkey, index))
   508  
   509  		ir.SetPos(elem)
   510  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, tmpelem, elem))
   511  
   512  		ir.SetPos(tmpelem)
   513  
   514  		
   515  		lhs := typecheck.AssignExpr(ir.NewIndexExpr(base.Pos, m, tmpkey)).(*ir.IndexExpr)
   516  		base.AssertfAt(lhs.Op() == ir.OINDEXMAP, lhs.Pos(), "want OINDEXMAP, have %+v", lhs)
   517  		lhs.RType = n.RType
   518  
   519  		var a ir.Node = ir.NewAssignStmt(base.Pos, lhs, tmpelem)
   520  		a = typecheck.Stmt(a)
   521  		a = orderStmtInPlace(a, map[string][]*ir.Name{})
   522  		appendWalkStmt(init, a)
   523  	}
   524  }
   525  
   526  func anylit(n ir.Node, var_ ir.Node, init *ir.Nodes) {
   527  	t := n.Type()
   528  	switch n.Op() {
   529  	default:
   530  		base.Fatalf("anylit: not lit, op=%v node=%v", n.Op(), n)
   531  
   532  	case ir.ONAME:
   533  		n := n.(*ir.Name)
   534  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, n))
   535  
   536  	case ir.OMETHEXPR:
   537  		n := n.(*ir.SelectorExpr)
   538  		anylit(n.FuncName(), var_, init)
   539  
   540  	case ir.OPTRLIT:
   541  		n := n.(*ir.AddrExpr)
   542  		if !t.IsPtr() {
   543  			base.Fatalf("anylit: not ptr")
   544  		}
   545  
   546  		var r ir.Node
   547  		if n.Prealloc != nil {
   548  			
   549  			r = initStackTemp(init, n.Prealloc, nil)
   550  		} else {
   551  			r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type()))
   552  			r.SetEsc(n.Esc())
   553  		}
   554  		appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, r))
   555  
   556  		var_ = ir.NewStarExpr(base.Pos, var_)
   557  		var_ = typecheck.AssignExpr(var_)
   558  		anylit(n.X, var_, init)
   559  
   560  	case ir.OSTRUCTLIT, ir.OARRAYLIT:
   561  		n := n.(*ir.CompLitExpr)
   562  		if !t.IsStruct() && !t.IsArray() {
   563  			base.Fatalf("anylit: not struct/array")
   564  		}
   565  
   566  		if isSimpleName(var_) && len(n.List) > 4 {
   567  			
   568  			vstat := readonlystaticname(t)
   569  
   570  			ctxt := inInitFunction
   571  			if n.Op() == ir.OARRAYLIT {
   572  				ctxt = inNonInitFunction
   573  			}
   574  			fixedlit(ctxt, initKindStatic, n, vstat, init)
   575  
   576  			
   577  			appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, vstat))
   578  
   579  			
   580  			fixedlit(inInitFunction, initKindDynamic, n, var_, init)
   581  			break
   582  		}
   583  
   584  		var components int64
   585  		if n.Op() == ir.OARRAYLIT {
   586  			components = t.NumElem()
   587  		} else {
   588  			components = int64(t.NumFields())
   589  		}
   590  		
   591  		if isSimpleName(var_) || int64(len(n.List)) < components {
   592  			appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil))
   593  		}
   594  
   595  		fixedlit(inInitFunction, initKindLocalCode, n, var_, init)
   596  
   597  	case ir.OSLICELIT:
   598  		n := n.(*ir.CompLitExpr)
   599  		slicelit(inInitFunction, n, var_, init)
   600  
   601  	case ir.OMAPLIT:
   602  		n := n.(*ir.CompLitExpr)
   603  		if !t.IsMap() {
   604  			base.Fatalf("anylit: not map")
   605  		}
   606  		maplit(n, var_, init)
   607  	}
   608  }
   609  
   610  
   611  
   612  
   613  func oaslit(n *ir.AssignStmt, init *ir.Nodes) bool {
   614  	if n.X == nil || n.Y == nil {
   615  		
   616  		return false
   617  	}
   618  	if n.X.Type() == nil || n.Y.Type() == nil {
   619  		
   620  		return false
   621  	}
   622  	if !isSimpleName(n.X) {
   623  		
   624  		return false
   625  	}
   626  	x := n.X.(*ir.Name)
   627  	if !types.Identical(n.X.Type(), n.Y.Type()) {
   628  		
   629  		return false
   630  	}
   631  	if x.Addrtaken() {
   632  		
   633  		
   634  		
   635  		return false
   636  	}
   637  
   638  	switch n.Y.Op() {
   639  	default:
   640  		
   641  		return false
   642  
   643  	case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT:
   644  		if ir.Any(n.Y, func(y ir.Node) bool { return ir.Uses(y, x) }) {
   645  			
   646  			return false
   647  		}
   648  		anylit(n.Y, n.X, init)
   649  	}
   650  
   651  	return true
   652  }
   653  
   654  func genAsStatic(as *ir.AssignStmt) {
   655  	if as.X.Type() == nil {
   656  		base.Fatalf("genAsStatic as.Left not typechecked")
   657  	}
   658  
   659  	name, offset, ok := staticinit.StaticLoc(as.X)
   660  	if !ok || (name.Class != ir.PEXTERN && as.X != ir.BlankNode) {
   661  		base.Fatalf("genAsStatic: lhs %v", as.X)
   662  	}
   663  
   664  	switch r := as.Y; r.Op() {
   665  	case ir.OLITERAL:
   666  		staticdata.InitConst(name, offset, r, int(r.Type().Size()))
   667  		return
   668  	case ir.OMETHEXPR:
   669  		r := r.(*ir.SelectorExpr)
   670  		staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r.FuncName()))
   671  		return
   672  	case ir.ONAME:
   673  		r := r.(*ir.Name)
   674  		if r.Offset_ != 0 {
   675  			base.Fatalf("genAsStatic %+v", as)
   676  		}
   677  		if r.Class == ir.PFUNC {
   678  			staticdata.InitAddr(name, offset, staticdata.FuncLinksym(r))
   679  			return
   680  		}
   681  	}
   682  	base.Fatalf("genAsStatic: rhs %v", as.Y)
   683  }
   684  
View as plain text