github.com/phuslu/lru@v1.0.16-0.20240421170520-46288a2fd47c/runtime.go (about)

     1  // Copyright 2024 The Cockroach Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // This file introspects into Go runtime internals. In order to prevent
    16  // accidental breakage when a new version of Go is released we require manual
    17  // bumping of the go versions supported by adjusting the build tags below. The
    18  // way go version tags work the tag for goX.Y will be declared for every
    19  // subsequent release. So go1.18 will be defined for go1.21, go1.22, etc. The
    20  // build tag "go1.18 && !go1.23" defines the range [go1.18, go1.23) (inclusive
    21  // on go1.18, exclusive on go1.23).
    22  
    23  //go:build go1.18 && !go1.23
    24  
    25  package lru
    26  
    27  import (
    28  	"unsafe"
    29  )
    30  
    31  //go:linkname fastrand64 runtime.fastrand64
    32  func fastrand64() uint64
    33  
    34  // getRuntimeHasher peeks inside the internals of map[K]struct{} and extracts
    35  // the function the runtime generated for hashing type K. This is a bit hacky,
    36  // but we can't use hash/maphash as that hashes only bytes and strings. While
    37  // we could use unsafe.{Slice,String} to pass in arbitrary structs we can't
    38  // pass in arbitrary types and have the hash function sometimes hash the type
    39  // memory and sometimes hash underlying.
    40  //
    41  // NOTE(peter): I did try using reflection on the type K to specialize a hash
    42  // function depending on the type's Kind, but that was measurably slower than
    43  // for integer types. This hackiness is quite localized. If it breaks in a
    44  // future Go version we can either repair it or go the reflection route.
    45  //
    46  // https://github.com/dolthub/maphash provided the inspiration and general
    47  // implementation technique.
    48  func getRuntimeHasher[K comparable]() func(key unsafe.Pointer, seed uintptr) uintptr {
    49  	a := any((map[K]struct{})(nil))
    50  	return (*rtEface)(unsafe.Pointer(&a)).typ.Hasher
    51  }
    52  
    53  // From runtime/runtime2.go:eface
    54  type rtEface struct {
    55  	typ  *rtMapType
    56  	data unsafe.Pointer
    57  }
    58  
    59  // From internal/abi/type.go:MapType
    60  type rtMapType struct {
    61  	rtType
    62  	Key    *rtType
    63  	Elem   *rtType
    64  	Bucket *rtType // internal type representing a hash bucket
    65  	// function for hashing keys (ptr to key, seed) -> hash
    66  	Hasher     func(unsafe.Pointer, uintptr) uintptr
    67  	KeySize    uint8  // size of key slot
    68  	ValueSize  uint8  // size of elem slot
    69  	BucketSize uint16 // size of bucket
    70  	Flags      uint32
    71  }
    72  
    73  type rtTFlag uint8
    74  type rtNameOff int32
    75  type rtTypeOff int32
    76  
    77  // From internal/abi/type.go:Type
    78  type rtType struct {
    79  	Size_       uintptr
    80  	PtrBytes    uintptr // number of (prefix) bytes in the type that can contain pointers
    81  	Hash        uint32  // hash of type; avoids computation in hash tables
    82  	TFlag       rtTFlag // extra type information flags
    83  	Align_      uint8   // alignment of variable with this type
    84  	FieldAlign_ uint8   // alignment of struct field with this type
    85  	Kind_       uint8   // enumeration for C
    86  	// function for comparing objects of this type
    87  	// (ptr to object A, ptr to object B) -> ==?
    88  	Equal func(unsafe.Pointer, unsafe.Pointer) bool
    89  	// GCData stores the GC type data for the garbage collector.
    90  	// If the KindGCProg bit is set in kind, GCData is a GC program.
    91  	// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
    92  	GCData    *byte
    93  	Str       rtNameOff // string form
    94  	PtrToThis rtTypeOff // type for pointer to this type, may be zero
    95  }
    96  
    97  // noescape hides a pointer from escape analysis.  noescape is
    98  // the identity function but escape analysis doesn't think the
    99  // output depends on the input.  noescape is inlined and currently
   100  // compiles down to zero instructions.
   101  // USE CAREFULLY!
   102  //
   103  //go:nosplit
   104  //go:nocheckptr
   105  func noescape(p unsafe.Pointer) unsafe.Pointer {
   106  	x := uintptr(p)
   107  	return unsafe.Pointer(x ^ 0)
   108  }
   109  
   110  func b2s(b []byte) string {
   111  	return *(*string)(unsafe.Pointer(&b))
   112  }