...

Source file src/runtime/map_test.go

Documentation: runtime

     1  // Copyright 2013 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  	"fmt"
     9  	"internal/abi"
    10  	"internal/goarch"
    11  	"internal/testenv"
    12  	"math"
    13  	"os"
    14  	"reflect"
    15  	"runtime"
    16  	"slices"
    17  	"strconv"
    18  	"strings"
    19  	"sync"
    20  	"testing"
    21  	"unsafe"
    22  )
    23  
    24  func TestHmapSize(t *testing.T) {
    25  	// The structure of hmap is defined in runtime/map.go
    26  	// and in cmd/compile/internal/gc/reflect.go and must be in sync.
    27  	// The size of hmap should be 48 bytes on 64 bit and 28 bytes on 32 bit platforms.
    28  	var hmapSize = uintptr(8 + 5*goarch.PtrSize)
    29  	if runtime.RuntimeHmapSize != hmapSize {
    30  		t.Errorf("sizeof(runtime.hmap{})==%d, want %d", runtime.RuntimeHmapSize, hmapSize)
    31  	}
    32  
    33  }
    34  
    35  // negative zero is a good test because:
    36  //  1. 0 and -0 are equal, yet have distinct representations.
    37  //  2. 0 is represented as all zeros, -0 isn't.
    38  //
    39  // I'm not sure the language spec actually requires this behavior,
    40  // but it's what the current map implementation does.
    41  func TestNegativeZero(t *testing.T) {
    42  	m := make(map[float64]bool, 0)
    43  
    44  	m[+0.0] = true
    45  	m[math.Copysign(0.0, -1.0)] = true // should overwrite +0 entry
    46  
    47  	if len(m) != 1 {
    48  		t.Error("length wrong")
    49  	}
    50  
    51  	for k := range m {
    52  		if math.Copysign(1.0, k) > 0 {
    53  			t.Error("wrong sign")
    54  		}
    55  	}
    56  
    57  	m = make(map[float64]bool, 0)
    58  	m[math.Copysign(0.0, -1.0)] = true
    59  	m[+0.0] = true // should overwrite -0.0 entry
    60  
    61  	if len(m) != 1 {
    62  		t.Error("length wrong")
    63  	}
    64  
    65  	for k := range m {
    66  		if math.Copysign(1.0, k) < 0 {
    67  			t.Error("wrong sign")
    68  		}
    69  	}
    70  }
    71  
    72  func testMapNan(t *testing.T, m map[float64]int) {
    73  	if len(m) != 3 {
    74  		t.Error("length wrong")
    75  	}
    76  	s := 0
    77  	for k, v := range m {
    78  		if k == k {
    79  			t.Error("nan disappeared")
    80  		}
    81  		if (v & (v - 1)) != 0 {
    82  			t.Error("value wrong")
    83  		}
    84  		s |= v
    85  	}
    86  	if s != 7 {
    87  		t.Error("values wrong")
    88  	}
    89  }
    90  
    91  // nan is a good test because nan != nan, and nan has
    92  // a randomized hash value.
    93  func TestMapAssignmentNan(t *testing.T) {
    94  	m := make(map[float64]int, 0)
    95  	nan := math.NaN()
    96  
    97  	// Test assignment.
    98  	m[nan] = 1
    99  	m[nan] = 2
   100  	m[nan] = 4
   101  	testMapNan(t, m)
   102  }
   103  
   104  // nan is a good test because nan != nan, and nan has
   105  // a randomized hash value.
   106  func TestMapOperatorAssignmentNan(t *testing.T) {
   107  	m := make(map[float64]int, 0)
   108  	nan := math.NaN()
   109  
   110  	// Test assignment operations.
   111  	m[nan] += 1
   112  	m[nan] += 2
   113  	m[nan] += 4
   114  	testMapNan(t, m)
   115  }
   116  
   117  func TestMapOperatorAssignment(t *testing.T) {
   118  	m := make(map[int]int, 0)
   119  
   120  	// "m[k] op= x" is rewritten into "m[k] = m[k] op x"
   121  	// differently when op is / or % than when it isn't.
   122  	// Simple test to make sure they all work as expected.
   123  	m[0] = 12345
   124  	m[0] += 67890
   125  	m[0] /= 123
   126  	m[0] %= 456
   127  
   128  	const want = (12345 + 67890) / 123 % 456
   129  	if got := m[0]; got != want {
   130  		t.Errorf("got %d, want %d", got, want)
   131  	}
   132  }
   133  
   134  var sinkAppend bool
   135  
   136  func TestMapAppendAssignment(t *testing.T) {
   137  	m := make(map[int][]int, 0)
   138  
   139  	m[0] = nil
   140  	m[0] = append(m[0], 12345)
   141  	m[0] = append(m[0], 67890)
   142  	sinkAppend, m[0] = !sinkAppend, append(m[0], 123, 456)
   143  	a := []int{7, 8, 9, 0}
   144  	m[0] = append(m[0], a...)
   145  
   146  	want := []int{12345, 67890, 123, 456, 7, 8, 9, 0}
   147  	if got := m[0]; !reflect.DeepEqual(got, want) {
   148  		t.Errorf("got %v, want %v", got, want)
   149  	}
   150  }
   151  
   152  // Maps aren't actually copied on assignment.
   153  func TestAlias(t *testing.T) {
   154  	m := make(map[int]int, 0)
   155  	m[0] = 5
   156  	n := m
   157  	n[0] = 6
   158  	if m[0] != 6 {
   159  		t.Error("alias didn't work")
   160  	}
   161  }
   162  
   163  func TestGrowWithNaN(t *testing.T) {
   164  	m := make(map[float64]int, 4)
   165  	nan := math.NaN()
   166  
   167  	// Use both assignment and assignment operations as they may
   168  	// behave differently.
   169  	m[nan] = 1
   170  	m[nan] = 2
   171  	m[nan] += 4
   172  
   173  	cnt := 0
   174  	s := 0
   175  	growflag := true
   176  	for k, v := range m {
   177  		if growflag {
   178  			// force a hashtable resize
   179  			for i := 0; i < 50; i++ {
   180  				m[float64(i)] = i
   181  			}
   182  			for i := 50; i < 100; i++ {
   183  				m[float64(i)] += i
   184  			}
   185  			growflag = false
   186  		}
   187  		if k != k {
   188  			cnt++
   189  			s |= v
   190  		}
   191  	}
   192  	if cnt != 3 {
   193  		t.Error("NaN keys lost during grow")
   194  	}
   195  	if s != 7 {
   196  		t.Error("NaN values lost during grow")
   197  	}
   198  }
   199  
   200  type FloatInt struct {
   201  	x float64
   202  	y int
   203  }
   204  
   205  func TestGrowWithNegativeZero(t *testing.T) {
   206  	negzero := math.Copysign(0.0, -1.0)
   207  	m := make(map[FloatInt]int, 4)
   208  	m[FloatInt{0.0, 0}] = 1
   209  	m[FloatInt{0.0, 1}] += 2
   210  	m[FloatInt{0.0, 2}] += 4
   211  	m[FloatInt{0.0, 3}] = 8
   212  	growflag := true
   213  	s := 0
   214  	cnt := 0
   215  	negcnt := 0
   216  	// The first iteration should return the +0 key.
   217  	// The subsequent iterations should return the -0 key.
   218  	// I'm not really sure this is required by the spec,
   219  	// but it makes sense.
   220  	// TODO: are we allowed to get the first entry returned again???
   221  	for k, v := range m {
   222  		if v == 0 {
   223  			continue
   224  		} // ignore entries added to grow table
   225  		cnt++
   226  		if math.Copysign(1.0, k.x) < 0 {
   227  			if v&16 == 0 {
   228  				t.Error("key/value not updated together 1")
   229  			}
   230  			negcnt++
   231  			s |= v & 15
   232  		} else {
   233  			if v&16 == 16 {
   234  				t.Error("key/value not updated together 2", k, v)
   235  			}
   236  			s |= v
   237  		}
   238  		if growflag {
   239  			// force a hashtable resize
   240  			for i := 0; i < 100; i++ {
   241  				m[FloatInt{3.0, i}] = 0
   242  			}
   243  			// then change all the entries
   244  			// to negative zero
   245  			m[FloatInt{negzero, 0}] = 1 | 16
   246  			m[FloatInt{negzero, 1}] = 2 | 16
   247  			m[FloatInt{negzero, 2}] = 4 | 16
   248  			m[FloatInt{negzero, 3}] = 8 | 16
   249  			growflag = false
   250  		}
   251  	}
   252  	if s != 15 {
   253  		t.Error("entry missing", s)
   254  	}
   255  	if cnt != 4 {
   256  		t.Error("wrong number of entries returned by iterator", cnt)
   257  	}
   258  	if negcnt != 3 {
   259  		t.Error("update to negzero missed by iteration", negcnt)
   260  	}
   261  }
   262  
   263  func TestIterGrowAndDelete(t *testing.T) {
   264  	m := make(map[int]int, 4)
   265  	for i := 0; i < 100; i++ {
   266  		m[i] = i
   267  	}
   268  	growflag := true
   269  	for k := range m {
   270  		if growflag {
   271  			// grow the table
   272  			for i := 100; i < 1000; i++ {
   273  				m[i] = i
   274  			}
   275  			// delete all odd keys
   276  			for i := 1; i < 1000; i += 2 {
   277  				delete(m, i)
   278  			}
   279  			growflag = false
   280  		} else {
   281  			if k&1 == 1 {
   282  				t.Error("odd value returned")
   283  			}
   284  		}
   285  	}
   286  }
   287  
   288  // make sure old bucket arrays don't get GCd while
   289  // an iterator is still using them.
   290  func TestIterGrowWithGC(t *testing.T) {
   291  	m := make(map[int]int, 4)
   292  	for i := 0; i < 8; i++ {
   293  		m[i] = i
   294  	}
   295  	for i := 8; i < 16; i++ {
   296  		m[i] += i
   297  	}
   298  	growflag := true
   299  	bitmask := 0
   300  	for k := range m {
   301  		if k < 16 {
   302  			bitmask |= 1 << uint(k)
   303  		}
   304  		if growflag {
   305  			// grow the table
   306  			for i := 100; i < 1000; i++ {
   307  				m[i] = i
   308  			}
   309  			// trigger a gc
   310  			runtime.GC()
   311  			growflag = false
   312  		}
   313  	}
   314  	if bitmask != 1<<16-1 {
   315  		t.Error("missing key", bitmask)
   316  	}
   317  }
   318  
   319  func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) {
   320  	t.Parallel()
   321  	if runtime.GOMAXPROCS(-1) == 1 {
   322  		defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(16))
   323  	}
   324  	numLoop := 10
   325  	numGrowStep := 250
   326  	numReader := 16
   327  	if testing.Short() {
   328  		numLoop, numGrowStep = 2, 100
   329  	}
   330  	for i := 0; i < numLoop; i++ {
   331  		m := make(map[int]int, 0)
   332  		for gs := 0; gs < numGrowStep; gs++ {
   333  			m[gs] = gs
   334  			var wg sync.WaitGroup
   335  			wg.Add(numReader * 2)
   336  			for nr := 0; nr < numReader; nr++ {
   337  				go func() {
   338  					defer wg.Done()
   339  					for range m {
   340  					}
   341  				}()
   342  				go func() {
   343  					defer wg.Done()
   344  					for key := 0; key < gs; key++ {
   345  						_ = m[key]
   346  					}
   347  				}()
   348  				if useReflect {
   349  					wg.Add(1)
   350  					go func() {
   351  						defer wg.Done()
   352  						mv := reflect.ValueOf(m)
   353  						keys := mv.MapKeys()
   354  						for _, k := range keys {
   355  							mv.MapIndex(k)
   356  						}
   357  					}()
   358  				}
   359  			}
   360  			wg.Wait()
   361  		}
   362  	}
   363  }
   364  
   365  func TestConcurrentReadsAfterGrowth(t *testing.T) {
   366  	testConcurrentReadsAfterGrowth(t, false)
   367  }
   368  
   369  func TestConcurrentReadsAfterGrowthReflect(t *testing.T) {
   370  	testConcurrentReadsAfterGrowth(t, true)
   371  }
   372  
   373  func TestBigItems(t *testing.T) {
   374  	var key [256]string
   375  	for i := 0; i < 256; i++ {
   376  		key[i] = "foo"
   377  	}
   378  	m := make(map[[256]string][256]string, 4)
   379  	for i := 0; i < 100; i++ {
   380  		key[37] = fmt.Sprintf("string%02d", i)
   381  		m[key] = key
   382  	}
   383  	var keys [100]string
   384  	var values [100]string
   385  	i := 0
   386  	for k, v := range m {
   387  		keys[i] = k[37]
   388  		values[i] = v[37]
   389  		i++
   390  	}
   391  	slices.Sort(keys[:])
   392  	slices.Sort(values[:])
   393  	for i := 0; i < 100; i++ {
   394  		if keys[i] != fmt.Sprintf("string%02d", i) {
   395  			t.Errorf("#%d: missing key: %v", i, keys[i])
   396  		}
   397  		if values[i] != fmt.Sprintf("string%02d", i) {
   398  			t.Errorf("#%d: missing value: %v", i, values[i])
   399  		}
   400  	}
   401  }
   402  
   403  func TestMapHugeZero(t *testing.T) {
   404  	type T [4000]byte
   405  	m := map[int]T{}
   406  	x := m[0]
   407  	if x != (T{}) {
   408  		t.Errorf("map value not zero")
   409  	}
   410  	y, ok := m[0]
   411  	if ok {
   412  		t.Errorf("map value should be missing")
   413  	}
   414  	if y != (T{}) {
   415  		t.Errorf("map value not zero")
   416  	}
   417  }
   418  
   419  type empty struct {
   420  }
   421  
   422  func TestEmptyKeyAndValue(t *testing.T) {
   423  	a := make(map[int]empty, 4)
   424  	b := make(map[empty]int, 4)
   425  	c := make(map[empty]empty, 4)
   426  	a[0] = empty{}
   427  	b[empty{}] = 0
   428  	b[empty{}] = 1
   429  	c[empty{}] = empty{}
   430  
   431  	if len(a) != 1 {
   432  		t.Errorf("empty value insert problem")
   433  	}
   434  	if b[empty{}] != 1 {
   435  		t.Errorf("empty key returned wrong value")
   436  	}
   437  }
   438  
   439  // Tests a map with a single bucket, with same-lengthed short keys
   440  // ("quick keys") as well as long keys.
   441  func TestSingleBucketMapStringKeys_DupLen(t *testing.T) {
   442  	testMapLookups(t, map[string]string{
   443  		"x":                      "x1val",
   444  		"xx":                     "x2val",
   445  		"foo":                    "fooval",
   446  		"bar":                    "barval", // same key length as "foo"
   447  		"xxxx":                   "x4val",
   448  		strings.Repeat("x", 128): "longval1",
   449  		strings.Repeat("y", 128): "longval2",
   450  	})
   451  }
   452  
   453  // Tests a map with a single bucket, with all keys having different lengths.
   454  func TestSingleBucketMapStringKeys_NoDupLen(t *testing.T) {
   455  	testMapLookups(t, map[string]string{
   456  		"x":                      "x1val",
   457  		"xx":                     "x2val",
   458  		"foo":                    "fooval",
   459  		"xxxx":                   "x4val",
   460  		"xxxxx":                  "x5val",
   461  		"xxxxxx":                 "x6val",
   462  		strings.Repeat("x", 128): "longval",
   463  	})
   464  }
   465  
   466  func testMapLookups(t *testing.T, m map[string]string) {
   467  	for k, v := range m {
   468  		if m[k] != v {
   469  			t.Fatalf("m[%q] = %q; want %q", k, m[k], v)
   470  		}
   471  	}
   472  }
   473  
   474  // Tests whether the iterator returns the right elements when
   475  // started in the middle of a grow, when the keys are NaNs.
   476  func TestMapNanGrowIterator(t *testing.T) {
   477  	m := make(map[float64]int)
   478  	nan := math.NaN()
   479  	const nBuckets = 16
   480  	// To fill nBuckets buckets takes LOAD * nBuckets keys.
   481  	nKeys := int(nBuckets * runtime.HashLoad)
   482  
   483  	// Get map to full point with nan keys.
   484  	for i := 0; i < nKeys; i++ {
   485  		m[nan] = i
   486  	}
   487  	// Trigger grow
   488  	m[1.0] = 1
   489  	delete(m, 1.0)
   490  
   491  	// Run iterator
   492  	found := make(map[int]struct{})
   493  	for _, v := range m {
   494  		if v != -1 {
   495  			if _, repeat := found[v]; repeat {
   496  				t.Fatalf("repeat of value %d", v)
   497  			}
   498  			found[v] = struct{}{}
   499  		}
   500  		if len(found) == nKeys/2 {
   501  			// Halfway through iteration, finish grow.
   502  			for i := 0; i < nBuckets; i++ {
   503  				delete(m, 1.0)
   504  			}
   505  		}
   506  	}
   507  	if len(found) != nKeys {
   508  		t.Fatalf("missing value")
   509  	}
   510  }
   511  
   512  func TestMapIterOrder(t *testing.T) {
   513  	sizes := []int{3, 7, 9, 15}
   514  	if abi.MapBucketCountBits >= 5 {
   515  		// it gets flaky (often only one iteration order) at size 3 when abi.MapBucketCountBits >=5.
   516  		t.Fatalf("This test becomes flaky if abi.MapBucketCountBits(=%d) is 5 or larger", abi.MapBucketCountBits)
   517  	}
   518  	for _, n := range sizes {
   519  		for i := 0; i < 1000; i++ {
   520  			// Make m be {0: true, 1: true, ..., n-1: true}.
   521  			m := make(map[int]bool)
   522  			for i := 0; i < n; i++ {
   523  				m[i] = true
   524  			}
   525  			// Check that iterating over the map produces at least two different orderings.
   526  			ord := func() []int {
   527  				var s []int
   528  				for key := range m {
   529  					s = append(s, key)
   530  				}
   531  				return s
   532  			}
   533  			first := ord()
   534  			ok := false
   535  			for try := 0; try < 100; try++ {
   536  				if !reflect.DeepEqual(first, ord()) {
   537  					ok = true
   538  					break
   539  				}
   540  			}
   541  			if !ok {
   542  				t.Errorf("Map with n=%d elements had consistent iteration order: %v", n, first)
   543  				break
   544  			}
   545  		}
   546  	}
   547  }
   548  
   549  // Issue 8410
   550  func TestMapSparseIterOrder(t *testing.T) {
   551  	// Run several rounds to increase the probability
   552  	// of failure. One is not enough.
   553  NextRound:
   554  	for round := 0; round < 10; round++ {
   555  		m := make(map[int]bool)
   556  		// Add 1000 items, remove 980.
   557  		for i := 0; i < 1000; i++ {
   558  			m[i] = true
   559  		}
   560  		for i := 20; i < 1000; i++ {
   561  			delete(m, i)
   562  		}
   563  
   564  		var first []int
   565  		for i := range m {
   566  			first = append(first, i)
   567  		}
   568  
   569  		// 800 chances to get a different iteration order.
   570  		// See bug 8736 for why we need so many tries.
   571  		for n := 0; n < 800; n++ {
   572  			idx := 0
   573  			for i := range m {
   574  				if i != first[idx] {
   575  					// iteration order changed.
   576  					continue NextRound
   577  				}
   578  				idx++
   579  			}
   580  		}
   581  		t.Fatalf("constant iteration order on round %d: %v", round, first)
   582  	}
   583  }
   584  
   585  func TestMapStringBytesLookup(t *testing.T) {
   586  	// Use large string keys to avoid small-allocation coalescing,
   587  	// which can cause AllocsPerRun to report lower counts than it should.
   588  	m := map[string]int{
   589  		"1000000000000000000000000000000000000000000000000": 1,
   590  		"2000000000000000000000000000000000000000000000000": 2,
   591  	}
   592  	buf := []byte("1000000000000000000000000000000000000000000000000")
   593  	if x := m[string(buf)]; x != 1 {
   594  		t.Errorf(`m[string([]byte("1"))] = %d, want 1`, x)
   595  	}
   596  	buf[0] = '2'
   597  	if x := m[string(buf)]; x != 2 {
   598  		t.Errorf(`m[string([]byte("2"))] = %d, want 2`, x)
   599  	}
   600  
   601  	var x int
   602  	n := testing.AllocsPerRun(100, func() {
   603  		x += m[string(buf)]
   604  	})
   605  	if n != 0 {
   606  		t.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n)
   607  	}
   608  
   609  	x = 0
   610  	n = testing.AllocsPerRun(100, func() {
   611  		y, ok := m[string(buf)]
   612  		if !ok {
   613  			panic("!ok")
   614  		}
   615  		x += y
   616  	})
   617  	if n != 0 {
   618  		t.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n)
   619  	}
   620  }
   621  
   622  func TestMapLargeKeyNoPointer(t *testing.T) {
   623  	const (
   624  		I = 1000
   625  		N = 64
   626  	)
   627  	type T [N]int
   628  	m := make(map[T]int)
   629  	for i := 0; i < I; i++ {
   630  		var v T
   631  		for j := 0; j < N; j++ {
   632  			v[j] = i + j
   633  		}
   634  		m[v] = i
   635  	}
   636  	runtime.GC()
   637  	for i := 0; i < I; i++ {
   638  		var v T
   639  		for j := 0; j < N; j++ {
   640  			v[j] = i + j
   641  		}
   642  		if m[v] != i {
   643  			t.Fatalf("corrupted map: want %+v, got %+v", i, m[v])
   644  		}
   645  	}
   646  }
   647  
   648  func TestMapLargeValNoPointer(t *testing.T) {
   649  	const (
   650  		I = 1000
   651  		N = 64
   652  	)
   653  	type T [N]int
   654  	m := make(map[int]T)
   655  	for i := 0; i < I; i++ {
   656  		var v T
   657  		for j := 0; j < N; j++ {
   658  			v[j] = i + j
   659  		}
   660  		m[i] = v
   661  	}
   662  	runtime.GC()
   663  	for i := 0; i < I; i++ {
   664  		var v T
   665  		for j := 0; j < N; j++ {
   666  			v[j] = i + j
   667  		}
   668  		v1 := m[i]
   669  		for j := 0; j < N; j++ {
   670  			if v1[j] != v[j] {
   671  				t.Fatalf("corrupted map: want %+v, got %+v", v, v1)
   672  			}
   673  		}
   674  	}
   675  }
   676  
   677  // Test that making a map with a large or invalid hint
   678  // doesn't panic. (Issue 19926).
   679  func TestIgnoreBogusMapHint(t *testing.T) {
   680  	for _, hint := range []int64{-1, 1 << 62} {
   681  		_ = make(map[int]int, hint)
   682  	}
   683  }
   684  
   685  const bs = abi.MapBucketCount
   686  
   687  // belowOverflow should be a pretty-full pair of buckets;
   688  // atOverflow is 1/8 bs larger = 13/8 buckets or two buckets
   689  // that are 13/16 full each, which is the overflow boundary.
   690  // Adding one to that should ensure overflow to the next higher size.
   691  const (
   692  	belowOverflow = bs * 3 / 2           // 1.5 bs = 2 buckets @ 75%
   693  	atOverflow    = belowOverflow + bs/8 // 2 buckets at 13/16 fill.
   694  )
   695  
   696  var mapBucketTests = [...]struct {
   697  	n        int // n is the number of map elements
   698  	noescape int // number of expected buckets for non-escaping map
   699  	escape   int // number of expected buckets for escaping map
   700  }{
   701  	{-(1 << 30), 1, 1},
   702  	{-1, 1, 1},
   703  	{0, 1, 1},
   704  	{1, 1, 1},
   705  	{bs, 1, 1},
   706  	{bs + 1, 2, 2},
   707  	{belowOverflow, 2, 2},  // 1.5 bs = 2 buckets @ 75%
   708  	{atOverflow + 1, 4, 4}, // 13/8 bs + 1 == overflow to 4
   709  
   710  	{2 * belowOverflow, 4, 4}, // 3 bs = 4 buckets @75%
   711  	{2*atOverflow + 1, 8, 8},  // 13/4 bs + 1 = overflow to 8
   712  
   713  	{4 * belowOverflow, 8, 8},  // 6 bs = 8 buckets @ 75%
   714  	{4*atOverflow + 1, 16, 16}, // 13/2 bs + 1 = overflow to 16
   715  }
   716  
   717  func TestMapBuckets(t *testing.T) {
   718  	// Test that maps of different sizes have the right number of buckets.
   719  	// Non-escaping maps with small buckets (like map[int]int) never
   720  	// have a nil bucket pointer due to starting with preallocated buckets
   721  	// on the stack. Escaping maps start with a non-nil bucket pointer if
   722  	// hint size is above bucketCnt and thereby have more than one bucket.
   723  	// These tests depend on bucketCnt and loadFactor* in map.go.
   724  	t.Run("mapliteral", func(t *testing.T) {
   725  		for _, tt := range mapBucketTests {
   726  			localMap := map[int]int{}
   727  			if runtime.MapBucketsPointerIsNil(localMap) {
   728  				t.Errorf("no escape: buckets pointer is nil for non-escaping map")
   729  			}
   730  			for i := 0; i < tt.n; i++ {
   731  				localMap[i] = i
   732  			}
   733  			if got := runtime.MapBucketsCount(localMap); got != tt.noescape {
   734  				t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got)
   735  			}
   736  			escapingMap := runtime.Escape(map[int]int{})
   737  			if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) {
   738  				t.Errorf("escape: buckets pointer is nil for n=%d buckets", count)
   739  			}
   740  			for i := 0; i < tt.n; i++ {
   741  				escapingMap[i] = i
   742  			}
   743  			if got := runtime.MapBucketsCount(escapingMap); got != tt.escape {
   744  				t.Errorf("escape n=%d want %d buckets, got %d", tt.n, tt.escape, got)
   745  			}
   746  		}
   747  	})
   748  	t.Run("nohint", func(t *testing.T) {
   749  		for _, tt := range mapBucketTests {
   750  			localMap := make(map[int]int)
   751  			if runtime.MapBucketsPointerIsNil(localMap) {
   752  				t.Errorf("no escape: buckets pointer is nil for non-escaping map")
   753  			}
   754  			for i := 0; i < tt.n; i++ {
   755  				localMap[i] = i
   756  			}
   757  			if got := runtime.MapBucketsCount(localMap); got != tt.noescape {
   758  				t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got)
   759  			}
   760  			escapingMap := runtime.Escape(make(map[int]int))
   761  			if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) {
   762  				t.Errorf("escape: buckets pointer is nil for n=%d buckets", count)
   763  			}
   764  			for i := 0; i < tt.n; i++ {
   765  				escapingMap[i] = i
   766  			}
   767  			if got := runtime.MapBucketsCount(escapingMap); got != tt.escape {
   768  				t.Errorf("escape: n=%d want %d buckets, got %d", tt.n, tt.escape, got)
   769  			}
   770  		}
   771  	})
   772  	t.Run("makemap", func(t *testing.T) {
   773  		for _, tt := range mapBucketTests {
   774  			localMap := make(map[int]int, tt.n)
   775  			if runtime.MapBucketsPointerIsNil(localMap) {
   776  				t.Errorf("no escape: buckets pointer is nil for non-escaping map")
   777  			}
   778  			for i := 0; i < tt.n; i++ {
   779  				localMap[i] = i
   780  			}
   781  			if got := runtime.MapBucketsCount(localMap); got != tt.noescape {
   782  				t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got)
   783  			}
   784  			escapingMap := runtime.Escape(make(map[int]int, tt.n))
   785  			if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) {
   786  				t.Errorf("escape: buckets pointer is nil for n=%d buckets", count)
   787  			}
   788  			for i := 0; i < tt.n; i++ {
   789  				escapingMap[i] = i
   790  			}
   791  			if got := runtime.MapBucketsCount(escapingMap); got != tt.escape {
   792  				t.Errorf("escape: n=%d want %d buckets, got %d", tt.n, tt.escape, got)
   793  			}
   794  		}
   795  	})
   796  	t.Run("makemap64", func(t *testing.T) {
   797  		for _, tt := range mapBucketTests {
   798  			localMap := make(map[int]int, int64(tt.n))
   799  			if runtime.MapBucketsPointerIsNil(localMap) {
   800  				t.Errorf("no escape: buckets pointer is nil for non-escaping map")
   801  			}
   802  			for i := 0; i < tt.n; i++ {
   803  				localMap[i] = i
   804  			}
   805  			if got := runtime.MapBucketsCount(localMap); got != tt.noescape {
   806  				t.Errorf("no escape: n=%d want %d buckets, got %d", tt.n, tt.noescape, got)
   807  			}
   808  			escapingMap := runtime.Escape(make(map[int]int, tt.n))
   809  			if count := runtime.MapBucketsCount(escapingMap); count > 1 && runtime.MapBucketsPointerIsNil(escapingMap) {
   810  				t.Errorf("escape: buckets pointer is nil for n=%d buckets", count)
   811  			}
   812  			for i := 0; i < tt.n; i++ {
   813  				escapingMap[i] = i
   814  			}
   815  			if got := runtime.MapBucketsCount(escapingMap); got != tt.escape {
   816  				t.Errorf("escape: n=%d want %d buckets, got %d", tt.n, tt.escape, got)
   817  			}
   818  		}
   819  	})
   820  
   821  }
   822  
   823  func benchmarkMapPop(b *testing.B, n int) {
   824  	m := map[int]int{}
   825  	for i := 0; i < b.N; i++ {
   826  		for j := 0; j < n; j++ {
   827  			m[j] = j
   828  		}
   829  		for j := 0; j < n; j++ {
   830  			// Use iterator to pop an element.
   831  			// We want this to be fast, see issue 8412.
   832  			for k := range m {
   833  				delete(m, k)
   834  				break
   835  			}
   836  		}
   837  	}
   838  }
   839  
   840  func BenchmarkMapPop100(b *testing.B)   { benchmarkMapPop(b, 100) }
   841  func BenchmarkMapPop1000(b *testing.B)  { benchmarkMapPop(b, 1000) }
   842  func BenchmarkMapPop10000(b *testing.B) { benchmarkMapPop(b, 10000) }
   843  
   844  var testNonEscapingMapVariable int = 8
   845  
   846  func TestNonEscapingMap(t *testing.T) {
   847  	n := testing.AllocsPerRun(1000, func() {
   848  		m := map[int]int{}
   849  		m[0] = 0
   850  	})
   851  	if n != 0 {
   852  		t.Fatalf("mapliteral: want 0 allocs, got %v", n)
   853  	}
   854  	n = testing.AllocsPerRun(1000, func() {
   855  		m := make(map[int]int)
   856  		m[0] = 0
   857  	})
   858  	if n != 0 {
   859  		t.Fatalf("no hint: want 0 allocs, got %v", n)
   860  	}
   861  	n = testing.AllocsPerRun(1000, func() {
   862  		m := make(map[int]int, 8)
   863  		m[0] = 0
   864  	})
   865  	if n != 0 {
   866  		t.Fatalf("with small hint: want 0 allocs, got %v", n)
   867  	}
   868  	n = testing.AllocsPerRun(1000, func() {
   869  		m := make(map[int]int, testNonEscapingMapVariable)
   870  		m[0] = 0
   871  	})
   872  	if n != 0 {
   873  		t.Fatalf("with variable hint: want 0 allocs, got %v", n)
   874  	}
   875  
   876  }
   877  
   878  func benchmarkMapAssignInt32(b *testing.B, n int) {
   879  	a := make(map[int32]int)
   880  	for i := 0; i < b.N; i++ {
   881  		a[int32(i&(n-1))] = i
   882  	}
   883  }
   884  
   885  func benchmarkMapOperatorAssignInt32(b *testing.B, n int) {
   886  	a := make(map[int32]int)
   887  	for i := 0; i < b.N; i++ {
   888  		a[int32(i&(n-1))] += i
   889  	}
   890  }
   891  
   892  func benchmarkMapAppendAssignInt32(b *testing.B, n int) {
   893  	a := make(map[int32][]int)
   894  	b.ReportAllocs()
   895  	b.ResetTimer()
   896  	for i := 0; i < b.N; i++ {
   897  		key := int32(i & (n - 1))
   898  		a[key] = append(a[key], i)
   899  	}
   900  }
   901  
   902  func benchmarkMapDeleteInt32(b *testing.B, n int) {
   903  	a := make(map[int32]int, n)
   904  	b.ResetTimer()
   905  	for i := 0; i < b.N; i++ {
   906  		if len(a) == 0 {
   907  			b.StopTimer()
   908  			for j := i; j < i+n; j++ {
   909  				a[int32(j)] = j
   910  			}
   911  			b.StartTimer()
   912  		}
   913  		delete(a, int32(i))
   914  	}
   915  }
   916  
   917  func benchmarkMapAssignInt64(b *testing.B, n int) {
   918  	a := make(map[int64]int)
   919  	for i := 0; i < b.N; i++ {
   920  		a[int64(i&(n-1))] = i
   921  	}
   922  }
   923  
   924  func benchmarkMapOperatorAssignInt64(b *testing.B, n int) {
   925  	a := make(map[int64]int)
   926  	for i := 0; i < b.N; i++ {
   927  		a[int64(i&(n-1))] += i
   928  	}
   929  }
   930  
   931  func benchmarkMapAppendAssignInt64(b *testing.B, n int) {
   932  	a := make(map[int64][]int)
   933  	b.ReportAllocs()
   934  	b.ResetTimer()
   935  	for i := 0; i < b.N; i++ {
   936  		key := int64(i & (n - 1))
   937  		a[key] = append(a[key], i)
   938  	}
   939  }
   940  
   941  func benchmarkMapDeleteInt64(b *testing.B, n int) {
   942  	a := make(map[int64]int, n)
   943  	b.ResetTimer()
   944  	for i := 0; i < b.N; i++ {
   945  		if len(a) == 0 {
   946  			b.StopTimer()
   947  			for j := i; j < i+n; j++ {
   948  				a[int64(j)] = j
   949  			}
   950  			b.StartTimer()
   951  		}
   952  		delete(a, int64(i))
   953  	}
   954  }
   955  
   956  func benchmarkMapAssignStr(b *testing.B, n int) {
   957  	k := make([]string, n)
   958  	for i := 0; i < len(k); i++ {
   959  		k[i] = strconv.Itoa(i)
   960  	}
   961  	b.ResetTimer()
   962  	a := make(map[string]int)
   963  	for i := 0; i < b.N; i++ {
   964  		a[k[i&(n-1)]] = i
   965  	}
   966  }
   967  
   968  func benchmarkMapOperatorAssignStr(b *testing.B, n int) {
   969  	k := make([]string, n)
   970  	for i := 0; i < len(k); i++ {
   971  		k[i] = strconv.Itoa(i)
   972  	}
   973  	b.ResetTimer()
   974  	a := make(map[string]string)
   975  	for i := 0; i < b.N; i++ {
   976  		key := k[i&(n-1)]
   977  		a[key] += key
   978  	}
   979  }
   980  
   981  func benchmarkMapAppendAssignStr(b *testing.B, n int) {
   982  	k := make([]string, n)
   983  	for i := 0; i < len(k); i++ {
   984  		k[i] = strconv.Itoa(i)
   985  	}
   986  	a := make(map[string][]string)
   987  	b.ReportAllocs()
   988  	b.ResetTimer()
   989  	for i := 0; i < b.N; i++ {
   990  		key := k[i&(n-1)]
   991  		a[key] = append(a[key], key)
   992  	}
   993  }
   994  
   995  func benchmarkMapDeleteStr(b *testing.B, n int) {
   996  	i2s := make([]string, n)
   997  	for i := 0; i < n; i++ {
   998  		i2s[i] = strconv.Itoa(i)
   999  	}
  1000  	a := make(map[string]int, n)
  1001  	b.ResetTimer()
  1002  	k := 0
  1003  	for i := 0; i < b.N; i++ {
  1004  		if len(a) == 0 {
  1005  			b.StopTimer()
  1006  			for j := 0; j < n; j++ {
  1007  				a[i2s[j]] = j
  1008  			}
  1009  			k = i
  1010  			b.StartTimer()
  1011  		}
  1012  		delete(a, i2s[i-k])
  1013  	}
  1014  }
  1015  
  1016  func benchmarkMapDeletePointer(b *testing.B, n int) {
  1017  	i2p := make([]*int, n)
  1018  	for i := 0; i < n; i++ {
  1019  		i2p[i] = new(int)
  1020  	}
  1021  	a := make(map[*int]int, n)
  1022  	b.ResetTimer()
  1023  	k := 0
  1024  	for i := 0; i < b.N; i++ {
  1025  		if len(a) == 0 {
  1026  			b.StopTimer()
  1027  			for j := 0; j < n; j++ {
  1028  				a[i2p[j]] = j
  1029  			}
  1030  			k = i
  1031  			b.StartTimer()
  1032  		}
  1033  		delete(a, i2p[i-k])
  1034  	}
  1035  }
  1036  
  1037  func runWith(f func(*testing.B, int), v ...int) func(*testing.B) {
  1038  	return func(b *testing.B) {
  1039  		for _, n := range v {
  1040  			b.Run(strconv.Itoa(n), func(b *testing.B) { f(b, n) })
  1041  		}
  1042  	}
  1043  }
  1044  
  1045  func BenchmarkMapAssign(b *testing.B) {
  1046  	b.Run("Int32", runWith(benchmarkMapAssignInt32, 1<<8, 1<<16))
  1047  	b.Run("Int64", runWith(benchmarkMapAssignInt64, 1<<8, 1<<16))
  1048  	b.Run("Str", runWith(benchmarkMapAssignStr, 1<<8, 1<<16))
  1049  }
  1050  
  1051  func BenchmarkMapOperatorAssign(b *testing.B) {
  1052  	b.Run("Int32", runWith(benchmarkMapOperatorAssignInt32, 1<<8, 1<<16))
  1053  	b.Run("Int64", runWith(benchmarkMapOperatorAssignInt64, 1<<8, 1<<16))
  1054  	b.Run("Str", runWith(benchmarkMapOperatorAssignStr, 1<<8, 1<<16))
  1055  }
  1056  
  1057  func BenchmarkMapAppendAssign(b *testing.B) {
  1058  	b.Run("Int32", runWith(benchmarkMapAppendAssignInt32, 1<<8, 1<<16))
  1059  	b.Run("Int64", runWith(benchmarkMapAppendAssignInt64, 1<<8, 1<<16))
  1060  	b.Run("Str", runWith(benchmarkMapAppendAssignStr, 1<<8, 1<<16))
  1061  }
  1062  
  1063  func BenchmarkMapDelete(b *testing.B) {
  1064  	b.Run("Int32", runWith(benchmarkMapDeleteInt32, 100, 1000, 10000))
  1065  	b.Run("Int64", runWith(benchmarkMapDeleteInt64, 100, 1000, 10000))
  1066  	b.Run("Str", runWith(benchmarkMapDeleteStr, 100, 1000, 10000))
  1067  	b.Run("Pointer", runWith(benchmarkMapDeletePointer, 100, 1000, 10000))
  1068  }
  1069  
  1070  func TestDeferDeleteSlow(t *testing.T) {
  1071  	ks := []complex128{0, 1, 2, 3}
  1072  
  1073  	m := make(map[any]int)
  1074  	for i, k := range ks {
  1075  		m[k] = i
  1076  	}
  1077  	if len(m) != len(ks) {
  1078  		t.Errorf("want %d elements, got %d", len(ks), len(m))
  1079  	}
  1080  
  1081  	func() {
  1082  		for _, k := range ks {
  1083  			defer delete(m, k)
  1084  		}
  1085  	}()
  1086  	if len(m) != 0 {
  1087  		t.Errorf("want 0 elements, got %d", len(m))
  1088  	}
  1089  }
  1090  
  1091  // TestIncrementAfterDeleteValueInt and other test Issue 25936.
  1092  // Value types int, int32, int64 are affected. Value type string
  1093  // works as expected.
  1094  func TestIncrementAfterDeleteValueInt(t *testing.T) {
  1095  	const key1 = 12
  1096  	const key2 = 13
  1097  
  1098  	m := make(map[int]int)
  1099  	m[key1] = 99
  1100  	delete(m, key1)
  1101  	m[key2]++
  1102  	if n2 := m[key2]; n2 != 1 {
  1103  		t.Errorf("incremented 0 to %d", n2)
  1104  	}
  1105  }
  1106  
  1107  func TestIncrementAfterDeleteValueInt32(t *testing.T) {
  1108  	const key1 = 12
  1109  	const key2 = 13
  1110  
  1111  	m := make(map[int]int32)
  1112  	m[key1] = 99
  1113  	delete(m, key1)
  1114  	m[key2]++
  1115  	if n2 := m[key2]; n2 != 1 {
  1116  		t.Errorf("incremented 0 to %d", n2)
  1117  	}
  1118  }
  1119  
  1120  func TestIncrementAfterDeleteValueInt64(t *testing.T) {
  1121  	const key1 = 12
  1122  	const key2 = 13
  1123  
  1124  	m := make(map[int]int64)
  1125  	m[key1] = 99
  1126  	delete(m, key1)
  1127  	m[key2]++
  1128  	if n2 := m[key2]; n2 != 1 {
  1129  		t.Errorf("incremented 0 to %d", n2)
  1130  	}
  1131  }
  1132  
  1133  func TestIncrementAfterDeleteKeyStringValueInt(t *testing.T) {
  1134  	const key1 = ""
  1135  	const key2 = "x"
  1136  
  1137  	m := make(map[string]int)
  1138  	m[key1] = 99
  1139  	delete(m, key1)
  1140  	m[key2] += 1
  1141  	if n2 := m[key2]; n2 != 1 {
  1142  		t.Errorf("incremented 0 to %d", n2)
  1143  	}
  1144  }
  1145  
  1146  func TestIncrementAfterDeleteKeyValueString(t *testing.T) {
  1147  	const key1 = ""
  1148  	const key2 = "x"
  1149  
  1150  	m := make(map[string]string)
  1151  	m[key1] = "99"
  1152  	delete(m, key1)
  1153  	m[key2] += "1"
  1154  	if n2 := m[key2]; n2 != "1" {
  1155  		t.Errorf("appended '1' to empty (nil) string, got %s", n2)
  1156  	}
  1157  }
  1158  
  1159  // TestIncrementAfterBulkClearKeyStringValueInt tests that map bulk
  1160  // deletion (mapclear) still works as expected. Note that it was not
  1161  // affected by Issue 25936.
  1162  func TestIncrementAfterBulkClearKeyStringValueInt(t *testing.T) {
  1163  	const key1 = ""
  1164  	const key2 = "x"
  1165  
  1166  	m := make(map[string]int)
  1167  	m[key1] = 99
  1168  	for k := range m {
  1169  		delete(m, k)
  1170  	}
  1171  	m[key2]++
  1172  	if n2 := m[key2]; n2 != 1 {
  1173  		t.Errorf("incremented 0 to %d", n2)
  1174  	}
  1175  }
  1176  
  1177  func TestMapTombstones(t *testing.T) {
  1178  	m := map[int]int{}
  1179  	const N = 10000
  1180  	// Fill a map.
  1181  	for i := 0; i < N; i++ {
  1182  		m[i] = i
  1183  	}
  1184  	runtime.MapTombstoneCheck(m)
  1185  	// Delete half of the entries.
  1186  	for i := 0; i < N; i += 2 {
  1187  		delete(m, i)
  1188  	}
  1189  	runtime.MapTombstoneCheck(m)
  1190  	// Add new entries to fill in holes.
  1191  	for i := N; i < 3*N/2; i++ {
  1192  		m[i] = i
  1193  	}
  1194  	runtime.MapTombstoneCheck(m)
  1195  	// Delete everything.
  1196  	for i := 0; i < 3*N/2; i++ {
  1197  		delete(m, i)
  1198  	}
  1199  	runtime.MapTombstoneCheck(m)
  1200  }
  1201  
  1202  type canString int
  1203  
  1204  func (c canString) String() string {
  1205  	return fmt.Sprintf("%d", int(c))
  1206  }
  1207  
  1208  func TestMapInterfaceKey(t *testing.T) {
  1209  	// Test all the special cases in runtime.typehash.
  1210  	type GrabBag struct {
  1211  		f32  float32
  1212  		f64  float64
  1213  		c64  complex64
  1214  		c128 complex128
  1215  		s    string
  1216  		i0   any
  1217  		i1   interface {
  1218  			String() string
  1219  		}
  1220  		a [4]string
  1221  	}
  1222  
  1223  	m := map[any]bool{}
  1224  	// Put a bunch of data in m, so that a bad hash is likely to
  1225  	// lead to a bad bucket, which will lead to a missed lookup.
  1226  	for i := 0; i < 1000; i++ {
  1227  		m[i] = true
  1228  	}
  1229  	m[GrabBag{f32: 1.0}] = true
  1230  	if !m[GrabBag{f32: 1.0}] {
  1231  		panic("f32 not found")
  1232  	}
  1233  	m[GrabBag{f64: 1.0}] = true
  1234  	if !m[GrabBag{f64: 1.0}] {
  1235  		panic("f64 not found")
  1236  	}
  1237  	m[GrabBag{c64: 1.0i}] = true
  1238  	if !m[GrabBag{c64: 1.0i}] {
  1239  		panic("c64 not found")
  1240  	}
  1241  	m[GrabBag{c128: 1.0i}] = true
  1242  	if !m[GrabBag{c128: 1.0i}] {
  1243  		panic("c128 not found")
  1244  	}
  1245  	m[GrabBag{s: "foo"}] = true
  1246  	if !m[GrabBag{s: "foo"}] {
  1247  		panic("string not found")
  1248  	}
  1249  	m[GrabBag{i0: "foo"}] = true
  1250  	if !m[GrabBag{i0: "foo"}] {
  1251  		panic("interface{} not found")
  1252  	}
  1253  	m[GrabBag{i1: canString(5)}] = true
  1254  	if !m[GrabBag{i1: canString(5)}] {
  1255  		panic("interface{String() string} not found")
  1256  	}
  1257  	m[GrabBag{a: [4]string{"foo", "bar", "baz", "bop"}}] = true
  1258  	if !m[GrabBag{a: [4]string{"foo", "bar", "baz", "bop"}}] {
  1259  		panic("array not found")
  1260  	}
  1261  }
  1262  
  1263  type panicStructKey struct {
  1264  	sli []int
  1265  }
  1266  
  1267  func (p panicStructKey) String() string {
  1268  	return "panic"
  1269  }
  1270  
  1271  type structKey struct {
  1272  }
  1273  
  1274  func (structKey) String() string {
  1275  	return "structKey"
  1276  }
  1277  
  1278  func TestEmptyMapWithInterfaceKey(t *testing.T) {
  1279  	var (
  1280  		b    bool
  1281  		i    int
  1282  		i8   int8
  1283  		i16  int16
  1284  		i32  int32
  1285  		i64  int64
  1286  		ui   uint
  1287  		ui8  uint8
  1288  		ui16 uint16
  1289  		ui32 uint32
  1290  		ui64 uint64
  1291  		uipt uintptr
  1292  		f32  float32
  1293  		f64  float64
  1294  		c64  complex64
  1295  		c128 complex128
  1296  		a    [4]string
  1297  		s    string
  1298  		p    *int
  1299  		up   unsafe.Pointer
  1300  		ch   chan int
  1301  		i0   any
  1302  		i1   interface {
  1303  			String() string
  1304  		}
  1305  		structKey structKey
  1306  		i0Panic   any = []int{}
  1307  		i1Panic   interface {
  1308  			String() string
  1309  		} = panicStructKey{}
  1310  		panicStructKey = panicStructKey{}
  1311  		sli            []int
  1312  		me             = map[any]struct{}{}
  1313  		mi             = map[interface {
  1314  			String() string
  1315  		}]struct{}{}
  1316  	)
  1317  	mustNotPanic := func(f func()) {
  1318  		f()
  1319  	}
  1320  	mustPanic := func(f func()) {
  1321  		defer func() {
  1322  			r := recover()
  1323  			if r == nil {
  1324  				t.Errorf("didn't panic")
  1325  			}
  1326  		}()
  1327  		f()
  1328  	}
  1329  	mustNotPanic(func() {
  1330  		_ = me[b]
  1331  	})
  1332  	mustNotPanic(func() {
  1333  		_ = me[i]
  1334  	})
  1335  	mustNotPanic(func() {
  1336  		_ = me[i8]
  1337  	})
  1338  	mustNotPanic(func() {
  1339  		_ = me[i16]
  1340  	})
  1341  	mustNotPanic(func() {
  1342  		_ = me[i32]
  1343  	})
  1344  	mustNotPanic(func() {
  1345  		_ = me[i64]
  1346  	})
  1347  	mustNotPanic(func() {
  1348  		_ = me[ui]
  1349  	})
  1350  	mustNotPanic(func() {
  1351  		_ = me[ui8]
  1352  	})
  1353  	mustNotPanic(func() {
  1354  		_ = me[ui16]
  1355  	})
  1356  	mustNotPanic(func() {
  1357  		_ = me[ui32]
  1358  	})
  1359  	mustNotPanic(func() {
  1360  		_ = me[ui64]
  1361  	})
  1362  	mustNotPanic(func() {
  1363  		_ = me[uipt]
  1364  	})
  1365  	mustNotPanic(func() {
  1366  		_ = me[f32]
  1367  	})
  1368  	mustNotPanic(func() {
  1369  		_ = me[f64]
  1370  	})
  1371  	mustNotPanic(func() {
  1372  		_ = me[c64]
  1373  	})
  1374  	mustNotPanic(func() {
  1375  		_ = me[c128]
  1376  	})
  1377  	mustNotPanic(func() {
  1378  		_ = me[a]
  1379  	})
  1380  	mustNotPanic(func() {
  1381  		_ = me[s]
  1382  	})
  1383  	mustNotPanic(func() {
  1384  		_ = me[p]
  1385  	})
  1386  	mustNotPanic(func() {
  1387  		_ = me[up]
  1388  	})
  1389  	mustNotPanic(func() {
  1390  		_ = me[ch]
  1391  	})
  1392  	mustNotPanic(func() {
  1393  		_ = me[i0]
  1394  	})
  1395  	mustNotPanic(func() {
  1396  		_ = me[i1]
  1397  	})
  1398  	mustNotPanic(func() {
  1399  		_ = me[structKey]
  1400  	})
  1401  	mustPanic(func() {
  1402  		_ = me[i0Panic]
  1403  	})
  1404  	mustPanic(func() {
  1405  		_ = me[i1Panic]
  1406  	})
  1407  	mustPanic(func() {
  1408  		_ = me[panicStructKey]
  1409  	})
  1410  	mustPanic(func() {
  1411  		_ = me[sli]
  1412  	})
  1413  	mustPanic(func() {
  1414  		_ = me[me]
  1415  	})
  1416  
  1417  	mustNotPanic(func() {
  1418  		_ = mi[structKey]
  1419  	})
  1420  	mustPanic(func() {
  1421  		_ = mi[panicStructKey]
  1422  	})
  1423  }
  1424  
  1425  func TestLoadFactor(t *testing.T) {
  1426  	for b := uint8(0); b < 20; b++ {
  1427  		count := 13 * (1 << b) / 2 // 6.5
  1428  		if b == 0 {
  1429  			count = 8
  1430  		}
  1431  		if runtime.OverLoadFactor(count, b) {
  1432  			t.Errorf("OverLoadFactor(%d,%d)=true, want false", count, b)
  1433  		}
  1434  		if !runtime.OverLoadFactor(count+1, b) {
  1435  			t.Errorf("OverLoadFactor(%d,%d)=false, want true", count+1, b)
  1436  		}
  1437  	}
  1438  }
  1439  
  1440  func TestMapKeys(t *testing.T) {
  1441  	type key struct {
  1442  		s   string
  1443  		pad [128]byte // sizeof(key) > abi.MapMaxKeyBytes
  1444  	}
  1445  	m := map[key]int{{s: "a"}: 1, {s: "b"}: 2}
  1446  	keys := make([]key, 0, len(m))
  1447  	runtime.MapKeys(m, unsafe.Pointer(&keys))
  1448  	for _, k := range keys {
  1449  		if len(k.s) != 1 {
  1450  			t.Errorf("len(k.s) == %d, want 1", len(k.s))
  1451  		}
  1452  	}
  1453  }
  1454  
  1455  func TestMapValues(t *testing.T) {
  1456  	type val struct {
  1457  		s   string
  1458  		pad [128]byte // sizeof(val) > abi.MapMaxElemBytes
  1459  	}
  1460  	m := map[int]val{1: {s: "a"}, 2: {s: "b"}}
  1461  	vals := make([]val, 0, len(m))
  1462  	runtime.MapValues(m, unsafe.Pointer(&vals))
  1463  	for _, v := range vals {
  1464  		if len(v.s) != 1 {
  1465  			t.Errorf("len(v.s) == %d, want 1", len(v.s))
  1466  		}
  1467  	}
  1468  }
  1469  
  1470  func computeHash() uintptr {
  1471  	var v struct{}
  1472  	return runtime.MemHash(unsafe.Pointer(&v), 0, unsafe.Sizeof(v))
  1473  }
  1474  
  1475  func subprocessHash(t *testing.T, env string) uintptr {
  1476  	t.Helper()
  1477  
  1478  	cmd := testenv.CleanCmdEnv(testenv.Command(t, os.Args[0], "-test.run=^TestMemHashGlobalSeed$"))
  1479  	cmd.Env = append(cmd.Env, "GO_TEST_SUBPROCESS_HASH=1")
  1480  	if env != "" {
  1481  		cmd.Env = append(cmd.Env, env)
  1482  	}
  1483  
  1484  	out, err := cmd.Output()
  1485  	if err != nil {
  1486  		t.Fatalf("cmd.Output got err %v want nil", err)
  1487  	}
  1488  
  1489  	s := strings.TrimSpace(string(out))
  1490  	h, err := strconv.ParseUint(s, 10, 64)
  1491  	if err != nil {
  1492  		t.Fatalf("Parse output %q got err %v want nil", s, err)
  1493  	}
  1494  	return uintptr(h)
  1495  }
  1496  
  1497  // memhash has unique per-process seeds, so hashes should differ across
  1498  // processes.
  1499  //
  1500  // Regression test for https://go.dev/issue/66885.
  1501  func TestMemHashGlobalSeed(t *testing.T) {
  1502  	if os.Getenv("GO_TEST_SUBPROCESS_HASH") != "" {
  1503  		fmt.Println(computeHash())
  1504  		os.Exit(0)
  1505  		return
  1506  	}
  1507  
  1508  	testenv.MustHaveExec(t)
  1509  
  1510  	// aeshash and memhashFallback use separate per-process seeds, so test
  1511  	// both.
  1512  	t.Run("aes", func(t *testing.T) {
  1513  		if !*runtime.UseAeshash {
  1514  			t.Skip("No AES")
  1515  		}
  1516  
  1517  		h1 := subprocessHash(t, "")
  1518  		t.Logf("%d", h1)
  1519  		h2 := subprocessHash(t, "")
  1520  		t.Logf("%d", h2)
  1521  		h3 := subprocessHash(t, "")
  1522  		t.Logf("%d", h3)
  1523  
  1524  		if h1 == h2 && h2 == h3 {
  1525  			t.Errorf("got duplicate hash %d want unique", h1)
  1526  		}
  1527  	})
  1528  
  1529  	t.Run("noaes", func(t *testing.T) {
  1530  		env := ""
  1531  		if *runtime.UseAeshash {
  1532  			env = "GODEBUG=cpu.aes=off"
  1533  		}
  1534  
  1535  		h1 := subprocessHash(t, env)
  1536  		t.Logf("%d", h1)
  1537  		h2 := subprocessHash(t, env)
  1538  		t.Logf("%d", h2)
  1539  		h3 := subprocessHash(t, env)
  1540  		t.Logf("%d", h3)
  1541  
  1542  		if h1 == h2 && h2 == h3 {
  1543  			t.Errorf("got duplicate hash %d want unique", h1)
  1544  		}
  1545  	})
  1546  }
  1547  

View as plain text