Anonymous pointer and slice types are very common and identical
anyway, so just reuse them rather than allocating new ones everywhere
they appear.
Turns out to be a small code/stack size win because SSA relies on
gc.Type identity for reusing temporary stack slots:
text data bss dec hex filename
6453005 231643 146328
6830976 683b80 go.old
6446660 231643 146328
6824631 6822b7 go.new
Saves on memory usage during compile time too, and maybe a small CPU
time win, but the benchmarks are pretty noisy:
name old time/op new time/op delta
Template 342ms ± 8% 339ms ± 9% ~ (p=0.332 n=99+99)
Unicode 183ms ± 9% 181ms ±11% ~ (p=0.274 n=95+98)
GoTypes 1.05s ± 4% 1.04s ± 3% -1.22% (p=0.000 n=97+95)
Compiler 4.49s ± 7% 4.46s ± 6% ~ (p=0.058 n=96+91)
name old user-ns/op new user-ns/op delta
Template 520M ±17% 522M ±20% ~ (p=0.544 n=98+100)
Unicode 331M ±27% 327M ±30% ~ (p=0.615 n=98+98)
GoTypes 1.54G ±10% 1.53G ±12% ~ (p=0.173 n=99+100)
Compiler 6.33G ±10% 6.33G ±10% ~ (p=0.682 n=98+98)
name old alloc/op new alloc/op delta
Template 44.5MB ± 0% 44.1MB ± 0% -0.80% (p=0.000 n=97+99)
Unicode 37.5MB ± 0% 37.3MB ± 0% -0.44% (p=0.000 n=98+100)
GoTypes 126MB ± 0% 124MB ± 0% -1.41% (p=0.000 n=98+99)
Compiler 518MB ± 0% 508MB ± 0% -1.90% (p=0.000 n=98+100)
name old allocs/op new allocs/op delta
Template 441k ± 0% 434k ± 0% -1.76% (p=0.000 n=100+97)
Unicode 368k ± 0% 365k ± 0% -0.69% (p=0.000 n=99+99)
GoTypes 1.26M ± 0% 1.23M ± 0% -2.27% (p=0.000 n=100+99)
Compiler 4.60M ± 0% 4.46M ± 0% -2.96% (p=0.000 n=100+99)
Change-Id: I94abce5c57aed0f9c48f567b3ac24c627d4c7c91
Reviewed-on: https://go-review.googlesource.com/30632
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
{Name{}, 52, 80},
{Node{}, 92, 144},
{Sym{}, 60, 112},
- {Type{}, 52, 80},
+ {Type{}, 60, 96},
{MapType{}, 20, 40},
{ForwardType{}, 16, 32},
{FuncType{}, 28, 48},
return binary.LittleEndian.Uint32(h[:4])
}
-var initPtrtoDone bool
-
-var (
- ptrToUint8 *Type
- ptrToAny *Type
- ptrToString *Type
- ptrToBool *Type
- ptrToInt32 *Type
-)
-
-func initPtrto() {
- ptrToUint8 = typPtr(Types[TUINT8])
- ptrToAny = typPtr(Types[TANY])
- ptrToString = typPtr(Types[TSTRING])
- ptrToBool = typPtr(Types[TBOOL])
- ptrToInt32 = typPtr(Types[TINT32])
-}
-
// ptrto returns the Type *t.
// The returned struct must not be modified.
func ptrto(t *Type) *Type {
if t == nil {
Fatalf("ptrto: nil ptr")
}
- // Reduce allocations by pre-creating common cases.
- if !initPtrtoDone {
- initPtrto()
- initPtrtoDone = true
- }
- switch t {
- case Types[TUINT8]:
- return ptrToUint8
- case Types[TINT32]:
- return ptrToInt32
- case Types[TANY]:
- return ptrToAny
- case Types[TSTRING]:
- return ptrToString
- case Types[TBOOL]:
- return ptrToBool
- }
return typPtr(t)
}
nod *Node // canonical OTYPE node
Orig *Type // original type (type literal or predefined type)
+ sliceOf *Type
+ ptrTo *Type
+
Sym *Sym // symbol containing name, for named types
Vargen int32 // unique name for OTYPE/ONAME
Lineno int32 // line at which this type was declared, implicitly or explicitly
return t
}
-// typSlice returns a new slice Type.
+// typSlice returns the slice Type with element type elem.
func typSlice(elem *Type) *Type {
+ if t := elem.sliceOf; t != nil {
+ if t.Elem() != elem {
+ Fatalf("elem mismatch")
+ }
+ return t
+ }
+
t := typ(TSLICE)
t.Extra = SliceType{Elem: elem}
+ elem.sliceOf = t
return t
}
return t
}
-// typPtr returns a new pointer type pointing to t.
+// typPtr returns the pointer type pointing to t.
func typPtr(elem *Type) *Type {
+ if t := elem.ptrTo; t != nil {
+ if t.Elem() != elem {
+ Fatalf("elem mismatch")
+ }
+ return t
+ }
+
t := typ(Tptr)
t.Extra = PtrType{Elem: elem}
t.Width = int64(Widthptr)
t.Align = uint8(Widthptr)
+ elem.ptrTo = t
return t
}
embedlineno := n.Type.ForwardType().Embedlineno
l := n.Type.ForwardType().Copyto
+ ptrTo := n.Type.ptrTo
+ sliceOf := n.Type.sliceOf
+
// TODO(mdempsky): Fix Type rekinding.
*n.Type = *t
t.allMethods = Fields{}
t.nod = nil
t.Deferwidth = false
+ t.ptrTo = ptrTo
+ t.sliceOf = sliceOf
// Update nodes waiting on this type.
for _, n := range l {