github.com/ugorji/go/codec@v1.2.13-0.20240307214044-07c54c229a5a/helper_unsafe_compiler_gc.go (about) 1 // Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved. 2 // Use of this source code is governed by a MIT license found in the LICENSE file. 3 4 //go:build !safe && !codec.safe && !appengine && go1.9 && gc 5 // +build !safe,!codec.safe,!appengine,go1.9,gc 6 7 package codec 8 9 import ( 10 "reflect" 11 _ "runtime" // needed for go linkname(s) 12 "unsafe" 13 ) 14 15 // keep in sync with 16 // 17 // $GOROOT/src/cmd/compile/internal/gc/reflect.go: MAXKEYSIZE, MAXELEMSIZE 18 // $GOROOT/src/runtime/map.go: maxKeySize, maxElemSize 19 // $GOROOT/src/reflect/type.go: maxKeySize, maxElemSize 20 // 21 // We use these to determine whether the type is stored indirectly in the map or not. 22 const ( 23 // mapMaxKeySize = 128 24 mapMaxElemSize = 128 25 ) 26 27 func unsafeGrowslice(typ unsafe.Pointer, old unsafeSlice, cap, incr int) (v unsafeSlice) { 28 return growslice(typ, old, cap+incr) 29 } 30 31 // func rvType(rv reflect.Value) reflect.Type { 32 // return rvPtrToType(((*unsafeReflectValue)(unsafe.Pointer(&rv))).typ) 33 // // return rv.Type() 34 // } 35 36 // mapStoresElemIndirect tells if the element type is stored indirectly in the map. 37 // 38 // This is used to determine valIsIndirect which is passed into mapSet/mapGet calls. 39 // 40 // If valIsIndirect doesn't matter, then just return false and ignore the value 41 // passed in mapGet/mapSet calls 42 func mapStoresElemIndirect(elemsize uintptr) bool { 43 return elemsize > mapMaxElemSize 44 } 45 46 func mapSet(m, k, v reflect.Value, keyFastKind mapKeyFastKind, valIsIndirect, valIsRef bool) { 47 var urv = (*unsafeReflectValue)(unsafe.Pointer(&k)) 48 var kptr = unsafeMapKVPtr(urv) 49 urv = (*unsafeReflectValue)(unsafe.Pointer(&v)) 50 var vtyp = urv.typ 51 var vptr = unsafeMapKVPtr(urv) 52 53 urv = (*unsafeReflectValue)(unsafe.Pointer(&m)) 54 mptr := rvRefPtr(urv) 55 56 var vvptr unsafe.Pointer 57 58 // mapassign_fastXXX don't take indirect into account. 59 // It was hard to infer what makes it work all the time. 60 // Sometimes, we got vvptr == nil when we dereferenced vvptr (if valIsIndirect). 61 // Consequently, only use fastXXX functions if !valIsIndirect 62 63 if valIsIndirect { 64 vvptr = mapassign(urv.typ, mptr, kptr) 65 typedmemmove(vtyp, vvptr, vptr) 66 // reflect_mapassign(urv.typ, mptr, kptr, vptr) 67 return 68 } 69 70 switch keyFastKind { 71 case mapKeyFastKind32: 72 vvptr = mapassign_fast32(urv.typ, mptr, *(*uint32)(kptr)) 73 case mapKeyFastKind32ptr: 74 vvptr = mapassign_fast32ptr(urv.typ, mptr, *(*unsafe.Pointer)(kptr)) 75 case mapKeyFastKind64: 76 vvptr = mapassign_fast64(urv.typ, mptr, *(*uint64)(kptr)) 77 case mapKeyFastKind64ptr: 78 vvptr = mapassign_fast64ptr(urv.typ, mptr, *(*unsafe.Pointer)(kptr)) 79 case mapKeyFastKindStr: 80 vvptr = mapassign_faststr(urv.typ, mptr, *(*string)(kptr)) 81 default: 82 vvptr = mapassign(urv.typ, mptr, kptr) 83 } 84 85 // if keyFastKind != 0 && valIsIndirect { 86 // vvptr = *(*unsafe.Pointer)(vvptr) 87 // } 88 89 typedmemmove(vtyp, vvptr, vptr) 90 } 91 92 func mapGet(m, k, v reflect.Value, keyFastKind mapKeyFastKind, valIsIndirect, valIsRef bool) (_ reflect.Value) { 93 var urv = (*unsafeReflectValue)(unsafe.Pointer(&k)) 94 var kptr = unsafeMapKVPtr(urv) 95 urv = (*unsafeReflectValue)(unsafe.Pointer(&m)) 96 mptr := rvRefPtr(urv) 97 98 var vvptr unsafe.Pointer 99 var ok bool 100 101 // Note that mapaccess2_fastXXX functions do not check if the value needs to be copied. 102 // if they do, we should dereference the pointer and return that 103 104 switch keyFastKind { 105 case mapKeyFastKind32, mapKeyFastKind32ptr: 106 vvptr, ok = mapaccess2_fast32(urv.typ, mptr, *(*uint32)(kptr)) 107 case mapKeyFastKind64, mapKeyFastKind64ptr: 108 vvptr, ok = mapaccess2_fast64(urv.typ, mptr, *(*uint64)(kptr)) 109 case mapKeyFastKindStr: 110 vvptr, ok = mapaccess2_faststr(urv.typ, mptr, *(*string)(kptr)) 111 default: 112 vvptr, ok = mapaccess2(urv.typ, mptr, kptr) 113 } 114 115 if !ok { 116 return 117 } 118 119 urv = (*unsafeReflectValue)(unsafe.Pointer(&v)) 120 121 if keyFastKind != 0 && valIsIndirect { 122 urv.ptr = *(*unsafe.Pointer)(vvptr) 123 } else if helperUnsafeDirectAssignMapEntry || valIsRef { 124 urv.ptr = vvptr 125 } else { 126 typedmemmove(urv.typ, urv.ptr, vvptr) 127 } 128 129 return v 130 } 131 132 //go:linkname unsafeZeroArr runtime.zeroVal 133 var unsafeZeroArr [1024]byte 134 135 // //go:linkname rvPtrToType reflect.toType 136 // //go:noescape 137 // func rvPtrToType(typ unsafe.Pointer) reflect.Type 138 139 //go:linkname mapassign_fast32 runtime.mapassign_fast32 140 //go:noescape 141 func mapassign_fast32(typ unsafe.Pointer, m unsafe.Pointer, key uint32) unsafe.Pointer 142 143 //go:linkname mapassign_fast32ptr runtime.mapassign_fast32ptr 144 //go:noescape 145 func mapassign_fast32ptr(typ unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer 146 147 //go:linkname mapassign_fast64 runtime.mapassign_fast64 148 //go:noescape 149 func mapassign_fast64(typ unsafe.Pointer, m unsafe.Pointer, key uint64) unsafe.Pointer 150 151 //go:linkname mapassign_fast64ptr runtime.mapassign_fast64ptr 152 //go:noescape 153 func mapassign_fast64ptr(typ unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer 154 155 //go:linkname mapassign_faststr runtime.mapassign_faststr 156 //go:noescape 157 func mapassign_faststr(typ unsafe.Pointer, m unsafe.Pointer, s string) unsafe.Pointer 158 159 //go:linkname mapaccess2_fast32 runtime.mapaccess2_fast32 160 //go:noescape 161 func mapaccess2_fast32(typ unsafe.Pointer, m unsafe.Pointer, key uint32) (val unsafe.Pointer, ok bool) 162 163 //go:linkname mapaccess2_fast64 runtime.mapaccess2_fast64 164 //go:noescape 165 func mapaccess2_fast64(typ unsafe.Pointer, m unsafe.Pointer, key uint64) (val unsafe.Pointer, ok bool) 166 167 //go:linkname mapaccess2_faststr runtime.mapaccess2_faststr 168 //go:noescape 169 func mapaccess2_faststr(typ unsafe.Pointer, m unsafe.Pointer, key string) (val unsafe.Pointer, ok bool)