mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
mapiterinit allows external linkname. These users must allocate their own iter struct for initialization by mapiterinit. Since the type is unexported, they also must define the struct themselves. As a result, they of course define the struct matching the old hiter definition (in map_noswiss.go). The old definition is smaller on 32-bit platforms. On those platforms, mapiternext will clobber memory outside of the caller's allocation. On all platforms, the pointer layout between the old hiter and new maps.Iter does not match. Thus the GC may miss pointers and free reachable objects early, or it may see non-pointers that look like heap pointers and throw due to invalid references to free objects. To avoid these issues, we must keep mapiterinit and mapiternext with the old hiter definition. The most straightforward way to do this is to use mapiterinit and mapiternext as a compatibility layer between the old and new iter types. The first step to that is to move normal map use off of these functions, which is what this CL does. Introduce new mapIterStart and mapIterNext functions that replace the former functions everywhere in the toolchain. These have the same behavior as the old functions. This CL temporarily makes the old functions throw to ensure we don't have hidden dependencies on them. We cannot remove them entirely because GOEXPERIMENT=noswissmap still uses the old names, and internal/goobj requires all builtins to exist regardless of GOEXPERIMENT. The next CL will introduce the compatibility layer. I want to avoid using linkname between runtime and reflect, as that would also allow external linknames. So mapIterStart and mapIterNext are duplicated in reflect, which can be done trivially, as it imports internal/runtime/maps. For #71408. Change-Id: I6a6a636c6d4bd1392618c67ca648d3f061afe669 Reviewed-on: https://go-review.googlesource.com/c/go/+/643898 Auto-Submit: Michael Pratt <mpratt@google.com> Reviewed-by: Keith Randall <khr@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@golang.org>
202 lines
3.7 KiB
Go
202 lines
3.7 KiB
Go
// asmcheck
|
|
|
|
// Copyright 2018 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 codegen
|
|
|
|
// This file contains code generation tests related to the handling of
|
|
// map types.
|
|
|
|
// ------------------- //
|
|
// Access Const //
|
|
// ------------------- //
|
|
|
|
// Direct use of constants in fast map access calls (Issue #19015).
|
|
|
|
func AccessInt1(m map[int]int) int {
|
|
// amd64:"MOV[LQ]\t[$]5"
|
|
return m[5]
|
|
}
|
|
|
|
func AccessInt2(m map[int]int) bool {
|
|
// amd64:"MOV[LQ]\t[$]5"
|
|
_, ok := m[5]
|
|
return ok
|
|
}
|
|
|
|
func AccessString1(m map[string]int) int {
|
|
// amd64:`.*"abc"`
|
|
return m["abc"]
|
|
}
|
|
|
|
func AccessString2(m map[string]int) bool {
|
|
// amd64:`.*"abc"`
|
|
_, ok := m["abc"]
|
|
return ok
|
|
}
|
|
|
|
// ------------------- //
|
|
// String Conversion //
|
|
// ------------------- //
|
|
|
|
func LookupStringConversionSimple(m map[string]int, bytes []byte) int {
|
|
// amd64:-`.*runtime\.slicebytetostring\(`
|
|
return m[string(bytes)]
|
|
}
|
|
|
|
func LookupStringConversionStructLit(m map[struct{ string }]int, bytes []byte) int {
|
|
// amd64:-`.*runtime\.slicebytetostring\(`
|
|
return m[struct{ string }{string(bytes)}]
|
|
}
|
|
|
|
func LookupStringConversionArrayLit(m map[[2]string]int, bytes []byte) int {
|
|
// amd64:-`.*runtime\.slicebytetostring\(`
|
|
return m[[2]string{string(bytes), string(bytes)}]
|
|
}
|
|
|
|
func LookupStringConversionNestedLit(m map[[1]struct{ s [1]string }]int, bytes []byte) int {
|
|
// amd64:-`.*runtime\.slicebytetostring\(`
|
|
return m[[1]struct{ s [1]string }{struct{ s [1]string }{s: [1]string{string(bytes)}}}]
|
|
}
|
|
|
|
func LookupStringConversionKeyedArrayLit(m map[[2]string]int, bytes []byte) int {
|
|
// amd64:-`.*runtime\.slicebytetostring\(`
|
|
return m[[2]string{0: string(bytes)}]
|
|
}
|
|
|
|
// ------------------- //
|
|
// Map Clear //
|
|
// ------------------- //
|
|
|
|
// Optimization of map clear idiom (Issue #20138).
|
|
|
|
func MapClearReflexive(m map[int]int) {
|
|
// amd64:`.*runtime\.mapclear`
|
|
// amd64:-`.*runtime\.(mapiterinit|mapIterStart)`
|
|
for k := range m {
|
|
delete(m, k)
|
|
}
|
|
}
|
|
|
|
func MapClearIndirect(m map[int]int) {
|
|
s := struct{ m map[int]int }{m: m}
|
|
// amd64:`.*runtime\.mapclear`
|
|
// amd64:-`.*runtime\.(mapiterinit|mapIterStart)`
|
|
for k := range s.m {
|
|
delete(s.m, k)
|
|
}
|
|
}
|
|
|
|
func MapClearPointer(m map[*byte]int) {
|
|
// amd64:`.*runtime\.mapclear`
|
|
// amd64:-`.*runtime\.(mapiterinit|mapIterStart)`
|
|
for k := range m {
|
|
delete(m, k)
|
|
}
|
|
}
|
|
|
|
func MapClearNotReflexive(m map[float64]int) {
|
|
// amd64:`.*runtime\.(mapiterinit|mapIterStart)`
|
|
// amd64:-`.*runtime\.mapclear`
|
|
for k := range m {
|
|
delete(m, k)
|
|
}
|
|
}
|
|
|
|
func MapClearInterface(m map[interface{}]int) {
|
|
// amd64:`.*runtime\.(mapiterinit|mapIterStart)`
|
|
// amd64:-`.*runtime\.mapclear`
|
|
for k := range m {
|
|
delete(m, k)
|
|
}
|
|
}
|
|
|
|
func MapClearSideEffect(m map[int]int) int {
|
|
k := 0
|
|
// amd64:`.*runtime\.(mapiterinit|mapIterStart)`
|
|
// amd64:-`.*runtime\.mapclear`
|
|
for k = range m {
|
|
delete(m, k)
|
|
}
|
|
return k
|
|
}
|
|
|
|
func MapLiteralSizing(x int) (map[int]int, map[int]int) {
|
|
// This is tested for internal/abi/maps.go:MapBucketCountBits={3,4,5}
|
|
// amd64:"MOVL\t[$]33,"
|
|
m := map[int]int{
|
|
0: 0,
|
|
1: 1,
|
|
2: 2,
|
|
3: 3,
|
|
4: 4,
|
|
5: 5,
|
|
6: 6,
|
|
7: 7,
|
|
8: 8,
|
|
9: 9,
|
|
10: 10,
|
|
11: 11,
|
|
12: 12,
|
|
13: 13,
|
|
14: 14,
|
|
15: 15,
|
|
16: 16,
|
|
17: 17,
|
|
18: 18,
|
|
19: 19,
|
|
20: 20,
|
|
21: 21,
|
|
22: 22,
|
|
23: 23,
|
|
24: 24,
|
|
25: 25,
|
|
26: 26,
|
|
27: 27,
|
|
28: 28,
|
|
29: 29,
|
|
30: 30,
|
|
31: 32,
|
|
32: 32,
|
|
}
|
|
// amd64:"MOVL\t[$]33,"
|
|
n := map[int]int{
|
|
0: 0,
|
|
1: 1,
|
|
2: 2,
|
|
3: 3,
|
|
4: 4,
|
|
5: 5,
|
|
6: 6,
|
|
7: 7,
|
|
8: 8,
|
|
9: 9,
|
|
10: 10,
|
|
11: 11,
|
|
12: 12,
|
|
13: 13,
|
|
14: 14,
|
|
15: 15,
|
|
16: 16,
|
|
17: 17,
|
|
18: 18,
|
|
19: 19,
|
|
20: 20,
|
|
21: 21,
|
|
22: 22,
|
|
23: 23,
|
|
24: 24,
|
|
25: 25,
|
|
26: 26,
|
|
27: 27,
|
|
28: 28,
|
|
29: 29,
|
|
30: 30,
|
|
31: 32,
|
|
32: 32,
|
|
}
|
|
return m, n
|
|
}
|