From 94179d61abf9516e24597ec8fa3888343d01388c Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 9 Aug 2013 10:49:01 +1000 Subject: [PATCH] reflect: avoid allocation when interface's contents are not addressable See issue 4949 for a full explanation. Allocs go from 1 to zero in the non-addressable case. Fixes #4949. BenchmarkInterfaceBig 90 14 -84.01% BenchmarkInterfaceSmall 14 14 +0.00% R=golang-dev, bradfitz CC=golang-dev https://golang.org/cl/12646043 --- src/pkg/reflect/all_test.go | 34 ++++++++++++++++++++++++++++++++++ src/pkg/reflect/value.go | 3 ++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go index 93df4d1365..fcdf87af81 100644 --- a/src/pkg/reflect/all_test.go +++ b/src/pkg/reflect/all_test.go @@ -3419,6 +3419,40 @@ func BenchmarkFieldByName3(b *testing.B) { } } +type S struct { + i1 int64 + i2 int64 +} + +func BenchmarkInterfaceBig(b *testing.B) { + v := ValueOf(S{}) + for i := 0; i < b.N; i++ { + v.Interface() + } + b.StopTimer() +} + +func TestAllocsInterfaceBig(t *testing.T) { + v := ValueOf(S{}) + if allocs := testing.AllocsPerRun(100, func() { v.Interface() }); allocs > 0 { + t.Errorf("allocs:", allocs) + } +} + +func BenchmarkInterfaceSmall(b *testing.B) { + v := ValueOf(int64(0)) + for i := 0; i < b.N; i++ { + v.Interface() + } +} + +func TestAllocsInterfaceSmall(t *testing.T) { + v := ValueOf(int64(0)) + if allocs := testing.AllocsPerRun(100, func() { v.Interface() }); allocs > 0 { + t.Errorf("allocs:", allocs) + } +} + // An exhaustive is a mechanism for writing exhaustive or stochastic tests. // The basic usage is: // diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go index 9b2630290a..112e17dff4 100644 --- a/src/pkg/reflect/value.go +++ b/src/pkg/reflect/value.go @@ -1004,7 +1004,8 @@ func valueInterface(v Value, safe bool) interface{} { eface.typ = v.typ eface.word = v.iword() - if v.flag&flagIndir != 0 && v.typ.size > ptrSize { + // Don't need to allocate if v is not addressable or fits in one word. + if v.flag&flagAddr != 0 && v.typ.size > ptrSize { // eface.word is a pointer to the actual data, // which might be changed. We need to return // a pointer to unchanging data, so make a copy. -- 2.48.1