mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile,runtime: allocate defer records on the stack
When a defer is executed at most once in a function body, we can allocate the defer record for it on the stack instead of on the heap. This should make defers like this (which are very common) faster. This optimization applies to 363 out of the 370 static defer sites in the cmd/go binary. name old time/op new time/op delta Defer-4 52.2ns ± 5% 36.2ns ± 3% -30.70% (p=0.000 n=10+10) Fixes #6980 Update #14939 Change-Id: I697109dd7aeef9e97a9eeba2ef65ff53d3ee1004 Reviewed-on: https://go-review.googlesource.com/c/go/+/171758 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
This commit is contained in:
parent
8343a0934d
commit
fff4f599fe
15 changed files with 328 additions and 108 deletions
|
|
@ -317,6 +317,48 @@ func hiter(t *types.Type) *types.Type {
|
|||
return hiter
|
||||
}
|
||||
|
||||
// deferstruct makes a runtime._defer structure, with additional space for
|
||||
// stksize bytes of args.
|
||||
func deferstruct(stksize int64) *types.Type {
|
||||
makefield := func(name string, typ *types.Type) *types.Field {
|
||||
f := types.NewField()
|
||||
f.Type = typ
|
||||
// Unlike the global makefield function, this one needs to set Pkg
|
||||
// because these types might be compared (in SSA CSE sorting).
|
||||
// TODO: unify this makefield and the global one above.
|
||||
f.Sym = &types.Sym{Name: name, Pkg: localpkg}
|
||||
return f
|
||||
}
|
||||
argtype := types.NewArray(types.Types[TUINT8], stksize)
|
||||
argtype.SetNoalg(true)
|
||||
argtype.Width = stksize
|
||||
argtype.Align = 1
|
||||
// These fields must match the ones in runtime/runtime2.go:_defer and
|
||||
// cmd/compile/internal/gc/ssa.go:(*state).call.
|
||||
fields := []*types.Field{
|
||||
makefield("siz", types.Types[TUINT32]),
|
||||
makefield("started", types.Types[TBOOL]),
|
||||
makefield("heap", types.Types[TBOOL]),
|
||||
makefield("sp", types.Types[TUINTPTR]),
|
||||
makefield("pc", types.Types[TUINTPTR]),
|
||||
// Note: the types here don't really matter. Defer structures
|
||||
// are always scanned explicitly during stack copying and GC,
|
||||
// so we make them uintptr type even though they are real pointers.
|
||||
makefield("fn", types.Types[TUINTPTR]),
|
||||
makefield("_panic", types.Types[TUINTPTR]),
|
||||
makefield("link", types.Types[TUINTPTR]),
|
||||
makefield("args", argtype),
|
||||
}
|
||||
|
||||
// build struct holding the above fields
|
||||
s := types.New(TSTRUCT)
|
||||
s.SetNoalg(true)
|
||||
s.SetFields(fields)
|
||||
s.Width = widstruct(s, s, 0, 1)
|
||||
s.Align = uint8(Widthptr)
|
||||
return s
|
||||
}
|
||||
|
||||
// f is method type, with receiver.
|
||||
// return function type, receiver as first argument (or not).
|
||||
func methodfunc(f *types.Type, receiver *types.Type) *types.Type {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue