Home | History | Annotate | Download | only in runtime
      1 // Copyright 2012 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package runtime_test
      6 
      7 import (
      8 	"runtime"
      9 	"testing"
     10 )
     11 
     12 type I1 interface {
     13 	Method1()
     14 }
     15 
     16 type I2 interface {
     17 	Method1()
     18 	Method2()
     19 }
     20 
     21 type TS uint16
     22 type TM uintptr
     23 type TL [2]uintptr
     24 
     25 func (TS) Method1() {}
     26 func (TS) Method2() {}
     27 func (TM) Method1() {}
     28 func (TM) Method2() {}
     29 func (TL) Method1() {}
     30 func (TL) Method2() {}
     31 
     32 type T8 uint8
     33 type T16 uint16
     34 type T32 uint32
     35 type T64 uint64
     36 type Tstr string
     37 type Tslice []byte
     38 
     39 func (T8) Method1()     {}
     40 func (T16) Method1()    {}
     41 func (T32) Method1()    {}
     42 func (T64) Method1()    {}
     43 func (Tstr) Method1()   {}
     44 func (Tslice) Method1() {}
     45 
     46 var (
     47 	e  interface{}
     48 	e_ interface{}
     49 	i1 I1
     50 	i2 I2
     51 	ts TS
     52 	tm TM
     53 	tl TL
     54 	ok bool
     55 )
     56 
     57 // Issue 9370
     58 func TestCmpIfaceConcreteAlloc(t *testing.T) {
     59 	if runtime.Compiler != "gc" {
     60 		t.Skip("skipping on non-gc compiler")
     61 	}
     62 
     63 	n := testing.AllocsPerRun(1, func() {
     64 		_ = e == ts
     65 		_ = i1 == ts
     66 		_ = e == 1
     67 	})
     68 
     69 	if n > 0 {
     70 		t.Fatalf("iface cmp allocs=%v; want 0", n)
     71 	}
     72 }
     73 
     74 func BenchmarkEqEfaceConcrete(b *testing.B) {
     75 	for i := 0; i < b.N; i++ {
     76 		_ = e == ts
     77 	}
     78 }
     79 
     80 func BenchmarkEqIfaceConcrete(b *testing.B) {
     81 	for i := 0; i < b.N; i++ {
     82 		_ = i1 == ts
     83 	}
     84 }
     85 
     86 func BenchmarkNeEfaceConcrete(b *testing.B) {
     87 	for i := 0; i < b.N; i++ {
     88 		_ = e != ts
     89 	}
     90 }
     91 
     92 func BenchmarkNeIfaceConcrete(b *testing.B) {
     93 	for i := 0; i < b.N; i++ {
     94 		_ = i1 != ts
     95 	}
     96 }
     97 
     98 func BenchmarkConvT2ESmall(b *testing.B) {
     99 	for i := 0; i < b.N; i++ {
    100 		e = ts
    101 	}
    102 }
    103 
    104 func BenchmarkConvT2EUintptr(b *testing.B) {
    105 	for i := 0; i < b.N; i++ {
    106 		e = tm
    107 	}
    108 }
    109 
    110 func BenchmarkConvT2ELarge(b *testing.B) {
    111 	for i := 0; i < b.N; i++ {
    112 		e = tl
    113 	}
    114 }
    115 
    116 func BenchmarkConvT2ISmall(b *testing.B) {
    117 	for i := 0; i < b.N; i++ {
    118 		i1 = ts
    119 	}
    120 }
    121 
    122 func BenchmarkConvT2IUintptr(b *testing.B) {
    123 	for i := 0; i < b.N; i++ {
    124 		i1 = tm
    125 	}
    126 }
    127 
    128 func BenchmarkConvT2ILarge(b *testing.B) {
    129 	for i := 0; i < b.N; i++ {
    130 		i1 = tl
    131 	}
    132 }
    133 
    134 func BenchmarkConvI2E(b *testing.B) {
    135 	i2 = tm
    136 	for i := 0; i < b.N; i++ {
    137 		e = i2
    138 	}
    139 }
    140 
    141 func BenchmarkConvI2I(b *testing.B) {
    142 	i2 = tm
    143 	for i := 0; i < b.N; i++ {
    144 		i1 = i2
    145 	}
    146 }
    147 
    148 func BenchmarkAssertE2T(b *testing.B) {
    149 	e = tm
    150 	for i := 0; i < b.N; i++ {
    151 		tm = e.(TM)
    152 	}
    153 }
    154 
    155 func BenchmarkAssertE2TLarge(b *testing.B) {
    156 	e = tl
    157 	for i := 0; i < b.N; i++ {
    158 		tl = e.(TL)
    159 	}
    160 }
    161 
    162 func BenchmarkAssertE2I(b *testing.B) {
    163 	e = tm
    164 	for i := 0; i < b.N; i++ {
    165 		i1 = e.(I1)
    166 	}
    167 }
    168 
    169 func BenchmarkAssertI2T(b *testing.B) {
    170 	i1 = tm
    171 	for i := 0; i < b.N; i++ {
    172 		tm = i1.(TM)
    173 	}
    174 }
    175 
    176 func BenchmarkAssertI2I(b *testing.B) {
    177 	i1 = tm
    178 	for i := 0; i < b.N; i++ {
    179 		i2 = i1.(I2)
    180 	}
    181 }
    182 
    183 func BenchmarkAssertI2E(b *testing.B) {
    184 	i1 = tm
    185 	for i := 0; i < b.N; i++ {
    186 		e = i1.(interface{})
    187 	}
    188 }
    189 
    190 func BenchmarkAssertE2E(b *testing.B) {
    191 	e = tm
    192 	for i := 0; i < b.N; i++ {
    193 		e_ = e
    194 	}
    195 }
    196 
    197 func BenchmarkAssertE2T2(b *testing.B) {
    198 	e = tm
    199 	for i := 0; i < b.N; i++ {
    200 		tm, ok = e.(TM)
    201 	}
    202 }
    203 
    204 func BenchmarkAssertE2T2Blank(b *testing.B) {
    205 	e = tm
    206 	for i := 0; i < b.N; i++ {
    207 		_, ok = e.(TM)
    208 	}
    209 }
    210 
    211 func BenchmarkAssertI2E2(b *testing.B) {
    212 	i1 = tm
    213 	for i := 0; i < b.N; i++ {
    214 		e, ok = i1.(interface{})
    215 	}
    216 }
    217 
    218 func BenchmarkAssertI2E2Blank(b *testing.B) {
    219 	i1 = tm
    220 	for i := 0; i < b.N; i++ {
    221 		_, ok = i1.(interface{})
    222 	}
    223 }
    224 
    225 func BenchmarkAssertE2E2(b *testing.B) {
    226 	e = tm
    227 	for i := 0; i < b.N; i++ {
    228 		e_, ok = e.(interface{})
    229 	}
    230 }
    231 
    232 func BenchmarkAssertE2E2Blank(b *testing.B) {
    233 	e = tm
    234 	for i := 0; i < b.N; i++ {
    235 		_, ok = e.(interface{})
    236 	}
    237 }
    238 
    239 func TestNonEscapingConvT2E(t *testing.T) {
    240 	m := make(map[interface{}]bool)
    241 	m[42] = true
    242 	if !m[42] {
    243 		t.Fatalf("42 is not present in the map")
    244 	}
    245 	if m[0] {
    246 		t.Fatalf("0 is present in the map")
    247 	}
    248 
    249 	n := testing.AllocsPerRun(1000, func() {
    250 		if m[0] {
    251 			t.Fatalf("0 is present in the map")
    252 		}
    253 	})
    254 	if n != 0 {
    255 		t.Fatalf("want 0 allocs, got %v", n)
    256 	}
    257 }
    258 
    259 func TestNonEscapingConvT2I(t *testing.T) {
    260 	m := make(map[I1]bool)
    261 	m[TM(42)] = true
    262 	if !m[TM(42)] {
    263 		t.Fatalf("42 is not present in the map")
    264 	}
    265 	if m[TM(0)] {
    266 		t.Fatalf("0 is present in the map")
    267 	}
    268 
    269 	n := testing.AllocsPerRun(1000, func() {
    270 		if m[TM(0)] {
    271 			t.Fatalf("0 is present in the map")
    272 		}
    273 	})
    274 	if n != 0 {
    275 		t.Fatalf("want 0 allocs, got %v", n)
    276 	}
    277 }
    278 
    279 func TestZeroConvT2x(t *testing.T) {
    280 	tests := []struct {
    281 		name string
    282 		fn   func()
    283 	}{
    284 		{name: "E8", fn: func() { e = eight8 }},  // any byte-sized value does not allocate
    285 		{name: "E16", fn: func() { e = zero16 }}, // zero values do not allocate
    286 		{name: "E32", fn: func() { e = zero32 }},
    287 		{name: "E64", fn: func() { e = zero64 }},
    288 		{name: "Estr", fn: func() { e = zerostr }},
    289 		{name: "Eslice", fn: func() { e = zeroslice }},
    290 		{name: "Econstflt", fn: func() { e = 99.0 }}, // constants do not allocate
    291 		{name: "Econststr", fn: func() { e = "change" }},
    292 		{name: "I8", fn: func() { i1 = eight8I }},
    293 		{name: "I16", fn: func() { i1 = zero16I }},
    294 		{name: "I32", fn: func() { i1 = zero32I }},
    295 		{name: "I64", fn: func() { i1 = zero64I }},
    296 		{name: "Istr", fn: func() { i1 = zerostrI }},
    297 		{name: "Islice", fn: func() { i1 = zerosliceI }},
    298 	}
    299 
    300 	for _, test := range tests {
    301 		t.Run(test.name, func(t *testing.T) {
    302 			n := testing.AllocsPerRun(1000, test.fn)
    303 			if n != 0 {
    304 				t.Errorf("want zero allocs, got %v", n)
    305 			}
    306 		})
    307 	}
    308 }
    309 
    310 var (
    311 	eight8  uint8 = 8
    312 	eight8I T8    = 8
    313 
    314 	zero16  uint16 = 0
    315 	zero16I T16    = 0
    316 	one16   uint16 = 1
    317 
    318 	zero32  uint32 = 0
    319 	zero32I T32    = 0
    320 	one32   uint32 = 1
    321 
    322 	zero64  uint64 = 0
    323 	zero64I T64    = 0
    324 	one64   uint64 = 1
    325 
    326 	zerostr  string = ""
    327 	zerostrI Tstr   = ""
    328 	nzstr    string = "abc"
    329 
    330 	zeroslice  []byte = nil
    331 	zerosliceI Tslice = nil
    332 	nzslice    []byte = []byte("abc")
    333 
    334 	zerobig [512]byte
    335 	nzbig   [512]byte = [512]byte{511: 1}
    336 )
    337 
    338 func BenchmarkConvT2Ezero(b *testing.B) {
    339 	b.Run("zero", func(b *testing.B) {
    340 		b.Run("16", func(b *testing.B) {
    341 			for i := 0; i < b.N; i++ {
    342 				e = zero16
    343 			}
    344 		})
    345 		b.Run("32", func(b *testing.B) {
    346 			for i := 0; i < b.N; i++ {
    347 				e = zero32
    348 			}
    349 		})
    350 		b.Run("64", func(b *testing.B) {
    351 			for i := 0; i < b.N; i++ {
    352 				e = zero64
    353 			}
    354 		})
    355 		b.Run("str", func(b *testing.B) {
    356 			for i := 0; i < b.N; i++ {
    357 				e = zerostr
    358 			}
    359 		})
    360 		b.Run("slice", func(b *testing.B) {
    361 			for i := 0; i < b.N; i++ {
    362 				e = zeroslice
    363 			}
    364 		})
    365 		b.Run("big", func(b *testing.B) {
    366 			for i := 0; i < b.N; i++ {
    367 				e = zerobig
    368 			}
    369 		})
    370 	})
    371 	b.Run("nonzero", func(b *testing.B) {
    372 		b.Run("16", func(b *testing.B) {
    373 			for i := 0; i < b.N; i++ {
    374 				e = one16
    375 			}
    376 		})
    377 		b.Run("32", func(b *testing.B) {
    378 			for i := 0; i < b.N; i++ {
    379 				e = one32
    380 			}
    381 		})
    382 		b.Run("64", func(b *testing.B) {
    383 			for i := 0; i < b.N; i++ {
    384 				e = one64
    385 			}
    386 		})
    387 		b.Run("str", func(b *testing.B) {
    388 			for i := 0; i < b.N; i++ {
    389 				e = nzstr
    390 			}
    391 		})
    392 		b.Run("slice", func(b *testing.B) {
    393 			for i := 0; i < b.N; i++ {
    394 				e = nzslice
    395 			}
    396 		})
    397 		b.Run("big", func(b *testing.B) {
    398 			for i := 0; i < b.N; i++ {
    399 				e = nzbig
    400 			}
    401 		})
    402 	})
    403 }
    404