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