github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/src/cmd/compile/internal/gc/pgen.go (about) 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 Fatalf("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 Fatalf("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 // cmpstackvarlt reports whether the stack variable a sorts before b. 168 // 169 // Sort the list of stack variables. Autos after anything else, 170 // within autos, unused after used, within used, things with 171 // pointers first, zeroed things first, and then decreasing size. 172 // Because autos are laid out in decreasing addresses 173 // on the stack, pointers first, zeroed things first and decreasing size 174 // really means, in memory, things with pointers needing zeroing at 175 // the top of the stack and increasing in size. 176 // Non-autos sort on offset. 177 func cmpstackvarlt(a, b *Node) bool { 178 if a.Class != b.Class { 179 if a.Class == PAUTO { 180 return false 181 } 182 return true 183 } 184 185 if a.Class != PAUTO { 186 if a.Xoffset < b.Xoffset { 187 return true 188 } 189 if a.Xoffset > b.Xoffset { 190 return false 191 } 192 return false 193 } 194 195 if a.Used != b.Used { 196 return a.Used 197 } 198 199 ap := haspointers(a.Type) 200 bp := haspointers(b.Type) 201 if ap != bp { 202 return ap 203 } 204 205 ap = a.Name.Needzero 206 bp = b.Name.Needzero 207 if ap != bp { 208 return ap 209 } 210 211 if a.Type.Width < b.Type.Width { 212 return false 213 } 214 if a.Type.Width > b.Type.Width { 215 return true 216 } 217 218 return a.Sym.Name < b.Sym.Name 219 } 220 221 // stkdelta records the stack offset delta for a node 222 // during the compaction of the stack frame to remove 223 // unused stack slots. 224 var stkdelta = map[*Node]int64{} 225 226 // TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. 227 func allocauto(ptxt *obj.Prog) { 228 Stksize = 0 229 stkptrsize = 0 230 231 if Curfn.Func.Dcl == nil { 232 return 233 } 234 235 // Mark the PAUTO's unused. 236 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 237 if ll.N.Class == PAUTO { 238 ll.N.Used = false 239 } 240 } 241 242 markautoused(ptxt) 243 244 listsort(&Curfn.Func.Dcl, cmpstackvarlt) 245 246 // Unused autos are at the end, chop 'em off. 247 ll := Curfn.Func.Dcl 248 249 n := ll.N 250 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 251 // No locals used at all 252 Curfn.Func.Dcl = nil 253 254 fixautoused(ptxt) 255 return 256 } 257 258 for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next { 259 n = ll.Next.N 260 if n.Class == PAUTO && n.Op == ONAME && !n.Used { 261 ll.Next = nil 262 Curfn.Func.Dcl.End = ll 263 break 264 } 265 } 266 267 // Reassign stack offsets of the locals that are still there. 268 var w int64 269 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 270 n = ll.N 271 if n.Class != PAUTO || n.Op != ONAME { 272 continue 273 } 274 275 dowidth(n.Type) 276 w = n.Type.Width 277 if w >= Thearch.MAXWIDTH || w < 0 { 278 Fatalf("bad width") 279 } 280 Stksize += w 281 Stksize = Rnd(Stksize, int64(n.Type.Align)) 282 if haspointers(n.Type) { 283 stkptrsize = Stksize 284 } 285 if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' { 286 Stksize = Rnd(Stksize, int64(Widthptr)) 287 } 288 if Stksize >= 1<<31 { 289 setlineno(Curfn) 290 Yyerror("stack frame too large (>2GB)") 291 } 292 293 stkdelta[n] = -Stksize - n.Xoffset 294 } 295 296 Stksize = Rnd(Stksize, int64(Widthreg)) 297 stkptrsize = Rnd(stkptrsize, int64(Widthreg)) 298 299 fixautoused(ptxt) 300 301 // The debug information needs accurate offsets on the symbols. 302 for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next { 303 if ll.N.Class != PAUTO || ll.N.Op != ONAME { 304 continue 305 } 306 ll.N.Xoffset += stkdelta[ll.N] 307 delete(stkdelta, ll.N) 308 } 309 } 310 311 func Cgen_checknil(n *Node) { 312 if Disable_checknil != 0 { 313 return 314 } 315 316 // Ideally we wouldn't see any integer types here, but we do. 317 if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) { 318 Dump("checknil", n) 319 Fatalf("bad checknil") 320 } 321 322 if ((Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL { 323 var reg Node 324 Regalloc(®, Types[Tptr], n) 325 Cgen(n, ®) 326 Thearch.Gins(obj.ACHECKNIL, ®, nil) 327 Regfree(®) 328 return 329 } 330 331 Thearch.Gins(obj.ACHECKNIL, n, nil) 332 } 333 334 func compile(fn *Node) { 335 if Newproc == nil { 336 Newproc = Sysfunc("newproc") 337 Deferproc = Sysfunc("deferproc") 338 Deferreturn = Sysfunc("deferreturn") 339 Panicindex = Sysfunc("panicindex") 340 panicslice = Sysfunc("panicslice") 341 throwreturn = Sysfunc("throwreturn") 342 } 343 344 lno := setlineno(fn) 345 346 Curfn = fn 347 dowidth(Curfn.Type) 348 349 var oldstksize int64 350 var nod1 Node 351 var ptxt *obj.Prog 352 var pl *obj.Plist 353 var p *obj.Prog 354 var n *Node 355 var nam *Node 356 var gcargs *Sym 357 var gclocals *Sym 358 if fn.Nbody == nil { 359 if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") { 360 Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name) 361 goto ret 362 } 363 364 if Debug['A'] != 0 { 365 goto ret 366 } 367 emitptrargsmap() 368 goto ret 369 } 370 371 saveerrors() 372 373 // set up domain for labels 374 clearlabels() 375 376 if Curfn.Type.Outnamed { 377 // add clearing of the output parameters 378 var save Iter 379 t := Structfirst(&save, Getoutarg(Curfn.Type)) 380 381 for t != nil { 382 if t.Nname != nil { 383 n = Nod(OAS, t.Nname, nil) 384 typecheck(&n, Etop) 385 Curfn.Nbody = concat(list1(n), Curfn.Nbody) 386 } 387 388 t = structnext(&save) 389 } 390 } 391 392 order(Curfn) 393 if nerrors != 0 { 394 goto ret 395 } 396 397 hasdefer = false 398 walk(Curfn) 399 if nerrors != 0 { 400 goto ret 401 } 402 if flag_race != 0 { 403 racewalk(Curfn) 404 } 405 if nerrors != 0 { 406 goto ret 407 } 408 409 continpc = nil 410 breakpc = nil 411 412 pl = newplist() 413 pl.Name = Linksym(Curfn.Func.Nname.Sym) 414 415 setlineno(Curfn) 416 417 Nodconst(&nod1, Types[TINT32], 0) 418 nam = Curfn.Func.Nname 419 if isblank(nam) { 420 nam = nil 421 } 422 ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1) 423 Afunclit(&ptxt.From, Curfn.Func.Nname) 424 ptxt.From3 = new(obj.Addr) 425 if fn.Func.Dupok { 426 ptxt.From3.Offset |= obj.DUPOK 427 } 428 if fn.Func.Wrapper { 429 ptxt.From3.Offset |= obj.WRAPPER 430 } 431 if fn.Func.Needctxt { 432 ptxt.From3.Offset |= obj.NEEDCTXT 433 } 434 if fn.Func.Nosplit { 435 ptxt.From3.Offset |= obj.NOSPLIT 436 } 437 if fn.Func.Systemstack { 438 ptxt.From.Sym.Cfunc = 1 439 } 440 441 // Clumsy but important. 442 // See test/recover.go for test cases and src/reflect/value.go 443 // for the actual functions being considered. 444 if myimportpath != "" && myimportpath == "reflect" { 445 if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" { 446 ptxt.From3.Offset |= obj.WRAPPER 447 } 448 } 449 450 ginit() 451 452 gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps) 453 gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps) 454 455 for _, t := range Curfn.Func.Fieldtrack { 456 gtrack(tracksym(t)) 457 } 458 459 for l := fn.Func.Dcl; l != nil; l = l.Next { 460 n = l.N 461 if n.Op != ONAME { // might be OTYPE or OLITERAL 462 continue 463 } 464 switch n.Class { 465 case PAUTO, PPARAM, PPARAMOUT: 466 Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width) 467 p = Thearch.Gins(obj.ATYPE, l.N, &nod1) 468 p.From.Gotype = Linksym(ngotype(l.N)) 469 } 470 } 471 472 Genlist(Curfn.Func.Enter) 473 Genlist(Curfn.Nbody) 474 gclean() 475 checklabels() 476 if nerrors != 0 { 477 goto ret 478 } 479 if Curfn.Func.Endlineno != 0 { 480 lineno = Curfn.Func.Endlineno 481 } 482 483 if Curfn.Type.Outtuple != 0 { 484 Ginscall(throwreturn, 0) 485 } 486 487 ginit() 488 489 // TODO: Determine when the final cgen_ret can be omitted. Perhaps always? 490 cgen_ret(nil) 491 492 if hasdefer { 493 // deferreturn pretends to have one uintptr argument. 494 // Reserve space for it so stack scanner is happy. 495 if Maxarg < int64(Widthptr) { 496 Maxarg = int64(Widthptr) 497 } 498 } 499 500 gclean() 501 if nerrors != 0 { 502 goto ret 503 } 504 505 Pc.As = obj.ARET // overwrite AEND 506 Pc.Lineno = lineno 507 508 fixjmp(ptxt) 509 if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 { 510 regopt(ptxt) 511 nilopt(ptxt) 512 } 513 514 Thearch.Expandchecks(ptxt) 515 516 oldstksize = Stksize 517 allocauto(ptxt) 518 519 if false { 520 fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize)) 521 } 522 523 setlineno(Curfn) 524 if int64(Stksize)+Maxarg > 1<<31 { 525 Yyerror("stack frame too large (>2GB)") 526 goto ret 527 } 528 529 // Emit garbage collection symbols. 530 liveness(Curfn, ptxt, gcargs, gclocals) 531 532 gcsymdup(gcargs) 533 gcsymdup(gclocals) 534 535 Thearch.Defframe(ptxt) 536 537 if Debug['f'] != 0 { 538 frame(0) 539 } 540 541 // Remove leftover instrumentation from the instruction stream. 542 removevardef(ptxt) 543 544 ret: 545 lineno = lno 546 }