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