Home | History | Annotate | Download | only in gc
      1 // Copyright 2011 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/internal/obj"
      9 	"crypto/md5"
     10 	"fmt"
     11 	"strings"
     12 )
     13 
     14 // "Portable" code generation.
     15 
     16 var makefuncdatasym_nsym int32
     17 
     18 func makefuncdatasym(namefmt string, funcdatakind int64) *Sym {
     19 	var nod Node
     20 
     21 	sym := Lookupf(namefmt, makefuncdatasym_nsym)
     22 	makefuncdatasym_nsym++
     23 	pnod := newname(sym)
     24 	pnod.Class = PEXTERN
     25 	Nodconst(&nod, Types[TINT32], funcdatakind)
     26 	Thearch.Gins(obj.AFUNCDATA, &nod, pnod)
     27 	return sym
     28 }
     29 
     30 // gvardef inserts a VARDEF for n into the instruction stream.
     31 // VARDEF is an annotation for the liveness analysis, marking a place
     32 // where a complete initialization (definition) of a variable begins.
     33 // Since the liveness analysis can see initialization of single-word
     34 // variables quite easy, gvardef is usually only called for multi-word
     35 // or 'fat' variables, those satisfying isfat(n->type).
     36 // However, gvardef is also called when a non-fat variable is initialized
     37 // via a block move; the only time this happens is when you have
     38 //	return f()
     39 // for a function with multiple return values exactly matching the return
     40 // types of the current function.
     41 //
     42 // A 'VARDEF x' annotation in the instruction stream tells the liveness
     43 // analysis to behave as though the variable x is being initialized at that
     44 // point in the instruction stream. The VARDEF must appear before the
     45 // actual (multi-instruction) initialization, and it must also appear after
     46 // any uses of the previous value, if any. For example, if compiling:
     47 //
     48 //	x = x[1:]
     49 //
     50 // it is important to generate code like:
     51 //
     52 //	base, len, cap = pieces of x[1:]
     53 //	VARDEF x
     54 //	x = {base, len, cap}
     55 //
     56 // If instead the generated code looked like:
     57 //
     58 //	VARDEF x
     59 //	base, len, cap = pieces of x[1:]
     60 //	x = {base, len, cap}
     61 //
     62 // then the liveness analysis would decide the previous value of x was
     63 // unnecessary even though it is about to be used by the x[1:] computation.
     64 // Similarly, if the generated code looked like:
     65 //
     66 //	base, len, cap = pieces of x[1:]
     67 //	x = {base, len, cap}
     68 //	VARDEF x
     69 //
     70 // then the liveness analysis will not preserve the new value of x, because
     71 // the VARDEF appears to have "overwritten" it.
     72 //
     73 // VARDEF is a bit of a kludge to work around the fact that the instruction
     74 // stream is working on single-word values but the liveness analysis
     75 // wants to work on individual variables, which might be multi-word
     76 // aggregates. It might make sense at some point to look into letting
     77 // the liveness analysis work on single-word values as well, although
     78 // there are complications around interface values, slices, and strings,
     79 // all of which cannot be treated as individual words.
     80 //
     81 // VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
     82 // even if its address has been taken. That is, a VARKILL annotation asserts
     83 // that its argument is certainly dead, for use when the liveness analysis
     84 // would not otherwise be able to deduce that fact.
     85 
     86 func gvardefx(n *Node, as int) {
     87 	if n == nil {
     88 		Fatal("gvardef nil")
     89 	}
     90 	if n.Op != ONAME {
     91 		Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), n)
     92 		return
     93 	}
     94 
     95 	switch n.Class {
     96 	case PAUTO, PPARAM, PPARAMOUT:
     97 		Thearch.Gins(as, nil, n)
     98 	}
     99 }
    100 
    101 func Gvardef(n *Node) {
    102 	gvardefx(n, obj.AVARDEF)
    103 }
    104 
    105 func gvarkill(n *Node) {
    106 	gvardefx(n, obj.AVARKILL)
    107 }
    108 
    109 func removevardef(firstp *obj.Prog) {
    110 	for p := firstp; p != nil; p = p.Link {
    111 		for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL) {
    112 			p.Link = p.Link.Link
    113 		}
    114 		if p.To.Type == obj.TYPE_BRANCH {
    115 			for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL) {
    116 				p.To.Val = p.To.Val.(*obj.Prog).Link
    117 			}
    118 		}
    119 	}
    120 }
    121 
    122 func gcsymdup(s *Sym) {
    123 	ls := Linksym(s)
    124 	if len(ls.R) > 0 {
    125 		Fatal("cannot rosymdup %s with relocations", ls.Name)
    126 	}
    127 	ls.Name = fmt.Sprintf("gclocals%x", md5.Sum(ls.P))
    128 	ls.Dupok = 1
    129 }
    130 
    131 func emitptrargsmap() {
    132 	sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
    133 
    134 	nptr := int(Curfn.Type.Argwid / int64(Widthptr))
    135 	bv := bvalloc(int32(nptr) * 2)
    136 	nbitmap := 1
    137 	if Curfn.Type.Outtuple > 0 {
    138 		nbitmap = 2
    139 	}
    140 	off := duint32(sym, 0, uint32(nbitmap))
    141 	off = duint32(sym, off, uint32(bv.n))
    142 	var xoffset int64
    143 	if Curfn.Type.Thistuple > 0 {
    144 		xoffset = 0
    145 		onebitwalktype1(getthisx(Curfn.Type), &xoffset, bv)
    146 	}
    147 
    148 	if Curfn.Type.Intuple > 0 {
    149 		xoffset = 0
    150 		onebitwalktype1(getinargx(Curfn.Type), &xoffset, bv)
    151 	}
    152 
    153 	for j := 0; int32(j) < bv.n; j += 32 {
    154 		off = duint32(sym, off, bv.b[j/32])
    155 	}
    156 	if Curfn.Type.Outtuple > 0 {
    157 		xoffset = 0
    158 		onebitwalktype1(getoutargx(Curfn.Type), &xoffset, bv)
    159 		for j := 0; int32(j) < bv.n; j += 32 {
    160 			off = duint32(sym, off, bv.b[j/32])
    161 		}
    162 	}
    163 
    164 	ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
    165 }
    166 
    167 // Sort the list of stack variables. Autos after anything else,
    168 // within autos, unused after used, within used, things with
    169 // pointers first, zeroed things first, and then decreasing size.
    170 // Because autos are laid out in decreasing addresses
    171 // on the stack, pointers first, zeroed things first and decreasing size
    172 // really means, in memory, things with pointers needing zeroing at
    173 // the top of the stack and increasing in size.
    174 // Non-autos sort on offset.
    175 func cmpstackvar(a *Node, b *Node) int {
    176 	if a.Class != b.Class {
    177 		if a.Class == PAUTO {
    178 			return +1
    179 		}
    180 		return -1
    181 	}
    182 
    183 	if a.Class != PAUTO {
    184 		if a.Xoffset < b.Xoffset {
    185 			return -1
    186 		}
    187 		if a.Xoffset > b.Xoffset {
    188 			return +1
    189 		}
    190 		return 0
    191 	}
    192 
    193 	if a.Used != b.Used {
    194 		return obj.Bool2int(b.Used) - obj.Bool2int(a.Used)
    195 	}
    196 
    197 	ap := obj.Bool2int(haspointers(a.Type))
    198 	bp := obj.Bool2int(haspointers(b.Type))
    199 	if ap != bp {
    200 		return bp - ap
    201 	}
    202 
    203 	ap = obj.Bool2int(a.Name.Needzero)
    204 	bp = obj.Bool2int(b.Name.Needzero)
    205 	if ap != bp {
    206 		return bp - ap
    207 	}
    208 
    209 	if a.Type.Width < b.Type.Width {
    210 		return +1
    211 	}
    212 	if a.Type.Width > b.Type.Width {
    213 		return -1
    214 	}
    215 
    216 	return stringsCompare(a.Sym.Name, b.Sym.Name)
    217 }
    218 
    219 // stkdelta records the stack offset delta for a node
    220 // during the compaction of the stack frame to remove
    221 // unused stack slots.
    222 var stkdelta = map[*Node]int64{}
    223 
    224 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
    225 func allocauto(ptxt *obj.Prog) {
    226 	Stksize = 0
    227 	stkptrsize = 0
    228 
    229 	if Curfn.Func.Dcl == nil {
    230 		return
    231 	}
    232 
    233 	// Mark the PAUTO's unused.
    234 	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
    235 		if ll.N.Class == PAUTO {
    236 			ll.N.Used = false
    237 		}
    238 	}
    239 
    240 	markautoused(ptxt)
    241 
    242 	listsort(&Curfn.Func.Dcl, cmpstackvar)
    243 
    244 	// Unused autos are at the end, chop 'em off.
    245 	ll := Curfn.Func.Dcl
    246 
    247 	n := ll.N
    248 	if n.Class == PAUTO && n.Op == ONAME && !n.Used {
    249 		// No locals used at all
    250 		Curfn.Func.Dcl = nil
    251 
    252 		fixautoused(ptxt)
    253 		return
    254 	}
    255 
    256 	for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next {
    257 		n = ll.Next.N
    258 		if n.Class == PAUTO && n.Op == ONAME && !n.Used {
    259 			ll.Next = nil
    260 			Curfn.Func.Dcl.End = ll
    261 			break
    262 		}
    263 	}
    264 
    265 	// Reassign stack offsets of the locals that are still there.
    266 	var w int64
    267 	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
    268 		n = ll.N
    269 		if n.Class != PAUTO || n.Op != ONAME {
    270 			continue
    271 		}
    272 
    273 		dowidth(n.Type)
    274 		w = n.Type.Width
    275 		if w >= Thearch.MAXWIDTH || w < 0 {
    276 			Fatal("bad width")
    277 		}
    278 		Stksize += w
    279 		Stksize = Rnd(Stksize, int64(n.Type.Align))
    280 		if haspointers(n.Type) {
    281 			stkptrsize = Stksize
    282 		}
    283 		if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
    284 			Stksize = Rnd(Stksize, int64(Widthptr))
    285 		}
    286 		if Stksize >= 1<<31 {
    287 			setlineno(Curfn)
    288 			Yyerror("stack frame too large (>2GB)")
    289 		}
    290 
    291 		stkdelta[n] = -Stksize - n.Xoffset
    292 	}
    293 
    294 	Stksize = Rnd(Stksize, int64(Widthreg))
    295 	stkptrsize = Rnd(stkptrsize, int64(Widthreg))
    296 
    297 	fixautoused(ptxt)
    298 
    299 	// The debug information needs accurate offsets on the symbols.
    300 	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
    301 		if ll.N.Class != PAUTO || ll.N.Op != ONAME {
    302 			continue
    303 		}
    304 		ll.N.Xoffset += stkdelta[ll.N]
    305 		delete(stkdelta, ll.N)
    306 	}
    307 }
    308 
    309 func Cgen_checknil(n *Node) {
    310 	if Disable_checknil != 0 {
    311 		return
    312 	}
    313 
    314 	// Ideally we wouldn't see any integer types here, but we do.
    315 	if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) {
    316 		Dump("checknil", n)
    317 		Fatal("bad checknil")
    318 	}
    319 
    320 	if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
    321 		var reg Node
    322 		Regalloc(&reg, Types[Tptr], n)
    323 		Cgen(n, &reg)
    324 		Thearch.Gins(obj.ACHECKNIL, &reg, nil)
    325 		Regfree(&reg)
    326 		return
    327 	}
    328 
    329 	Thearch.Gins(obj.ACHECKNIL, n, nil)
    330 }
    331 
    332 func compile(fn *Node) {
    333 	if Newproc == nil {
    334 		Newproc = Sysfunc("newproc")
    335 		Deferproc = Sysfunc("deferproc")
    336 		Deferreturn = Sysfunc("deferreturn")
    337 		Panicindex = Sysfunc("panicindex")
    338 		panicslice = Sysfunc("panicslice")
    339 		throwreturn = Sysfunc("throwreturn")
    340 	}
    341 
    342 	lno := setlineno(fn)
    343 
    344 	Curfn = fn
    345 	dowidth(Curfn.Type)
    346 
    347 	var oldstksize int64
    348 	var nod1 Node
    349 	var ptxt *obj.Prog
    350 	var pl *obj.Plist
    351 	var p *obj.Prog
    352 	var n *Node
    353 	var nam *Node
    354 	var gcargs *Sym
    355 	var gclocals *Sym
    356 	if fn.Nbody == nil {
    357 		if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
    358 			Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
    359 			goto ret
    360 		}
    361 
    362 		if Debug['A'] != 0 {
    363 			goto ret
    364 		}
    365 		emitptrargsmap()
    366 		goto ret
    367 	}
    368 
    369 	saveerrors()
    370 
    371 	// set up domain for labels
    372 	clearlabels()
    373 
    374 	if Curfn.Type.Outnamed != 0 {
    375 		// add clearing of the output parameters
    376 		var save Iter
    377 		t := Structfirst(&save, Getoutarg(Curfn.Type))
    378 
    379 		for t != nil {
    380 			if t.Nname != nil {
    381 				n = Nod(OAS, t.Nname, nil)
    382 				typecheck(&n, Etop)
    383 				Curfn.Nbody = concat(list1(n), Curfn.Nbody)
    384 			}
    385 
    386 			t = structnext(&save)
    387 		}
    388 	}
    389 
    390 	order(Curfn)
    391 	if nerrors != 0 {
    392 		goto ret
    393 	}
    394 
    395 	Hasdefer = 0
    396 	walk(Curfn)
    397 	if nerrors != 0 {
    398 		goto ret
    399 	}
    400 	if flag_race != 0 {
    401 		racewalk(Curfn)
    402 	}
    403 	if nerrors != 0 {
    404 		goto ret
    405 	}
    406 
    407 	continpc = nil
    408 	breakpc = nil
    409 
    410 	pl = newplist()
    411 	pl.Name = Linksym(Curfn.Func.Nname.Sym)
    412 
    413 	setlineno(Curfn)
    414 
    415 	Nodconst(&nod1, Types[TINT32], 0)
    416 	nam = Curfn.Func.Nname
    417 	if isblank(nam) {
    418 		nam = nil
    419 	}
    420 	ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
    421 	Afunclit(&ptxt.From, Curfn.Func.Nname)
    422 	ptxt.From3 = new(obj.Addr)
    423 	if fn.Func.Dupok {
    424 		ptxt.From3.Offset |= obj.DUPOK
    425 	}
    426 	if fn.Func.Wrapper {
    427 		ptxt.From3.Offset |= obj.WRAPPER
    428 	}
    429 	if fn.Func.Needctxt {
    430 		ptxt.From3.Offset |= obj.NEEDCTXT
    431 	}
    432 	if fn.Func.Nosplit {
    433 		ptxt.From3.Offset |= obj.NOSPLIT
    434 	}
    435 	if fn.Func.Systemstack {
    436 		ptxt.From.Sym.Cfunc = 1
    437 	}
    438 
    439 	// Clumsy but important.
    440 	// See test/recover.go for test cases and src/reflect/value.go
    441 	// for the actual functions being considered.
    442 	if myimportpath != "" && myimportpath == "reflect" {
    443 		if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
    444 			ptxt.From3.Offset |= obj.WRAPPER
    445 		}
    446 	}
    447 
    448 	ginit()
    449 
    450 	gcargs = makefuncdatasym("gcargs%d", obj.FUNCDATA_ArgsPointerMaps)
    451 	gclocals = makefuncdatasym("gclocals%d", obj.FUNCDATA_LocalsPointerMaps)
    452 
    453 	for _, t := range Curfn.Func.Fieldtrack {
    454 		gtrack(tracksym(t))
    455 	}
    456 
    457 	for l := fn.Func.Dcl; l != nil; l = l.Next {
    458 		n = l.N
    459 		if n.Op != ONAME { // might be OTYPE or OLITERAL
    460 			continue
    461 		}
    462 		switch n.Class {
    463 		case PAUTO, PPARAM, PPARAMOUT:
    464 			Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width)
    465 			p = Thearch.Gins(obj.ATYPE, l.N, &nod1)
    466 			p.From.Gotype = Linksym(ngotype(l.N))
    467 		}
    468 	}
    469 
    470 	Genlist(Curfn.Func.Enter)
    471 	Genlist(Curfn.Nbody)
    472 	gclean()
    473 	checklabels()
    474 	if nerrors != 0 {
    475 		goto ret
    476 	}
    477 	if Curfn.Func.Endlineno != 0 {
    478 		lineno = Curfn.Func.Endlineno
    479 	}
    480 
    481 	if Curfn.Type.Outtuple != 0 {
    482 		Ginscall(throwreturn, 0)
    483 	}
    484 
    485 	ginit()
    486 
    487 	// TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
    488 	cgen_ret(nil)
    489 
    490 	if Hasdefer != 0 {
    491 		// deferreturn pretends to have one uintptr argument.
    492 		// Reserve space for it so stack scanner is happy.
    493 		if Maxarg < int64(Widthptr) {
    494 			Maxarg = int64(Widthptr)
    495 		}
    496 	}
    497 
    498 	gclean()
    499 	if nerrors != 0 {
    500 		goto ret
    501 	}
    502 
    503 	Pc.As = obj.ARET // overwrite AEND
    504 	Pc.Lineno = lineno
    505 
    506 	fixjmp(ptxt)
    507 	if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
    508 		regopt(ptxt)
    509 		nilopt(ptxt)
    510 	}
    511 
    512 	Thearch.Expandchecks(ptxt)
    513 
    514 	oldstksize = Stksize
    515 	allocauto(ptxt)
    516 
    517 	if false {
    518 		fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize))
    519 	}
    520 
    521 	setlineno(Curfn)
    522 	if int64(Stksize)+Maxarg > 1<<31 {
    523 		Yyerror("stack frame too large (>2GB)")
    524 		goto ret
    525 	}
    526 
    527 	// Emit garbage collection symbols.
    528 	liveness(Curfn, ptxt, gcargs, gclocals)
    529 
    530 	gcsymdup(gcargs)
    531 	gcsymdup(gclocals)
    532 
    533 	Thearch.Defframe(ptxt)
    534 
    535 	if Debug['f'] != 0 {
    536 		frame(0)
    537 	}
    538 
    539 	// Remove leftover instrumentation from the instruction stream.
    540 	removevardef(ptxt)
    541 
    542 ret:
    543 	lineno = lno
    544 }
    545