| // Copyright 2012 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | package runtime_test | 
 |  | 
 | import ( | 
 | 	"runtime" | 
 | 	"testing" | 
 | ) | 
 |  | 
 | type I1 interface { | 
 | 	Method1() | 
 | } | 
 |  | 
 | type I2 interface { | 
 | 	Method1() | 
 | 	Method2() | 
 | } | 
 |  | 
 | type TS uint16 | 
 | type TM uintptr | 
 | type TL [2]uintptr | 
 |  | 
 | func (TS) Method1() {} | 
 | func (TS) Method2() {} | 
 | func (TM) Method1() {} | 
 | func (TM) Method2() {} | 
 | func (TL) Method1() {} | 
 | func (TL) Method2() {} | 
 |  | 
 | type T8 uint8 | 
 | type T16 uint16 | 
 | type T32 uint32 | 
 | type T64 uint64 | 
 | type Tstr string | 
 | type Tslice []byte | 
 |  | 
 | func (T8) Method1()     {} | 
 | func (T16) Method1()    {} | 
 | func (T32) Method1()    {} | 
 | func (T64) Method1()    {} | 
 | func (Tstr) Method1()   {} | 
 | func (Tslice) Method1() {} | 
 |  | 
 | var ( | 
 | 	e  any | 
 | 	e_ any | 
 | 	i1 I1 | 
 | 	i2 I2 | 
 | 	ts TS | 
 | 	tm TM | 
 | 	tl TL | 
 | 	ok bool | 
 | ) | 
 |  | 
 | // 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 BenchmarkConvT2EByteSized(b *testing.B) { | 
 | 	b.Run("bool", func(b *testing.B) { | 
 | 		for i := 0; i < b.N; i++ { | 
 | 			e = yes | 
 | 		} | 
 | 	}) | 
 | 	b.Run("uint8", func(b *testing.B) { | 
 | 		for i := 0; i < b.N; i++ { | 
 | 			e = eight8 | 
 | 		} | 
 | 	}) | 
 | } | 
 |  | 
 | func BenchmarkConvT2ESmall(b *testing.B) { | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		e = ts | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkConvT2EUintptr(b *testing.B) { | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		e = tm | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkConvT2ELarge(b *testing.B) { | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		e = tl | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkConvT2ISmall(b *testing.B) { | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		i1 = ts | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkConvT2IUintptr(b *testing.B) { | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		i1 = tm | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkConvT2ILarge(b *testing.B) { | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		i1 = tl | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkConvI2E(b *testing.B) { | 
 | 	i2 = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		e = i2 | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkConvI2I(b *testing.B) { | 
 | 	i2 = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		i1 = i2 | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertE2T(b *testing.B) { | 
 | 	e = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		tm = e.(TM) | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertE2TLarge(b *testing.B) { | 
 | 	e = tl | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		tl = e.(TL) | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertE2I(b *testing.B) { | 
 | 	e = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		i1 = e.(I1) | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertI2T(b *testing.B) { | 
 | 	i1 = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		tm = i1.(TM) | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertI2I(b *testing.B) { | 
 | 	i1 = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		i2 = i1.(I2) | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertI2E(b *testing.B) { | 
 | 	i1 = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		e = i1.(any) | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertE2E(b *testing.B) { | 
 | 	e = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		e_ = e | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertE2T2(b *testing.B) { | 
 | 	e = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		tm, ok = e.(TM) | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertE2T2Blank(b *testing.B) { | 
 | 	e = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		_, ok = e.(TM) | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertI2E2(b *testing.B) { | 
 | 	i1 = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		e, ok = i1.(any) | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertI2E2Blank(b *testing.B) { | 
 | 	i1 = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		_, ok = i1.(any) | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertE2E2(b *testing.B) { | 
 | 	e = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		e_, ok = e.(any) | 
 | 	} | 
 | } | 
 |  | 
 | func BenchmarkAssertE2E2Blank(b *testing.B) { | 
 | 	e = tm | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		_, ok = e.(any) | 
 | 	} | 
 | } | 
 |  | 
 | func TestNonEscapingConvT2E(t *testing.T) { | 
 | 	if runtime.Compiler == "gccgo" { | 
 | 		t.Skip("does not work on gccgo without better escape analysis") | 
 | 	} | 
 |  | 
 | 	m := make(map[any]bool) | 
 | 	m[42] = true | 
 | 	if !m[42] { | 
 | 		t.Fatalf("42 is not present in the map") | 
 | 	} | 
 | 	if m[0] { | 
 | 		t.Fatalf("0 is present in the map") | 
 | 	} | 
 |  | 
 | 	n := testing.AllocsPerRun(1000, func() { | 
 | 		if m[0] { | 
 | 			t.Fatalf("0 is present in the map") | 
 | 		} | 
 | 	}) | 
 | 	if n != 0 { | 
 | 		t.Fatalf("want 0 allocs, got %v", n) | 
 | 	} | 
 | } | 
 |  | 
 | func TestNonEscapingConvT2I(t *testing.T) { | 
 | 	if runtime.Compiler == "gccgo" { | 
 | 		t.Skip("does not work on gccgo without better escape analysis") | 
 | 	} | 
 |  | 
 | 	m := make(map[I1]bool) | 
 | 	m[TM(42)] = true | 
 | 	if !m[TM(42)] { | 
 | 		t.Fatalf("42 is not present in the map") | 
 | 	} | 
 | 	if m[TM(0)] { | 
 | 		t.Fatalf("0 is present in the map") | 
 | 	} | 
 |  | 
 | 	n := testing.AllocsPerRun(1000, func() { | 
 | 		if m[TM(0)] { | 
 | 			t.Fatalf("0 is present in the map") | 
 | 		} | 
 | 	}) | 
 | 	if n != 0 { | 
 | 		t.Fatalf("want 0 allocs, got %v", n) | 
 | 	} | 
 | } | 
 |  | 
 | func TestZeroConvT2x(t *testing.T) { | 
 | 	if runtime.Compiler == "gccgo" { | 
 | 		t.Skip("does not work on gccgo without better escape analysis") | 
 | 	} | 
 |  | 
 | 	tests := []struct { | 
 | 		name string | 
 | 		fn   func() | 
 | 	}{ | 
 | 		{name: "E8", fn: func() { e = eight8 }},  // any byte-sized value does not allocate | 
 | 		{name: "E16", fn: func() { e = zero16 }}, // zero values do not allocate | 
 | 		{name: "E32", fn: func() { e = zero32 }}, | 
 | 		{name: "E64", fn: func() { e = zero64 }}, | 
 | 		{name: "Estr", fn: func() { e = zerostr }}, | 
 | 		{name: "Eslice", fn: func() { e = zeroslice }}, | 
 | 		{name: "Econstflt", fn: func() { e = 99.0 }}, // constants do not allocate | 
 | 		{name: "Econststr", fn: func() { e = "change" }}, | 
 | 		{name: "I8", fn: func() { i1 = eight8I }}, | 
 | 		{name: "I16", fn: func() { i1 = zero16I }}, | 
 | 		{name: "I32", fn: func() { i1 = zero32I }}, | 
 | 		{name: "I64", fn: func() { i1 = zero64I }}, | 
 | 		{name: "Istr", fn: func() { i1 = zerostrI }}, | 
 | 		{name: "Islice", fn: func() { i1 = zerosliceI }}, | 
 | 	} | 
 |  | 
 | 	for _, test := range tests { | 
 | 		t.Run(test.name, func(t *testing.T) { | 
 | 			n := testing.AllocsPerRun(1000, test.fn) | 
 | 			if n != 0 { | 
 | 				t.Errorf("want zero allocs, got %v", n) | 
 | 			} | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | var ( | 
 | 	eight8  uint8 = 8 | 
 | 	eight8I T8    = 8 | 
 | 	yes     bool  = true | 
 |  | 
 | 	zero16     uint16 = 0 | 
 | 	zero16I    T16    = 0 | 
 | 	one16      uint16 = 1 | 
 | 	thousand16 uint16 = 1000 | 
 |  | 
 | 	zero32     uint32 = 0 | 
 | 	zero32I    T32    = 0 | 
 | 	one32      uint32 = 1 | 
 | 	thousand32 uint32 = 1000 | 
 |  | 
 | 	zero64     uint64 = 0 | 
 | 	zero64I    T64    = 0 | 
 | 	one64      uint64 = 1 | 
 | 	thousand64 uint64 = 1000 | 
 |  | 
 | 	zerostr  string = "" | 
 | 	zerostrI Tstr   = "" | 
 | 	nzstr    string = "abc" | 
 |  | 
 | 	zeroslice  []byte = nil | 
 | 	zerosliceI Tslice = nil | 
 | 	nzslice    []byte = []byte("abc") | 
 |  | 
 | 	zerobig [512]byte | 
 | 	nzbig   [512]byte = [512]byte{511: 1} | 
 | ) | 
 |  | 
 | func BenchmarkConvT2Ezero(b *testing.B) { | 
 | 	b.Run("zero", func(b *testing.B) { | 
 | 		b.Run("16", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = zero16 | 
 | 			} | 
 | 		}) | 
 | 		b.Run("32", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = zero32 | 
 | 			} | 
 | 		}) | 
 | 		b.Run("64", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = zero64 | 
 | 			} | 
 | 		}) | 
 | 		b.Run("str", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = zerostr | 
 | 			} | 
 | 		}) | 
 | 		b.Run("slice", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = zeroslice | 
 | 			} | 
 | 		}) | 
 | 		b.Run("big", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = zerobig | 
 | 			} | 
 | 		}) | 
 | 	}) | 
 | 	b.Run("nonzero", func(b *testing.B) { | 
 | 		b.Run("str", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = nzstr | 
 | 			} | 
 | 		}) | 
 | 		b.Run("slice", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = nzslice | 
 | 			} | 
 | 		}) | 
 | 		b.Run("big", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = nzbig | 
 | 			} | 
 | 		}) | 
 | 	}) | 
 | 	b.Run("smallint", func(b *testing.B) { | 
 | 		b.Run("16", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = one16 | 
 | 			} | 
 | 		}) | 
 | 		b.Run("32", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = one32 | 
 | 			} | 
 | 		}) | 
 | 		b.Run("64", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = one64 | 
 | 			} | 
 | 		}) | 
 | 	}) | 
 | 	b.Run("largeint", func(b *testing.B) { | 
 | 		b.Run("16", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = thousand16 | 
 | 			} | 
 | 		}) | 
 | 		b.Run("32", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = thousand32 | 
 | 			} | 
 | 		}) | 
 | 		b.Run("64", func(b *testing.B) { | 
 | 			for i := 0; i < b.N; i++ { | 
 | 				e = thousand64 | 
 | 			} | 
 | 		}) | 
 | 	}) | 
 | } |