mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: mark DIEs of captured variables
Adds a new custom attribute to the DIE of captured variables,
containing the offset for the variable inside the closure struct. This
can be used by debuggers to display the contents of a closure variable.
Based on a sample program (delve) this increases the executable size by 0.06%.
benchstat output:
│ old.txt │ new.txt │
│ sec/op │ sec/op vs base │
Template 153.0m ± 6% 152.5m ± 14% ~ (p=0.684 n=10)
Unicode 100.2m ± 15% 104.9m ± 7% ~ (p=0.247 n=10)
GoTypes 943.6m ± 8% 986.2m ± 10% ~ (p=0.280 n=10)
Compiler 97.79m ± 6% 101.63m ± 12% ~ (p=0.393 n=10)
SSA 6.872 ± 37% 9.413 ± 106% ~ (p=0.190 n=10)
Flate 128.0m ± 36% 125.0m ± 56% ~ (p=0.481 n=10)
GoParser 214.9m ± 26% 201.4m ± 68% ~ (p=0.579 n=10)
Reflect 452.6m ± 22% 412.2m ± 74% ~ (p=0.739 n=10)
Tar 166.2m ± 27% 155.9m ± 73% ~ (p=0.393 n=10)
XML 219.3m ± 24% 211.3m ± 76% ~ (p=0.739 n=10)
LinkCompiler 523.2m ± 13% 513.5m ± 47% ~ (p=0.631 n=10)
ExternalLinkCompiler 1.684 ± 2% 1.659 ± 25% ~ (p=0.218 n=10)
LinkWithoutDebugCompiler 304.9m ± 12% 309.1m ± 7% ~ (p=0.631 n=10)
StdCmd 70.76 ± 14% 68.66 ± 53% ~ (p=1.000 n=10)
geomean 511.5m 515.4m +0.77%
│ old.txt │ new.txt │
│ user-sec/op │ user-sec/op vs base │
Template 269.6m ± 13% 292.3m ± 17% ~ (p=0.393 n=10)
Unicode 110.2m ± 8% 101.7m ± 18% ~ (p=0.247 n=10)
GoTypes 2.181 ± 9% 2.356 ± 12% ~ (p=0.280 n=10)
Compiler 119.1m ± 11% 121.9m ± 15% ~ (p=0.481 n=10)
SSA 17.75 ± 52% 26.94 ± 123% ~ (p=0.190 n=10)
Flate 256.2m ± 43% 226.8m ± 73% ~ (p=0.739 n=10)
GoParser 427.0m ± 24% 422.3m ± 72% ~ (p=0.529 n=10)
Reflect 990.5m ± 23% 905.5m ± 75% ~ (p=0.912 n=10)
Tar 307.9m ± 27% 308.9m ± 64% ~ (p=0.393 n=10)
XML 432.8m ± 24% 427.6m ± 89% ~ (p=0.796 n=10)
LinkCompiler 796.9m ± 14% 800.4m ± 56% ~ (p=0.481 n=10)
ExternalLinkCompiler 1.666 ± 4% 1.671 ± 28% ~ (p=0.971 n=10)
LinkWithoutDebugCompiler 316.7m ± 12% 325.6m ± 8% ~ (p=0.579 n=10)
geomean 579.5m 594.0m +2.51%
│ old.txt │ new.txt │
│ text-bytes │ text-bytes vs base │
HelloSize 842.9Ki ± 0% 842.9Ki ± 0% ~ (p=1.000 n=10) ¹
CmdGoSize 10.95Mi ± 0% 10.95Mi ± 0% ~ (p=1.000 n=10) ¹
geomean 3.003Mi 3.003Mi +0.00%
¹ all samples are equal
│ old.txt │ new.txt │
│ data-bytes │ data-bytes vs base │
HelloSize 15.08Ki ± 0% 15.08Ki ± 0% ~ (p=1.000 n=10) ¹
CmdGoSize 314.7Ki ± 0% 314.7Ki ± 0% ~ (p=1.000 n=10) ¹
geomean 68.88Ki 68.88Ki +0.00%
¹ all samples are equal
│ old.txt │ new.txt │
│ bss-bytes │ bss-bytes vs base │
HelloSize 396.8Ki ± 0% 396.8Ki ± 0% ~ (p=1.000 n=10) ¹
CmdGoSize 428.8Ki ± 0% 428.8Ki ± 0% ~ (p=1.000 n=10) ¹
geomean 412.5Ki 412.5Ki +0.00%
¹ all samples are equal
│ old.txt │ new.txt │
│ exe-bytes │ exe-bytes vs base │
HelloSize 1.310Mi ± 0% 1.310Mi ± 0% +0.02% (p=0.000 n=10)
CmdGoSize 16.37Mi ± 0% 16.38Mi ± 0% +0.01% (p=0.000 n=10)
geomean 4.631Mi 4.632Mi +0.02%
Change-Id: Ib416ee2d916ec61ad4a5c26bab09597595f57e04
Reviewed-on: https://go-review.googlesource.com/c/go/+/563816
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
e8b5bc63be
commit
f048829d70
5 changed files with 172 additions and 45 deletions
|
|
@ -16,6 +16,7 @@ import (
|
|||
"cmd/compile/internal/reflectdata"
|
||||
"cmd/compile/internal/ssa"
|
||||
"cmd/compile/internal/ssagen"
|
||||
"cmd/compile/internal/typecheck"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/dwarf"
|
||||
"cmd/internal/obj"
|
||||
|
|
@ -100,7 +101,23 @@ func Info(fnsym *obj.LSym, infosym *obj.LSym, curfn obj.Func) (scopes []dwarf.Sc
|
|||
}
|
||||
}
|
||||
|
||||
decls, dwarfVars := createDwarfVars(fnsym, isODCLFUNC, fn, apdecls)
|
||||
var closureVars map[*ir.Name]int64
|
||||
if fn.Needctxt() {
|
||||
closureVars = make(map[*ir.Name]int64)
|
||||
csiter := typecheck.NewClosureStructIter(fn.ClosureVars)
|
||||
for {
|
||||
n, _, offset := csiter.Next()
|
||||
if n == nil {
|
||||
break
|
||||
}
|
||||
closureVars[n] = offset
|
||||
if n.Heapaddr != nil {
|
||||
closureVars[n.Heapaddr] = offset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
decls, dwarfVars := createDwarfVars(fnsym, isODCLFUNC, fn, apdecls, closureVars)
|
||||
|
||||
// For each type referenced by the functions auto vars but not
|
||||
// already referenced by a dwarf var, attach an R_USETYPE relocation to
|
||||
|
|
@ -137,18 +154,18 @@ func declPos(decl *ir.Name) src.XPos {
|
|||
|
||||
// createDwarfVars process fn, returning a list of DWARF variables and the
|
||||
// Nodes they represent.
|
||||
func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir.Name) ([]*ir.Name, []*dwarf.Var) {
|
||||
func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var) {
|
||||
// Collect a raw list of DWARF vars.
|
||||
var vars []*dwarf.Var
|
||||
var decls []*ir.Name
|
||||
var selected ir.NameSet
|
||||
|
||||
if base.Ctxt.Flag_locationlists && base.Ctxt.Flag_optimize && fn.DebugInfo != nil && complexOK {
|
||||
decls, vars, selected = createComplexVars(fnsym, fn)
|
||||
decls, vars, selected = createComplexVars(fnsym, fn, closureVars)
|
||||
} else if fn.ABI == obj.ABIInternal && base.Flag.N != 0 && complexOK {
|
||||
decls, vars, selected = createABIVars(fnsym, fn, apDecls)
|
||||
decls, vars, selected = createABIVars(fnsym, fn, apDecls, closureVars)
|
||||
} else {
|
||||
decls, vars, selected = createSimpleVars(fnsym, apDecls)
|
||||
decls, vars, selected = createSimpleVars(fnsym, apDecls, closureVars)
|
||||
}
|
||||
if fn.DebugInfo != nil {
|
||||
// Recover zero sized variables eliminated by the stackframe pass
|
||||
|
|
@ -159,7 +176,7 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
|
|||
types.CalcSize(n.Type())
|
||||
if n.Type().Size() == 0 {
|
||||
decls = append(decls, n)
|
||||
vars = append(vars, createSimpleVar(fnsym, n))
|
||||
vars = append(vars, createSimpleVar(fnsym, n, closureVars))
|
||||
vars[len(vars)-1].StackOffset = 0
|
||||
fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
|
||||
}
|
||||
|
|
@ -212,7 +229,7 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
|
|||
// Args not of SSA-able type are treated here; they
|
||||
// are homed on the stack in a single place for the
|
||||
// entire call.
|
||||
vars = append(vars, createSimpleVar(fnsym, n))
|
||||
vars = append(vars, createSimpleVar(fnsym, n, closureVars))
|
||||
decls = append(decls, n)
|
||||
continue
|
||||
}
|
||||
|
|
@ -251,6 +268,7 @@ func createDwarfVars(fnsym *obj.LSym, complexOK bool, fn *ir.Func, apDecls []*ir
|
|||
InlIndex: int32(inlIndex),
|
||||
ChildIndex: -1,
|
||||
DictIndex: n.DictIndex,
|
||||
ClosureOffset: closureOffset(n, closureVars),
|
||||
})
|
||||
// Record go type of to insure that it gets emitted by the linker.
|
||||
fnsym.Func().RecordAutoType(reflectdata.TypeLinksym(n.Type()))
|
||||
|
|
@ -334,7 +352,7 @@ func preInliningDcls(fnsym *obj.LSym) []*ir.Name {
|
|||
|
||||
// createSimpleVars creates a DWARF entry for every variable declared in the
|
||||
// function, claiming that they are permanently on the stack.
|
||||
func createSimpleVars(fnsym *obj.LSym, apDecls []*ir.Name) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
|
||||
func createSimpleVars(fnsym *obj.LSym, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
|
||||
var vars []*dwarf.Var
|
||||
var decls []*ir.Name
|
||||
var selected ir.NameSet
|
||||
|
|
@ -344,13 +362,13 @@ func createSimpleVars(fnsym *obj.LSym, apDecls []*ir.Name) ([]*ir.Name, []*dwarf
|
|||
}
|
||||
|
||||
decls = append(decls, n)
|
||||
vars = append(vars, createSimpleVar(fnsym, n))
|
||||
vars = append(vars, createSimpleVar(fnsym, n, closureVars))
|
||||
selected.Add(n)
|
||||
}
|
||||
return decls, vars, selected
|
||||
}
|
||||
|
||||
func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
|
||||
func createSimpleVar(fnsym *obj.LSym, n *ir.Name, closureVars map[*ir.Name]int64) *dwarf.Var {
|
||||
var tag int
|
||||
var offs int64
|
||||
|
||||
|
|
@ -406,6 +424,7 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
|
|||
InlIndex: int32(inlIndex),
|
||||
ChildIndex: -1,
|
||||
DictIndex: n.DictIndex,
|
||||
ClosureOffset: closureOffset(n, closureVars),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -414,11 +433,11 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
|
|||
// hybrid approach in which register-resident input params are
|
||||
// captured with location lists, and all other vars use the "simple"
|
||||
// strategy.
|
||||
func createABIVars(fnsym *obj.LSym, fn *ir.Func, apDecls []*ir.Name) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
|
||||
func createABIVars(fnsym *obj.LSym, fn *ir.Func, apDecls []*ir.Name, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
|
||||
|
||||
// Invoke createComplexVars to generate dwarf vars for input parameters
|
||||
// that are register-allocated according to the ABI rules.
|
||||
decls, vars, selected := createComplexVars(fnsym, fn)
|
||||
decls, vars, selected := createComplexVars(fnsym, fn, closureVars)
|
||||
|
||||
// Now fill in the remainder of the variables: input parameters
|
||||
// that are not register-resident, output parameters, and local
|
||||
|
|
@ -433,7 +452,7 @@ func createABIVars(fnsym *obj.LSym, fn *ir.Func, apDecls []*ir.Name) ([]*ir.Name
|
|||
}
|
||||
|
||||
decls = append(decls, n)
|
||||
vars = append(vars, createSimpleVar(fnsym, n))
|
||||
vars = append(vars, createSimpleVar(fnsym, n, closureVars))
|
||||
selected.Add(n)
|
||||
}
|
||||
|
||||
|
|
@ -442,7 +461,7 @@ func createABIVars(fnsym *obj.LSym, fn *ir.Func, apDecls []*ir.Name) ([]*ir.Name
|
|||
|
||||
// createComplexVars creates recomposed DWARF vars with location lists,
|
||||
// suitable for describing optimized code.
|
||||
func createComplexVars(fnsym *obj.LSym, fn *ir.Func) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
|
||||
func createComplexVars(fnsym *obj.LSym, fn *ir.Func, closureVars map[*ir.Name]int64) ([]*ir.Name, []*dwarf.Var, ir.NameSet) {
|
||||
debugInfo := fn.DebugInfo.(*ssa.FuncDebug)
|
||||
|
||||
// Produce a DWARF variable entry for each user variable.
|
||||
|
|
@ -457,7 +476,7 @@ func createComplexVars(fnsym *obj.LSym, fn *ir.Func) ([]*ir.Name, []*dwarf.Var,
|
|||
ssaVars.Add(debugInfo.Slots[slot].N)
|
||||
}
|
||||
|
||||
if dvar := createComplexVar(fnsym, fn, ssa.VarID(varID)); dvar != nil {
|
||||
if dvar := createComplexVar(fnsym, fn, ssa.VarID(varID), closureVars); dvar != nil {
|
||||
decls = append(decls, n)
|
||||
vars = append(vars, dvar)
|
||||
}
|
||||
|
|
@ -467,7 +486,7 @@ func createComplexVars(fnsym *obj.LSym, fn *ir.Func) ([]*ir.Name, []*dwarf.Var,
|
|||
}
|
||||
|
||||
// createComplexVar builds a single DWARF variable entry and location list.
|
||||
func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var {
|
||||
func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID, closureVars map[*ir.Name]int64) *dwarf.Var {
|
||||
debug := fn.DebugInfo.(*ssa.FuncDebug)
|
||||
n := debug.Vars[varID]
|
||||
|
||||
|
|
@ -505,13 +524,14 @@ func createComplexVar(fnsym *obj.LSym, fn *ir.Func, varID ssa.VarID) *dwarf.Var
|
|||
// variables just give it the first one. It's not used otherwise.
|
||||
// This won't work well if the first slot hasn't been assigned a stack
|
||||
// location, but it's not obvious how to do better.
|
||||
StackOffset: ssagen.StackOffset(debug.Slots[debug.VarSlots[varID][0]]),
|
||||
DeclFile: declpos.RelFilename(),
|
||||
DeclLine: declpos.RelLine(),
|
||||
DeclCol: declpos.RelCol(),
|
||||
InlIndex: int32(inlIndex),
|
||||
ChildIndex: -1,
|
||||
DictIndex: n.DictIndex,
|
||||
StackOffset: ssagen.StackOffset(debug.Slots[debug.VarSlots[varID][0]]),
|
||||
DeclFile: declpos.RelFilename(),
|
||||
DeclLine: declpos.RelLine(),
|
||||
DeclCol: declpos.RelCol(),
|
||||
InlIndex: int32(inlIndex),
|
||||
ChildIndex: -1,
|
||||
DictIndex: n.DictIndex,
|
||||
ClosureOffset: closureOffset(n, closureVars),
|
||||
}
|
||||
list := debug.LocationLists[varID]
|
||||
if len(list) != 0 {
|
||||
|
|
@ -594,3 +614,7 @@ func RecordPackageName() {
|
|||
base.Ctxt.Data = append(base.Ctxt.Data, s)
|
||||
s.P = []byte(types.LocalPkg.Name)
|
||||
}
|
||||
|
||||
func closureOffset(n *ir.Name, closureVars map[*ir.Name]int64) int64 {
|
||||
return closureVars[n]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue