From 2413629aa8a2737fb0343d8bc9107208ae7d643f Mon Sep 17 00:00:00 2001 From: Joe Tsai Date: Fri, 12 Jan 2024 18:13:14 -0800 Subject: [PATCH] reflect: optimize TypeFor for non-interface types MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The reflect.Type.Elem method is somewhat slow, which is unfortunate since the reflect.TypeOf((*T)(nil)).Elem() trick is only needed if T is an interface. Optimize for concrete types by doing the faster reflect.TypeOf(v) call first and only falling back on the Elem method if needed. Performance: name old time/op new time/op delta TypeForString-24 9.10ns ± 1% 1.78ns ± 2% -80.49% (p=0.000 n=10+10) TypeForError-24 9.55ns ± 1% 9.78ns ± 1% +2.39% (p=0.000 n=10+9) Updates #60088 Change-Id: I2ae76988c9a3dbcbae10d2c19b55db3c8d4559bf Reviewed-on: https://go-review.googlesource.com/c/go/+/555597 Auto-Submit: Joseph Tsai Reviewed-by: Ian Lance Taylor Reviewed-by: Than McIntosh Run-TryBot: Joseph Tsai LUCI-TryBot-Result: Go LUCI TryBot-Result: Gopher Robot Reviewed-by: Mauri de Souza Meneguzzo --- src/reflect/type.go | 6 +++++- src/reflect/type_test.go | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/reflect/type.go b/src/reflect/type.go index a1a618ad59..9a2e41f0b2 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -2920,5 +2920,9 @@ func addTypeBits(bv *bitVector, offset uintptr, t *abi.Type) { // TypeFor returns the [Type] that represents the type argument T. func TypeFor[T any]() Type { - return TypeOf((*T)(nil)).Elem() + var v T + if t := TypeOf(v); t != nil { + return t // optimize for T being a non-interface kind + } + return TypeOf((*T)(nil)).Elem() // only for an interface kind } diff --git a/src/reflect/type_test.go b/src/reflect/type_test.go index 4ba4536d66..200ecf6eca 100644 --- a/src/reflect/type_test.go +++ b/src/reflect/type_test.go @@ -103,3 +103,17 @@ func TestIsRegularMemory(t *testing.T) { }) } } + +var sinkType reflect.Type + +func BenchmarkTypeForString(b *testing.B) { + for i := 0; i < b.N; i++ { + sinkType = reflect.TypeFor[string]() + } +} + +func BenchmarkTypeForError(b *testing.B) { + for i := 0; i < b.N; i++ { + sinkType = reflect.TypeFor[error]() + } +} -- 2.48.1