diff options
author | Josh Bleecher Snyder <josharian@gmail.com> | 2014-12-23 18:28:02 -0800 |
---|---|---|
committer | Josh Bleecher Snyder <josharian@gmail.com> | 2015-02-12 22:23:38 +0000 |
commit | 77a2113925b516c0ead2ae258c4d41ac3fdc0836 (patch) | |
tree | 9dce58ccff89194921957f0023c9c35a784cea29 /src/runtime/iface_test.go | |
parent | 747c8498339b799eb613db1701a927a3549d389a (diff) | |
download | go-77a2113925b516c0ead2ae258c4d41ac3fdc0836.tar.gz go-77a2113925b516c0ead2ae258c4d41ac3fdc0836.zip |
cmd/gc: evaluate concrete == interface without allocating
Consider an interface value i of type I and concrete value c of type C.
Prior to this CL, i==c was evaluated as
I(c) == i
Evaluating I(c) can allocate.
This CL changes the evaluation of i==c to
x, ok := i.(C); ok && x == c
The new generated code is shorter and does not allocate directly.
If C is small, as it is in every instance in the stdlib,
the new code also uses less stack space
and makes one runtime call instead of two.
If C is very large, the original implementation is used.
The cutoff for "very large" is 1<<16,
following the stack vs heap cutoff used elsewhere.
This kind of comparison occurs in 38 places in the stdlib,
mostly in the net and os packages.
benchmark old ns/op new ns/op delta
BenchmarkEqEfaceConcrete 29.5 7.92 -73.15%
BenchmarkEqIfaceConcrete 32.1 7.90 -75.39%
BenchmarkNeEfaceConcrete 29.9 7.90 -73.58%
BenchmarkNeIfaceConcrete 35.9 7.90 -77.99%
Fixes #9370.
Change-Id: I7c4555950bcd6406ee5c613be1f2128da2c9a2b7
Reviewed-on: https://go-review.googlesource.com/2096
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
Diffstat (limited to 'src/runtime/iface_test.go')
-rw-r--r-- | src/runtime/iface_test.go | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/src/runtime/iface_test.go b/src/runtime/iface_test.go index bca0ea0ee7..bfeb94b8aa 100644 --- a/src/runtime/iface_test.go +++ b/src/runtime/iface_test.go @@ -5,6 +5,7 @@ package runtime_test import ( + "runtime" "testing" ) @@ -38,6 +39,47 @@ var ( tl TL ) +// Issue 9370 +func TestCmpIfaceConcreteAlloc(t *testing.T) { + if runtime.Compiler != "gc" { + t.Skip("skipping on non-gc compiler") + } + + n := testing.AllocsPerRun(1, func() { + _ = e == ts + _ = i1 == ts + _ = e == 1 + }) + + if n > 0 { + t.Fatalf("iface cmp allocs=%v; want 0", n) + } +} + +func BenchmarkEqEfaceConcrete(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = e == ts + } +} + +func BenchmarkEqIfaceConcrete(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = i1 == ts + } +} + +func BenchmarkNeEfaceConcrete(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = e != ts + } +} + +func BenchmarkNeIfaceConcrete(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = i1 != ts + } +} + func BenchmarkConvT2ESmall(b *testing.B) { for i := 0; i < b.N; i++ { e = ts |