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 }