Source file src/runtime/linkname_shim.go

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

View as plain text