]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: avoid allocation when interface's contents are not addressable
authorRob Pike <r@golang.org>
Fri, 9 Aug 2013 00:49:01 +0000 (10:49 +1000)
committerRob Pike <r@golang.org>
Fri, 9 Aug 2013 00:49:01 +0000 (10:49 +1000)
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
src/pkg/reflect/value.go

index 93df4d13654af8da9c121ff4b4b91c279bcaff71..fcdf87af817cfcc1e047a4c134f68740685a4fb0 100644 (file)
@@ -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:
 //
index 9b2630290af627815a1aa0f00c1d3a2d5cccde4a..112e17dff49077ce79b410e363dffca7b496ac6a 100644 (file)
@@ -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.