...

Source file src/runtime/linkname_swiss.go

Documentation: runtime

     1  // Copyright 2025 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  //go:build goexperiment.swissmap
     6  
     7  package runtime
     8  
     9  import (
    10  	"internal/abi"
    11  	"internal/runtime/maps"
    12  	"internal/runtime/sys"
    13  	"unsafe"
    14  )
    15  
    16  // Legacy //go:linkname compatibility shims
    17  //
    18  // The functions below are unused by the toolchain, and exist only for
    19  // compatibility with existing //go:linkname use in the ecosystem (and in
    20  // map_noswiss.go for normal use via GOEXPERIMENT=noswissmap).
    21  
    22  // linknameIter is the it argument to mapiterinit and mapiternext.
    23  //
    24  // Callers of mapiterinit allocate their own iter structure, which has the
    25  // layout of the pre-Go 1.24 hiter structure, shown here for posterity:
    26  //
    27  //	type hiter struct {
    28  //		key         unsafe.Pointer
    29  //		elem        unsafe.Pointer
    30  //		t           *maptype
    31  //		h           *hmap
    32  //		buckets     unsafe.Pointer
    33  //		bptr        *bmap
    34  //		overflow    *[]*bmap
    35  //		oldoverflow *[]*bmap
    36  //		startBucket uintptr
    37  //		offset      uint8
    38  //		wrapped     bool
    39  //		B           uint8
    40  //		i           uint8
    41  //		bucket      uintptr
    42  //		checkBucket uintptr
    43  //	}
    44  //
    45  // Our structure must maintain compatibility with the old structure. This
    46  // means:
    47  //
    48  //   - Our structure must be the same size or smaller than hiter. Otherwise we
    49  //     may write outside the caller's hiter allocation.
    50  //   - Our structure must have the same pointer layout as hiter, so that the GC
    51  //     tracks pointers properly.
    52  //
    53  // Based on analysis of the "hall of shame" users of these linknames:
    54  //
    55  //   - The key and elem fields must be kept up to date with the current key/elem.
    56  //     Some users directly access the key and elem fields rather than calling
    57  //     reflect.mapiterkey/reflect.mapiterelem.
    58  //   - The t field must be non-nil after mapiterinit. gonum.org/v1/gonum uses
    59  //     this to verify the iterator is initialized.
    60  //   - github.com/segmentio/encoding and github.com/RomiChan/protobuf check if h
    61  //     is non-nil, but the code has no effect. Thus the value of h does not
    62  //     matter. See internal/runtime_reflect/map.go.
    63  type linknameIter struct {
    64  	// Fields from hiter.
    65  	key  unsafe.Pointer
    66  	elem unsafe.Pointer
    67  	typ  *abi.SwissMapType
    68  
    69  	// The real iterator.
    70  	it *maps.Iter
    71  }
    72  
    73  // mapiterinit is a compatibility wrapper for map iterator for users of
    74  // //go:linkname from before Go 1.24. It is not used by Go itself. New users
    75  // should use reflect or the maps package.
    76  //
    77  // mapiterinit should be an internal detail,
    78  // but widely used packages access it using linkname.
    79  // Notable members of the hall of shame include:
    80  //   - github.com/bytedance/sonic
    81  //   - github.com/goccy/go-json
    82  //   - github.com/RomiChan/protobuf
    83  //   - github.com/segmentio/encoding
    84  //   - github.com/ugorji/go/codec
    85  //   - github.com/wI2L/jettison
    86  //
    87  // Do not remove or change the type signature.
    88  // See go.dev/issue/67401.
    89  //
    90  //go:linkname mapiterinit
    91  func mapiterinit(t *abi.SwissMapType, m *maps.Map, it *linknameIter) {
    92  	if raceenabled && m != nil {
    93  		callerpc := sys.GetCallerPC()
    94  		racereadpc(unsafe.Pointer(m), callerpc, abi.FuncPCABIInternal(mapiterinit))
    95  	}
    96  
    97  	it.typ = t
    98  
    99  	it.it = new(maps.Iter)
   100  	it.it.Init(t, m)
   101  	it.it.Next()
   102  
   103  	it.key = it.it.Key()
   104  	it.elem = it.it.Elem()
   105  }
   106  
   107  // reflect_mapiterinit is a compatibility wrapper for map iterator for users of
   108  // //go:linkname from before Go 1.24. It is not used by Go itself. New users
   109  // should use reflect or the maps package.
   110  //
   111  // reflect_mapiterinit should be an internal detail,
   112  // but widely used packages access it using linkname.
   113  // Notable members of the hall of shame include:
   114  //   - github.com/modern-go/reflect2
   115  //   - gitee.com/quant1x/gox
   116  //   - github.com/v2pro/plz
   117  //   - github.com/wI2L/jettison
   118  //
   119  // Do not remove or change the type signature.
   120  // See go.dev/issue/67401.
   121  //
   122  //go:linkname reflect_mapiterinit reflect.mapiterinit
   123  func reflect_mapiterinit(t *abi.SwissMapType, m *maps.Map, it *linknameIter) {
   124  	mapiterinit(t, m, it)
   125  }
   126  
   127  // mapiternext is a compatibility wrapper for map iterator for users of
   128  // //go:linkname from before Go 1.24. It is not used by Go itself. New users
   129  // should use reflect or the maps package.
   130  //
   131  // mapiternext should be an internal detail,
   132  // but widely used packages access it using linkname.
   133  // Notable members of the hall of shame include:
   134  //   - github.com/bytedance/sonic
   135  //   - github.com/RomiChan/protobuf
   136  //   - github.com/segmentio/encoding
   137  //   - github.com/ugorji/go/codec
   138  //   - gonum.org/v1/gonum
   139  //
   140  // Do not remove or change the type signature.
   141  // See go.dev/issue/67401.
   142  //
   143  //go:linkname mapiternext
   144  func mapiternext(it *linknameIter) {
   145  	if raceenabled {
   146  		callerpc := sys.GetCallerPC()
   147  		racereadpc(unsafe.Pointer(it.it.Map()), callerpc, abi.FuncPCABIInternal(mapiternext))
   148  	}
   149  
   150  	it.it.Next()
   151  
   152  	it.key = it.it.Key()
   153  	it.elem = it.it.Elem()
   154  }
   155  
   156  // reflect_mapiternext is a compatibility wrapper for map iterator for users of
   157  // //go:linkname from before Go 1.24. It is not used by Go itself. New users
   158  // should use reflect or the maps package.
   159  //
   160  // reflect_mapiternext is for package reflect,
   161  // but widely used packages access it using linkname.
   162  // Notable members of the hall of shame include:
   163  //   - gitee.com/quant1x/gox
   164  //   - github.com/modern-go/reflect2
   165  //   - github.com/goccy/go-json
   166  //   - github.com/v2pro/plz
   167  //   - github.com/wI2L/jettison
   168  //
   169  // Do not remove or change the type signature.
   170  // See go.dev/issue/67401.
   171  //
   172  //go:linkname reflect_mapiternext reflect.mapiternext
   173  func reflect_mapiternext(it *linknameIter) {
   174  	mapiternext(it)
   175  }
   176  
   177  // reflect_mapiterkey is a compatibility wrapper for map iterator for users of
   178  // //go:linkname from before Go 1.24. It is not used by Go itself. New users
   179  // should use reflect or the maps package.
   180  //
   181  // reflect_mapiterkey should be an internal detail,
   182  // but widely used packages access it using linkname.
   183  // Notable members of the hall of shame include:
   184  //   - github.com/goccy/go-json
   185  //   - gonum.org/v1/gonum
   186  //
   187  // Do not remove or change the type signature.
   188  // See go.dev/issue/67401.
   189  //
   190  //go:linkname reflect_mapiterkey reflect.mapiterkey
   191  func reflect_mapiterkey(it *linknameIter) unsafe.Pointer {
   192  	return it.it.Key()
   193  }
   194  
   195  // reflect_mapiterelem is a compatibility wrapper for map iterator for users of
   196  // //go:linkname from before Go 1.24. It is not used by Go itself. New users
   197  // should use reflect or the maps package.
   198  //
   199  // reflect_mapiterelem should be an internal detail,
   200  // but widely used packages access it using linkname.
   201  // Notable members of the hall of shame include:
   202  //   - github.com/goccy/go-json
   203  //   - gonum.org/v1/gonum
   204  //
   205  // Do not remove or change the type signature.
   206  // See go.dev/issue/67401.
   207  //
   208  //go:linkname reflect_mapiterelem reflect.mapiterelem
   209  func reflect_mapiterelem(it *linknameIter) unsafe.Pointer {
   210  	return it.it.Elem()
   211  }
   212  

View as plain text