Source file src/cmd/compile/internal/gc/pgen.go

Documentation: cmd/compile/internal/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/compile/internal/ssa"
     9  	"cmd/compile/internal/types"
    10  	"cmd/internal/dwarf"
    11  	"cmd/internal/obj"
    12  	"cmd/internal/objabi"
    13  	"cmd/internal/src"
    14  	"cmd/internal/sys"
    15  	"fmt"
    16  	"internal/race"
    17  	"math/rand"
    18  	"sort"
    19  	"sync"
    20  	"time"
    21  )
    22  
    23  // "Portable" code generation.
    24  
    25  var (
    26  	nBackendWorkers int     // number of concurrent backend workers, set by a compiler flag
    27  	compilequeue    []*Node // functions waiting to be compiled
    28  )
    29  
    30  func emitptrargsmap(fn *Node) {
    31  	if fn.funcname() == "_" {
    32  		return
    33  	}
    34  	sym := lookup(fmt.Sprintf("%s.args_stackmap", fn.funcname()))
    35  	lsym := sym.Linksym()
    36  
    37  	nptr := int(fn.Type.ArgWidth() / int64(Widthptr))
    38  	bv := bvalloc(int32(nptr) * 2)
    39  	nbitmap := 1
    40  	if fn.Type.NumResults() > 0 {
    41  		nbitmap = 2
    42  	}
    43  	off := duint32(lsym, 0, uint32(nbitmap))
    44  	off = duint32(lsym, off, uint32(bv.n))
    45  
    46  	if fn.IsMethod() {
    47  		onebitwalktype1(fn.Type.Recvs(), 0, bv)
    48  	}
    49  	if fn.Type.NumParams() > 0 {
    50  		onebitwalktype1(fn.Type.Params(), 0, bv)
    51  	}
    52  	off = dbvec(lsym, off, bv)
    53  
    54  	if fn.Type.NumResults() > 0 {
    55  		onebitwalktype1(fn.Type.Results(), 0, bv)
    56  		off = dbvec(lsym, off, bv)
    57  	}
    58  
    59  	ggloblsym(lsym, int32(off), obj.RODATA|obj.LOCAL)
    60  }
    61  
    62  // cmpstackvarlt reports whether the stack variable a sorts before b.
    63  //
    64  // Sort the list of stack variables. Autos after anything else,
    65  // within autos, unused after used, within used, things with
    66  // pointers first, zeroed things first, and then decreasing size.
    67  // Because autos are laid out in decreasing addresses
    68  // on the stack, pointers first, zeroed things first and decreasing size
    69  // really means, in memory, things with pointers needing zeroing at
    70  // the top of the stack and increasing in size.
    71  // Non-autos sort on offset.
    72  func cmpstackvarlt(a, b *Node) bool {
    73  	if (a.Class() == PAUTO) != (b.Class() == PAUTO) {
    74  		return b.Class() == PAUTO
    75  	}
    76  
    77  	if a.Class() != PAUTO {
    78  		return a.Xoffset < b.Xoffset
    79  	}
    80  
    81  	if a.Name.Used() != b.Name.Used() {
    82  		return a.Name.Used()
    83  	}
    84  
    85  	ap := types.Haspointers(a.Type)
    86  	bp := types.Haspointers(b.Type)
    87  	if ap != bp {
    88  		return ap
    89  	}
    90  
    91  	ap = a.Name.Needzero()
    92  	bp = b.Name.Needzero()
    93  	if ap != bp {
    94  		return ap
    95  	}
    96  
    97  	if a.Type.Width != b.Type.Width {
    98  		return a.Type.Width > b.Type.Width
    99  	}
   100  
   101  	return a.Sym.Name < b.Sym.Name
   102  }
   103  
   104  // byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
   105  type byStackVar []*Node
   106  
   107  func (s byStackVar) Len() int           { return len(s) }
   108  func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
   109  func (s byStackVar) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   110  
   111  func (s *ssafn) AllocFrame(f *ssa.Func) {
   112  	s.stksize = 0
   113  	s.stkptrsize = 0
   114  	fn := s.curfn.Func
   115  
   116  	// Mark the PAUTO's unused.
   117  	for _, ln := range fn.Dcl {
   118  		if ln.Class() == PAUTO {
   119  			ln.Name.SetUsed(false)
   120  		}
   121  	}
   122  
   123  	for _, l := range f.RegAlloc {
   124  		if ls, ok := l.(ssa.LocalSlot); ok {
   125  			ls.N.(*Node).Name.SetUsed(true)
   126  		}
   127  	}
   128  
   129  	scratchUsed := false
   130  	for _, b := range f.Blocks {
   131  		for _, v := range b.Values {
   132  			if n, ok := v.Aux.(*Node); ok {
   133  				switch n.Class() {
   134  				case PPARAM, PPARAMOUT:
   135  					// Don't modify nodfp; it is a global.
   136  					if n != nodfp {
   137  						n.Name.SetUsed(true)
   138  					}
   139  				case PAUTO:
   140  					n.Name.SetUsed(true)
   141  				}
   142  			}
   143  			if !scratchUsed {
   144  				scratchUsed = v.Op.UsesScratch()
   145  			}
   146  
   147  		}
   148  	}
   149  
   150  	if f.Config.NeedsFpScratch && scratchUsed {
   151  		s.scratchFpMem = tempAt(src.NoXPos, s.curfn, types.Types[TUINT64])
   152  	}
   153  
   154  	sort.Sort(byStackVar(fn.Dcl))
   155  
   156  	// Reassign stack offsets of the locals that are used.
   157  	lastHasPtr := false
   158  	for i, n := range fn.Dcl {
   159  		if n.Op != ONAME || n.Class() != PAUTO {
   160  			continue
   161  		}
   162  		if !n.Name.Used() {
   163  			fn.Dcl = fn.Dcl[:i]
   164  			break
   165  		}
   166  
   167  		dowidth(n.Type)
   168  		w := n.Type.Width
   169  		if w >= thearch.MAXWIDTH || w < 0 {
   170  			Fatalf("bad width")
   171  		}
   172  		if w == 0 && lastHasPtr {
   173  			// Pad between a pointer-containing object and a zero-sized object.
   174  			// This prevents a pointer to the zero-sized object from being interpreted
   175  			// as a pointer to the pointer-containing object (and causing it
   176  			// to be scanned when it shouldn't be). See issue 24993.
   177  			w = 1
   178  		}
   179  		s.stksize += w
   180  		s.stksize = Rnd(s.stksize, int64(n.Type.Align))
   181  		if types.Haspointers(n.Type) {
   182  			s.stkptrsize = s.stksize
   183  			lastHasPtr = true
   184  		} else {
   185  			lastHasPtr = false
   186  		}
   187  		if thearch.LinkArch.InFamily(sys.MIPS, sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64, sys.S390X) {
   188  			s.stksize = Rnd(s.stksize, int64(Widthptr))
   189  		}
   190  		n.Xoffset = -s.stksize
   191  	}
   192  
   193  	s.stksize = Rnd(s.stksize, int64(Widthreg))
   194  	s.stkptrsize = Rnd(s.stkptrsize, int64(Widthreg))
   195  }
   196  
   197  func funccompile(fn *Node) {
   198  	if Curfn != nil {
   199  		Fatalf("funccompile %v inside %v", fn.Func.Nname.Sym, Curfn.Func.Nname.Sym)
   200  	}
   201  
   202  	if fn.Type == nil {
   203  		if nerrors == 0 {
   204  			Fatalf("funccompile missing type")
   205  		}
   206  		return
   207  	}
   208  
   209  	// assign parameter offsets
   210  	dowidth(fn.Type)
   211  
   212  	if fn.Nbody.Len() == 0 {
   213  		// Initialize ABI wrappers if necessary.
   214  		fn.Func.initLSym(false)
   215  		emitptrargsmap(fn)
   216  		return
   217  	}
   218  
   219  	dclcontext = PAUTO
   220  	Curfn = fn
   221  
   222  	compile(fn)
   223  
   224  	Curfn = nil
   225  	dclcontext = PEXTERN
   226  }
   227  
   228  func compile(fn *Node) {
   229  	saveerrors()
   230  
   231  	order(fn)
   232  	if nerrors != 0 {
   233  		return
   234  	}
   235  
   236  	walk(fn)
   237  	if nerrors != 0 {
   238  		return
   239  	}
   240  	if instrumenting {
   241  		instrument(fn)
   242  	}
   243  
   244  	// From this point, there should be no uses of Curfn. Enforce that.
   245  	Curfn = nil
   246  
   247  	if fn.funcname() == "_" {
   248  		// We don't need to generate code for this function, just report errors in its body.
   249  		// At this point we've generated any errors needed.
   250  		// (Beyond here we generate only non-spec errors, like "stack frame too large".)
   251  		// See issue 29870.
   252  		return
   253  	}
   254  
   255  	// Set up the function's LSym early to avoid data races with the assemblers.
   256  	fn.Func.initLSym(true)
   257  
   258  	// Make sure type syms are declared for all types that might
   259  	// be types of stack objects. We need to do this here
   260  	// because symbols must be allocated before the parallel
   261  	// phase of the compiler.
   262  	for _, n := range fn.Func.Dcl {
   263  		switch n.Class() {
   264  		case PPARAM, PPARAMOUT, PAUTO:
   265  			if livenessShouldTrack(n) && n.Name.Addrtaken() {
   266  				dtypesym(n.Type)
   267  				// Also make sure we allocate a linker symbol
   268  				// for the stack object data, for the same reason.
   269  				if fn.Func.lsym.Func.StackObjects == nil {
   270  					fn.Func.lsym.Func.StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
   271  				}
   272  			}
   273  		}
   274  	}
   275  
   276  	if compilenow() {
   277  		compileSSA(fn, 0)
   278  	} else {
   279  		compilequeue = append(compilequeue, fn)
   280  	}
   281  }
   282  
   283  // compilenow reports whether to compile immediately.
   284  // If functions are not compiled immediately,
   285  // they are enqueued in compilequeue,
   286  // which is drained by compileFunctions.
   287  func compilenow() bool {
   288  	return nBackendWorkers == 1 && Debug_compilelater == 0
   289  }
   290  
   291  const maxStackSize = 1 << 30
   292  
   293  // compileSSA builds an SSA backend function,
   294  // uses it to generate a plist,
   295  // and flushes that plist to machine code.
   296  // worker indicates which of the backend workers is doing the processing.
   297  func compileSSA(fn *Node, worker int) {
   298  	f := buildssa(fn, worker)
   299  	// Note: check arg size to fix issue 25507.
   300  	if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type.ArgWidth() >= maxStackSize {
   301  		largeStackFramesMu.Lock()
   302  		largeStackFrames = append(largeStackFrames, largeStack{locals: f.Frontend().(*ssafn).stksize, args: fn.Type.ArgWidth(), pos: fn.Pos})
   303  		largeStackFramesMu.Unlock()
   304  		return
   305  	}
   306  	pp := newProgs(fn, worker)
   307  	defer pp.Free()
   308  	genssa(f, pp)
   309  	// Check frame size again.
   310  	// The check above included only the space needed for local variables.
   311  	// After genssa, the space needed includes local variables and the callee arg region.
   312  	// We must do this check prior to calling pp.Flush.
   313  	// If there are any oversized stack frames,
   314  	// the assembler may emit inscrutable complaints about invalid instructions.
   315  	if pp.Text.To.Offset >= maxStackSize {
   316  		largeStackFramesMu.Lock()
   317  		locals := f.Frontend().(*ssafn).stksize
   318  		largeStackFrames = append(largeStackFrames, largeStack{locals: locals, args: fn.Type.ArgWidth(), callee: pp.Text.To.Offset - locals, pos: fn.Pos})
   319  		largeStackFramesMu.Unlock()
   320  		return
   321  	}
   322  
   323  	pp.Flush() // assemble, fill in boilerplate, etc.
   324  	// fieldtrack must be called after pp.Flush. See issue 20014.
   325  	fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack)
   326  }
   327  
   328  func init() {
   329  	if race.Enabled {
   330  		rand.Seed(time.Now().UnixNano())
   331  	}
   332  }
   333  
   334  // compileFunctions compiles all functions in compilequeue.
   335  // It fans out nBackendWorkers to do the work
   336  // and waits for them to complete.
   337  func compileFunctions() {
   338  	if len(compilequeue) != 0 {
   339  		sizeCalculationDisabled = true // not safe to calculate sizes concurrently
   340  		if race.Enabled {
   341  			// Randomize compilation order to try to shake out races.
   342  			tmp := make([]*Node, len(compilequeue))
   343  			perm := rand.Perm(len(compilequeue))
   344  			for i, v := range perm {
   345  				tmp[v] = compilequeue[i]
   346  			}
   347  			copy(compilequeue, tmp)
   348  		} else {
   349  			// Compile the longest functions first,
   350  			// since they're most likely to be the slowest.
   351  			// This helps avoid stragglers.
   352  			sort.Slice(compilequeue, func(i, j int) bool {
   353  				return compilequeue[i].Nbody.Len() > compilequeue[j].Nbody.Len()
   354  			})
   355  		}
   356  		var wg sync.WaitGroup
   357  		Ctxt.InParallel = true
   358  		c := make(chan *Node, nBackendWorkers)
   359  		for i := 0; i < nBackendWorkers; i++ {
   360  			wg.Add(1)
   361  			go func(worker int) {
   362  				for fn := range c {
   363  					compileSSA(fn, worker)
   364  				}
   365  				wg.Done()
   366  			}(i)
   367  		}
   368  		for _, fn := range compilequeue {
   369  			c <- fn
   370  		}
   371  		close(c)
   372  		compilequeue = nil
   373  		wg.Wait()
   374  		Ctxt.InParallel = false
   375  		sizeCalculationDisabled = false
   376  	}
   377  }
   378  
   379  func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) {
   380  	fn := curfn.(*Node)
   381  	if fn.Func.Nname != nil {
   382  		if expect := fn.Func.Nname.Sym.Linksym(); fnsym != expect {
   383  			Fatalf("unexpected fnsym: %v != %v", fnsym, expect)
   384  		}
   385  	}
   386  
   387  	var apdecls []*Node
   388  	// Populate decls for fn.
   389  	for _, n := range fn.Func.Dcl {
   390  		if n.Op != ONAME { // might be OTYPE or OLITERAL
   391  			continue
   392  		}
   393  		switch n.Class() {
   394  		case PAUTO:
   395  			if !n.Name.Used() {
   396  				// Text == nil -> generating abstract function
   397  				if fnsym.Func.Text != nil {
   398  					Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
   399  				}
   400  				continue
   401  			}
   402  		case PPARAM, PPARAMOUT:
   403  		default:
   404  			continue
   405  		}
   406  		apdecls = append(apdecls, n)
   407  		fnsym.Func.RecordAutoType(ngotype(n).Linksym())
   408  	}
   409  
   410  	decls, dwarfVars := createDwarfVars(fnsym, fn.Func, apdecls)
   411  
   412  	// For each type referenced by the functions auto vars, attach a
   413  	// dummy relocation to the function symbol to insure that the type
   414  	// included in DWARF processing during linking.
   415  	typesyms := []*obj.LSym{}
   416  	for t, _ := range fnsym.Func.Autot {
   417  		typesyms = append(typesyms, t)
   418  	}
   419  	sort.Sort(obj.BySymName(typesyms))
   420  	for _, sym := range typesyms {
   421  		r := obj.Addrel(infosym)
   422  		r.Sym = sym
   423  		r.Type = objabi.R_USETYPE
   424  	}
   425  	fnsym.Func.Autot = nil
   426  
   427  	var varScopes []ScopeID
   428  	for _, decl := range decls {
   429  		pos := decl.Pos
   430  		if decl.Name.Defn != nil && (decl.Name.Captured() || decl.Name.Byval()) {
   431  			// It's not clear which position is correct for captured variables here:
   432  			// * decl.Pos is the wrong position for captured variables, in the inner
   433  			//   function, but it is the right position in the outer function.
   434  			// * decl.Name.Defn is nil for captured variables that were arguments
   435  			//   on the outer function, however the decl.Pos for those seems to be
   436  			//   correct.
   437  			// * decl.Name.Defn is the "wrong" thing for variables declared in the
   438  			//   header of a type switch, it's their position in the header, rather
   439  			//   than the position of the case statement. In principle this is the
   440  			//   right thing, but here we prefer the latter because it makes each
   441  			//   instance of the header variable local to the lexical block of its
   442  			//   case statement.
   443  			// This code is probably wrong for type switch variables that are also
   444  			// captured.
   445  			pos = decl.Name.Defn.Pos
   446  		}
   447  		varScopes = append(varScopes, findScope(fn.Func.Marks, pos))
   448  	}
   449  
   450  	scopes := assembleScopes(fnsym, fn, dwarfVars, varScopes)
   451  	var inlcalls dwarf.InlCalls
   452  	if genDwarfInline > 0 {
   453  		inlcalls = assembleInlines(fnsym, dwarfVars)
   454  	}
   455  	return scopes, inlcalls
   456  }
   457  
   458  // createSimpleVars creates a DWARF entry for every variable declared in the
   459  // function, claiming that they are permanently on the stack.
   460  func createSimpleVars(apDecls []*Node) ([]*Node, []*dwarf.Var, map[*Node]bool) {
   461  	var vars []*dwarf.Var
   462  	var decls []*Node
   463  	selected := make(map[*Node]bool)
   464  	for _, n := range apDecls {
   465  		if n.IsAutoTmp() {
   466  			continue
   467  		}
   468  
   469  		decls = append(decls, n)
   470  		vars = append(vars, createSimpleVar(n))
   471  		selected[n] = true
   472  	}
   473  	return decls, vars, selected
   474  }
   475  
   476  func createSimpleVar(n *Node) *dwarf.Var {
   477  	var abbrev int
   478  	offs := n.Xoffset
   479  
   480  	switch n.Class() {
   481  	case PAUTO:
   482  		abbrev = dwarf.DW_ABRV_AUTO
   483  		if Ctxt.FixedFrameSize() == 0 {
   484  			offs -= int64(Widthptr)
   485  		}
   486  		if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" {
   487  			// There is a word space for FP on ARM64 even if the frame pointer is disabled
   488  			offs -= int64(Widthptr)
   489  		}
   490  
   491  	case PPARAM, PPARAMOUT:
   492  		abbrev = dwarf.DW_ABRV_PARAM
   493  		offs += Ctxt.FixedFrameSize()
   494  	default:
   495  		Fatalf("createSimpleVar unexpected class %v for node %v", n.Class(), n)
   496  	}
   497  
   498  	typename := dwarf.InfoPrefix + typesymname(n.Type)
   499  	inlIndex := 0
   500  	if genDwarfInline > 1 {
   501  		if n.Name.InlFormal() || n.Name.InlLocal() {
   502  			inlIndex = posInlIndex(n.Pos) + 1
   503  			if n.Name.InlFormal() {
   504  				abbrev = dwarf.DW_ABRV_PARAM
   505  			}
   506  		}
   507  	}
   508  	declpos := Ctxt.InnermostPos(n.Pos)
   509  	return &dwarf.Var{
   510  		Name:          n.Sym.Name,
   511  		IsReturnValue: n.Class() == PPARAMOUT,
   512  		IsInlFormal:   n.Name.InlFormal(),
   513  		Abbrev:        abbrev,
   514  		StackOffset:   int32(offs),
   515  		Type:          Ctxt.Lookup(typename),
   516  		DeclFile:      declpos.RelFilename(),
   517  		DeclLine:      declpos.RelLine(),
   518  		DeclCol:       declpos.Col(),
   519  		InlIndex:      int32(inlIndex),
   520  		ChildIndex:    -1,
   521  	}
   522  }
   523  
   524  // createComplexVars creates recomposed DWARF vars with location lists,
   525  // suitable for describing optimized code.
   526  func createComplexVars(fn *Func) ([]*Node, []*dwarf.Var, map[*Node]bool) {
   527  	debugInfo := fn.DebugInfo
   528  
   529  	// Produce a DWARF variable entry for each user variable.
   530  	var decls []*Node
   531  	var vars []*dwarf.Var
   532  	ssaVars := make(map[*Node]bool)
   533  
   534  	for varID, dvar := range debugInfo.Vars {
   535  		n := dvar.(*Node)
   536  		ssaVars[n] = true
   537  		for _, slot := range debugInfo.VarSlots[varID] {
   538  			ssaVars[debugInfo.Slots[slot].N.(*Node)] = true
   539  		}
   540  
   541  		if dvar := createComplexVar(fn, ssa.VarID(varID)); dvar != nil {
   542  			decls = append(decls, n)
   543  			vars = append(vars, dvar)
   544  		}
   545  	}
   546  
   547  	return decls, vars, ssaVars
   548  }
   549  
   550  // createDwarfVars process fn, returning a list of DWARF variables and the
   551  // Nodes they represent.
   552  func createDwarfVars(fnsym *obj.LSym, fn *Func, apDecls []*Node) ([]*Node, []*dwarf.Var) {
   553  	// Collect a raw list of DWARF vars.
   554  	var vars []*dwarf.Var
   555  	var decls []*Node
   556  	var selected map[*Node]bool
   557  	if Ctxt.Flag_locationlists && Ctxt.Flag_optimize && fn.DebugInfo != nil {
   558  		decls, vars, selected = createComplexVars(fn)
   559  	} else {
   560  		decls, vars, selected = createSimpleVars(apDecls)
   561  	}
   562  
   563  	dcl := apDecls
   564  	if fnsym.WasInlined() {
   565  		dcl = preInliningDcls(fnsym)
   566  	}
   567  
   568  	// If optimization is enabled, the list above will typically be
   569  	// missing some of the original pre-optimization variables in the
   570  	// function (they may have been promoted to registers, folded into
   571  	// constants, dead-coded away, etc).  Input arguments not eligible
   572  	// for SSA optimization are also missing.  Here we add back in entries
   573  	// for selected missing vars. Note that the recipe below creates a
   574  	// conservative location. The idea here is that we want to
   575  	// communicate to the user that "yes, there is a variable named X
   576  	// in this function, but no, I don't have enough information to
   577  	// reliably report its contents."
   578  	// For non-SSA-able arguments, however, the correct information
   579  	// is known -- they have a single home on the stack.
   580  	for _, n := range dcl {
   581  		if _, found := selected[n]; found {
   582  			continue
   583  		}
   584  		c := n.Sym.Name[0]
   585  		if c == '.' || n.Type.IsUntyped() {
   586  			continue
   587  		}
   588  		if n.Class() == PPARAM && !canSSAType(n.Type) {
   589  			// SSA-able args get location lists, and may move in and
   590  			// out of registers, so those are handled elsewhere.
   591  			// Autos and named output params seem to get handled
   592  			// with VARDEF, which creates location lists.
   593  			// Args not of SSA-able type are treated here; they
   594  			// are homed on the stack in a single place for the
   595  			// entire call.
   596  			vars = append(vars, createSimpleVar(n))
   597  			decls = append(decls, n)
   598  			continue
   599  		}
   600  		typename := dwarf.InfoPrefix + typesymname(n.Type)
   601  		decls = append(decls, n)
   602  		abbrev := dwarf.DW_ABRV_AUTO_LOCLIST
   603  		isReturnValue := (n.Class() == PPARAMOUT)
   604  		if n.Class() == PPARAM || n.Class() == PPARAMOUT {
   605  			abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   606  		} else if n.Class() == PAUTOHEAP {
   607  			// If dcl in question has been promoted to heap, do a bit
   608  			// of extra work to recover original class (auto or param);
   609  			// see issue 30908. This insures that we get the proper
   610  			// signature in the abstract function DIE, but leaves a
   611  			// misleading location for the param (we want pointer-to-heap
   612  			// and not stack).
   613  			// TODO(thanm): generate a better location expression
   614  			stackcopy := n.Name.Param.Stackcopy
   615  			if stackcopy != nil && (stackcopy.Class() == PPARAM || stackcopy.Class() == PPARAMOUT) {
   616  				abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   617  				isReturnValue = (stackcopy.Class() == PPARAMOUT)
   618  			}
   619  		}
   620  		inlIndex := 0
   621  		if genDwarfInline > 1 {
   622  			if n.Name.InlFormal() || n.Name.InlLocal() {
   623  				inlIndex = posInlIndex(n.Pos) + 1
   624  				if n.Name.InlFormal() {
   625  					abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   626  				}
   627  			}
   628  		}
   629  		declpos := Ctxt.InnermostPos(n.Pos)
   630  		vars = append(vars, &dwarf.Var{
   631  			Name:          n.Sym.Name,
   632  			IsReturnValue: isReturnValue,
   633  			Abbrev:        abbrev,
   634  			StackOffset:   int32(n.Xoffset),
   635  			Type:          Ctxt.Lookup(typename),
   636  			DeclFile:      declpos.RelFilename(),
   637  			DeclLine:      declpos.RelLine(),
   638  			DeclCol:       declpos.Col(),
   639  			InlIndex:      int32(inlIndex),
   640  			ChildIndex:    -1,
   641  		})
   642  		// Record go type of to insure that it gets emitted by the linker.
   643  		fnsym.Func.RecordAutoType(ngotype(n).Linksym())
   644  	}
   645  
   646  	return decls, vars
   647  }
   648  
   649  // Given a function that was inlined at some point during the
   650  // compilation, return a sorted list of nodes corresponding to the
   651  // autos/locals in that function prior to inlining. If this is a
   652  // function that is not local to the package being compiled, then the
   653  // names of the variables may have been "versioned" to avoid conflicts
   654  // with local vars; disregard this versioning when sorting.
   655  func preInliningDcls(fnsym *obj.LSym) []*Node {
   656  	fn := Ctxt.DwFixups.GetPrecursorFunc(fnsym).(*Node)
   657  	var rdcl []*Node
   658  	for _, n := range fn.Func.Inl.Dcl {
   659  		c := n.Sym.Name[0]
   660  		// Avoid reporting "_" parameters, since if there are more than
   661  		// one, it can result in a collision later on, as in #23179.
   662  		if unversion(n.Sym.Name) == "_" || c == '.' || n.Type.IsUntyped() {
   663  			continue
   664  		}
   665  		rdcl = append(rdcl, n)
   666  	}
   667  	return rdcl
   668  }
   669  
   670  // stackOffset returns the stack location of a LocalSlot relative to the
   671  // stack pointer, suitable for use in a DWARF location entry. This has nothing
   672  // to do with its offset in the user variable.
   673  func stackOffset(slot ssa.LocalSlot) int32 {
   674  	n := slot.N.(*Node)
   675  	var base int64
   676  	switch n.Class() {
   677  	case PAUTO:
   678  		if Ctxt.FixedFrameSize() == 0 {
   679  			base -= int64(Widthptr)
   680  		}
   681  		if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" {
   682  			// There is a word space for FP on ARM64 even if the frame pointer is disabled
   683  			base -= int64(Widthptr)
   684  		}
   685  	case PPARAM, PPARAMOUT:
   686  		base += Ctxt.FixedFrameSize()
   687  	}
   688  	return int32(base + n.Xoffset + slot.Off)
   689  }
   690  
   691  // createComplexVar builds a single DWARF variable entry and location list.
   692  func createComplexVar(fn *Func, varID ssa.VarID) *dwarf.Var {
   693  	debug := fn.DebugInfo
   694  	n := debug.Vars[varID].(*Node)
   695  
   696  	var abbrev int
   697  	switch n.Class() {
   698  	case PAUTO:
   699  		abbrev = dwarf.DW_ABRV_AUTO_LOCLIST
   700  	case PPARAM, PPARAMOUT:
   701  		abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   702  	default:
   703  		return nil
   704  	}
   705  
   706  	gotype := ngotype(n).Linksym()
   707  	typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
   708  	inlIndex := 0
   709  	if genDwarfInline > 1 {
   710  		if n.Name.InlFormal() || n.Name.InlLocal() {
   711  			inlIndex = posInlIndex(n.Pos) + 1
   712  			if n.Name.InlFormal() {
   713  				abbrev = dwarf.DW_ABRV_PARAM_LOCLIST
   714  			}
   715  		}
   716  	}
   717  	declpos := Ctxt.InnermostPos(n.Pos)
   718  	dvar := &dwarf.Var{
   719  		Name:          n.Sym.Name,
   720  		IsReturnValue: n.Class() == PPARAMOUT,
   721  		IsInlFormal:   n.Name.InlFormal(),
   722  		Abbrev:        abbrev,
   723  		Type:          Ctxt.Lookup(typename),
   724  		// The stack offset is used as a sorting key, so for decomposed
   725  		// variables just give it the first one. It's not used otherwise.
   726  		// This won't work well if the first slot hasn't been assigned a stack
   727  		// location, but it's not obvious how to do better.
   728  		StackOffset: stackOffset(debug.Slots[debug.VarSlots[varID][0]]),
   729  		DeclFile:    declpos.RelFilename(),
   730  		DeclLine:    declpos.RelLine(),
   731  		DeclCol:     declpos.Col(),
   732  		InlIndex:    int32(inlIndex),
   733  		ChildIndex:  -1,
   734  	}
   735  	list := debug.LocationLists[varID]
   736  	if len(list) != 0 {
   737  		dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
   738  			debug.PutLocationList(list, Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
   739  		}
   740  	}
   741  	return dvar
   742  }
   743  
   744  // fieldtrack adds R_USEFIELD relocations to fnsym to record any
   745  // struct fields that it used.
   746  func fieldtrack(fnsym *obj.LSym, tracked map[*types.Sym]struct{}) {
   747  	if fnsym == nil {
   748  		return
   749  	}
   750  	if objabi.Fieldtrack_enabled == 0 || len(tracked) == 0 {
   751  		return
   752  	}
   753  
   754  	trackSyms := make([]*types.Sym, 0, len(tracked))
   755  	for sym := range tracked {
   756  		trackSyms = append(trackSyms, sym)
   757  	}
   758  	sort.Sort(symByName(trackSyms))
   759  	for _, sym := range trackSyms {
   760  		r := obj.Addrel(fnsym)
   761  		r.Sym = sym.Linksym()
   762  		r.Type = objabi.R_USEFIELD
   763  	}
   764  }
   765  
   766  type symByName []*types.Sym
   767  
   768  func (a symByName) Len() int           { return len(a) }
   769  func (a symByName) Less(i, j int) bool { return a[i].Name < a[j].Name }
   770  func (a symByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   771  

View as plain text