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